@vite-pwa/workbox-window
Version:
Simplifies communications with Workbox packages running in the service worker
374 lines (368 loc) • 17.1 kB
TypeScript
import { TrustedScriptURL } from 'trusted-types/lib';
/**
* Sends a data object to a service worker via `postMessage` and resolves with
* a response (if any).
*
* A response can be set in a message handler in the service worker by
* calling `event.ports[0].postMessage(...)`, which will resolve the promise
* returned by `messageSW()`. If no response is set, the promise will not
* resolve.
*
* @param {ServiceWorker} sw The service worker to send the message to.
* @param {object} data An object to send to the service worker.
* @return {Promise<object | undefined>}
*/
declare function messageSW(sw: ServiceWorker, data: any): Promise<unknown>;
/**
* A minimal `Event` subclass shim.
* This doesn't *actually* subclass `Event` because not all browsers support
* constructable `EventTarget`, and using a real `Event` will error.
* @private
*/
declare class WorkboxEvent<K extends keyof WorkboxEventMap> {
type: K;
target?: WorkboxEventTarget;
sw?: ServiceWorker;
originalEvent?: Event;
isExternal?: boolean;
constructor(type: K, props: Omit<WorkboxEventMap[K], 'target' | 'type'>);
}
interface WorkboxMessageEvent extends WorkboxEvent<'message'> {
data: any;
originalEvent: Event;
ports: readonly MessagePort[];
}
interface WorkboxLifecycleEvent extends WorkboxEvent<keyof WorkboxLifecycleEventMap> {
isUpdate?: boolean;
}
interface WorkboxLifecycleWaitingEvent extends WorkboxLifecycleEvent {
wasWaitingBeforeRegister?: boolean;
}
interface WorkboxLifecycleEventMap {
/**
* The `installing` event is dispatched if the service-worker
* find the new version and start installing.
*
* @event workbox-window.Workbox#installing
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The installing service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {string} type `installing`.
* @property {Workbox} target The `Workbox` instance.
*/
installing: WorkboxLifecycleEvent;
/**
* The `installed` event is dispatched if the state of a
* {@link workbox-window.Workbox} instance's
* {@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw|registered service worker}
* changes to `installed`.
*
* Then can happen either the very first time a service worker is installed,
* or after an update to the current service worker is found. In the case
* of an update being found, the event's `isUpdate` property will be `true`.
*
* @event workbox-window.Workbox#installed
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {boolean|undefined} isExternal True if this event is associated
* with an [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}.
* @property {string} type `installed`.
* @property {Workbox} target The `Workbox` instance.
*/
installed: WorkboxLifecycleEvent;
/**
* The `waiting` event is dispatched if the state of a
* {@link workbox-window.Workbox} instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}
* changes to `installed` and then doesn't immediately change to `activating`.
* It may also be dispatched if a service worker with the same
* [`scriptURL`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/scriptURL}
* was already waiting when the {@link workbox-window.Workbox#register}
* method was called.
*
* @event workbox-window.Workbox#waiting
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event|undefined} originalEvent The original
* [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event, or `undefined` in the case where the service worker was waiting
* to before `.register()` was called.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {boolean|undefined} isExternal True if this event is associated
* with an [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}.
* @property {boolean|undefined} wasWaitingBeforeRegister True if a service worker with
* a matching `scriptURL` was already waiting when this `Workbox`
* instance called `register()`.
* @property {string} type `waiting`.
* @property {Workbox} target The `Workbox` instance.
*/
waiting: WorkboxLifecycleWaitingEvent;
activating: WorkboxLifecycleEvent;
/**
* The `activated` event is dispatched if the state of a
* {@link workbox-window.Workbox} instance's
* {@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw|registered service worker}
* changes to `activated`.
*
* @event workbox-window.Workbox#activated
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {boolean|undefined} isExternal True if this event is associated
* with an [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}.
* @property {string} type `activated`.
* @property {Workbox} target The `Workbox` instance.
*/
activated: WorkboxLifecycleEvent;
/**
* The `controlling` event is dispatched if a
* [`controllerchange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/oncontrollerchange}
* fires on the service worker [container]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer}
* and the [`scriptURL`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/scriptURL}
* of the new [controller]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/controller}
* matches the `scriptURL` of the `Workbox` instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}.
*
* @event workbox-window.Workbox#controlling
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`controllerchange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/oncontrollerchange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this service worker was registered.
* @property {boolean|undefined} isExternal True if this event is associated
* with an [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}.
* @property {string} type `controlling`.
* @property {Workbox} target The `Workbox` instance.
*/
controlling: WorkboxLifecycleEvent;
/**
* The `redundant` event is dispatched if the state of a
* {@link workbox-window.Workbox} instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}
* changes to `redundant`.
*
* @event workbox-window.Workbox#redundant
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {string} type `redundant`.
* @property {Workbox} target The `Workbox` instance.
*/
redundant: WorkboxLifecycleEvent;
}
interface WorkboxEventMap extends WorkboxLifecycleEventMap {
/**
* The `message` event is dispatched any time a `postMessage` is received.
*
* @event workbox-window.Workbox#message
* @type {WorkboxEvent}
* @property {*} data The `data` property from the original `message` event.
* @property {Event} originalEvent The original [`message`]{@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent}
* event.
* @property {string} type `message`.
* @property {MessagePort[]} ports The `ports` value from `originalEvent`.
* @property {Workbox} target The `Workbox` instance.
*/
message: WorkboxMessageEvent;
}
/**
* A minimal `EventTarget` shim.
* This is necessary because not all browsers support constructable
* `EventTarget`, so using a real `EventTarget` will error.
* @private
*/
declare class WorkboxEventTarget {
private readonly _eventListenerRegistry;
/**
* @param {string} type
* @param {Function} listener
* @private
*/
addEventListener<K extends keyof WorkboxEventMap>(type: K, listener: (event: WorkboxEventMap[K]) => any): void;
/**
* @param {string} type
* @param {Function} listener
* @private
*/
removeEventListener<K extends keyof WorkboxEventMap>(type: K, listener: (event: WorkboxEventMap[K]) => any): void;
/**
* @param {object} event
* @private
*/
dispatchEvent(event: WorkboxEvent<any>): void;
/**
* Returns a Set of listeners associated with the passed event type.
* If no handlers have been registered, an empty Set is returned.
*
* @param {string} type The event type.
* @return {Set<ListenerCallback>} An array of handler functions.
* @private
*/
private _getEventListenersByType;
}
/**
* A class to aid in handling service worker registration, updates, and
* reacting to service worker lifecycle events.
*
* @fires WorkboxEventMap#message
* @fires WorkboxLifecycleEventMap#installing
* @fires WorkboxLifecycleEventMap#installed
* @fires WorkboxLifecycleEventMap#waiting
* @fires WorkboxLifecycleEventMap#controlling
* @fires WorkboxLifecycleEventMap#activated
* @fires WorkboxLifecycleEventMap#redundant
*/
declare class Workbox extends WorkboxEventTarget {
private readonly _scriptURL;
private readonly _registerOptions;
private _updateFoundCount;
private readonly _swDeferred;
private readonly _activeDeferred;
private readonly _controllingDeferred;
private _registrationTime;
private _isUpdate?;
private _compatibleControllingSW?;
private _registration?;
private _sw?;
private readonly _ownSWs;
private _externalSW?;
private _waitingTimeout?;
/**
* Creates a new Workbox instance with a script URL and service worker
* options. The script URL and options are the same as those used when
* calling [navigator.serviceWorker.register(scriptURL, options)](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register).
*
* @param {string|TrustedScriptURL} scriptURL The service worker script
* associated with this instance. Using a
* [`TrustedScriptURL`](https://web.dev/trusted-types/) is supported.
* @param {object} [registerOptions] The service worker options associated
* with this instance.
*/
constructor(scriptURL: string | TrustedScriptURL, registerOptions?: {});
/**
* Registers a service worker for this instances script URL and service
* worker options. By default this method delays registration until after
* the window has loaded.
*
* @param {object} [options]
* @param {Function} [options.immediate] Setting this to true will
* register the service worker immediately, even if the window has
* not loaded (not recommended).
*/
register({ immediate }?: {
immediate?: boolean | undefined;
}): Promise<ServiceWorkerRegistration | undefined>;
/**
* Checks for updates of the registered service worker.
*/
update(): Promise<void>;
/**
* Resolves to the service worker registered by this instance as soon as it
* is active. If a service worker was already controlling at registration
* time then it will resolve to that if the script URLs (and optionally
* script versions) match, otherwise it will wait until an update is found
* and activates.
*
* @return {Promise<ServiceWorker>}
*/
get active(): Promise<ServiceWorker>;
/**
* Resolves to the service worker registered by this instance as soon as it
* is controlling the page. If a service worker was already controlling at
* registration time then it will resolve to that if the script URLs (and
* optionally script versions) match, otherwise it will wait until an update
* is found and starts controlling the page.
* Note: the first time a service worker is installed it will active but
* not start controlling the page unless `clients.claim()` is called in the
* service worker.
*
* @return {Promise<ServiceWorker>}
*/
get controlling(): Promise<ServiceWorker>;
/**
* Resolves with a reference to a service worker that matches the script URL
* of this instance, as soon as it's available.
*
* If, at registration time, there's already an active or waiting service
* worker with a matching script URL, it will be used (with the waiting
* service worker taking precedence over the active service worker if both
* match, since the waiting service worker would have been registered more
* recently).
* If there's no matching active or waiting service worker at registration
* time then the promise will not resolve until an update is found and starts
* installing, at which point the installing service worker is used.
*
* @return {Promise<ServiceWorker>}
*/
getSW(): Promise<ServiceWorker>;
/**
* Sends the passed data object to the service worker registered by this
* instance (via {@link workbox-window.Workbox#getSW}) and resolves
* with a response (if any).
*
* A response can be set in a message handler in the service worker by
* calling `event.ports[0].postMessage(...)`, which will resolve the promise
* returned by `messageSW()`. If no response is set, the promise will never
* resolve.
*
* @param {object} data An object to send to the service worker
* @return {Promise<object>}
*/
messageSW(data: object): Promise<any>;
/**
* Sends a `{type: 'SKIP_WAITING'}` message to the service worker that's
* currently in the `waiting` state associated with the current registration.
*
* If there is no current registration or no service worker is `waiting`,
* calling this will have no effect.
*/
messageSkipWaiting(): void;
/**
* Checks for a service worker already controlling the page and returns
* it if its script URL matches.
*
* @private
* @return {ServiceWorker|undefined}
*/
private _getControllingSWIfCompatible;
/**
* Registers a service worker for this instances script URL and register
* options and tracks the time registration was complete.
*
* @private
*/
private _registerScript;
/**
* @private
*/
private readonly _onUpdateFound;
/**
* @private
* @param {Event} originalEvent
*/
private readonly _onStateChange;
/**
* @private
* @param {Event} originalEvent
*/
private readonly _onControllerChange;
/**
* @private
* @param {Event} originalEvent
*/
private readonly _onMessage;
}
export { Workbox, WorkboxEvent, type WorkboxEventMap, type WorkboxLifecycleEvent, type WorkboxLifecycleEventMap, type WorkboxLifecycleWaitingEvent, type WorkboxMessageEvent, messageSW };