{"version":3,"file":"register-service-worker.cjs","names":[],"sources":["../../src/sw/register-service-worker.ts"],"sourcesContent":["export interface RegisterServiceWorkerOptions {\n    /** Public URL of the compiled service worker file (e.g. `/sw.js`). */\n    url: string;\n    /** SW scope (default: SW directory). */\n    scope?: string;\n    /** Called once the registration is active. */\n    onReady?: (registration: ServiceWorkerRegistration) => void;\n    /**\n     * Called when a new worker has finished installing while another worker\n     * still controls the page. The host app typically prompts the user to\n     * reload and then calls {@link skipWaiting} on the returned worker.\n     *\n     * Fires for a worker that was already `waiting` when `register()` resolved\n     * — the state a user returning after a deploy actually finds — as well as\n     * for one that installs during this session, and at most once per worker.\n     */\n    onUpdate?: (waiting: ServiceWorker, registration: ServiceWorkerRegistration) => void;\n    /** Called on registration failure. */\n    onError?: (error: unknown) => void;\n    /**\n     * When `true`, poll the server for a fresh service worker on an interval\n     * (see {@link RegisterServiceWorkerOptions.updateIntervalMs}) and, unless\n     * {@link RegisterServiceWorkerOptions.reloadOnActivate} is disabled, reload\n     * the page as soon as a new worker takes control. Mirrors the auto-update\n     * behaviour of `vite-plugin-pwa` without depending on it. Default `false`.\n     */\n    autoUpdate?: boolean;\n    /**\n     * How often, in ms, to call `registration.update()` while `autoUpdate` is\n     * on. Browsers already re-check roughly every 24h; an hourly poll keeps\n     * long-lived sessions current without flooding the network. Default\n     * `3600000` (1 hour).\n     */\n    updateIntervalMs?: number;\n    /**\n     * When `autoUpdate` is on, reload the page once a new worker takes control\n     * (`controllerchange`), guarded against reload loops. Set to `false` to\n     * keep polling but leave the reload to the host app. Default `true`.\n     */\n    reloadOnActivate?: boolean;\n}\n\nconst DEFAULT_UPDATE_INTERVAL_MS = 60 * 60 * 1000;\n\n/**\n * Workers already handed to `onUpdate`, so no worker is announced twice.\n *\n * Two paths reach the same waiting worker and both are needed: `updatefound`\n * catches the worker that installs while the tab is open, and the `waiting`\n * read at registration catches the one that installed on an earlier visit. In\n * the session where a deploy lands *and* the tab stays open, both fire for the\n * same worker — without this the app prompts twice.\n *\n * Keyed by worker identity rather than by registration, so a second deploy in\n * the same session still announces: that is a different `ServiceWorker` object.\n * A `WeakSet` because the entry should die with the worker it names.\n */\nconst announcedWorkers = new WeakSet<ServiceWorker>();\n\n/**\n * Hand a waiting worker to `onUpdate`, at most once per worker.\n *\n * @param worker - The worker that finished installing.\n * @param registration - The registration it belongs to.\n * @param options - The caller's options, whose `onUpdate` is invoked.\n */\nfunction announceUpdate(\n    worker: ServiceWorker,\n    registration: ServiceWorkerRegistration,\n    options: RegisterServiceWorkerOptions,\n): void {\n    if (announcedWorkers.has(worker)) return;\n    announcedWorkers.add(worker);\n    options.onUpdate?.(worker, registration);\n}\n\nlet controllerReloadWired = false;\n\nfunction wireControllerReload(): void {\n    if (controllerReloadWired) return;\n    controllerReloadWired = true;\n    let refreshing = false;\n    navigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n        if (refreshing) return;\n        refreshing = true;\n        window.location.reload();\n    });\n}\n\n/**\n * Register a service worker with consistent update-detection wiring.\n *\n * Skips silently when the runtime has no `serviceWorker` support. The host\n * app keeps full control over the SW file — this helper only handles the\n * boilerplate around `register()` and update detection.\n *\n * Two things can mean \"an update is ready\", and only one of them is an event.\n * `updatefound` covers the worker that installs while this tab is open. The\n * commoner case has no event at all: the user visited after a deploy, the new\n * worker installed and went to `waiting`, they closed the tab, and they are back\n * now. `install` already happened, so nothing fires — which is why `waiting` is\n * read directly once the registration resolves. Both routes go through the same\n * dedupe, so a worker is announced once even when both apply.\n *\n * Neither route fires without `navigator.serviceWorker.controller`: no\n * controller means this is the first install, which is `onReady` territory, not\n * an update the user should be prompted about.\n *\n * With `autoUpdate` enabled it additionally polls `registration.update()` on\n * an interval and (by default) reloads the page when a freshly activated worker\n * takes control — a framework-agnostic equivalent of `vite-plugin-pwa`'s\n * auto-update client, implemented directly on `navigator.serviceWorker`.\n *\n * @returns The registration when it succeeds, or `null` when unsupported.\n */\nexport async function registerServiceWorker(\n    options: RegisterServiceWorkerOptions,\n): Promise<ServiceWorkerRegistration | null> {\n    if (typeof navigator === \"undefined\" || !(\"serviceWorker\" in navigator)) {\n        return null;\n    }\n\n    try {\n        const registration = await navigator.serviceWorker.register(options.url, {\n            scope: options.scope,\n        });\n\n        if (registration.active) options.onReady?.(registration);\n\n        if (registration.waiting && navigator.serviceWorker.controller) {\n            announceUpdate(registration.waiting, registration, options);\n        }\n\n        registration.addEventListener(\"updatefound\", () => {\n            const installing = registration.installing;\n            if (!installing) return;\n            installing.addEventListener(\"statechange\", () => {\n                if (installing.state === \"installed\" && navigator.serviceWorker.controller) {\n                    announceUpdate(installing, registration, options);\n                }\n            });\n        });\n\n        if (options.autoUpdate) {\n            if (options.reloadOnActivate !== false) wireControllerReload();\n            const intervalMs = options.updateIntervalMs ?? DEFAULT_UPDATE_INTERVAL_MS;\n            window.setInterval(() => {\n                void registration.update();\n            }, intervalMs);\n        }\n\n        return registration;\n    } catch (error) {\n        options.onError?.(error);\n        return null;\n    }\n}\n\n/**\n * Tell a waiting worker to activate immediately. Pair with `onUpdate` to roll\n * out updates after the user confirms a reload prompt.\n */\nexport function skipWaiting(worker: ServiceWorker): void {\n    worker.postMessage({ type: \"SKIP_WAITING\" });\n}\n\n/**\n * Unregister all registered service workers for this origin.\n *\n * @returns Number of workers that were unregistered.\n */\nexport async function unregisterAllServiceWorkers(): Promise<number> {\n    if (typeof navigator === \"undefined\" || !(\"serviceWorker\" in navigator)) return 0;\n    const registrations = await navigator.serviceWorker.getRegistrations();\n    let count = 0;\n    for (const registration of registrations) {\n        const result = await registration.unregister();\n        if (result) count += 1;\n    }\n    return count;\n}\n"],"mappings":"AA0CA,IAeM,EAAmB,IAAI,QAS7B,SAAS,EACL,EACA,EACA,EACI,CACA,EAAiB,IAAI,CAAM,IAC/B,EAAiB,IAAI,CAAM,EAC3B,EAAQ,WAAW,EAAQ,CAAY,EAC3C,CAEA,IAAI,EAAwB,GAE5B,SAAS,GAA6B,CAClC,GAAI,EAAuB,OAC3B,EAAwB,GACxB,IAAI,EAAa,GACjB,UAAU,cAAc,iBAAiB,uBAA0B,CAC3D,IACJ,EAAa,GACb,OAAO,SAAS,OAAO,EAC3B,CAAC,CACL,CA4BA,eAAsB,EAClB,EACyC,CACzC,GAAI,OAAO,UAAc,KAAe,EAAE,kBAAmB,WACzD,OAAO,KAGX,GAAI,CACA,IAAM,EAAe,MAAM,UAAU,cAAc,SAAS,EAAQ,IAAK,CACrE,MAAO,EAAQ,KACnB,CAAC,EAkBD,GAhBI,EAAa,QAAQ,EAAQ,UAAU,CAAY,EAEnD,EAAa,SAAW,UAAU,cAAc,YAChD,EAAe,EAAa,QAAS,EAAc,CAAO,EAG9D,EAAa,iBAAiB,kBAAqB,CAC/C,IAAM,EAAa,EAAa,WAC3B,GACL,EAAW,iBAAiB,kBAAqB,CACzC,EAAW,QAAU,aAAe,UAAU,cAAc,YAC5D,EAAe,EAAY,EAAc,CAAO,CAExD,CAAC,CACL,CAAC,EAEG,EAAQ,WAAY,CAChB,EAAQ,mBAAqB,IAAO,EAAqB,EAC7D,IAAM,EAAa,EAAQ,kBAAoB,KAC/C,OAAO,gBAAkB,CACrB,EAAkB,OAAO,CAC7B,EAAG,CAAU,CACjB,CAEA,OAAO,CACX,OAAS,EAAO,CAEZ,OADA,EAAQ,UAAU,CAAK,EAChB,IACX,CACJ,CAMA,SAAgB,EAAY,EAA6B,CACrD,EAAO,YAAY,CAAE,KAAM,cAAe,CAAC,CAC/C,CAOA,eAAsB,GAA+C,CACjE,GAAI,OAAO,UAAc,KAAe,EAAE,kBAAmB,WAAY,MAAO,GAChF,IAAM,EAAgB,MAAM,UAAU,cAAc,iBAAiB,EACjE,EAAQ,EACZ,IAAK,IAAM,KAAgB,EAEnB,MADiB,EAAa,WAAW,IACjC,GAAS,GAEzB,OAAO,CACX"}