58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
import type { ServiceWorkerEventHost } from "./service-worker-runtime.ts";
|
|
|
|
type NotificationOptions = Parameters<
|
|
ServiceWorkerEventHost["registration"]["showNotification"]
|
|
>[1];
|
|
type MatchAllOptions = Parameters<
|
|
ServiceWorkerEventHost["clients"]["matchAll"]
|
|
>[0];
|
|
|
|
/**
|
|
* Adapts a native Service Worker global scope onto the structural
|
|
* {@link ServiceWorkerEventHost} facade.
|
|
*
|
|
* The native `showNotification` call lives here because `src/adapters/web-push`
|
|
* is the owner of the notification API. The single physical worker entry
|
|
* (§17.1) composes the runtime but never touches the native API itself.
|
|
*/
|
|
|
|
export type NativeWorkerScope = Readonly<{
|
|
location: Readonly<{ origin: string }>;
|
|
registration: Readonly<{
|
|
showNotification(title: string, options: unknown): Promise<void>;
|
|
}>;
|
|
clients: Readonly<{
|
|
matchAll(options: unknown): Promise<readonly unknown[]>;
|
|
openWindow(url: string): Promise<unknown>;
|
|
}>;
|
|
// Deliberately loose: a native scope declares a richly overloaded listener
|
|
// signature, and this facade only needs to forward the registration.
|
|
addEventListener(type: string, listener: never, options?: never): void;
|
|
removeEventListener(type: string, listener: never, options?: never): void;
|
|
}>;
|
|
|
|
export function createServiceWorkerScopeHost(
|
|
scope: NativeWorkerScope,
|
|
): ServiceWorkerEventHost {
|
|
return Object.freeze({
|
|
origin: scope.location.origin,
|
|
registration: Object.freeze({
|
|
showNotification: (title: string, options: NotificationOptions) =>
|
|
scope.registration.showNotification(title, {
|
|
body: options.body,
|
|
data: options.data,
|
|
requireInteraction: options.requireInteraction,
|
|
tag: options.tag,
|
|
}),
|
|
}),
|
|
clients: Object.freeze({
|
|
matchAll: (options: MatchAllOptions) => scope.clients.matchAll(options),
|
|
openWindow: (url: string) => scope.clients.openWindow(url),
|
|
}),
|
|
addEventListener: (type, listener) =>
|
|
scope.addEventListener(type, listener as never),
|
|
removeEventListener: (type, listener) =>
|
|
scope.removeEventListener(type, listener as never),
|
|
});
|
|
}
|