@swimmesberger/elarion-webpush 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,10 @@ package (`IWebPushSender`, VAPID keys, the subscription store).
10
10
  - `enablePush(api)` — asks for permission **inside the click handler** (before any `await`, which Safari
11
11
  requires) and subscribes.
12
12
  - `subscribe`, `unsubscribe`, `isSubscribed`, and `refreshOnStart(api)` — call the last one on every app start
13
- to heal subscriptions the push service rotated or the server cleaned up.
13
+ to heal subscriptions the push service rotated or the server cleaned up. They subscribe through the page's
14
+ active service-worker registration (or the `registration` option) and wait at most `registrationTimeoutMs`
15
+ (10 s) for a worker to activate, then throw a `WebPushRegistrationError` — `navigator.serviceWorker.ready`
16
+ alone never settles when no worker is registered, for example on a dev server that does not serve one.
14
17
  - `@swimmesberger/elarion-webpush/sw` — `registerWebPushHandlers(self)` for the service worker: shows the
15
18
  notification, focuses or opens the app at its URL on click, and re-subscribes on `pushsubscriptionchange`.
16
19
 
package/dist/index.d.ts CHANGED
@@ -15,10 +15,19 @@ export type EnablePushOutcome = 'subscribed' | 'denied' | 'dismissed' | 'install
15
15
  /** Options shared by the subscription helpers. */
16
16
  export interface PushHelperOptions {
17
17
  /**
18
- * The service-worker registration to subscribe through. Defaults to `navigator.serviceWorker.ready` — which
19
- * never settles when no service worker is registered, so register one before calling the helpers.
18
+ * The service-worker registration to subscribe through — pass the one `navigator.serviceWorker.register(...)`
19
+ * returned when you have it. Without it the helpers use the page's active registration, and otherwise wait for
20
+ * `navigator.serviceWorker.ready` for at most {@link registrationTimeoutMs}, failing with a
21
+ * {@link WebPushRegistrationError} instead of hanging when no service worker ever takes over (a dev server
22
+ * that does not serve one, a page outside the worker's scope).
20
23
  */
21
24
  registration?: ServiceWorkerRegistration;
25
+ /** How long to wait for a service worker to become active when none is yet. Defaults to 10 000 ms. */
26
+ registrationTimeoutMs?: number;
27
+ }
28
+ /** Thrown when no active service-worker registration is available to subscribe through. */
29
+ export declare class WebPushRegistrationError extends Error {
30
+ constructor(message: string);
22
31
  }
23
32
  /** Detects push support; see {@link PushAvailability}. Safe to call during rendering. */
24
33
  export declare function pushAvailability(): PushAvailability;
package/dist/index.js CHANGED
@@ -9,6 +9,14 @@ import { toSubscriptionJson } from './api.js';
9
9
  import { isSameKey, urlBase64ToUint8Array } from './base64url.js';
10
10
  export { fetchWebPushApi, toSubscriptionJson, } from './api.js';
11
11
  export { urlBase64ToUint8Array } from './base64url.js';
12
+ /** Thrown when no active service-worker registration is available to subscribe through. */
13
+ export class WebPushRegistrationError extends Error {
14
+ constructor(message) {
15
+ super(message);
16
+ this.name = 'WebPushRegistrationError';
17
+ }
18
+ }
19
+ const DEFAULT_REGISTRATION_TIMEOUT_MS = 10_000;
12
20
  /** Detects push support; see {@link PushAvailability}. Safe to call during rendering. */
13
21
  export function pushAvailability() {
14
22
  if (typeof navigator === 'undefined' || typeof window === 'undefined')
@@ -90,7 +98,27 @@ export async function refreshOnStart(api, options = {}) {
90
98
  return true;
91
99
  }
92
100
  async function resolveRegistration(options) {
93
- return options.registration ?? navigator.serviceWorker.ready;
101
+ if (options.registration)
102
+ return options.registration;
103
+ const container = navigator.serviceWorker;
104
+ // `ready` waits for a worker to become active and never settles when none is ever registered, so look for an
105
+ // active registration first and bound the wait for the rest.
106
+ const existing = await container.getRegistration?.();
107
+ if (existing?.active)
108
+ return existing;
109
+ const timeoutMs = options.registrationTimeoutMs ?? DEFAULT_REGISTRATION_TIMEOUT_MS;
110
+ let timer;
111
+ const timeout = new Promise((_, reject) => {
112
+ timer = setTimeout(() => reject(new WebPushRegistrationError(`No active service worker registration after ${timeoutMs} ms. Web Push needs a registered service worker: ` +
113
+ `call navigator.serviceWorker.register('/sw.js', { type: 'module' }) first (a dev server that does not ` +
114
+ `serve the worker never activates one), or pass the registration as the 'registration' option.`)), timeoutMs);
115
+ });
116
+ try {
117
+ return await Promise.race([container.ready, timeout]);
118
+ }
119
+ finally {
120
+ clearTimeout(timer);
121
+ }
94
122
  }
95
123
  function iosVersion() {
96
124
  const userAgent = navigator.userAgent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swimmesberger/elarion-webpush",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "The browser half of Elarion Web Push: push availability detection (including the iOS Home Screen requirement), gesture-safe permission and subscribe/unsubscribe/refresh helpers over a pluggable server API, and a service-worker module for push, notificationclick, and pushsubscriptionchange.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",