@develemit/web-hooks 0.3.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 - 2026-11-06
4
+
5
+ - `service-worker`: `useServiceWorker({ onError })` and `registerServiceWorker({ onError })`. Called with the rejection when `register()` fails (not after unmount or dispose). The latest callback is used; a throwing callback is swallowed. Registration failure still never throws into React.
6
+ - `push`: an empty or whitespace `vapidPublicKey` is "not ready". The on-load re-subscribe waits for the key and runs once when it arrives; `subscribe()` sets `error` to `'push key not ready'` and never prompts or calls `pushManager.subscribe`. `shouldResubscribe` takes an optional `hasKey` (default `true`); new `isKeyReady`.
7
+ - `service-worker`: a worker that skips waiting no longer makes the tab reload unasked on `controllerchange`. The hook reports `updateAvailable` and `applyUpdate()` reloads once. **Behaviour change:** this also replaces the old behaviour of following another tab's update with an automatic reload; that tab now shows the update prompt instead. No app relied on the old behaviour, so it ships as a patch.
8
+
3
9
  ## 0.3.0 - 2026-11-06
4
10
 
5
11
  - `push`: `usePushSubscription({ vapidPublicKey, onSubscribe, onUnsubscribe, resubscribeOnLoad = true })` returning `{ support, permission, subscribed, busy, error, subscribe, unsubscribe }`, plus `urlBase64ToUint8Array`, `getPushSupport` (`'supported' | 'unsupported' | 'ios-needs-install'`) and the pure `shouldResubscribe`. The VAPID key is always converted to a `Uint8Array`, the browser's `pushManager.getSubscription()` is the source of truth, mounting never asks for permission, a dropped iOS subscription is re-made silently when permission is already granted, and an `onSubscribe` rejection with `status` 410 unsubscribes and subscribes once more. The package makes no HTTP requests; the app's callbacks do.
package/README.md CHANGED
@@ -301,6 +301,7 @@ const { updateAvailable, applyUpdate, supported } = useServiceWorker({
301
301
  url: '/sw.js',
302
302
  scope: '/',
303
303
  enabled: process.env.NODE_ENV === 'production',
304
+ onError: (error) => captureError(error), // registration failed; never throws into React
304
305
  });
305
306
  if (updateAvailable) showBanner({ onTap: applyUpdate });
306
307
  ```
@@ -315,6 +316,12 @@ self.addEventListener('message', (event) => {
315
316
  });
316
317
  ```
317
318
 
319
+ Workers that call `self.skipWaiting()` on install (as emit-infra's does) take
320
+ control with no waiting stage. The page is never reloaded unasked: when a new
321
+ worker takes control of a tab that was already controlled, `updateAvailable`
322
+ becomes `true` and `applyUpdate()` reloads the page once. The same applies when
323
+ another tab applied the update.
324
+
318
325
  A first install (no controller yet) is not reported as an update. In dev, call
319
326
  `unregisterAll()` to clear workers left by a production build. Browsers without
320
327
  service workers get `supported: false`.
@@ -373,6 +380,11 @@ if (push.support === 'ios-needs-install') return <InstallHint />;
373
380
  <button onClick={push.subscribe} disabled={push.busy}>Enable</button>
374
381
  ```
375
382
 
383
+ `vapidPublicKey` may be `''` while the app is still fetching it. Until it is
384
+ non-blank, the on-load re-subscribe is skipped (and runs once when the key
385
+ arrives) and `subscribe()` sets `error` to `'push key not ready'` without
386
+ asking for permission or touching the push manager.
387
+
376
388
  Returns `{ support, permission, subscribed, busy, error, subscribe, unsubscribe }`.
377
389
  `support` is `'supported'`, `'unsupported'` or `'ios-needs-install'`: iOS only
378
390
  allows Web Push in an installed PWA (16.4+), so an iPhone Safari tab (or any
@@ -27,8 +27,11 @@ function readPermission() {
27
27
  if (typeof window === "undefined" || !("Notification" in window)) return "unsupported";
28
28
  return Notification.permission;
29
29
  }
30
- function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }) {
31
- return resubscribeOnLoad && permission === "granted" && !hasSubscription;
30
+ function isKeyReady(key) {
31
+ return key.trim().length > 0;
32
+ }
33
+ function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad, hasKey = true }) {
34
+ return hasKey && resubscribeOnLoad && permission === "granted" && !hasSubscription;
32
35
  }
33
36
  function isGone(error) {
34
37
  return typeof error === "object" && error !== null && error.status === 410;
@@ -74,6 +77,7 @@ function usePushSubscription(options) {
74
77
  const [subscribed, setSubscribed] = useState(false);
75
78
  const [busy, setBusy] = useState(false);
76
79
  const [error, setError] = useState(null);
80
+ const hasKey = isKeyReady(options.vapidPublicKey);
77
81
  const latest = useRef(options);
78
82
  latest.current = options;
79
83
  useEffect(() => {
@@ -90,7 +94,7 @@ function usePushSubscription(options) {
90
94
  const permissionNow = readPermission();
91
95
  setPermission(permissionNow);
92
96
  if (existing) return setSubscribed(true);
93
- if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad })) return;
97
+ if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad, hasKey })) return;
94
98
  await ensureSubscribed(reg, latest.current);
95
99
  if (!cancelled) setSubscribed(true);
96
100
  } catch {
@@ -99,9 +103,13 @@ function usePushSubscription(options) {
99
103
  return () => {
100
104
  cancelled = true;
101
105
  };
102
- }, [resubscribeOnLoad]);
106
+ }, [resubscribeOnLoad, hasKey]);
103
107
  const subscribe = useCallback(async () => {
104
108
  if (getPushSupport() !== "supported") return;
109
+ if (!isKeyReady(latest.current.vapidPublicKey)) {
110
+ setError("push key not ready");
111
+ return;
112
+ }
105
113
  setError(null);
106
114
  setBusy(true);
107
115
  try {
@@ -23,17 +23,24 @@ async function unregisterAll() {
23
23
  } catch {
24
24
  }
25
25
  }
26
- function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = () => window.location.reload() } = {}) {
26
+ function registerServiceWorker({ url, scope, onUpdateAvailable, onError }, { reload = () => window.location.reload() } = {}) {
27
27
  let registration;
28
28
  let disposed = false;
29
29
  let applying = false;
30
30
  const cleanups = [];
31
31
  const controlledAtStart = hasController();
32
- const onControllerChange = () => {
33
- if (!(applying || controlledAtStart) || reloaded) return;
32
+ let activatedUnasked = false;
33
+ const reloadOnce = () => {
34
+ if (reloaded) return;
34
35
  reloaded = true;
35
36
  reload();
36
37
  };
38
+ const onControllerChange = () => {
39
+ if (applying) return reloadOnce();
40
+ if (!controlledAtStart || activatedUnasked) return;
41
+ activatedUnasked = true;
42
+ onUpdateAvailable();
43
+ };
37
44
  navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
38
45
  cleanups.push(() => navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange));
39
46
  const watchInstalling = (reg) => {
@@ -56,10 +63,16 @@ function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = ()
56
63
  const onUpdateFound = () => watchInstalling(reg);
57
64
  reg.addEventListener("updatefound", onUpdateFound);
58
65
  cleanups.push(() => reg.removeEventListener("updatefound", onUpdateFound));
59
- }).catch(() => {
66
+ }).catch((error) => {
67
+ if (disposed) return;
68
+ try {
69
+ onError?.(error);
70
+ } catch {
71
+ }
60
72
  });
61
73
  return {
62
74
  applyUpdate() {
75
+ if (activatedUnasked) return reloadOnce();
63
76
  const waiting = registration?.waiting;
64
77
  if (!waiting) return;
65
78
  applying = true;
@@ -73,9 +86,11 @@ function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = ()
73
86
  }
74
87
 
75
88
  // src/service-worker/use-service-worker.ts
76
- function useServiceWorker({ url, scope, enabled = true }) {
89
+ function useServiceWorker({ url, scope, enabled = true, onError }) {
77
90
  const [supported, setSupported] = useState(true);
78
91
  const [updateAvailable, setUpdateAvailable] = useState(false);
92
+ const onErrorRef = useRef(onError);
93
+ onErrorRef.current = onError;
79
94
  const handle = useRef(void 0);
80
95
  useEffect(() => {
81
96
  if (!enabled) return;
@@ -83,7 +98,12 @@ function useServiceWorker({ url, scope, enabled = true }) {
83
98
  setSupported(false);
84
99
  return;
85
100
  }
86
- const registered = registerServiceWorker({ url, scope, onUpdateAvailable: () => setUpdateAvailable(true) });
101
+ const registered = registerServiceWorker({
102
+ url,
103
+ scope,
104
+ onUpdateAvailable: () => setUpdateAvailable(true),
105
+ onError: (error) => onErrorRef.current?.(error)
106
+ });
87
107
  handle.current = registered;
88
108
  return () => {
89
109
  registered.dispose();
package/dist/index.cjs CHANGED
@@ -1089,17 +1089,24 @@ async function unregisterAll() {
1089
1089
  } catch {
1090
1090
  }
1091
1091
  }
1092
- function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = () => window.location.reload() } = {}) {
1092
+ function registerServiceWorker({ url, scope, onUpdateAvailable, onError }, { reload = () => window.location.reload() } = {}) {
1093
1093
  let registration;
1094
1094
  let disposed = false;
1095
1095
  let applying = false;
1096
1096
  const cleanups = [];
1097
1097
  const controlledAtStart = hasController();
1098
- const onControllerChange = () => {
1099
- if (!(applying || controlledAtStart) || reloaded) return;
1098
+ let activatedUnasked = false;
1099
+ const reloadOnce = () => {
1100
+ if (reloaded) return;
1100
1101
  reloaded = true;
1101
1102
  reload();
1102
1103
  };
1104
+ const onControllerChange = () => {
1105
+ if (applying) return reloadOnce();
1106
+ if (!controlledAtStart || activatedUnasked) return;
1107
+ activatedUnasked = true;
1108
+ onUpdateAvailable();
1109
+ };
1103
1110
  navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
1104
1111
  cleanups.push(() => navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange));
1105
1112
  const watchInstalling = (reg) => {
@@ -1122,10 +1129,16 @@ function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = ()
1122
1129
  const onUpdateFound = () => watchInstalling(reg);
1123
1130
  reg.addEventListener("updatefound", onUpdateFound);
1124
1131
  cleanups.push(() => reg.removeEventListener("updatefound", onUpdateFound));
1125
- }).catch(() => {
1132
+ }).catch((error) => {
1133
+ if (disposed) return;
1134
+ try {
1135
+ onError?.(error);
1136
+ } catch {
1137
+ }
1126
1138
  });
1127
1139
  return {
1128
1140
  applyUpdate() {
1141
+ if (activatedUnasked) return reloadOnce();
1129
1142
  const waiting = registration?.waiting;
1130
1143
  if (!waiting) return;
1131
1144
  applying = true;
@@ -1139,9 +1152,11 @@ function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = ()
1139
1152
  }
1140
1153
 
1141
1154
  // src/service-worker/use-service-worker.ts
1142
- function useServiceWorker({ url, scope, enabled = true }) {
1155
+ function useServiceWorker({ url, scope, enabled = true, onError }) {
1143
1156
  const [supported, setSupported] = (0, import_react18.useState)(true);
1144
1157
  const [updateAvailable, setUpdateAvailable] = (0, import_react18.useState)(false);
1158
+ const onErrorRef = (0, import_react18.useRef)(onError);
1159
+ onErrorRef.current = onError;
1145
1160
  const handle = (0, import_react18.useRef)(void 0);
1146
1161
  (0, import_react18.useEffect)(() => {
1147
1162
  if (!enabled) return;
@@ -1149,7 +1164,12 @@ function useServiceWorker({ url, scope, enabled = true }) {
1149
1164
  setSupported(false);
1150
1165
  return;
1151
1166
  }
1152
- const registered = registerServiceWorker({ url, scope, onUpdateAvailable: () => setUpdateAvailable(true) });
1167
+ const registered = registerServiceWorker({
1168
+ url,
1169
+ scope,
1170
+ onUpdateAvailable: () => setUpdateAvailable(true),
1171
+ onError: (error) => onErrorRef.current?.(error)
1172
+ });
1153
1173
  handle.current = registered;
1154
1174
  return () => {
1155
1175
  registered.dispose();
@@ -1324,8 +1344,11 @@ function readPermission() {
1324
1344
  if (typeof window === "undefined" || !("Notification" in window)) return "unsupported";
1325
1345
  return Notification.permission;
1326
1346
  }
1327
- function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }) {
1328
- return resubscribeOnLoad && permission === "granted" && !hasSubscription;
1347
+ function isKeyReady(key) {
1348
+ return key.trim().length > 0;
1349
+ }
1350
+ function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad, hasKey = true }) {
1351
+ return hasKey && resubscribeOnLoad && permission === "granted" && !hasSubscription;
1329
1352
  }
1330
1353
  function isGone(error) {
1331
1354
  return typeof error === "object" && error !== null && error.status === 410;
@@ -1371,6 +1394,7 @@ function usePushSubscription(options) {
1371
1394
  const [subscribed, setSubscribed] = (0, import_react21.useState)(false);
1372
1395
  const [busy, setBusy] = (0, import_react21.useState)(false);
1373
1396
  const [error, setError] = (0, import_react21.useState)(null);
1397
+ const hasKey = isKeyReady(options.vapidPublicKey);
1374
1398
  const latest = (0, import_react21.useRef)(options);
1375
1399
  latest.current = options;
1376
1400
  (0, import_react21.useEffect)(() => {
@@ -1387,7 +1411,7 @@ function usePushSubscription(options) {
1387
1411
  const permissionNow = readPermission();
1388
1412
  setPermission(permissionNow);
1389
1413
  if (existing) return setSubscribed(true);
1390
- if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad })) return;
1414
+ if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad, hasKey })) return;
1391
1415
  await ensureSubscribed(reg, latest.current);
1392
1416
  if (!cancelled) setSubscribed(true);
1393
1417
  } catch {
@@ -1396,9 +1420,13 @@ function usePushSubscription(options) {
1396
1420
  return () => {
1397
1421
  cancelled = true;
1398
1422
  };
1399
- }, [resubscribeOnLoad]);
1423
+ }, [resubscribeOnLoad, hasKey]);
1400
1424
  const subscribe3 = (0, import_react21.useCallback)(async () => {
1401
1425
  if (getPushSupport() !== "supported") return;
1426
+ if (!isKeyReady(latest.current.vapidPublicKey)) {
1427
+ setError("push key not ready");
1428
+ return;
1429
+ }
1402
1430
  setError(null);
1403
1431
  setBusy(true);
1404
1432
  try {
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  deriveUpdateState,
4
4
  unregisterAll,
5
5
  useServiceWorker
6
- } from "./chunk-JG3GPTMY.js";
6
+ } from "./chunk-UVJBJETY.js";
7
7
  import {
8
8
  canShareFiles,
9
9
  isShareCancel,
@@ -21,7 +21,7 @@ import {
21
21
  shouldResubscribe,
22
22
  urlBase64ToUint8Array,
23
23
  usePushSubscription
24
- } from "./chunk-UJ366T3Y.js";
24
+ } from "./chunk-R2PFNE3U.js";
25
25
  import {
26
26
  nextDelay,
27
27
  useVisibilityPolling
package/dist/push.cjs CHANGED
@@ -82,8 +82,11 @@ function readPermission() {
82
82
  if (typeof window === "undefined" || !("Notification" in window)) return "unsupported";
83
83
  return Notification.permission;
84
84
  }
85
- function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }) {
86
- return resubscribeOnLoad && permission === "granted" && !hasSubscription;
85
+ function isKeyReady(key) {
86
+ return key.trim().length > 0;
87
+ }
88
+ function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad, hasKey = true }) {
89
+ return hasKey && resubscribeOnLoad && permission === "granted" && !hasSubscription;
87
90
  }
88
91
  function isGone(error) {
89
92
  return typeof error === "object" && error !== null && error.status === 410;
@@ -129,6 +132,7 @@ function usePushSubscription(options) {
129
132
  const [subscribed, setSubscribed] = (0, import_react.useState)(false);
130
133
  const [busy, setBusy] = (0, import_react.useState)(false);
131
134
  const [error, setError] = (0, import_react.useState)(null);
135
+ const hasKey = isKeyReady(options.vapidPublicKey);
132
136
  const latest = (0, import_react.useRef)(options);
133
137
  latest.current = options;
134
138
  (0, import_react.useEffect)(() => {
@@ -145,7 +149,7 @@ function usePushSubscription(options) {
145
149
  const permissionNow = readPermission();
146
150
  setPermission(permissionNow);
147
151
  if (existing) return setSubscribed(true);
148
- if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad })) return;
152
+ if (!shouldResubscribe({ permission: permissionNow, hasSubscription: false, resubscribeOnLoad, hasKey })) return;
149
153
  await ensureSubscribed(reg, latest.current);
150
154
  if (!cancelled) setSubscribed(true);
151
155
  } catch {
@@ -154,9 +158,13 @@ function usePushSubscription(options) {
154
158
  return () => {
155
159
  cancelled = true;
156
160
  };
157
- }, [resubscribeOnLoad]);
161
+ }, [resubscribeOnLoad, hasKey]);
158
162
  const subscribe = (0, import_react.useCallback)(async () => {
159
163
  if (getPushSupport() !== "supported") return;
164
+ if (!isKeyReady(latest.current.vapidPublicKey)) {
165
+ setError("push key not ready");
166
+ return;
167
+ }
160
168
  setError(null);
161
169
  setBusy(true);
162
170
  try {
package/dist/push.d.cts CHANGED
@@ -12,8 +12,9 @@ interface ResubscribeInput {
12
12
  permission: PushPermission;
13
13
  hasSubscription: boolean;
14
14
  resubscribeOnLoad: boolean;
15
+ hasKey?: boolean;
15
16
  }
16
- declare function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }: ResubscribeInput): boolean;
17
+ declare function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad, hasKey }: ResubscribeInput): boolean;
17
18
 
18
19
  interface UsePushSubscriptionOptions {
19
20
  vapidPublicKey: string;
package/dist/push.d.ts CHANGED
@@ -12,8 +12,9 @@ interface ResubscribeInput {
12
12
  permission: PushPermission;
13
13
  hasSubscription: boolean;
14
14
  resubscribeOnLoad: boolean;
15
+ hasKey?: boolean;
15
16
  }
16
- declare function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad }: ResubscribeInput): boolean;
17
+ declare function shouldResubscribe({ permission, hasSubscription, resubscribeOnLoad, hasKey }: ResubscribeInput): boolean;
17
18
 
18
19
  interface UsePushSubscriptionOptions {
19
20
  vapidPublicKey: string;
package/dist/push.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  shouldResubscribe,
5
5
  urlBase64ToUint8Array,
6
6
  usePushSubscription
7
- } from "./chunk-UJ366T3Y.js";
7
+ } from "./chunk-R2PFNE3U.js";
8
8
  import "./chunk-YFMMSLMB.js";
9
9
  export {
10
10
  getPushSupport,
@@ -50,17 +50,24 @@ async function unregisterAll() {
50
50
  } catch {
51
51
  }
52
52
  }
53
- function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = () => window.location.reload() } = {}) {
53
+ function registerServiceWorker({ url, scope, onUpdateAvailable, onError }, { reload = () => window.location.reload() } = {}) {
54
54
  let registration;
55
55
  let disposed = false;
56
56
  let applying = false;
57
57
  const cleanups = [];
58
58
  const controlledAtStart = hasController();
59
- const onControllerChange = () => {
60
- if (!(applying || controlledAtStart) || reloaded) return;
59
+ let activatedUnasked = false;
60
+ const reloadOnce = () => {
61
+ if (reloaded) return;
61
62
  reloaded = true;
62
63
  reload();
63
64
  };
65
+ const onControllerChange = () => {
66
+ if (applying) return reloadOnce();
67
+ if (!controlledAtStart || activatedUnasked) return;
68
+ activatedUnasked = true;
69
+ onUpdateAvailable();
70
+ };
64
71
  navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
65
72
  cleanups.push(() => navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange));
66
73
  const watchInstalling = (reg) => {
@@ -83,10 +90,16 @@ function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = ()
83
90
  const onUpdateFound = () => watchInstalling(reg);
84
91
  reg.addEventListener("updatefound", onUpdateFound);
85
92
  cleanups.push(() => reg.removeEventListener("updatefound", onUpdateFound));
86
- }).catch(() => {
93
+ }).catch((error) => {
94
+ if (disposed) return;
95
+ try {
96
+ onError?.(error);
97
+ } catch {
98
+ }
87
99
  });
88
100
  return {
89
101
  applyUpdate() {
102
+ if (activatedUnasked) return reloadOnce();
90
103
  const waiting = registration?.waiting;
91
104
  if (!waiting) return;
92
105
  applying = true;
@@ -100,9 +113,11 @@ function registerServiceWorker({ url, scope, onUpdateAvailable }, { reload = ()
100
113
  }
101
114
 
102
115
  // src/service-worker/use-service-worker.ts
103
- function useServiceWorker({ url, scope, enabled = true }) {
116
+ function useServiceWorker({ url, scope, enabled = true, onError }) {
104
117
  const [supported, setSupported] = (0, import_react.useState)(true);
105
118
  const [updateAvailable, setUpdateAvailable] = (0, import_react.useState)(false);
119
+ const onErrorRef = (0, import_react.useRef)(onError);
120
+ onErrorRef.current = onError;
106
121
  const handle = (0, import_react.useRef)(void 0);
107
122
  (0, import_react.useEffect)(() => {
108
123
  if (!enabled) return;
@@ -110,7 +125,12 @@ function useServiceWorker({ url, scope, enabled = true }) {
110
125
  setSupported(false);
111
126
  return;
112
127
  }
113
- const registered = registerServiceWorker({ url, scope, onUpdateAvailable: () => setUpdateAvailable(true) });
128
+ const registered = registerServiceWorker({
129
+ url,
130
+ scope,
131
+ onUpdateAvailable: () => setUpdateAvailable(true),
132
+ onError: (error) => onErrorRef.current?.(error)
133
+ });
114
134
  handle.current = registered;
115
135
  return () => {
116
136
  registered.dispose();
@@ -2,13 +2,14 @@ interface UseServiceWorkerOptions {
2
2
  url: string;
3
3
  scope?: string;
4
4
  enabled?: boolean;
5
+ onError?: (error: unknown) => void;
5
6
  }
6
7
  interface ServiceWorkerState$1 {
7
8
  supported: boolean;
8
9
  updateAvailable: boolean;
9
10
  applyUpdate: () => void;
10
11
  }
11
- declare function useServiceWorker({ url, scope, enabled }: UseServiceWorkerOptions): ServiceWorkerState$1;
12
+ declare function useServiceWorker({ url, scope, enabled, onError }: UseServiceWorkerOptions): ServiceWorkerState$1;
12
13
 
13
14
  declare function unregisterAll(): Promise<void>;
14
15
 
@@ -2,13 +2,14 @@ interface UseServiceWorkerOptions {
2
2
  url: string;
3
3
  scope?: string;
4
4
  enabled?: boolean;
5
+ onError?: (error: unknown) => void;
5
6
  }
6
7
  interface ServiceWorkerState$1 {
7
8
  supported: boolean;
8
9
  updateAvailable: boolean;
9
10
  applyUpdate: () => void;
10
11
  }
11
- declare function useServiceWorker({ url, scope, enabled }: UseServiceWorkerOptions): ServiceWorkerState$1;
12
+ declare function useServiceWorker({ url, scope, enabled, onError }: UseServiceWorkerOptions): ServiceWorkerState$1;
12
13
 
13
14
  declare function unregisterAll(): Promise<void>;
14
15
 
@@ -3,7 +3,7 @@ import {
3
3
  deriveUpdateState,
4
4
  unregisterAll,
5
5
  useServiceWorker
6
- } from "./chunk-JG3GPTMY.js";
6
+ } from "./chunk-UVJBJETY.js";
7
7
  export {
8
8
  deriveUpdateState,
9
9
  unregisterAll,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@develemit/web-hooks",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Shared React behavior hooks for develemit web apps: drawer swipe, focus trap, escape key and clipboard.",
5
5
  "license": "MIT",
6
6
  "author": "Emit Dutcher",