@asteby/metacore-pwa 0.6.14 → 0.7.0

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
@@ -114,6 +114,49 @@ By default, `PushNotificationService` calls these endpoints on your injected `ap
114
114
 
115
115
  Override any path via `<PWAProvider pushOptions={{ publicKeyPath: '/v1/webpush/key' }} />`.
116
116
 
117
+ ## Política de actualización
118
+
119
+ Por defecto (`updateStrategy="auto"`) nada cambia: el provider recarga en cada `controllerchange`. Con `updateStrategy="prompt"` la actualización la gobierna una política compartida, sin cambios de comportamiento para quien no la activa.
120
+
121
+ ```tsx
122
+ <PWAProvider
123
+ api={api}
124
+ updateStrategy="prompt"
125
+ updateCheckIntervalMs={5 * 60_000} // update() cada 5 min (solo pestaña visible) + al volver + focus
126
+ autoApplyAfterMs={24 * 60 * 60_000} // opcional: aplicar solo tras 24 h esperando, en momento seguro
127
+ staleAutoApplyAfterMs={10 * 60_000} // opcional: umbral cuando versionCheck detecta desfase
128
+ versionCheck={{
129
+ current: __APP_COMMIT__, // versión embebida en el build (Vite `define`)
130
+ fetchLatest: async () => (await fetch('/health').then((r) => r.json())).commit,
131
+ }}
132
+ >
133
+ <PWAUpdatePrompt /> {/* solo UI: toast compartido, se retrae con un modal abierto */}
134
+ </PWAProvider>
135
+ ```
136
+
137
+ Requisito: el `sw.js` no debe hacer `skipWaiting` al instalar, solo al mensaje `SKIP_WAITING` (como la plantilla incluida).
138
+
139
+ | Opción | Default | Efecto |
140
+ |---|---|---|
141
+ | `dismissTtlMs` | 1 h | "Después" oculta el aviso ese tiempo |
142
+ | (interno) `acceptedTtlMs` | 2 min | tras "Actualizar", un SW aún en espera se aplica sin re-preguntar |
143
+ | `autoApplyAfterMs` | `undefined` | **nunca** auto-aplica; si se define, aplica al cumplirse y en momento seguro (también si se descartó el aviso) |
144
+ | `staleAutoApplyAfterMs` | `undefined` | umbral usado mientras `versionCheck` indique que el cliente está desfasado (gana el menor de los dos) |
145
+ | `isSafeToApply` | ver abajo | reemplaza el test de momento seguro |
146
+ | `versionCheck` | — | `{ current, fetchLatest, intervalMs = 5 min }`. Si `fetchLatest()` difiere de `current` se marca *stale* y se fuerza `registration.update()` al instante. La librería no asume el endpoint |
147
+
148
+ **Momento seguro** (por defecto; un `apply` nunca ocurre sin él): sin diálogo Radix abierto; sin campo enfocado con contenido ni campo en el que el usuario escribió (evento `input` de confianza, últimos 30 min) que aún tenga contenido (los campos precargados/autocompletados no cuentan); y pestaña oculta, o usuario inactivo ≥ 60 s. Se reevalúa cada 15 s mientras hay una actualización esperando.
149
+
150
+ Un `<input type="file">` con archivos seleccionados cuenta como edición en curso (no seguro). Limitaciones del test por defecto: **no detecta subidas, peticiones `fetch`/XHR ni escrituras en curso** que no pasen por un campo con contenido, y el clic explícito en "Actualizar" **omite** el momento seguro (es decisión del usuario). Si tu host tiene subidas o formularios críticos, pasa tu propio `isSafeToApply` (por ejemplo, devolviendo `false` mientras haya una subida o mutación activa).
151
+
152
+ **Garantía anti-bucle**: máximo UN intento de recarga por `acceptedTtlMs` (2 min) y por worker en espera. Se persiste `metacore_pwa_update_last_apply_attempt_at`; si tras recargar el worker sigue en espera (p. ej. un `sw.js` que ignora `SKIP_WAITING`) no se vuelve a aplicar de forma automática (ni por aceptación previa ni por `autoApplyAfterMs`): se limpia la aceptación y se vuelve al aviso. Solo un clic explícito en "Actualizar" puede reintentar. Cuando cambia el worker en espera (otro `scriptURL` o instancia) se reinician su antigüedad, el descarte y el intento.
153
+
154
+ **Recarga**: una sola, solo tras `SKIP_WAITING` -> `controllerchange`, con fallback a 5 s. En modo `prompt` un `controllerchange` ajeno (otra pestaña) no recarga esta.
155
+
156
+ Los estados de persistencia (`metacore_pwa_update_*` en `localStorage`) permiten que `autoApplyAfterMs` cuente desde la primera vez que se vio la actualización aunque el usuario recargue sin activarla. Si el storage no está disponible la política degrada a solo-sesión.
157
+
158
+ Capas reutilizables: `decideUpdate` / `isSafeSnapshot` (puras), `createUpdateController` (sin React) y `useServiceWorkerUpdate` (hook) para hosts que no usan `PWAProvider`.
159
+
117
160
  ## Exports
118
161
 
119
162
  ```ts
@@ -0,0 +1,31 @@
1
+ /**
2
+ * "Safe moment" to reload the app. We only reload when ALL hold:
3
+ * - no modal/dialog is open (a form is likely in there);
4
+ * - the user is not mid-input: no focused field with content, and no field the
5
+ * user typed into (trusted `input` event) within the last `EDIT_WINDOW_MS`
6
+ * that still has content (a file input with selected files counts).
7
+ * Prefilled/autofilled fields don't count;
8
+ * - the tab is hidden, OR the user has been idle for `minIdleMs` (default 60 s)
9
+ * so we don't yank the page from under someone who is reading/scrolling.
10
+ * Hosts with other needs pass `isSafeToApply` to replace this.
11
+ */
12
+ export interface SafetySnapshot {
13
+ modalOpen: boolean;
14
+ editingInProgress: boolean;
15
+ visible: boolean;
16
+ /** ms since the last pointer/keyboard/touch/wheel activity. */
17
+ idleMs: number;
18
+ }
19
+ export interface SafetyOptions {
20
+ /** Idle time required to reload a VISIBLE tab. Default 60 s. */
21
+ minIdleMs?: number;
22
+ }
23
+ export declare const DEFAULT_MIN_IDLE_MS: number;
24
+ export declare function isSafeSnapshot(s: SafetySnapshot, opts?: SafetyOptions): boolean;
25
+ /**
26
+ * Starts (ref-counted) tracking of user edits and activity. Returns a disposer.
27
+ * No-op outside the browser.
28
+ */
29
+ export declare function installActivityTracking(doc?: Document | undefined): () => void;
30
+ export declare function readSafetySnapshot(doc?: Document | undefined, now?: number): SafetySnapshot;
31
+ //# sourceMappingURL=dom-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-safety.d.ts","sourceRoot":"","sources":["../src/dom-safety.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAA;IAClB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,mBAAmB,QAAY,CAAA;AAG5C,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAInF;AA0BD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,QAAQ,GAAG,SAAkE,GAAG,MAAM,IAAI,CAsCtI;AAED,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,QAAQ,GAAG,SAAkE,EAAE,GAAG,SAAa,GAAG,cAAc,CAqBvJ"}
@@ -0,0 +1,104 @@
1
+ import { hasOpenModal } from './use-modal-open';
2
+ export const DEFAULT_MIN_IDLE_MS = 60 * 1000;
3
+ const EDIT_WINDOW_MS = 30 * 60 * 1000;
4
+ export function isSafeSnapshot(s, opts = {}) {
5
+ const minIdle = opts.minIdleMs ?? DEFAULT_MIN_IDLE_MS;
6
+ if (s.modalOpen || s.editingInProgress)
7
+ return false;
8
+ return !s.visible || s.idleMs >= minIdle;
9
+ }
10
+ const NON_TEXT_INPUTS = new Set([
11
+ 'hidden', 'checkbox', 'radio', 'button', 'submit', 'reset', 'range', 'color', 'image',
12
+ ]);
13
+ function hasContent(el) {
14
+ if (typeof HTMLInputElement !== 'undefined' && el instanceof HTMLInputElement) {
15
+ // A <input type=file> with selected files is work in progress too.
16
+ if (el.type === 'file')
17
+ return (el.files?.length ?? 0) > 0;
18
+ return !NON_TEXT_INPUTS.has(el.type) && el.value.trim().length > 0;
19
+ }
20
+ if (typeof HTMLTextAreaElement !== 'undefined' && el instanceof HTMLTextAreaElement) {
21
+ return el.value.trim().length > 0;
22
+ }
23
+ if (el instanceof HTMLElement && el.isContentEditable) {
24
+ return (el.textContent ?? '').trim().length > 0;
25
+ }
26
+ return false;
27
+ }
28
+ const edited = new WeakMap();
29
+ let lastActivity = Date.now();
30
+ let trackers = 0;
31
+ let untrack;
32
+ /**
33
+ * Starts (ref-counted) tracking of user edits and activity. Returns a disposer.
34
+ * No-op outside the browser.
35
+ */
36
+ export function installActivityTracking(doc = typeof document === 'undefined' ? undefined : document) {
37
+ if (!doc)
38
+ return () => { };
39
+ if (trackers === 0) {
40
+ const onInput = (e) => {
41
+ if (e.isTrusted && e.target instanceof Element)
42
+ edited.set(e.target, Date.now());
43
+ lastActivity = Date.now();
44
+ };
45
+ const onActivity = () => {
46
+ lastActivity = Date.now();
47
+ };
48
+ const onFormDone = (e) => {
49
+ if (typeof HTMLFormElement !== 'undefined' && e.target instanceof HTMLFormElement) {
50
+ for (const el of Array.from(e.target.elements))
51
+ edited.delete(el);
52
+ }
53
+ };
54
+ const activity = ['pointerdown', 'keydown', 'touchstart', 'wheel'];
55
+ doc.addEventListener('input', onInput, true);
56
+ doc.addEventListener('submit', onFormDone, true);
57
+ doc.addEventListener('reset', onFormDone, true);
58
+ for (const t of activity)
59
+ doc.addEventListener(t, onActivity, { capture: true, passive: true });
60
+ untrack = () => {
61
+ doc.removeEventListener('input', onInput, true);
62
+ doc.removeEventListener('submit', onFormDone, true);
63
+ doc.removeEventListener('reset', onFormDone, true);
64
+ for (const t of activity)
65
+ doc.removeEventListener(t, onActivity, true);
66
+ };
67
+ }
68
+ trackers += 1;
69
+ let done = false;
70
+ return () => {
71
+ if (done)
72
+ return;
73
+ done = true;
74
+ trackers -= 1;
75
+ if (trackers === 0) {
76
+ untrack?.();
77
+ untrack = undefined;
78
+ }
79
+ };
80
+ }
81
+ export function readSafetySnapshot(doc = typeof document === 'undefined' ? undefined : document, now = Date.now()) {
82
+ if (!doc)
83
+ return { modalOpen: false, editingInProgress: false, visible: false, idleMs: Infinity };
84
+ const active = doc.activeElement;
85
+ let editing = !!active && active !== doc.body && hasContent(active);
86
+ if (!editing) {
87
+ // WeakMap is not iterable: probe the editable candidates currently in the DOM.
88
+ const candidates = doc.querySelectorAll('input, textarea, [contenteditable]');
89
+ for (const el of Array.from(candidates)) {
90
+ const at = edited.get(el);
91
+ if (at !== undefined && now - at < EDIT_WINDOW_MS && el.isConnected && hasContent(el)) {
92
+ editing = true;
93
+ break;
94
+ }
95
+ }
96
+ }
97
+ return {
98
+ modalOpen: hasOpenModal(doc),
99
+ editingInProgress: editing,
100
+ visible: doc.visibilityState === 'visible',
101
+ idleMs: now - lastActivity,
102
+ };
103
+ }
104
+ //# sourceMappingURL=dom-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-safety.js","sourceRoot":"","sources":["../src/dom-safety.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,6 +6,14 @@ export { PushNotificationService, } from './push-service';
6
6
  export type { PushApiClient, PushServiceOptions } from './push-service';
7
7
  export { NotificationManager, notificationManager, } from './notification-manager';
8
8
  export type { NotificationOptions, NotificationManagerOptions } from './notification-manager';
9
+ export { decideUpdate, resolveUpdatePolicy, autoApplyThreshold, isWithinTtl, DEFAULT_UPDATE_POLICY, } from './update-policy';
10
+ export type { UpdatePolicy, UpdateState, UpdateDecision } from './update-policy';
11
+ export { isSafeSnapshot, readSafetySnapshot, installActivityTracking } from './dom-safety';
12
+ export type { SafetySnapshot, SafetyOptions } from './dom-safety';
13
+ export { createUpdateController } from './update-controller';
14
+ export type { UpdateController, UpdateControllerOptions, UpdateSnapshot, VersionCheck, } from './update-controller';
15
+ export { useServiceWorkerUpdate } from './use-service-worker-update';
16
+ export type { UseServiceWorkerUpdateOptions, UseServiceWorkerUpdateResult, } from './use-service-worker-update';
9
17
  export { useModalOpen, hasOpenModal } from './use-modal-open';
10
18
  export { PWAInstallPrompt, PWAUpdatePrompt, OfflineIndicator, NotificationPermissionPrompt, } from './components';
11
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACvD,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAClD,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAErD,OAAO,EACL,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEvE,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAE7F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE7D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACvD,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAClD,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAErD,OAAO,EACL,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEvE,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AAE7F,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,GACtB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAC1F,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,YAAY,GACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,YAAY,EACV,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE7D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,cAAc,CAAA"}
package/dist/index.js CHANGED
@@ -2,6 +2,10 @@ export { PWAProvider, usePWAContext } from './provider';
2
2
  export { usePWA, useNotifications } from './hooks';
3
3
  export { PushNotificationService, } from './push-service';
4
4
  export { NotificationManager, notificationManager, } from './notification-manager';
5
+ export { decideUpdate, resolveUpdatePolicy, autoApplyThreshold, isWithinTtl, DEFAULT_UPDATE_POLICY, } from './update-policy';
6
+ export { isSafeSnapshot, readSafetySnapshot, installActivityTracking } from './dom-safety';
7
+ export { createUpdateController } from './update-controller';
8
+ export { useServiceWorkerUpdate } from './use-service-worker-update';
5
9
  export { useModalOpen, hasOpenModal } from './use-modal-open';
6
10
  export { PWAInstallPrompt, PWAUpdatePrompt, OfflineIndicator, NotificationPermissionPrompt, } from './components';
7
11
  // `metacorePWA` lives in the dedicated `@asteby/metacore-pwa/vite-plugin`
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAOvD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAGlD,OAAO,EACL,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE7D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,cAAc,CAAA;AAErB,0EAA0E;AAC1E,yEAAyE;AACzE,kEAAkE;AAClE,yEAAyE;AACzE,uBAAuB;AACvB,EAAE;AACF,mEAAmE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAOvD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAGlD,OAAO,EACL,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,GACtB,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAE1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAO5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAMpE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE7D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,cAAc,CAAA;AAErB,0EAA0E;AAC1E,yEAAyE;AACzE,kEAAkE;AAClE,yEAAyE;AACzE,uBAAuB;AACvB,EAAE;AACF,mEAAmE"}
@@ -1,4 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
+ import type { VersionCheck } from './update-controller';
3
+ import type { UpdatePolicy } from './update-policy';
2
4
  import { type PushApiClient, type PushServiceOptions } from './push-service';
3
5
  export interface PWAContextValue {
4
6
  isOnline: boolean;
@@ -46,8 +48,30 @@ export interface PWAProviderProps {
46
48
  pushOptions?: PushServiceOptions;
47
49
  /** Override user-facing toast messages. */
48
50
  messages?: PWAProviderMessages;
49
- /** Interval in ms between SW update checks. Default: 1 hour. Set to 0 to disable. */
51
+ /** Interval in ms between SW update checks. Default: 1 hour (5 min when `updateStrategy="prompt"`). Set to 0 to disable. */
50
52
  updateCheckIntervalMs?: number;
53
+ /**
54
+ * How a waiting service worker is handled.
55
+ * - `'auto'` (default, unchanged): the provider reloads on every
56
+ * `controllerchange` (hosts whose sw.js does skipWaiting + clientsClaim).
57
+ * - `'prompt'`: shared update policy. Nothing reloads until the user accepts
58
+ * (`updateApp`) or, if configured, `autoApplyAfterMs` /
59
+ * `staleAutoApplyAfterMs` elapse at a safe moment (no open modal, no
60
+ * half-filled form, tab hidden or idle). Pair with `<PWAUpdatePrompt />`
61
+ * and a sw.js that does NOT skipWaiting on install (only on the
62
+ * `SKIP_WAITING` message, as in the packaged template).
63
+ */
64
+ updateStrategy?: 'auto' | 'prompt';
65
+ /** Prompt strategy: auto-apply after the update has waited this long (safe moments only). Default: never. */
66
+ autoApplyAfterMs?: number;
67
+ /** Prompt strategy: like `autoApplyAfterMs` once `versionCheck` found the client outdated. Default: never. */
68
+ staleAutoApplyAfterMs?: number;
69
+ /** Prompt strategy: how long a dismissal hides the prompt. Default 1 h. */
70
+ dismissTtlMs?: UpdatePolicy['dismissTtlMs'];
71
+ /** Prompt strategy: replaces the default "safe to reload" test. */
72
+ isSafeToApply?: () => boolean;
73
+ /** Prompt strategy: compare the embedded build version with the server's. */
74
+ versionCheck?: VersionCheck;
51
75
  /**
52
76
  * Automatically create the push subscription once notification permission is
53
77
  * granted (default: true). Having permission is NOT enough — without a
@@ -64,7 +88,7 @@ export interface PWAProviderProps {
64
88
  /** Called when SW registration fails. */
65
89
  onRegisterError?: (error: unknown) => void;
66
90
  }
67
- export declare function PWAProvider({ children, api, pushOptions, messages, updateCheckIntervalMs, autoSubscribeOnGranted, onRegistered, onRegisterError, }: PWAProviderProps): import("react").JSX.Element;
91
+ export declare function PWAProvider({ children, api, pushOptions, messages, updateCheckIntervalMs, updateStrategy, autoApplyAfterMs, staleAutoApplyAfterMs, dismissTtlMs, isSafeToApply, versionCheck, autoSubscribeOnGranted, onRegistered, onRegisterError, }: PWAProviderProps): import("react").JSX.Element;
68
92
  export declare function usePWAContext(): PWAContextValue;
69
93
  export {};
70
94
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAGd,OAAO,EAA2B,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAErG,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAA;IACjB,aAAa,EAAE,OAAO,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;IACpB,eAAe,EAAE,OAAO,CAAA;IACxB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAClC,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,iBAAiB,EAAE,MAAM,IAAI,CAAA;IAC7B,eAAe,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACvC,mBAAmB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C;AAID,2DAA2D;AAC3D,UAAU,wBAAyB,SAAQ,KAAK;IAC9C,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,UAAU,EAAE,OAAO,CAAC;QAAE,OAAO,EAAE,UAAU,GAAG,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC7E;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,cAAc,EAAE,wBAAwB,GAAG,IAAI,CAAA;KAChD;CACF;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAYD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,SAAS,CAAA;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,aAAa,CAAA;IACnB,oCAAoC;IACpC,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAChC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,mBAAmB,CAAA;IAC9B,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,yBAAyB,GAAG,SAAS,KAAK,IAAI,CAAA;IAC5E,yCAAyC;IACzC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC3C;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,GAAG,EACH,WAAW,EACX,QAAQ,EACR,qBAAsC,EACtC,sBAA6B,EAC7B,YAAY,EACZ,eAAe,GAChB,EAAE,gBAAgB,+BA0SlB;AAED,wBAAgB,aAAa,IAAI,eAAe,CAM/C"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
package/dist/provider.js CHANGED
@@ -3,6 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { createContext, useContext, useEffect, useMemo, useRef, useState, } from 'react';
4
4
  import { useRegisterSW } from 'virtual:pwa-register/react';
5
5
  import { toast } from 'sonner';
6
+ import { useServiceWorkerUpdate } from './use-service-worker-update';
6
7
  import { PushNotificationService } from './push-service';
7
8
  const PWAContext = createContext(undefined);
8
9
  const DEFAULT_MESSAGES = {
@@ -14,7 +15,10 @@ const DEFAULT_MESSAGES = {
14
15
  cannotInstall: 'La app ya está instalada o no se puede instalar',
15
16
  installing: 'Instalando app...',
16
17
  };
17
- export function PWAProvider({ children, api, pushOptions, messages, updateCheckIntervalMs = 60 * 60 * 1000, autoSubscribeOnGranted = true, onRegistered, onRegisterError, }) {
18
+ export function PWAProvider({ children, api, pushOptions, messages, updateCheckIntervalMs, updateStrategy = 'auto', autoApplyAfterMs, staleAutoApplyAfterMs, dismissTtlMs, isSafeToApply, versionCheck, autoSubscribeOnGranted = true, onRegistered, onRegisterError, }) {
19
+ const promptMode = updateStrategy === 'prompt';
20
+ // Legacy cadence: 1 h. The policy machine defaults to 5 min (its own default).
21
+ const legacyIntervalMs = updateCheckIntervalMs ?? 60 * 60 * 1000;
18
22
  const msgs = useMemo(() => ({ ...DEFAULT_MESSAGES, ...messages }), [messages]);
19
23
  const [isOnline, setIsOnline] = useState(typeof navigator !== 'undefined' ? navigator.onLine : true);
20
24
  const [isInstallable, setIsInstallable] = useState(false);
@@ -25,13 +29,22 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
25
29
  if (api && !pushServiceRef.current) {
26
30
  pushServiceRef.current = new PushNotificationService(api, pushOptions);
27
31
  }
28
- const { needRefresh: [needRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({
32
+ const policyUpdate = useServiceWorkerUpdate({
33
+ enabled: promptMode,
34
+ checkIntervalMs: updateCheckIntervalMs,
35
+ autoApplyAfterMs,
36
+ staleAutoApplyAfterMs,
37
+ dismissTtlMs,
38
+ isSafeToApply,
39
+ versionCheck,
40
+ });
41
+ const { needRefresh: [legacyNeedRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({
29
42
  onRegistered(registration) {
30
43
  onRegistered?.(registration);
31
- if (registration && updateCheckIntervalMs > 0) {
44
+ if (!promptMode && registration && legacyIntervalMs > 0) {
32
45
  setInterval(() => {
33
46
  registration.update();
34
- }, updateCheckIntervalMs);
47
+ }, legacyIntervalMs);
35
48
  }
36
49
  },
37
50
  onRegisterError(error) {
@@ -157,6 +170,10 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
157
170
  };
158
171
  }, [msgs]);
159
172
  useEffect(() => {
173
+ // Prompt strategy: the reload is owned by the update policy (single reload
174
+ // after OUR SKIP_WAITING), never by a bare controllerchange.
175
+ if (promptMode)
176
+ return;
160
177
  if (typeof navigator === 'undefined' || !('serviceWorker' in navigator))
161
178
  return;
162
179
  let refreshing = false;
@@ -170,7 +187,7 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
170
187
  return () => {
171
188
  navigator.serviceWorker.removeEventListener('controllerchange', handleControllerChange);
172
189
  };
173
- }, []);
190
+ }, [promptMode]);
174
191
  // Independent SW update detection. A host may alias `virtual:pwa-register/react`
175
192
  // to a no-op stub (e.g. ops's module-federation setup), in which case
176
193
  // useRegisterSW.onRegistered never fires and the periodic update() above never
@@ -184,7 +201,7 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
184
201
  useEffect(() => {
185
202
  if (typeof navigator === 'undefined' || !('serviceWorker' in navigator))
186
203
  return;
187
- if (updateCheckIntervalMs <= 0)
204
+ if (promptMode || legacyIntervalMs <= 0)
188
205
  return;
189
206
  let reg;
190
207
  let interval;
@@ -195,7 +212,7 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
195
212
  .then((registration) => {
196
213
  reg = registration;
197
214
  check();
198
- interval = setInterval(check, updateCheckIntervalMs);
215
+ interval = setInterval(check, legacyIntervalMs);
199
216
  })
200
217
  .catch(() => { });
201
218
  const onVisible = () => {
@@ -214,7 +231,7 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
214
231
  }
215
232
  window.removeEventListener('focus', check);
216
233
  };
217
- }, [updateCheckIntervalMs]);
234
+ }, [promptMode, legacyIntervalMs]);
218
235
  const installApp = async () => {
219
236
  if (!deferredPrompt) {
220
237
  toast.error(msgs.cannotInstall);
@@ -232,6 +249,10 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
232
249
  return false;
233
250
  };
234
251
  const updateApp = () => {
252
+ if (promptMode) {
253
+ policyUpdate.applyNow();
254
+ return;
255
+ }
235
256
  // For autoUpdate SWs (skipWaiting + clientsClaim on install) there is no
236
257
  // "waiting" worker at click-time — the new SW is already active and
237
258
  // serving the updated assets. updateServiceWorker(true) posts a
@@ -279,12 +300,12 @@ export function PWAProvider({ children, api, pushOptions, messages, updateCheckI
279
300
  const value = {
280
301
  isOnline,
281
302
  isInstallable,
282
- needRefresh,
303
+ needRefresh: promptMode ? policyUpdate.updatePending : legacyNeedRefresh,
283
304
  isPushSupported,
284
305
  isPushSubscribed,
285
306
  installApp,
286
307
  updateApp,
287
- closeUpdatePrompt: () => setNeedRefresh(false),
308
+ closeUpdatePrompt: () => (promptMode ? policyUpdate.dismiss() : setNeedRefresh(false)),
288
309
  subscribeToPush,
289
310
  unsubscribeFromPush,
290
311
  testPushNotification,
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,+CAA+C;AAC/C,OAAO,EACL,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,MAAM,EACN,QAAQ,GAET,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAGpE,OAAO,EAAE,uBAAuB,EAA+C,MAAM,gBAAgB,CAAA;AAgBrG,MAAM,UAAU,GAAG,aAAa,CAA8B,SAAS,CAAC,CAAA;AAwBxE,MAAM,gBAAgB,GAAkC;IACtD,YAAY,EAAE,uCAAuC;IACrD,kBAAkB,EAAE,qBAAqB;IACzC,OAAO,EAAE,yBAAyB;IAClC,YAAY,EAAE,6BAA6B;IAC3C,gBAAgB,EAAE,uBAAuB;IACzC,aAAa,EAAE,iDAAiD;IAChE,UAAU,EAAE,mBAAmB;CAChC,CAAA;AAsDD,MAAM,UAAU,WAAW,CAAC,EAC1B,QAAQ,EACR,GAAG,EACH,WAAW,EACX,QAAQ,EACR,qBAAqB,EACrB,cAAc,GAAG,MAAM,EACvB,gBAAgB,EAChB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,sBAAsB,GAAG,IAAI,EAC7B,YAAY,EACZ,eAAe,GACE;IACjB,MAAM,UAAU,GAAG,cAAc,KAAK,QAAQ,CAAA;IAC9C,+EAA+E;IAC/E,MAAM,gBAAgB,GAAG,qBAAqB,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IAChE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,gBAAgB,EAAE,GAAG,QAAQ,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAE9E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CACtC,OAAO,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAC3D,CAAA;IACD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACzD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAkC,IAAI,CAAC,CAAA;IAC3F,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7D,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE/D,MAAM,cAAc,GAAG,MAAM,CAAiC,IAAI,CAAC,CAAA;IACnE,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;QACnC,cAAc,CAAC,OAAO,GAAG,IAAI,uBAAuB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;IACxE,CAAC;IAED,MAAM,YAAY,GAAG,sBAAsB,CAAC;QAC1C,OAAO,EAAE,UAAU;QACnB,eAAe,EAAE,qBAAqB;QACtC,gBAAgB;QAChB,qBAAqB;QACrB,YAAY;QACZ,aAAa;QACb,YAAY;KACb,CAAC,CAAA;IAEF,MAAM,EACJ,WAAW,EAAE,CAAC,iBAAiB,EAAE,cAAc,CAAC,EAChD,mBAAmB,GACpB,GAAG,aAAa,CAAC;QAChB,YAAY,CAAC,YAAY;YACvB,YAAY,EAAE,CAAC,YAAY,CAAC,CAAA;YAC5B,IAAI,CAAC,UAAU,IAAI,YAAY,IAAI,gBAAgB,GAAG,CAAC,EAAE,CAAC;gBACxD,WAAW,CAAC,GAAG,EAAE;oBACf,YAAY,CAAC,MAAM,EAAE,CAAA;gBACvB,CAAC,EAAE,gBAAgB,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;QACD,eAAe,CAAC,KAAK;YACnB,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAA;YAC9C,eAAe,EAAE,CAAC,KAAK,CAAC,CAAA;QAC1B,CAAC;QACD,cAAc;YACZ,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAClC,CAAC;KACF,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAA;QAC1C,IAAI,CAAC,WAAW;YAAE,OAAM;QAExB,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,MAAM,aAAa,GAAG,GAAG,EAAE,CACzB,OAAO,YAAY,KAAK,WAAW,IAAI,YAAY,CAAC,UAAU,KAAK,SAAS,CAAA;QAE9E,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;YAC1B,kBAAkB,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,CAAA;YAC9C,MAAM,WAAW,CAAC,IAAI,EAAE,CAAA;YACxB,IAAI,SAAS;gBAAE,OAAM;YACrB,IAAI,UAAU,GAAG,WAAW,CAAC,YAAY,EAAE,CAAA;YAC3C,wEAAwE;YACxE,qEAAqE;YACrE,mEAAmE;YACnE,wCAAwC;YACxC,IAAI,sBAAsB,IAAI,CAAC,UAAU,IAAI,WAAW,CAAC,YAAY,EAAE,IAAI,aAAa,EAAE,EAAE,CAAC;gBAC3F,UAAU,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;YAChF,CAAC;YACD,IAAI,CAAC,SAAS;gBAAE,mBAAmB,CAAC,UAAU,CAAC,CAAA;QACjD,CAAC,CAAA;QACD,KAAK,QAAQ,EAAE,CAAA;QAEf,yEAAyE;QACzE,2EAA2E;QAC3E,0EAA0E;QAC1E,IAAI,IAAgD,CAAA;QACpD,IAAI,sBAAsB,IAAI,WAAW,CAAC,YAAY,EAAE,IAAI,OAAO,YAAY,KAAK,WAAW,EAAE,CAAC;YAChG,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;gBACtB,IAAI,SAAS;oBAAE,OAAM;gBACrB,IAAI,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC;oBACnD,KAAK,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;wBAC3E,IAAI,CAAC,SAAS;4BAAE,mBAAmB,CAAC,EAAE,CAAC,CAAA;oBACzC,CAAC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,CAAA;QACV,CAAC;QAED,yEAAyE;QACzE,yEAAyE;QACzE,0EAA0E;QAC1E,4EAA4E;QAC5E,yEAAyE;QACzE,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,SAAS,IAAI,CAAC,sBAAsB;gBAAE,OAAM;YAChD,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;gBAAE,OAAM;YACrF,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE;gBAAE,OAAM;YAC3D,KAAK,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;gBAC3E,IAAI,CAAC,SAAS;oBAAE,mBAAmB,CAAC,EAAE,CAAC,CAAA;YACzC,CAAC,CAAC,CAAA;QACJ,CAAC,CAAA;QACD,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACpC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAA;QAC1D,CAAC;QACD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAC7C,CAAC;QAED,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;YAChB,IAAI,IAAI;gBAAE,aAAa,CAAC,IAAI,CAAC,CAAA;YAC7B,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACpC,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAA;YAC7D,CAAC;YACD,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;YAChD,CAAC;QACH,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAE5B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAM;QAEzC,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;YAC1B,iBAAiB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;YACxC,gBAAgB,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,WAAW,CAAC,IAAI,CAAC,CAAA;YACjB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACxC,CAAC,CAAA;QAED,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,WAAW,CAAC,KAAK,CAAC,CAAA;YAClB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,CAAC,CAAA;QAED,MAAM,yBAAyB,GAAG,CAAC,CAAQ,EAAE,EAAE;YAC7C,CAAC,CAAC,cAAc,EAAE,CAAA;YAClB,MAAM,GAAG,GAAG,CAA6B,CAAA;YACzC,iBAAiB,CAAC,GAAG,CAAC,CAAA;YACtB,gBAAgB,CAAC,IAAI,CAAC,CAAA;YACtB,MAAM,CAAC,cAAc,GAAG,GAAG,CAAA;QAC7B,CAAC,CAAA;QAED,MAAM,kBAAkB,GAAG,GAAG,EAAE;YAC9B,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACvB,iBAAiB,CAAC,IAAI,CAAC,CAAA;YACvB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAA;YAC5B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAClC,CAAC,CAAA;QAED,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QAC/C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;QACjD,MAAM,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,yBAAyB,CAAC,CAAA;QACzE,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;QAE3D,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;YAClD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;YACpD,MAAM,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,yBAAyB,CAAC,CAAA;YAC5E,MAAM,CAAC,mBAAmB,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;QAChE,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,SAAS,CAAC,GAAG,EAAE;QACb,2EAA2E;QAC3E,6DAA6D;QAC7D,IAAI,UAAU;YAAE,OAAM;QACtB,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,CAAC,eAAe,IAAI,SAAS,CAAC;YAAE,OAAM;QAE/E,IAAI,UAAU,GAAG,KAAK,CAAA;QACtB,MAAM,sBAAsB,GAAG,GAAG,EAAE;YAClC,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,UAAU,GAAG,IAAI,CAAA;gBACjB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAA;YAC1B,CAAC;QACH,CAAC,CAAA;QAED,SAAS,CAAC,aAAa,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAA;QACpF,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,aAAa,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAA;QACzF,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAEhB,iFAAiF;IACjF,sEAAsE;IACtE,+EAA+E;IAC/E,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,yEAAyE;IACzE,4EAA4E;IAC5E,sEAAsE;IACtE,+EAA+E;IAC/E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,CAAC,eAAe,IAAI,SAAS,CAAC;YAAE,OAAM;QAC/E,IAAI,UAAU,IAAI,gBAAgB,IAAI,CAAC;YAAE,OAAM;QAE/C,IAAI,GAA0C,CAAA;QAC9C,IAAI,QAAoD,CAAA;QACxD,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,KAAK,GAAG,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACpC,CAAC,CAAA;QAED,SAAS,CAAC,aAAa,CAAC,KAAK;aAC1B,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE;YACrB,GAAG,GAAG,YAAY,CAAA;YAClB,KAAK,EAAE,CAAA;YACP,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAA;QACjD,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAElB,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;gBAAE,KAAK,EAAE,CAAA;QACxF,CAAC,CAAA;QACD,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACpC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAA;QAC1D,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAEvC,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;YACrC,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACpC,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAA;YAC7D,CAAC;YACD,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAC5C,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAElC,MAAM,UAAU,GAAG,KAAK,IAAsB,EAAE;QAC9C,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YAC/B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,MAAM,cAAc,CAAC,MAAM,EAAE,CAAA;QAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,cAAc,CAAC,UAAU,CAAA;QAEnD,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;YAC3B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YAC9B,iBAAiB,CAAC,IAAI,CAAC,CAAA;YACvB,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACvB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QACjC,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,GAAG,EAAE;QACrB,IAAI,UAAU,EAAE,CAAC;YACf,YAAY,CAAC,QAAQ,EAAE,CAAA;YACvB,OAAM;QACR,CAAC;QACD,yEAAyE;QACzE,oEAAoE;QACpE,iEAAiE;QACjE,uEAAuE;QACvE,+BAA+B;QAC/B,EAAE;QACF,yEAAyE;QACzE,uEAAuE;QACvE,SAAS;QACT,qEAAqE;QACrE,qBAAqB;QACrB,qEAAqE;QACrE,0EAA0E;QAC1E,2EAA2E;QAC3E,wCAAwC;QACxC,KAAK,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAC9B,UAAU,CAAC,GAAG,EAAE;YACd,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAA;QAC1B,CAAC,EAAE,GAAG,CAAC,CAAA;IACT,CAAC,CAAA;IAED,MAAM,eAAe,GAAG,KAAK,IAAsB,EAAE;QACnD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAA;QAC1C,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAA;QAC9B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,CAAA;QAC5C,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC3B,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,MAAM,mBAAmB,GAAG,KAAK,IAAsB,EAAE;QACvD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAA;QAC1C,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAA;QAC9B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,CAAA;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,mBAAmB,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,MAAM,oBAAoB,GAAG,KAAK,IAAmB,EAAE;QACrD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAA;QAC1C,IAAI,CAAC,WAAW;YAAE,OAAM;QACxB,MAAM,WAAW,CAAC,gBAAgB,EAAE,CAAA;IACtC,CAAC,CAAA;IAED,MAAM,KAAK,GAAoB;QAC7B,QAAQ;QACR,aAAa;QACb,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB;QACxE,eAAe;QACf,gBAAgB;QAChB,UAAU;QACV,SAAS;QACT,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACtF,eAAe;QACf,mBAAmB;QACnB,oBAAoB;KACrB,CAAA;IAED,OAAO,KAAC,UAAU,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAuB,CAAA;AAC5E,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,CAAA;IACtC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;IAC7D,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { type UpdatePolicy } from './update-policy';
2
+ /**
3
+ * Framework-free state machine that drives a service-worker update according to
4
+ * an {@link UpdatePolicy}. The React hook / PWAProvider are thin wrappers, and
5
+ * tests drive it with a fake registration.
6
+ *
7
+ * Effects: periodic `registration.update()` (visible tab only), re-check on
8
+ * visibilitychange/focus, `updatefound` -> `statechange` detection of the
9
+ * waiting worker, periodic re-evaluation while an update waits (so
10
+ * `autoApplyAfterMs` and "becomes safe" are noticed), optional version-drift
11
+ * check, and a single guarded reload after `SKIP_WAITING` -> `controllerchange`
12
+ * (with a fallback timer).
13
+ */
14
+ export interface VersionCheck {
15
+ /** Version embedded in this build (e.g. commit hash via Vite `define`). */
16
+ current: string;
17
+ /** Fetches the latest deployed version. Return undefined when unknown. The library assumes no endpoint. */
18
+ fetchLatest: () => Promise<string | undefined>;
19
+ /** How often to compare. Default 5 min. */
20
+ intervalMs?: number;
21
+ }
22
+ export interface UpdateControllerOptions {
23
+ policy?: Partial<UpdatePolicy>;
24
+ /** `registration.update()` cadence while visible. Default 5 min. 0 disables. */
25
+ checkIntervalMs?: number;
26
+ /** Re-evaluation cadence while an update is waiting. Default 15 s. */
27
+ evaluateIntervalMs?: number;
28
+ /** Replaces the default safe-moment test (modal/edit/idle). */
29
+ isSafeToApply?: () => boolean;
30
+ versionCheck?: VersionCheck;
31
+ /** localStorage key prefix. Default `metacore_pwa_update`. */
32
+ storagePrefix?: string;
33
+ /** Reload anyway if `controllerchange` never fires. Default 5 s. */
34
+ reloadFallbackMs?: number;
35
+ /** Delay between `update()` and re-reading `registration.waiting`. Default 5 s. */
36
+ postCheckDelayMs?: number;
37
+ }
38
+ export type UpdateRegistration = Pick<ServiceWorkerRegistration, 'waiting' | 'installing' | 'update' | 'addEventListener' | 'removeEventListener'>;
39
+ export interface UpdateControllerDeps {
40
+ now: () => number;
41
+ storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | undefined;
42
+ container: Pick<ServiceWorkerContainer, 'addEventListener' | 'removeEventListener'> | undefined;
43
+ doc: Pick<Document, 'addEventListener' | 'removeEventListener' | 'visibilityState'> | undefined;
44
+ win: Pick<Window, 'addEventListener' | 'removeEventListener'> | undefined;
45
+ reload: () => void;
46
+ }
47
+ export interface UpdateSnapshot {
48
+ /** The prompt should be shown (decision === 'prompt'). */
49
+ updatePending: boolean;
50
+ /** SKIP_WAITING sent, waiting for controllerchange/reload. */
51
+ applying: boolean;
52
+ /** Client is known to be older than the server. */
53
+ stale: boolean;
54
+ }
55
+ export interface UpdateController {
56
+ /** Binds the live registration and starts evaluating. */
57
+ attach: (registration: UpdateRegistration) => void;
58
+ /** Starts listeners/timers (idempotent). Returns a disposer. */
59
+ start: () => () => void;
60
+ stop: () => void;
61
+ evaluate: () => void;
62
+ applyNow: () => void;
63
+ dismiss: () => void;
64
+ getSnapshot: () => UpdateSnapshot;
65
+ subscribe: (fn: (s: UpdateSnapshot) => void) => () => void;
66
+ }
67
+ export declare function createUpdateController(options?: UpdateControllerOptions, depsOverride?: Partial<UpdateControllerDeps>): UpdateController;
68
+ //# sourceMappingURL=update-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-controller.d.ts","sourceRoot":"","sources":["../src/update-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAA;AAGxB;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAA;IACf,2GAA2G;IAC3G,WAAW,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAC9C,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAC9B,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,OAAO,CAAA;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,yBAAyB,EACzB,SAAS,GAAG,YAAY,GAAG,QAAQ,GAAG,kBAAkB,GAAG,qBAAqB,CACjF,CAAA;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,MAAM,CAAA;IACjB,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC,GAAG,SAAS,CAAA;IACxE,SAAS,EAAE,IAAI,CAAC,sBAAsB,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,GAAG,SAAS,CAAA;IAC/F,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,kBAAkB,GAAG,qBAAqB,GAAG,iBAAiB,CAAC,GAAG,SAAS,CAAA;IAC/F,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,GAAG,SAAS,CAAA;IACzE,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,aAAa,EAAE,OAAO,CAAA;IACtB,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAA;IACjB,mDAAmD;IACnD,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,MAAM,EAAE,CAAC,YAAY,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAClD,gEAAgE;IAChE,KAAK,EAAE,MAAM,MAAM,IAAI,CAAA;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,WAAW,EAAE,MAAM,cAAc,CAAA;IACjC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;CAC3D;AAsBD,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,OAAO,CAAC,oBAAoB,CAAM,GAC/C,gBAAgB,CA2RlB"}
@@ -0,0 +1,309 @@
1
+ import { decideUpdate, isWithinTtl, resolveUpdatePolicy, } from './update-policy';
2
+ import { installActivityTracking, isSafeSnapshot, readSafetySnapshot } from './dom-safety';
3
+ const safeStorage = () => {
4
+ try {
5
+ return typeof localStorage === 'undefined' ? undefined : localStorage;
6
+ }
7
+ catch {
8
+ return undefined;
9
+ }
10
+ };
11
+ function defaultDeps() {
12
+ const hasSW = typeof navigator !== 'undefined' && 'serviceWorker' in navigator;
13
+ return {
14
+ now: () => Date.now(),
15
+ storage: safeStorage(),
16
+ container: hasSW ? navigator.serviceWorker : undefined,
17
+ doc: typeof document === 'undefined' ? undefined : document,
18
+ win: typeof window === 'undefined' ? undefined : window,
19
+ reload: () => window.location.reload(),
20
+ };
21
+ }
22
+ export function createUpdateController(options = {}, depsOverride = {}) {
23
+ const deps = { ...defaultDeps(), ...depsOverride };
24
+ const policy = resolveUpdatePolicy(options.policy);
25
+ const checkIntervalMs = options.checkIntervalMs ?? 5 * 60 * 1000;
26
+ const evaluateIntervalMs = options.evaluateIntervalMs ?? 15 * 1000;
27
+ const fallbackMs = options.reloadFallbackMs ?? 5000;
28
+ const postCheckMs = options.postCheckDelayMs ?? 5000;
29
+ const prefix = options.storagePrefix ?? 'metacore_pwa_update';
30
+ const K = {
31
+ since: `${prefix}_waiting_since`,
32
+ dismissed: `${prefix}_dismissed_at`,
33
+ accepted: `${prefix}_accepted_at`,
34
+ attempt: `${prefix}_last_apply_attempt_at`,
35
+ };
36
+ const read = (key) => {
37
+ try {
38
+ const v = deps.storage?.getItem(key);
39
+ if (!v)
40
+ return undefined;
41
+ const n = Number(v);
42
+ return Number.isFinite(n) ? n : undefined;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ };
48
+ const write = (key, value) => {
49
+ try {
50
+ if (value === undefined)
51
+ deps.storage?.removeItem(key);
52
+ else
53
+ deps.storage?.setItem(key, String(value));
54
+ }
55
+ catch {
56
+ /* storage unavailable: policy degrades to in-session behaviour */
57
+ }
58
+ };
59
+ let registration;
60
+ let snapshot = { updatePending: false, applying: false, stale: false };
61
+ const listeners = new Set();
62
+ let started = false;
63
+ let reloaded = false;
64
+ let evalTimer;
65
+ let cleanups = [];
66
+ let installingCleanup;
67
+ let controllerChangeCleanup;
68
+ // Identity of the waiting worker last seen by THIS instance (a new deploy replaces it).
69
+ let seenWaiting;
70
+ const timeouts = new Set();
71
+ const patch = (p) => {
72
+ const next = { ...snapshot, ...p };
73
+ if (next.updatePending === snapshot.updatePending &&
74
+ next.applying === snapshot.applying &&
75
+ next.stale === snapshot.stale) {
76
+ return;
77
+ }
78
+ snapshot = next;
79
+ listeners.forEach((fn) => fn(snapshot));
80
+ };
81
+ const later = (fn, ms) => {
82
+ const t = setTimeout(() => {
83
+ timeouts.delete(t);
84
+ fn();
85
+ }, ms);
86
+ timeouts.add(t);
87
+ };
88
+ const isSafe = () => options.isSafeToApply ? options.isSafeToApply() : isSafeSnapshot(readSafetySnapshot(undefined, deps.now()));
89
+ const reloadOnce = () => {
90
+ if (reloaded)
91
+ return;
92
+ reloaded = true;
93
+ deps.reload();
94
+ };
95
+ const stopEvalTimer = () => {
96
+ if (evalTimer)
97
+ clearInterval(evalTimer);
98
+ evalTimer = undefined;
99
+ };
100
+ const evaluate = () => {
101
+ if (!registration)
102
+ return;
103
+ const now = deps.now();
104
+ const hasWaiting = !!registration.waiting;
105
+ if (!hasWaiting) {
106
+ // Nothing pending: a previous acceptance has been fulfilled.
107
+ seenWaiting = undefined;
108
+ write(K.since, undefined);
109
+ write(K.accepted, undefined);
110
+ write(K.attempt, undefined);
111
+ stopEvalTimer();
112
+ patch({ updatePending: false });
113
+ return;
114
+ }
115
+ if (snapshot.applying)
116
+ return; // reload in flight: never decide again
117
+ const waiting = registration.waiting;
118
+ const identity = { ref: waiting, scriptURL: waiting?.scriptURL };
119
+ if (seenWaiting && (seenWaiting.ref !== identity.ref || seenWaiting.scriptURL !== identity.scriptURL)) {
120
+ // A different worker is waiting (e.g. v2 deployed over a waiting v1): it
121
+ // inherits neither v1's age, its dismissal nor its apply attempt.
122
+ write(K.since, undefined);
123
+ write(K.dismissed, undefined);
124
+ write(K.accepted, undefined);
125
+ write(K.attempt, undefined);
126
+ }
127
+ seenWaiting = identity;
128
+ // Hard loop guard: at most ONE automatic apply attempt per acceptedTtlMs. If
129
+ // we already tried and a worker is STILL waiting, applying again would loop
130
+ // (sw.js ignoring SKIP_WAITING...). Forget the acceptance and go back to
131
+ // asking; only an explicit click on "Update" may retry.
132
+ const recentAttempt = isWithinTtl(read(K.attempt), now, policy.acceptedTtlMs);
133
+ if (recentAttempt)
134
+ write(K.accepted, undefined);
135
+ let waitingSince = read(K.since);
136
+ if (waitingSince === undefined || waitingSince > now) {
137
+ waitingSince = now;
138
+ write(K.since, now);
139
+ }
140
+ const decision = decideUpdate({
141
+ hasWaiting,
142
+ now,
143
+ waitingSince,
144
+ dismissedAt: read(K.dismissed),
145
+ acceptedAt: read(K.accepted),
146
+ stale: snapshot.stale,
147
+ safe: !recentAttempt && isSafe(),
148
+ }, policy);
149
+ if (decision === 'apply') {
150
+ applyNow();
151
+ return;
152
+ }
153
+ patch({ updatePending: decision === 'prompt' });
154
+ if (started && !evalTimer && evaluateIntervalMs > 0) {
155
+ evalTimer = setInterval(evaluate, evaluateIntervalMs);
156
+ }
157
+ };
158
+ function applyNow() {
159
+ if (snapshot.applying || !registration)
160
+ return;
161
+ patch({ applying: true, updatePending: false });
162
+ // Next deploy must notify again; remember the acceptance so a still-waiting
163
+ // worker after the reload is applied without re-asking.
164
+ const at = deps.now();
165
+ write(K.dismissed, undefined);
166
+ // Never renew a still-valid acceptance; always stamp the attempt (loop guard).
167
+ if (!isWithinTtl(read(K.accepted), at, policy.acceptedTtlMs))
168
+ write(K.accepted, at);
169
+ write(K.attempt, at);
170
+ // ONE reload, and only once the new worker controls the page. Reloading
171
+ // earlier leaves a blank page on mobile (old precache already cleaned).
172
+ controllerChangeCleanup?.();
173
+ deps.container?.addEventListener('controllerchange', reloadOnce, { once: true });
174
+ controllerChangeCleanup = () => deps.container?.removeEventListener('controllerchange', reloadOnce);
175
+ later(reloadOnce, fallbackMs);
176
+ const waiting = registration?.waiting;
177
+ if (waiting) {
178
+ try {
179
+ waiting.postMessage({ type: 'SKIP_WAITING' });
180
+ }
181
+ catch {
182
+ reloadOnce();
183
+ }
184
+ }
185
+ else {
186
+ // Already active (skipWaiting worker) or nothing to activate: reload picks the new build.
187
+ reloadOnce();
188
+ }
189
+ }
190
+ const check = () => {
191
+ if (!registration)
192
+ return;
193
+ void registration.update().catch(() => { });
194
+ // update() installs in the background; look again shortly after.
195
+ later(evaluate, postCheckMs);
196
+ };
197
+ const checkVisible = () => {
198
+ if (deps.doc && deps.doc.visibilityState !== 'visible')
199
+ return;
200
+ check();
201
+ };
202
+ const checkVersion = async () => {
203
+ const vc = options.versionCheck;
204
+ if (!vc)
205
+ return;
206
+ let latest;
207
+ try {
208
+ latest = await vc.fetchLatest();
209
+ }
210
+ catch {
211
+ return;
212
+ }
213
+ if (!latest)
214
+ return;
215
+ const stale = latest !== vc.current;
216
+ const wasStale = snapshot.stale;
217
+ patch({ stale });
218
+ if (stale && (!wasStale || !registration?.waiting))
219
+ check();
220
+ else if (stale !== wasStale)
221
+ evaluate();
222
+ };
223
+ const onUpdateFound = () => {
224
+ const installing = registration?.installing;
225
+ if (!installing)
226
+ return;
227
+ installingCleanup?.();
228
+ const onState = () => {
229
+ if (installing.state === 'installed')
230
+ evaluate();
231
+ };
232
+ installing.addEventListener('statechange', onState);
233
+ installingCleanup = () => installing.removeEventListener('statechange', onState);
234
+ };
235
+ const controller = {
236
+ attach(reg) {
237
+ if (registration === reg)
238
+ return;
239
+ registration?.removeEventListener('updatefound', onUpdateFound);
240
+ installingCleanup?.();
241
+ installingCleanup = undefined;
242
+ registration = reg;
243
+ reg.addEventListener('updatefound', onUpdateFound);
244
+ evaluate();
245
+ if (started)
246
+ checkVisible();
247
+ },
248
+ start() {
249
+ if (started)
250
+ return () => { };
251
+ started = true;
252
+ const onVisible = () => {
253
+ if (deps.doc?.visibilityState === 'visible') {
254
+ checkVisible();
255
+ void checkVersion();
256
+ evaluate();
257
+ }
258
+ };
259
+ deps.doc?.addEventListener('visibilitychange', onVisible);
260
+ deps.win?.addEventListener('focus', onVisible);
261
+ cleanups.push(() => deps.doc?.removeEventListener('visibilitychange', onVisible));
262
+ cleanups.push(() => deps.win?.removeEventListener('focus', onVisible));
263
+ if (!options.isSafeToApply)
264
+ cleanups.push(installActivityTracking());
265
+ if (checkIntervalMs > 0) {
266
+ const id = setInterval(checkVisible, checkIntervalMs);
267
+ cleanups.push(() => clearInterval(id));
268
+ }
269
+ if (options.versionCheck) {
270
+ void checkVersion();
271
+ const id = setInterval(() => void checkVersion(), options.versionCheck.intervalMs ?? 5 * 60 * 1000);
272
+ cleanups.push(() => clearInterval(id));
273
+ }
274
+ if (registration) {
275
+ evaluate();
276
+ checkVisible();
277
+ }
278
+ return () => controller.stop();
279
+ },
280
+ stop() {
281
+ started = false;
282
+ stopEvalTimer();
283
+ registration?.removeEventListener('updatefound', onUpdateFound);
284
+ installingCleanup?.();
285
+ installingCleanup = undefined;
286
+ controllerChangeCleanup?.();
287
+ controllerChangeCleanup = undefined;
288
+ cleanups.forEach((fn) => fn());
289
+ cleanups = [];
290
+ timeouts.forEach((t) => clearTimeout(t));
291
+ timeouts.clear();
292
+ },
293
+ evaluate,
294
+ applyNow,
295
+ dismiss() {
296
+ write(K.dismissed, deps.now());
297
+ patch({ updatePending: false });
298
+ },
299
+ getSnapshot: () => snapshot,
300
+ subscribe(fn) {
301
+ listeners.add(fn);
302
+ return () => {
303
+ listeners.delete(fn);
304
+ };
305
+ },
306
+ };
307
+ return controller;
308
+ }
309
+ //# sourceMappingURL=update-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-controller.js","sourceRoot":"","sources":["../src/update-controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Pure (React-free, DOM-free) update policy.
3
+ *
4
+ * Given a snapshot of the service-worker update state, decides whether the
5
+ * host should do nothing, ask the user, or silently apply the update. All
6
+ * functions are deterministic so the whole decision table is unit-testable.
7
+ *
8
+ * Invariants:
9
+ * - Nothing is ever applied unless `safe` is true (never reload a half-filled form).
10
+ * - With the default policy nothing is ever auto-applied: the worst case is a
11
+ * prompt (current behaviour of every Metacore host).
12
+ */
13
+ export type UpdateDecision = 'none' | 'prompt' | 'apply';
14
+ export interface UpdatePolicy {
15
+ /** How long a dismissal ("Después") keeps the prompt hidden. Default: 1 h. */
16
+ dismissTtlMs: number;
17
+ /**
18
+ * How long after the user clicked "Actualizar" a still-waiting worker is
19
+ * applied without asking again (reload that lost the race, other tab open…).
20
+ * Default: 2 min.
21
+ */
22
+ acceptedTtlMs: number;
23
+ /**
24
+ * Apply on its own once the update has been waiting this long AND the moment
25
+ * is safe. Default: undefined = never auto-apply.
26
+ */
27
+ autoApplyAfterMs?: number;
28
+ /**
29
+ * Same as `autoApplyAfterMs` but used when the client is known to run an
30
+ * older build than the server (see `versionCheck`). When both are set the
31
+ * smaller one wins while stale. Default: undefined.
32
+ */
33
+ staleAutoApplyAfterMs?: number;
34
+ }
35
+ export declare const DEFAULT_UPDATE_POLICY: UpdatePolicy;
36
+ export interface UpdateState {
37
+ /** A worker is installed and waiting to activate. */
38
+ hasWaiting: boolean;
39
+ /** Current epoch ms. */
40
+ now: number;
41
+ /** Epoch ms when the waiting worker was first seen (persisted across reloads). */
42
+ waitingSince?: number;
43
+ /** Epoch ms of the last dismissal. */
44
+ dismissedAt?: number;
45
+ /** Epoch ms of the last explicit "update now" click. */
46
+ acceptedAt?: number;
47
+ /** The client is known to be older than the server. */
48
+ stale: boolean;
49
+ /** Applying (reloading) right now would not interrupt the user. */
50
+ safe: boolean;
51
+ }
52
+ export declare function resolveUpdatePolicy(policy?: Partial<UpdatePolicy>): UpdatePolicy;
53
+ /** True when `at` happened within the last `ttl` ms (future timestamps never count). */
54
+ export declare function isWithinTtl(at: number | undefined, now: number, ttl: number): boolean;
55
+ /** The auto-apply threshold in force for this state, or undefined when disabled. */
56
+ export declare function autoApplyThreshold(stale: boolean, policy: UpdatePolicy): number | undefined;
57
+ /**
58
+ * Decision table (first match wins):
59
+ * 1. no waiting worker -> none
60
+ * 2. accepted recently -> apply if safe, else none (never re-ask)
61
+ * 3. auto-apply threshold reached -> apply if safe
62
+ * 4. dismissed within TTL -> none
63
+ * 5. otherwise -> prompt
64
+ * A threshold reached while unsafe falls through to 4/5 (prompt unless dismissed).
65
+ */
66
+ export declare function decideUpdate(state: UpdateState, policyInput?: Partial<UpdatePolicy>): UpdateDecision;
67
+ //# sourceMappingURL=update-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-policy.d.ts","sourceRoot":"","sources":["../src/update-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAExD,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,eAAO,MAAM,qBAAqB,EAAE,YAKnC,CAAA;AAED,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,UAAU,EAAE,OAAO,CAAA;IACnB,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uDAAuD;IACvD,KAAK,EAAE,OAAO,CAAA;IACd,mEAAmE;IACnE,IAAI,EAAE,OAAO,CAAA;CACd;AAED,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAQhF;AAKD,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAIrF;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAM3F;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,cAAc,CAoBpG"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Pure (React-free, DOM-free) update policy.
3
+ *
4
+ * Given a snapshot of the service-worker update state, decides whether the
5
+ * host should do nothing, ask the user, or silently apply the update. All
6
+ * functions are deterministic so the whole decision table is unit-testable.
7
+ *
8
+ * Invariants:
9
+ * - Nothing is ever applied unless `safe` is true (never reload a half-filled form).
10
+ * - With the default policy nothing is ever auto-applied: the worst case is a
11
+ * prompt (current behaviour of every Metacore host).
12
+ */
13
+ export const DEFAULT_UPDATE_POLICY = {
14
+ dismissTtlMs: 60 * 60 * 1000,
15
+ acceptedTtlMs: 2 * 60 * 1000,
16
+ autoApplyAfterMs: undefined,
17
+ staleAutoApplyAfterMs: undefined,
18
+ };
19
+ export function resolveUpdatePolicy(policy) {
20
+ const out = { ...DEFAULT_UPDATE_POLICY };
21
+ if (!policy)
22
+ return out;
23
+ for (const k of Object.keys(policy)) {
24
+ const v = policy[k];
25
+ if (v !== undefined)
26
+ out[k] = v;
27
+ }
28
+ return out;
29
+ }
30
+ const validMs = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0;
31
+ /** True when `at` happened within the last `ttl` ms (future timestamps never count). */
32
+ export function isWithinTtl(at, now, ttl) {
33
+ if (at === undefined || !Number.isFinite(at))
34
+ return false;
35
+ const age = now - at;
36
+ return age >= 0 && age < ttl;
37
+ }
38
+ /** The auto-apply threshold in force for this state, or undefined when disabled. */
39
+ export function autoApplyThreshold(stale, policy) {
40
+ const normal = validMs(policy.autoApplyAfterMs) ? policy.autoApplyAfterMs : undefined;
41
+ const staleMs = stale && validMs(policy.staleAutoApplyAfterMs) ? policy.staleAutoApplyAfterMs : undefined;
42
+ if (normal === undefined)
43
+ return staleMs;
44
+ if (staleMs === undefined)
45
+ return normal;
46
+ return Math.min(normal, staleMs);
47
+ }
48
+ /**
49
+ * Decision table (first match wins):
50
+ * 1. no waiting worker -> none
51
+ * 2. accepted recently -> apply if safe, else none (never re-ask)
52
+ * 3. auto-apply threshold reached -> apply if safe
53
+ * 4. dismissed within TTL -> none
54
+ * 5. otherwise -> prompt
55
+ * A threshold reached while unsafe falls through to 4/5 (prompt unless dismissed).
56
+ */
57
+ export function decideUpdate(state, policyInput) {
58
+ if (!state.hasWaiting)
59
+ return 'none';
60
+ const policy = resolveUpdatePolicy(policyInput);
61
+ if (isWithinTtl(state.acceptedAt, state.now, policy.acceptedTtlMs)) {
62
+ return state.safe ? 'apply' : 'none';
63
+ }
64
+ const threshold = autoApplyThreshold(state.stale, policy);
65
+ if (threshold !== undefined &&
66
+ state.waitingSince !== undefined &&
67
+ state.now - state.waitingSince >= threshold &&
68
+ state.safe) {
69
+ return 'apply';
70
+ }
71
+ if (isWithinTtl(state.dismissedAt, state.now, policy.dismissTtlMs))
72
+ return 'none';
73
+ return 'prompt';
74
+ }
75
+ //# sourceMappingURL=update-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-policy.js","sourceRoot":"","sources":["../src/update-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type UpdateSnapshot, type VersionCheck } from './update-controller';
2
+ import type { UpdatePolicy } from './update-policy';
3
+ export interface UseServiceWorkerUpdateOptions extends Partial<UpdatePolicy> {
4
+ /** Turn the whole machine off (default true). Lets PWAProvider keep its legacy path. */
5
+ enabled?: boolean;
6
+ /** `registration.update()` cadence while the tab is visible. Default 5 min. 0 disables. */
7
+ checkIntervalMs?: number;
8
+ /** Replaces the default safe-moment test. */
9
+ isSafeToApply?: () => boolean;
10
+ versionCheck?: VersionCheck;
11
+ storagePrefix?: string;
12
+ }
13
+ export interface UseServiceWorkerUpdateResult extends UpdateSnapshot {
14
+ /** User accepted: SKIP_WAITING + single reload after controllerchange. */
15
+ applyNow: () => void;
16
+ /** User dismissed: hides the prompt for `dismissTtlMs`. */
17
+ dismiss: () => void;
18
+ }
19
+ /**
20
+ * React wrapper over {@link createUpdateController}. Binds to
21
+ * `navigator.serviceWorker.ready`, so it works regardless of how the host
22
+ * registers the worker (including a stubbed `virtual:pwa-register`).
23
+ */
24
+ export declare function useServiceWorkerUpdate(options?: UseServiceWorkerUpdateOptions): UseServiceWorkerUpdateResult;
25
+ //# sourceMappingURL=use-service-worker-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-service-worker-update.d.ts","sourceRoot":"","sources":["../src/use-service-worker-update.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEnD,MAAM,WAAW,6BAA8B,SAAQ,OAAO,CAAC,YAAY,CAAC;IAC1E,wFAAwF;IACxF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,OAAO,CAAA;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,4BAA6B,SAAQ,cAAc;IAClE,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAID;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,6BAAkC,GAAG,4BAA4B,CA8DhH"}
@@ -0,0 +1,70 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { createUpdateController, } from './update-controller';
3
+ const IDLE = { updatePending: false, applying: false, stale: false };
4
+ /**
5
+ * React wrapper over {@link createUpdateController}. Binds to
6
+ * `navigator.serviceWorker.ready`, so it works regardless of how the host
7
+ * registers the worker (including a stubbed `virtual:pwa-register`).
8
+ */
9
+ export function useServiceWorkerUpdate(options = {}) {
10
+ const { enabled = true, checkIntervalMs, storagePrefix } = options;
11
+ const optsRef = useRef(options);
12
+ optsRef.current = options;
13
+ const [snap, setSnap] = useState(IDLE);
14
+ const ctrlRef = useRef(null);
15
+ const policyKey = [
16
+ options.dismissTtlMs,
17
+ options.acceptedTtlMs,
18
+ options.autoApplyAfterMs,
19
+ options.staleAutoApplyAfterMs,
20
+ ].join('|');
21
+ const vc = options.versionCheck;
22
+ const hasVc = !!vc;
23
+ const vcCurrent = vc?.current;
24
+ const vcInterval = vc?.intervalMs;
25
+ useEffect(() => {
26
+ if (!enabled || typeof navigator === 'undefined' || !('serviceWorker' in navigator))
27
+ return;
28
+ const o = optsRef.current;
29
+ const ctrl = createUpdateController({
30
+ policy: {
31
+ dismissTtlMs: o.dismissTtlMs,
32
+ acceptedTtlMs: o.acceptedTtlMs,
33
+ autoApplyAfterMs: o.autoApplyAfterMs,
34
+ staleAutoApplyAfterMs: o.staleAutoApplyAfterMs,
35
+ },
36
+ checkIntervalMs,
37
+ storagePrefix,
38
+ // Read through the ref so inline callbacks don't restart the machine.
39
+ isSafeToApply: o.isSafeToApply ? () => optsRef.current.isSafeToApply?.() ?? true : undefined,
40
+ versionCheck: hasVc && vcCurrent !== undefined
41
+ ? {
42
+ current: vcCurrent,
43
+ intervalMs: vcInterval,
44
+ fetchLatest: () => optsRef.current.versionCheck?.fetchLatest() ?? Promise.resolve(undefined),
45
+ }
46
+ : undefined,
47
+ });
48
+ ctrlRef.current = ctrl;
49
+ const unsub = ctrl.subscribe(setSnap);
50
+ const stop = ctrl.start();
51
+ let cancelled = false;
52
+ navigator.serviceWorker.ready
53
+ .then((reg) => {
54
+ if (!cancelled)
55
+ ctrl.attach(reg);
56
+ })
57
+ .catch(() => { });
58
+ return () => {
59
+ cancelled = true;
60
+ unsub();
61
+ stop();
62
+ ctrlRef.current = null;
63
+ setSnap(IDLE);
64
+ };
65
+ }, [enabled, checkIntervalMs, storagePrefix, policyKey, hasVc, vcCurrent, vcInterval]);
66
+ const applyNow = useCallback(() => ctrlRef.current?.applyNow(), []);
67
+ const dismiss = useCallback(() => ctrlRef.current?.dismiss(), []);
68
+ return { ...snap, applyNow, dismiss };
69
+ }
70
+ //# sourceMappingURL=use-service-worker-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-service-worker-update.js","sourceRoot":"","sources":["../src/use-service-worker-update.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-pwa",
3
- "version": "0.6.14",
3
+ "version": "0.7.0",
4
4
  "description": "Metacore PWA helpers — vite plugin wrapper, install/update prompts, push notifications, offline indicator",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "lucide-react": "^1.0.0",
52
- "@asteby/metacore-notifications": "37.0.0"
52
+ "@asteby/metacore-notifications": "38.0.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/react": "^19.0.0",
@@ -59,7 +59,8 @@
59
59
  "sonner": "^2.0.0",
60
60
  "typescript": "^6.0.0",
61
61
  "vite": "^8.0.0",
62
- "vite-plugin-pwa": "^1.2.0"
62
+ "vite-plugin-pwa": "^1.2.0",
63
+ "vitest": "^4.0.0"
63
64
  },
64
65
  "publishConfig": {
65
66
  "access": "public"
@@ -68,6 +69,7 @@
68
69
  "build": "tsc -p tsconfig.json",
69
70
  "dev": "tsc -w -p tsconfig.json",
70
71
  "typecheck": "tsc -p tsconfig.json --noEmit",
72
+ "test": "vitest run",
71
73
  "clean": "rm -rf dist"
72
74
  }
73
75
  }