MiniSearch / client /modules /notifications.ts
github-actions[bot]
Sync from https://github.com/felladrin/MiniSearch
6c3af4e
Raw History Blame Contribute Delete
1.95 kB
import { addLogEntry } from "./logEntries";
const MAX_NOTIFICATION_QUERY_LENGTH = 100;
export const REQUEST_PERMISSION_TIMEOUT_MS = 8000;
/**
* Requests permission to show browser notifications. Some browsers can
* silently never resolve this request (e.g. Brave has been observed doing
* this on localhost), so it falls back to "default" after a timeout instead
* of leaving the caller waiting forever.
*/
export async function requestNotificationPermission(): Promise<NotificationPermission> {
if (!("Notification" in window)) {
return "denied";
}
if (Notification.permission === "granted") {
return "granted";
}
if (Notification.permission === "denied") {
return "denied";
}
return new Promise((resolve) => {
const timeoutId = setTimeout(
() => resolve("default"),
REQUEST_PERMISSION_TIMEOUT_MS,
);
Notification.requestPermission().then((permission) => {
clearTimeout(timeoutId);
resolve(permission);
});
});
}
/**
* Shows a browser notification that the AI answer is ready, unless this page
* already has the focus.
*/
export function showAiCompleteNotification(query: string) {
if (!("Notification" in window)) {
return;
}
if (Notification.permission !== "granted") {
return;
}
if (document.hasFocus()) {
return;
}
const truncatedQuery =
query.length > MAX_NOTIFICATION_QUERY_LENGTH
? `${query.slice(0, MAX_NOTIFICATION_QUERY_LENGTH)}โ€ฆ`
: query;
try {
const notification = new Notification(truncatedQuery, {
body: "AI response is ready on MiniSearch.",
icon: "/favicon.png",
tag: "ai-complete",
requireInteraction: false,
});
notification.onclick = () => {
window.focus();
notification.close();
};
} catch (error) {
addLogEntry(
`Failed to show AI-complete notification: ${error instanceof Error ? error.message : String(error)}`,
);
}
}