@ryuzaki13/react-foundation-lib 1.8.3 → 2.0.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.
Files changed (43) hide show
  1. package/README.md +5 -3
  2. package/dist/error-report/breadcrumbs.d.ts.map +1 -1
  3. package/dist/error-report/capture.d.ts.map +1 -1
  4. package/dist/error-report/diagnostics.d.ts.map +1 -1
  5. package/dist/error-report/drafts.d.ts +2 -11
  6. package/dist/error-report/drafts.d.ts.map +1 -1
  7. package/dist/error-report/errorInfo.d.ts.map +1 -1
  8. package/dist/error-report/index.d.ts +5 -0
  9. package/dist/error-report/index.d.ts.map +1 -1
  10. package/dist/error-report/index.js +920 -210
  11. package/dist/error-report/index.js.map +1 -1
  12. package/dist/error-report/payload.d.ts +13 -0
  13. package/dist/error-report/payload.d.ts.map +1 -0
  14. package/dist/error-report/queue.d.ts +15 -0
  15. package/dist/error-report/queue.d.ts.map +1 -0
  16. package/dist/error-report/queueContract.d.ts +62 -0
  17. package/dist/error-report/queueContract.d.ts.map +1 -0
  18. package/dist/error-report/queueRecord.d.ts +9 -0
  19. package/dist/error-report/queueRecord.d.ts.map +1 -0
  20. package/dist/error-report/safeValue.d.ts +26 -2
  21. package/dist/error-report/safeValue.d.ts.map +1 -1
  22. package/dist/error-report/schema.d.ts +14 -0
  23. package/dist/error-report/schema.d.ts.map +1 -0
  24. package/dist/error-report/transport.d.ts +0 -2
  25. package/dist/error-report/transport.d.ts.map +1 -1
  26. package/dist/error-report/types.d.ts +26 -1
  27. package/dist/error-report/types.d.ts.map +1 -1
  28. package/dist/pwa/index.d.ts +1 -0
  29. package/dist/pwa/index.d.ts.map +1 -1
  30. package/dist/pwa/index.js +75 -59
  31. package/dist/pwa/index.js.map +1 -1
  32. package/dist/pwa/useBrowserOnlineStatus.d.ts +3 -0
  33. package/dist/pwa/useBrowserOnlineStatus.d.ts.map +1 -0
  34. package/dist/query-client/index.js +137 -43
  35. package/dist/query-client/index.js.map +1 -1
  36. package/dist/query-client/persistence.d.ts +21 -3
  37. package/dist/query-client/persistence.d.ts.map +1 -1
  38. package/dist/query-client/queryMeta.d.ts +21 -2
  39. package/dist/query-client/queryMeta.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/error-report/README.mdx +133 -27
  42. package/src/pwa/README.mdx +4 -0
  43. package/src/query-client/README.mdx +48 -7
@@ -1,6 +1,7 @@
1
1
  import type { QueryKey } from "@tanstack/react-query";
2
2
  export type ErrorReportCategory = "query" | "mutation" | "runtime" | "react";
3
3
  export type ErrorReportStatus = "pending" | "sending" | "sent" | "failed";
4
+ export type ErrorReportPayloadVersion = 1;
4
5
  export type ErrorReportSafeValue = string | number | boolean | null | ErrorReportSafeValue[] | {
5
6
  [key: string]: ErrorReportSafeValue;
6
7
  };
@@ -43,7 +44,6 @@ export type ErrorReportMutationDiagnostics = {
43
44
  error?: ErrorReportErrorInfo;
44
45
  };
45
46
  export type ErrorReportPersistedQueryDiagnostics = {
46
- storageKey: string;
47
47
  buster?: string;
48
48
  queryHash?: string;
49
49
  queryKey?: ErrorReportSafeValue;
@@ -55,6 +55,8 @@ export type ErrorReportPersistedQueryDiagnostics = {
55
55
  error?: ErrorReportErrorInfo;
56
56
  };
57
57
  export type ErrorReportPayload = {
58
+ payloadVersion: ErrorReportPayloadVersion;
59
+ application: string;
58
60
  reportId: string;
59
61
  sessionId: string;
60
62
  createdUtc: string;
@@ -91,6 +93,12 @@ export type ErrorReportPayload = {
91
93
  persistedQueries?: ErrorReportPersistedQueryDiagnostics[];
92
94
  breadcrumbs: ErrorReportBreadcrumb[];
93
95
  context?: Record<string, ErrorReportSafeValue>;
96
+ truncation?: {
97
+ reason: "payload-size";
98
+ limitBytes: number;
99
+ originalBytes: number;
100
+ droppedSections: string[];
101
+ };
94
102
  };
95
103
  export type ErrorReportDraft = {
96
104
  reportId: string;
@@ -102,6 +110,12 @@ export type ErrorReportDraft = {
102
110
  failedReason?: string;
103
111
  payload: ErrorReportPayload;
104
112
  };
113
+ /** Единственные поля draft, которые delivery lifecycle вправе изменять. */
114
+ export type ErrorReportDraftLifecyclePatch = {
115
+ status?: ErrorReportStatus;
116
+ sentUtc?: string;
117
+ failedReason?: string;
118
+ };
105
119
  export type ErrorReportRuntimeContext = {
106
120
  category?: Extract<ErrorReportCategory, "runtime" | "react">;
107
121
  source?: string;
@@ -120,4 +134,15 @@ export type ErrorReportMutationContext = {
120
134
  errorInfo?: ErrorReportErrorInfo;
121
135
  detail?: Record<string, unknown>;
122
136
  };
137
+ export type ErrorReportSanitizationScope = "breadcrumb-detail" | "context" | "draft-failed-reason" | "error-message" | "mutation-key" | "mutation-meta" | "persisted-query-key" | "query-data-shape" | "query-key" | "query-meta" | "stack-trace";
138
+ export type ErrorReportSanitizationContext = {
139
+ scope: ErrorReportSanitizationScope;
140
+ source?: string;
141
+ };
142
+ /**
143
+ * App-level callback получает уже bounded JSON-совместимое значение и может
144
+ * применить предметный allow-list. Foundation повторно нормализует результат,
145
+ * поэтому callback не может обойти ограничения глубины, размера строк и циклов.
146
+ */
147
+ export type ErrorReportSanitizer = (value: ErrorReportSafeValue, context: ErrorReportSanitizationContext) => ErrorReportSafeValue | undefined;
123
148
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/error-report/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/error-report/types.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export * from "./swCachePolicy";
2
+ export * from "./useBrowserOnlineStatus";
2
3
  export * from "./useServiceWorkerUpdate";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pwa/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pwa/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC"}
package/dist/pwa/index.js CHANGED
@@ -1,133 +1,149 @@
1
1
  import { i as e } from "../chunks/isRecord-DXDTW-jA.js";
2
2
  import { logError as t } from "../utils/index.js";
3
3
  import { buildSwCachePolicyValue as n, normalizeSwCacheName as r, parseSwCachePolicy as i, resolveSwCacheCacheNameByPolicy as a } from "./sw-cache-policy.js";
4
- import { useCallback as o, useEffect as s, useState as c } from "react";
4
+ import { useCallback as o, useEffect as s, useState as c, useSyncExternalStore as l } from "react";
5
+ //#region src/pwa/useBrowserOnlineStatus.ts
6
+ function u(e) {
7
+ return window.addEventListener("online", e), window.addEventListener("offline", e), () => {
8
+ window.removeEventListener("online", e), window.removeEventListener("offline", e);
9
+ };
10
+ }
11
+ function d() {
12
+ return navigator.onLine;
13
+ }
14
+ function f() {
15
+ return !0;
16
+ }
17
+ function p() {
18
+ return l(u, d, f);
19
+ }
20
+ //#endregion
5
21
  //#region src/pwa/serviceWorker.ts
6
- var l = __SERVICE_WORKER_SCOPE__, u = __SERVICE_WORKER_URL__, d = "SW_ACTIVATED_BY_CLIENT", f = __SERVICE_WORKER_UPDATE_RELOAD_COUNT_KEY__, p = __SERVICE_WORKER_MAX_AUTO_UPDATE_RELOADS__, m = /* @__PURE__ */ new WeakSet(), h = /* @__PURE__ */ new Set(), g = null, _ = !1, v = !1, y = !1, b = !1;
7
- function x(t) {
8
- return e(t) && t.type === d ? { type: d } : null;
22
+ var m = __SERVICE_WORKER_SCOPE__, h = __SERVICE_WORKER_URL__, g = "SW_ACTIVATED_BY_CLIENT", _ = __SERVICE_WORKER_UPDATE_RELOAD_COUNT_KEY__, v = __SERVICE_WORKER_MAX_AUTO_UPDATE_RELOADS__, y = /* @__PURE__ */ new WeakSet(), b = /* @__PURE__ */ new Set(), x = null, S = !1, C = !1, w = !1, T = !1;
23
+ function E(t) {
24
+ return e(t) && t.type === g ? { type: g } : null;
9
25
  }
10
- function S() {
26
+ function D() {
11
27
  try {
12
- let e = window.sessionStorage.getItem(f), t = Number(e);
28
+ let e = window.sessionStorage.getItem(_), t = Number(e);
13
29
  return Number.isInteger(t) && t > 0 ? t : 0;
14
30
  } catch {
15
31
  return 0;
16
32
  }
17
33
  }
18
- function C() {
34
+ function O() {
19
35
  try {
20
- let e = Math.min(S() + 1, p);
21
- window.sessionStorage.setItem(f, String(e));
36
+ let e = Math.min(D() + 1, v);
37
+ window.sessionStorage.setItem(_, String(e));
22
38
  } catch {}
23
39
  }
24
- function w() {
25
- return S() < p;
40
+ function k() {
41
+ return D() < v;
26
42
  }
27
- function T() {
43
+ function A() {
28
44
  try {
29
- window.sessionStorage.removeItem(f);
45
+ window.sessionStorage.removeItem(_);
30
46
  } catch {}
31
47
  }
32
- function E() {
33
- _ || (_ = !0, window.location.reload());
48
+ function j() {
49
+ S || (S = !0, window.location.reload());
34
50
  }
35
- function D() {
36
- y || (y = !0, navigator.serviceWorker.addEventListener("controllerchange", () => {
37
- v && E();
51
+ function M() {
52
+ w || (w = !0, navigator.serviceWorker.addEventListener("controllerchange", () => {
53
+ C && j();
38
54
  }));
39
55
  }
40
- function O() {
41
- b || (b = !0, navigator.serviceWorker.addEventListener("message", (e) => {
42
- x(e.data) && (_ || (C(), E()));
56
+ function N() {
57
+ T || (T = !0, navigator.serviceWorker.addEventListener("message", (e) => {
58
+ E(e.data) && (S || (O(), j()));
43
59
  }));
44
60
  }
45
- function k(e) {
46
- for (let t of h) t(e);
61
+ function P(e) {
62
+ for (let t of b) t(e);
47
63
  }
48
- function A(e) {
49
- m.has(e) || (m.add(e), e.addEventListener("updatefound", () => {
64
+ function F(e) {
65
+ y.has(e) || (y.add(e), e.addEventListener("updatefound", () => {
50
66
  let t = e.installing;
51
67
  t && t.addEventListener("statechange", () => {
52
- t.state === "installed" && navigator.serviceWorker.controller && (g = e, k(e));
68
+ t.state === "installed" && navigator.serviceWorker.controller && (x = e, P(e));
53
69
  });
54
- }), D(), O());
70
+ }), M(), N());
55
71
  }
56
- async function j(e = {}) {
72
+ async function I(e = {}) {
57
73
  if (!("serviceWorker" in navigator)) return null;
58
- e.onUpdate && h.add(e.onUpdate);
74
+ e.onUpdate && b.add(e.onUpdate);
59
75
  try {
60
- let t = g ?? await navigator.serviceWorker.getRegistration(l) ?? await navigator.serviceWorker.register(u, {
61
- scope: l,
76
+ let t = x ?? await navigator.serviceWorker.getRegistration(m) ?? await navigator.serviceWorker.register(h, {
77
+ scope: m,
62
78
  updateViaCache: "none"
63
79
  });
64
- return g = t, A(t), e.onReady?.(t), t;
80
+ return x = t, F(t), e.onReady?.(t), t;
65
81
  } catch (e) {
66
82
  return t("[SW] registration failed:", e), null;
67
83
  }
68
84
  }
69
- function M(e) {
70
- h.delete(e);
85
+ function L(e) {
86
+ b.delete(e);
71
87
  }
72
- function N(e) {
88
+ function R(e) {
73
89
  return !!e?.waiting;
74
90
  }
75
- function P(e = g) {
91
+ function z(e = x) {
76
92
  let t = e?.waiting;
77
- return t ? (v = !0, C(), t.postMessage({ type: "SKIP_WAITING" }), !0) : !1;
93
+ return t ? (C = !0, O(), t.postMessage({ type: "SKIP_WAITING" }), !0) : !1;
78
94
  }
79
- function F() {
80
- return C(), E(), !0;
95
+ function B() {
96
+ return O(), j(), !0;
81
97
  }
82
- async function I() {
98
+ async function V() {
83
99
  if (!("serviceWorker" in navigator)) return null;
84
100
  try {
85
- let e = g ?? await navigator.serviceWorker.getRegistration(l);
86
- return e ? (g = e, A(e), await e.update(), e) : null;
101
+ let e = x ?? await navigator.serviceWorker.getRegistration(m);
102
+ return e ? (x = e, F(e), await e.update(), e) : null;
87
103
  } catch (e) {
88
104
  return t("[SW] update check failed:", e), null;
89
105
  }
90
106
  }
91
107
  //#endregion
92
108
  //#region src/pwa/useServiceWorkerUpdate.ts
93
- var L = 3e5, R = 3e4;
94
- function z() {
109
+ var H = 3e5, U = 3e4;
110
+ function W() {
95
111
  let [e] = performance.getEntriesByType("navigation");
96
112
  return e?.type === "reload" || e?.type === "navigate";
97
113
  }
98
- function B() {
99
- let [e, t] = c(null), n = e !== null, r = o(() => P(e) ? !0 : e ? F() : !1, [e]), i = o(() => {
114
+ function G() {
115
+ let [e, t] = c(null), n = e !== null, r = o(() => z(e) ? !0 : e ? B() : !1, [e]), i = o(() => {
100
116
  t(null);
101
117
  }, []);
102
118
  return s(() => {
103
119
  if (__DEV__) return;
104
- let e = !0, n = Date.now(), r = null, i = !1, a = () => z() && Date.now() - n <= R && w(), o = (e) => {
120
+ let e = !0, n = Date.now(), r = null, i = !1, a = () => W() && Date.now() - n <= U && k(), o = (e) => {
105
121
  if (i) return !0;
106
122
  if (!a()) return !1;
107
- let t = P(e);
123
+ let t = z(e);
108
124
  return i = t, t;
109
125
  }, s = () => {
110
- let t = Date.now() - n, i = Math.max(R - t, 0);
126
+ let t = Date.now() - n, i = Math.max(U - t, 0);
111
127
  r = window.setTimeout(() => {
112
- e && T();
128
+ e && A();
113
129
  }, i);
114
130
  }, c = (n) => {
115
131
  e && (o(n) || t(n));
116
132
  };
117
133
  async function l() {
118
- let n = await j({ onUpdate: c });
119
- if (!e || N(n) && o(n)) return;
120
- let r = await I();
121
- e && (i || N(r) && o(r) || (N(r) && t(r), s()));
134
+ let n = await I({ onUpdate: c });
135
+ if (!e || R(n) && o(n)) return;
136
+ let r = await V();
137
+ e && (i || R(r) && o(r) || (R(r) && t(r), s()));
122
138
  }
123
139
  l();
124
140
  let u = window.setInterval(() => {
125
- I().then((n) => {
126
- e && N(n) && t(n);
141
+ V().then((n) => {
142
+ e && R(n) && t(n);
127
143
  });
128
- }, L);
144
+ }, H);
129
145
  return () => {
130
- e = !1, r !== null && window.clearTimeout(r), window.clearInterval(u), M(c);
146
+ e = !1, r !== null && window.clearTimeout(r), window.clearInterval(u), L(c);
131
147
  };
132
148
  }, []), {
133
149
  hasUpdate: n,
@@ -136,6 +152,6 @@ function B() {
136
152
  };
137
153
  }
138
154
  //#endregion
139
- export { n as buildSwCachePolicyValue, r as normalizeSwCacheName, i as parseSwCachePolicy, a as resolveSwCacheCacheNameByPolicy, B as useServiceWorkerUpdate };
155
+ export { n as buildSwCachePolicyValue, r as normalizeSwCacheName, i as parseSwCachePolicy, a as resolveSwCacheCacheNameByPolicy, p as useBrowserOnlineStatus, G as useServiceWorkerUpdate };
140
156
 
141
157
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/pwa/serviceWorker.ts","../../src/pwa/useServiceWorkerUpdate.ts"],"sourcesContent":["import { logError } from \"../utils\";\nimport { isRecord } from \"../validators\";\n\nconst SW_SCOPE = __SERVICE_WORKER_SCOPE__;\nconst SW_URL = __SERVICE_WORKER_URL__;\nconst SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE = \"SW_ACTIVATED_BY_CLIENT\";\nconst SW_UPDATE_RELOAD_COUNT_KEY = __SERVICE_WORKER_UPDATE_RELOAD_COUNT_KEY__;\nconst MAX_SW_AUTO_UPDATE_RELOADS = __SERVICE_WORKER_MAX_AUTO_UPDATE_RELOADS__;\n\ntype SWUpdateHandler = (reg: ServiceWorkerRegistration) => void;\n\ntype ServiceWorkerClientMessage = {\n\ttype: typeof SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE;\n};\n\ntype RegisterSWOptions = {\n\t/**\n\t * Вызывается, когда новый SW установлен и ждёт активации.\n\t */\n\tonUpdate?: SWUpdateHandler;\n\n\t/**\n\t * Вызывается после успешной регистрации.\n\t */\n\tonReady?: (reg: ServiceWorkerRegistration) => void;\n};\n\nconst observedRegistrations = new WeakSet<ServiceWorkerRegistration>();\nconst updateHandlers = new Set<SWUpdateHandler>();\n\nlet latestRegistration: ServiceWorkerRegistration | null = null;\nlet refreshing = false;\nlet updateRequested = false;\nlet controllerChangeSubscribed = false;\nlet serviceWorkerMessageSubscribed = false;\n\nfunction readServiceWorkerClientMessage(value: unknown): ServiceWorkerClientMessage | null {\n\tif (!isRecord(value)) return null;\n\n\treturn value.type === SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE ? { type: SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE } : null;\n}\n\nfunction readServiceWorkerUpdateReloadCount(): number {\n\ttry {\n\t\tconst value = window.sessionStorage.getItem(SW_UPDATE_RELOAD_COUNT_KEY);\n\t\tconst count = Number(value);\n\n\t\treturn Number.isInteger(count) && count > 0 ? count : 0;\n\t} catch {\n\t\treturn 0;\n\t}\n}\n\nexport function recordServiceWorkerUpdateReload() {\n\ttry {\n\t\tconst nextCount = Math.min(readServiceWorkerUpdateReloadCount() + 1, MAX_SW_AUTO_UPDATE_RELOADS);\n\t\twindow.sessionStorage.setItem(SW_UPDATE_RELOAD_COUNT_KEY, String(nextCount));\n\t} catch {\n\t\t/**\n\t\t * sessionStorage может быть недоступен в приватном режиме или при\n\t\t * жёстких browser policy. Обновление всё равно должно продолжиться.\n\t\t */\n\t}\n}\n\nexport function canAutoApplyServiceWorkerUpdate(): boolean {\n\treturn readServiceWorkerUpdateReloadCount() < MAX_SW_AUTO_UPDATE_RELOADS;\n}\n\nexport function clearServiceWorkerUpdateReloadChain() {\n\ttry {\n\t\twindow.sessionStorage.removeItem(SW_UPDATE_RELOAD_COUNT_KEY);\n\t} catch {\n\t\t/**\n\t\t * Очистка маркера не критична: максимум пользователь увидит обычный\n\t\t * баннер вместо автоматического продолжения цепочки обновлений.\n\t\t */\n\t}\n}\n\nfunction reloadPage() {\n\tif (refreshing) return;\n\n\trefreshing = true;\n\twindow.location.reload();\n}\n\nfunction subscribeControllerChangeReload() {\n\tif (controllerChangeSubscribed) return;\n\n\tcontrollerChangeSubscribed = true;\n\n\tnavigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n\t\t/**\n\t\t * Не перезагружаем страницу от любого controllerchange.\n\t\t * Перезагрузка нужна только когда мы сами вызвали SKIP_WAITING.\n\t\t */\n\t\tif (!updateRequested) return;\n\n\t\treloadPage();\n\t});\n}\n\nfunction subscribeServiceWorkerMessages() {\n\tif (serviceWorkerMessageSubscribed) return;\n\n\tserviceWorkerMessageSubscribed = true;\n\n\tnavigator.serviceWorker.addEventListener(\"message\", (event) => {\n\t\tconst message = readServiceWorkerClientMessage(event.data);\n\t\tif (!message) return;\n\t\tif (refreshing) return;\n\n\t\trecordServiceWorkerUpdateReload();\n\t\treloadPage();\n\t});\n}\n\nfunction emitUpdate(reg: ServiceWorkerRegistration) {\n\tfor (const handler of updateHandlers) {\n\t\thandler(reg);\n\t}\n}\n\nfunction observeRegistration(reg: ServiceWorkerRegistration) {\n\tif (observedRegistrations.has(reg)) return;\n\n\tobservedRegistrations.add(reg);\n\n\treg.addEventListener(\"updatefound\", () => {\n\t\tconst newWorker = reg.installing;\n\t\tif (!newWorker) return;\n\n\t\tnewWorker.addEventListener(\"statechange\", () => {\n\t\t\t/**\n\t\t\t * installed + есть controller = новая версия установлена,\n\t\t\t * но текущая страница всё ещё под старым SW.\n\t\t\t */\n\t\t\tif (newWorker.state === \"installed\" && navigator.serviceWorker.controller) {\n\t\t\t\tlatestRegistration = reg;\n\t\t\t\temitUpdate(reg);\n\t\t\t}\n\t\t});\n\t});\n\n\tsubscribeControllerChangeReload();\n\tsubscribeServiceWorkerMessages();\n}\n\nexport async function getServiceWorkerRegistration(): Promise<ServiceWorkerRegistration | null> {\n\tif (!(\"serviceWorker\" in navigator)) return null;\n\n\ttry {\n\t\tconst reg = latestRegistration ?? (await navigator.serviceWorker.getRegistration(SW_SCOPE));\n\n\t\tif (!reg) return null;\n\n\t\tlatestRegistration = reg;\n\t\tobserveRegistration(reg);\n\n\t\treturn reg;\n\t} catch (err) {\n\t\tlogError(\"[SW] get registration failed:\", err);\n\t\treturn null;\n\t}\n}\n\nexport async function registerServiceWorker(options: RegisterSWOptions = {}) {\n\tif (!(\"serviceWorker\" in navigator)) return null;\n\n\tif (options.onUpdate) {\n\t\tupdateHandlers.add(options.onUpdate);\n\t}\n\n\ttry {\n\t\tconst existingRegistration = latestRegistration ?? (await navigator.serviceWorker.getRegistration(SW_SCOPE));\n\n\t\tconst reg =\n\t\t\texistingRegistration ??\n\t\t\t(await navigator.serviceWorker.register(SW_URL, {\n\t\t\t\tscope: SW_SCOPE,\n\t\t\t\tupdateViaCache: \"none\"\n\t\t\t}));\n\n\t\tlatestRegistration = reg;\n\t\tobserveRegistration(reg);\n\n\t\toptions.onReady?.(reg);\n\n\t\treturn reg;\n\t} catch (err) {\n\t\tlogError(\"[SW] registration failed:\", err);\n\t\treturn null;\n\t}\n}\n\nexport function unsubscribeServiceWorkerUpdate(handler: SWUpdateHandler) {\n\tupdateHandlers.delete(handler);\n}\n\nexport function hasWaitingServiceWorker(reg: ServiceWorkerRegistration | null | undefined): reg is ServiceWorkerRegistration {\n\treturn Boolean(reg?.waiting);\n}\n\nexport function applyServiceWorkerUpdate(reg: ServiceWorkerRegistration | null = latestRegistration) {\n\tconst waiting = reg?.waiting;\n\tif (!waiting) return false;\n\n\tupdateRequested = true;\n\trecordServiceWorkerUpdateReload();\n\n\twaiting.postMessage({ type: \"SKIP_WAITING\" });\n\n\treturn true;\n}\n\nexport function reloadPageForServiceWorkerUpdate() {\n\trecordServiceWorkerUpdateReload();\n\treloadPage();\n\n\treturn true;\n}\n\nexport async function checkServiceWorkerUpdate() {\n\tif (!(\"serviceWorker\" in navigator)) return null;\n\n\ttry {\n\t\tconst reg = latestRegistration ?? (await navigator.serviceWorker.getRegistration(SW_SCOPE));\n\t\tif (!reg) return null;\n\n\t\tlatestRegistration = reg;\n\t\tobserveRegistration(reg);\n\n\t\tawait reg.update();\n\n\t\treturn reg;\n\t} catch (err) {\n\t\tlogError(\"[SW] update check failed:\", err);\n\t\treturn null;\n\t}\n}\n\n/**\n * Очищает SW-кеш OData для указанной политики.\n *\n * Примеры: `\"ttl=24h;name=ref\"`, `\"ttl=10m;max=200;name=ui\"`.\n *\n * После вызова следующий запрос с той же политикой пойдёт в сеть.\n */\nexport function invalidateSwCacheProfile(profile: string) {\n\tnavigator.serviceWorker?.controller?.postMessage({\n\t\ttype: \"invalidateProfile\",\n\t\tprofile\n\t});\n}\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport {\n\tapplyServiceWorkerUpdate,\n\tcanAutoApplyServiceWorkerUpdate,\n\tcheckServiceWorkerUpdate,\n\tclearServiceWorkerUpdateReloadChain,\n\thasWaitingServiceWorker,\n\tregisterServiceWorker,\n\treloadPageForServiceWorkerUpdate,\n\tunsubscribeServiceWorkerUpdate\n} from \"./serviceWorker\";\n\n// TODO: Vite env\nconst SW_UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000;\n// TODO: Vite env\nconst SW_STARTUP_AUTO_UPDATE_GRACE_MS = 30 * 1000;\n\nfunction isStartupNavigationForAutoUpdate(): boolean {\n\tconst [entry] = performance.getEntriesByType(\"navigation\") as PerformanceNavigationTiming[];\n\n\t/**\n\t * reload — пользователь явно обновил страницу.\n\t * navigate — пользователь открыл страницу по ссылке/закладке.\n\t */\n\treturn entry?.type === \"reload\" || entry?.type === \"navigate\";\n}\n\nexport function useServiceWorkerUpdate() {\n\tconst [waitingRegistration, setWaitingRegistration] = useState<ServiceWorkerRegistration | null>(null);\n\n\tconst hasUpdate = waitingRegistration !== null;\n\n\tconst applyUpdate = useCallback(() => {\n\t\tif (applyServiceWorkerUpdate(waitingRegistration)) return true;\n\t\tif (!waitingRegistration) return false;\n\n\t\t/**\n\t\t * Если другой клиент уже активировал waiting worker, в текущей вкладке\n\t\t * registration.waiting станет пустым, но баннер ещё может быть видимым.\n\t\t */\n\t\treturn reloadPageForServiceWorkerUpdate();\n\t}, [waitingRegistration]);\n\n\tconst dismiss = useCallback(() => {\n\t\tsetWaitingRegistration(null);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (__DEV__) return;\n\n\t\tlet isActive = true;\n\t\tconst startupStartedAt = Date.now();\n\t\tlet startupResetTimerId: number | null = null;\n\t\tlet startupUpdateApplied = false;\n\n\t\tconst canApplyStartupUpdate = () =>\n\t\t\tisStartupNavigationForAutoUpdate() &&\n\t\t\tDate.now() - startupStartedAt <= SW_STARTUP_AUTO_UPDATE_GRACE_MS &&\n\t\t\tcanAutoApplyServiceWorkerUpdate();\n\n\t\tconst tryApplyStartupUpdate = (reg: ServiceWorkerRegistration) => {\n\t\t\tif (startupUpdateApplied) return true;\n\t\t\tif (!canApplyStartupUpdate()) return false;\n\n\t\t\tconst applied = applyServiceWorkerUpdate(reg);\n\t\t\tstartupUpdateApplied = applied;\n\n\t\t\treturn applied;\n\t\t};\n\n\t\tconst scheduleStartupChainReset = () => {\n\t\t\tconst elapsedMs = Date.now() - startupStartedAt;\n\t\t\tconst timeoutMs = Math.max(SW_STARTUP_AUTO_UPDATE_GRACE_MS - elapsedMs, 0);\n\n\t\t\tstartupResetTimerId = window.setTimeout(() => {\n\t\t\t\tif (!isActive) return;\n\n\t\t\t\tclearServiceWorkerUpdateReloadChain();\n\t\t\t}, timeoutMs);\n\t\t};\n\n\t\tconst handleUpdate = (reg: ServiceWorkerRegistration) => {\n\t\t\tif (!isActive) return;\n\n\t\t\t/**\n\t\t\t * Если update найден вскоре после reload/navigate, применяем его\n\t\t\t * автоматически. Это закрывает цепочку из нескольких деплоев,\n\t\t\t * накопленных во время простоя вкладки.\n\t\t\t */\n\t\t\tif (tryApplyStartupUpdate(reg)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Если update найден уже во время активной сессии —\n\t\t\t * показываем баннер.\n\t\t\t */\n\t\t\tsetWaitingRegistration(reg);\n\t\t};\n\n\t\tasync function init() {\n\t\t\tconst reg = await registerServiceWorker({\n\t\t\t\tonUpdate: handleUpdate\n\t\t\t});\n\n\t\t\tif (!isActive) return;\n\n\t\t\t/**\n\t\t\t * Важный сценарий:\n\t\t\t * пользователь перезагрузил страницу, а новый SW уже был в waiting.\n\t\t\t * В этом случае не показываем баннер, а применяем update сразу.\n\t\t\t */\n\t\t\tif (hasWaitingServiceWorker(reg) && tryApplyStartupUpdate(reg)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst checkedReg = await checkServiceWorkerUpdate();\n\n\t\t\tif (!isActive) return;\n\t\t\tif (startupUpdateApplied) return;\n\n\t\t\tif (hasWaitingServiceWorker(checkedReg) && tryApplyStartupUpdate(checkedReg)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (hasWaitingServiceWorker(checkedReg)) {\n\t\t\t\tsetWaitingRegistration(checkedReg);\n\t\t\t}\n\n\t\t\tscheduleStartupChainReset();\n\t\t}\n\n\t\tvoid init();\n\n\t\tconst intervalId = window.setInterval(() => {\n\t\t\tvoid checkServiceWorkerUpdate().then((reg) => {\n\t\t\t\tif (!isActive) return;\n\n\t\t\t\tif (hasWaitingServiceWorker(reg)) {\n\t\t\t\t\tsetWaitingRegistration(reg);\n\t\t\t\t}\n\t\t\t});\n\t\t}, SW_UPDATE_CHECK_INTERVAL_MS);\n\n\t\treturn () => {\n\t\t\tisActive = false;\n\t\t\tif (startupResetTimerId !== null) {\n\t\t\t\twindow.clearTimeout(startupResetTimerId);\n\t\t\t}\n\t\t\twindow.clearInterval(intervalId);\n\t\t\tunsubscribeServiceWorkerUpdate(handleUpdate);\n\t\t};\n\t}, []);\n\n\treturn {\n\t\thasUpdate,\n\t\tapplyUpdate,\n\t\tdismiss\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/pwa/useBrowserOnlineStatus.ts","../../src/pwa/serviceWorker.ts","../../src/pwa/useServiceWorkerUpdate.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\n\nfunction subscribe(onStoreChange: () => void) {\n\twindow.addEventListener(\"online\", onStoreChange);\n\twindow.addEventListener(\"offline\", onStoreChange);\n\treturn () => {\n\t\twindow.removeEventListener(\"online\", onStoreChange);\n\t\twindow.removeEventListener(\"offline\", onStoreChange);\n\t};\n}\n\nfunction getSnapshot() {\n\treturn navigator.onLine;\n}\n\nfunction getServerSnapshot() {\n\treturn true;\n}\n\n/** Наблюдает browser online hint без попытки подменить им проверку доступности конкретного сервера. */\nexport function useBrowserOnlineStatus() {\n\treturn useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","import { logError } from \"../utils\";\nimport { isRecord } from \"../validators\";\n\nconst SW_SCOPE = __SERVICE_WORKER_SCOPE__;\nconst SW_URL = __SERVICE_WORKER_URL__;\nconst SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE = \"SW_ACTIVATED_BY_CLIENT\";\nconst SW_UPDATE_RELOAD_COUNT_KEY = __SERVICE_WORKER_UPDATE_RELOAD_COUNT_KEY__;\nconst MAX_SW_AUTO_UPDATE_RELOADS = __SERVICE_WORKER_MAX_AUTO_UPDATE_RELOADS__;\n\ntype SWUpdateHandler = (reg: ServiceWorkerRegistration) => void;\n\ntype ServiceWorkerClientMessage = {\n\ttype: typeof SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE;\n};\n\ntype RegisterSWOptions = {\n\t/**\n\t * Вызывается, когда новый SW установлен и ждёт активации.\n\t */\n\tonUpdate?: SWUpdateHandler;\n\n\t/**\n\t * Вызывается после успешной регистрации.\n\t */\n\tonReady?: (reg: ServiceWorkerRegistration) => void;\n};\n\nconst observedRegistrations = new WeakSet<ServiceWorkerRegistration>();\nconst updateHandlers = new Set<SWUpdateHandler>();\n\nlet latestRegistration: ServiceWorkerRegistration | null = null;\nlet refreshing = false;\nlet updateRequested = false;\nlet controllerChangeSubscribed = false;\nlet serviceWorkerMessageSubscribed = false;\n\nfunction readServiceWorkerClientMessage(value: unknown): ServiceWorkerClientMessage | null {\n\tif (!isRecord(value)) return null;\n\n\treturn value.type === SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE ? { type: SW_ACTIVATED_BY_CLIENT_MESSAGE_TYPE } : null;\n}\n\nfunction readServiceWorkerUpdateReloadCount(): number {\n\ttry {\n\t\tconst value = window.sessionStorage.getItem(SW_UPDATE_RELOAD_COUNT_KEY);\n\t\tconst count = Number(value);\n\n\t\treturn Number.isInteger(count) && count > 0 ? count : 0;\n\t} catch {\n\t\treturn 0;\n\t}\n}\n\nexport function recordServiceWorkerUpdateReload() {\n\ttry {\n\t\tconst nextCount = Math.min(readServiceWorkerUpdateReloadCount() + 1, MAX_SW_AUTO_UPDATE_RELOADS);\n\t\twindow.sessionStorage.setItem(SW_UPDATE_RELOAD_COUNT_KEY, String(nextCount));\n\t} catch {\n\t\t/**\n\t\t * sessionStorage может быть недоступен в приватном режиме или при\n\t\t * жёстких browser policy. Обновление всё равно должно продолжиться.\n\t\t */\n\t}\n}\n\nexport function canAutoApplyServiceWorkerUpdate(): boolean {\n\treturn readServiceWorkerUpdateReloadCount() < MAX_SW_AUTO_UPDATE_RELOADS;\n}\n\nexport function clearServiceWorkerUpdateReloadChain() {\n\ttry {\n\t\twindow.sessionStorage.removeItem(SW_UPDATE_RELOAD_COUNT_KEY);\n\t} catch {\n\t\t/**\n\t\t * Очистка маркера не критична: максимум пользователь увидит обычный\n\t\t * баннер вместо автоматического продолжения цепочки обновлений.\n\t\t */\n\t}\n}\n\nfunction reloadPage() {\n\tif (refreshing) return;\n\n\trefreshing = true;\n\twindow.location.reload();\n}\n\nfunction subscribeControllerChangeReload() {\n\tif (controllerChangeSubscribed) return;\n\n\tcontrollerChangeSubscribed = true;\n\n\tnavigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n\t\t/**\n\t\t * Не перезагружаем страницу от любого controllerchange.\n\t\t * Перезагрузка нужна только когда мы сами вызвали SKIP_WAITING.\n\t\t */\n\t\tif (!updateRequested) return;\n\n\t\treloadPage();\n\t});\n}\n\nfunction subscribeServiceWorkerMessages() {\n\tif (serviceWorkerMessageSubscribed) return;\n\n\tserviceWorkerMessageSubscribed = true;\n\n\tnavigator.serviceWorker.addEventListener(\"message\", (event) => {\n\t\tconst message = readServiceWorkerClientMessage(event.data);\n\t\tif (!message) return;\n\t\tif (refreshing) return;\n\n\t\trecordServiceWorkerUpdateReload();\n\t\treloadPage();\n\t});\n}\n\nfunction emitUpdate(reg: ServiceWorkerRegistration) {\n\tfor (const handler of updateHandlers) {\n\t\thandler(reg);\n\t}\n}\n\nfunction observeRegistration(reg: ServiceWorkerRegistration) {\n\tif (observedRegistrations.has(reg)) return;\n\n\tobservedRegistrations.add(reg);\n\n\treg.addEventListener(\"updatefound\", () => {\n\t\tconst newWorker = reg.installing;\n\t\tif (!newWorker) return;\n\n\t\tnewWorker.addEventListener(\"statechange\", () => {\n\t\t\t/**\n\t\t\t * installed + есть controller = новая версия установлена,\n\t\t\t * но текущая страница всё ещё под старым SW.\n\t\t\t */\n\t\t\tif (newWorker.state === \"installed\" && navigator.serviceWorker.controller) {\n\t\t\t\tlatestRegistration = reg;\n\t\t\t\temitUpdate(reg);\n\t\t\t}\n\t\t});\n\t});\n\n\tsubscribeControllerChangeReload();\n\tsubscribeServiceWorkerMessages();\n}\n\nexport async function getServiceWorkerRegistration(): Promise<ServiceWorkerRegistration | null> {\n\tif (!(\"serviceWorker\" in navigator)) return null;\n\n\ttry {\n\t\tconst reg = latestRegistration ?? (await navigator.serviceWorker.getRegistration(SW_SCOPE));\n\n\t\tif (!reg) return null;\n\n\t\tlatestRegistration = reg;\n\t\tobserveRegistration(reg);\n\n\t\treturn reg;\n\t} catch (err) {\n\t\tlogError(\"[SW] get registration failed:\", err);\n\t\treturn null;\n\t}\n}\n\nexport async function registerServiceWorker(options: RegisterSWOptions = {}) {\n\tif (!(\"serviceWorker\" in navigator)) return null;\n\n\tif (options.onUpdate) {\n\t\tupdateHandlers.add(options.onUpdate);\n\t}\n\n\ttry {\n\t\tconst existingRegistration = latestRegistration ?? (await navigator.serviceWorker.getRegistration(SW_SCOPE));\n\n\t\tconst reg =\n\t\t\texistingRegistration ??\n\t\t\t(await navigator.serviceWorker.register(SW_URL, {\n\t\t\t\tscope: SW_SCOPE,\n\t\t\t\tupdateViaCache: \"none\"\n\t\t\t}));\n\n\t\tlatestRegistration = reg;\n\t\tobserveRegistration(reg);\n\n\t\toptions.onReady?.(reg);\n\n\t\treturn reg;\n\t} catch (err) {\n\t\tlogError(\"[SW] registration failed:\", err);\n\t\treturn null;\n\t}\n}\n\nexport function unsubscribeServiceWorkerUpdate(handler: SWUpdateHandler) {\n\tupdateHandlers.delete(handler);\n}\n\nexport function hasWaitingServiceWorker(reg: ServiceWorkerRegistration | null | undefined): reg is ServiceWorkerRegistration {\n\treturn Boolean(reg?.waiting);\n}\n\nexport function applyServiceWorkerUpdate(reg: ServiceWorkerRegistration | null = latestRegistration) {\n\tconst waiting = reg?.waiting;\n\tif (!waiting) return false;\n\n\tupdateRequested = true;\n\trecordServiceWorkerUpdateReload();\n\n\twaiting.postMessage({ type: \"SKIP_WAITING\" });\n\n\treturn true;\n}\n\nexport function reloadPageForServiceWorkerUpdate() {\n\trecordServiceWorkerUpdateReload();\n\treloadPage();\n\n\treturn true;\n}\n\nexport async function checkServiceWorkerUpdate() {\n\tif (!(\"serviceWorker\" in navigator)) return null;\n\n\ttry {\n\t\tconst reg = latestRegistration ?? (await navigator.serviceWorker.getRegistration(SW_SCOPE));\n\t\tif (!reg) return null;\n\n\t\tlatestRegistration = reg;\n\t\tobserveRegistration(reg);\n\n\t\tawait reg.update();\n\n\t\treturn reg;\n\t} catch (err) {\n\t\tlogError(\"[SW] update check failed:\", err);\n\t\treturn null;\n\t}\n}\n\n/**\n * Очищает SW-кеш OData для указанной политики.\n *\n * Примеры: `\"ttl=24h;name=ref\"`, `\"ttl=10m;max=200;name=ui\"`.\n *\n * После вызова следующий запрос с той же политикой пойдёт в сеть.\n */\nexport function invalidateSwCacheProfile(profile: string) {\n\tnavigator.serviceWorker?.controller?.postMessage({\n\t\ttype: \"invalidateProfile\",\n\t\tprofile\n\t});\n}\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport {\n\tapplyServiceWorkerUpdate,\n\tcanAutoApplyServiceWorkerUpdate,\n\tcheckServiceWorkerUpdate,\n\tclearServiceWorkerUpdateReloadChain,\n\thasWaitingServiceWorker,\n\tregisterServiceWorker,\n\treloadPageForServiceWorkerUpdate,\n\tunsubscribeServiceWorkerUpdate\n} from \"./serviceWorker\";\n\n// TODO: Vite env\nconst SW_UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000;\n// TODO: Vite env\nconst SW_STARTUP_AUTO_UPDATE_GRACE_MS = 30 * 1000;\n\nfunction isStartupNavigationForAutoUpdate(): boolean {\n\tconst [entry] = performance.getEntriesByType(\"navigation\") as PerformanceNavigationTiming[];\n\n\t/**\n\t * reload — пользователь явно обновил страницу.\n\t * navigate — пользователь открыл страницу по ссылке/закладке.\n\t */\n\treturn entry?.type === \"reload\" || entry?.type === \"navigate\";\n}\n\nexport function useServiceWorkerUpdate() {\n\tconst [waitingRegistration, setWaitingRegistration] = useState<ServiceWorkerRegistration | null>(null);\n\n\tconst hasUpdate = waitingRegistration !== null;\n\n\tconst applyUpdate = useCallback(() => {\n\t\tif (applyServiceWorkerUpdate(waitingRegistration)) return true;\n\t\tif (!waitingRegistration) return false;\n\n\t\t/**\n\t\t * Если другой клиент уже активировал waiting worker, в текущей вкладке\n\t\t * registration.waiting станет пустым, но баннер ещё может быть видимым.\n\t\t */\n\t\treturn reloadPageForServiceWorkerUpdate();\n\t}, [waitingRegistration]);\n\n\tconst dismiss = useCallback(() => {\n\t\tsetWaitingRegistration(null);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (__DEV__) return;\n\n\t\tlet isActive = true;\n\t\tconst startupStartedAt = Date.now();\n\t\tlet startupResetTimerId: number | null = null;\n\t\tlet startupUpdateApplied = false;\n\n\t\tconst canApplyStartupUpdate = () =>\n\t\t\tisStartupNavigationForAutoUpdate() &&\n\t\t\tDate.now() - startupStartedAt <= SW_STARTUP_AUTO_UPDATE_GRACE_MS &&\n\t\t\tcanAutoApplyServiceWorkerUpdate();\n\n\t\tconst tryApplyStartupUpdate = (reg: ServiceWorkerRegistration) => {\n\t\t\tif (startupUpdateApplied) return true;\n\t\t\tif (!canApplyStartupUpdate()) return false;\n\n\t\t\tconst applied = applyServiceWorkerUpdate(reg);\n\t\t\tstartupUpdateApplied = applied;\n\n\t\t\treturn applied;\n\t\t};\n\n\t\tconst scheduleStartupChainReset = () => {\n\t\t\tconst elapsedMs = Date.now() - startupStartedAt;\n\t\t\tconst timeoutMs = Math.max(SW_STARTUP_AUTO_UPDATE_GRACE_MS - elapsedMs, 0);\n\n\t\t\tstartupResetTimerId = window.setTimeout(() => {\n\t\t\t\tif (!isActive) return;\n\n\t\t\t\tclearServiceWorkerUpdateReloadChain();\n\t\t\t}, timeoutMs);\n\t\t};\n\n\t\tconst handleUpdate = (reg: ServiceWorkerRegistration) => {\n\t\t\tif (!isActive) return;\n\n\t\t\t/**\n\t\t\t * Если update найден вскоре после reload/navigate, применяем его\n\t\t\t * автоматически. Это закрывает цепочку из нескольких деплоев,\n\t\t\t * накопленных во время простоя вкладки.\n\t\t\t */\n\t\t\tif (tryApplyStartupUpdate(reg)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Если update найден уже во время активной сессии —\n\t\t\t * показываем баннер.\n\t\t\t */\n\t\t\tsetWaitingRegistration(reg);\n\t\t};\n\n\t\tasync function init() {\n\t\t\tconst reg = await registerServiceWorker({\n\t\t\t\tonUpdate: handleUpdate\n\t\t\t});\n\n\t\t\tif (!isActive) return;\n\n\t\t\t/**\n\t\t\t * Важный сценарий:\n\t\t\t * пользователь перезагрузил страницу, а новый SW уже был в waiting.\n\t\t\t * В этом случае не показываем баннер, а применяем update сразу.\n\t\t\t */\n\t\t\tif (hasWaitingServiceWorker(reg) && tryApplyStartupUpdate(reg)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst checkedReg = await checkServiceWorkerUpdate();\n\n\t\t\tif (!isActive) return;\n\t\t\tif (startupUpdateApplied) return;\n\n\t\t\tif (hasWaitingServiceWorker(checkedReg) && tryApplyStartupUpdate(checkedReg)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (hasWaitingServiceWorker(checkedReg)) {\n\t\t\t\tsetWaitingRegistration(checkedReg);\n\t\t\t}\n\n\t\t\tscheduleStartupChainReset();\n\t\t}\n\n\t\tvoid init();\n\n\t\tconst intervalId = window.setInterval(() => {\n\t\t\tvoid checkServiceWorkerUpdate().then((reg) => {\n\t\t\t\tif (!isActive) return;\n\n\t\t\t\tif (hasWaitingServiceWorker(reg)) {\n\t\t\t\t\tsetWaitingRegistration(reg);\n\t\t\t\t}\n\t\t\t});\n\t\t}, SW_UPDATE_CHECK_INTERVAL_MS);\n\n\t\treturn () => {\n\t\t\tisActive = false;\n\t\t\tif (startupResetTimerId !== null) {\n\t\t\t\twindow.clearTimeout(startupResetTimerId);\n\t\t\t}\n\t\t\twindow.clearInterval(intervalId);\n\t\t\tunsubscribeServiceWorkerUpdate(handleUpdate);\n\t\t};\n\t}, []);\n\n\treturn {\n\t\thasUpdate,\n\t\tapplyUpdate,\n\t\tdismiss\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Наблюдает browser online hint без попытки подменить им проверку доступности конкретного сервера. */
2
+ export declare function useBrowserOnlineStatus(): boolean;
3
+ //# sourceMappingURL=useBrowserOnlineStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBrowserOnlineStatus.d.ts","sourceRoot":"","sources":["../../src/pwa/useBrowserOnlineStatus.ts"],"names":[],"mappings":"AAmBA,uGAAuG;AACvG,wBAAgB,sBAAsB,YAErC"}