fix(web): support service worker notifications in PWAs (#1025)
* fix(web): support service worker notifications in PWAs * fix(web): skip service worker wait without registration --------- Co-authored-by: vhqtvn <8930337+vhqtvn@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
vhqtvn
parent
8cce0b4c7b
commit
33b1b67514
@@ -1,5 +1,59 @@
|
|||||||
import type { NotificationPayload, NotificationsAPI } from '@openchamber/ui/lib/api/types';
|
import type { NotificationPayload, NotificationsAPI } from '@openchamber/ui/lib/api/types';
|
||||||
|
|
||||||
|
const SW_READY_TIMEOUT_MS = 1500;
|
||||||
|
|
||||||
|
const getNotificationRegistration = async (): Promise<ServiceWorkerRegistration | null> => {
|
||||||
|
if (typeof navigator === 'undefined' || !('serviceWorker' in navigator)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let existing: ServiceWorkerRegistration | null = null;
|
||||||
|
try {
|
||||||
|
existing = (await navigator.serviceWorker.getRegistration()) ?? null;
|
||||||
|
} catch {
|
||||||
|
existing = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing?.active) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ready = await Promise.race<ServiceWorkerRegistration | null>([
|
||||||
|
navigator.serviceWorker.ready,
|
||||||
|
new Promise<null>((resolve) => {
|
||||||
|
setTimeout(() => resolve(null), SW_READY_TIMEOUT_MS);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return ready ?? existing;
|
||||||
|
} catch {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const notifyWithServiceWorker = async (payload?: NotificationPayload): Promise<boolean> => {
|
||||||
|
const registration = await getNotificationRegistration();
|
||||||
|
if (!registration || typeof registration.showNotification !== 'function') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await registration.showNotification(payload?.title ?? 'OpenChamber', {
|
||||||
|
body: payload?.body,
|
||||||
|
tag: payload?.tag,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to send notification via service worker', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const notifyWithWebAPI = async (payload?: NotificationPayload): Promise<boolean> => {
|
const notifyWithWebAPI = async (payload?: NotificationPayload): Promise<boolean> => {
|
||||||
if (typeof Notification === 'undefined') {
|
if (typeof Notification === 'undefined') {
|
||||||
console.info('Notifications not supported in this environment', payload);
|
console.info('Notifications not supported in this environment', payload);
|
||||||
@@ -20,6 +74,12 @@ const notifyWithWebAPI = async (payload?: NotificationPayload): Promise<boolean>
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Some installed PWAs expose Notification.permission but only allow
|
||||||
|
// notifications through an active service worker registration.
|
||||||
|
if (await notifyWithServiceWorker(payload)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
new Notification(payload?.title ?? 'OpenChamber', {
|
new Notification(payload?.title ?? 'OpenChamber', {
|
||||||
body: payload?.body,
|
body: payload?.body,
|
||||||
tag: payload?.tag,
|
tag: payload?.tag,
|
||||||
@@ -58,7 +118,7 @@ const notifyWithTauri = async (payload?: NotificationPayload): Promise<boolean>
|
|||||||
|
|
||||||
export const createWebNotificationsAPI = (): NotificationsAPI => ({
|
export const createWebNotificationsAPI = (): NotificationsAPI => ({
|
||||||
async notifyAgentCompletion(payload?: NotificationPayload): Promise<boolean> {
|
async notifyAgentCompletion(payload?: NotificationPayload): Promise<boolean> {
|
||||||
return (await notifyWithTauri(payload)) || notifyWithWebAPI(payload);
|
return (await notifyWithTauri(payload)) || (await notifyWithWebAPI(payload));
|
||||||
},
|
},
|
||||||
canNotify: () => {
|
canNotify: () => {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
|
|||||||
Reference in New Issue
Block a user