@sweidos/eidos 1.0.17 → 1.0.20

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/dist/eidos.es.js CHANGED
@@ -1,333 +1,285 @@
1
- import { jsx, Fragment } from "react/jsx-runtime";
2
- import { useEffect, useRef, useSyncExternalStore } from "react";
3
- let _state;
4
- const _listeners = /* @__PURE__ */ new Set();
5
- function _notify() {
6
- _listeners.forEach((fn) => fn());
7
- }
8
- function _set(updater) {
9
- _state = { ..._state, ...updater(_state) };
10
- _notify();
11
- }
12
- _state = {
13
- isOnline: typeof navigator !== "undefined" ? navigator.onLine : true,
1
+ import { jsx as B, Fragment as F } from "react/jsx-runtime";
2
+ import { useEffect as U, useRef as N, useSyncExternalStore as $ } from "react";
3
+ let y;
4
+ const D = /* @__PURE__ */ new Set();
5
+ function W() {
6
+ D.forEach((e) => e());
7
+ }
8
+ function g(e) {
9
+ y = { ...y, ...e(y) }, W();
10
+ }
11
+ y = {
12
+ isOnline: typeof navigator < "u" ? navigator.onLine : !0,
14
13
  swStatus: "idle",
15
14
  swError: void 0,
16
15
  resources: {},
17
16
  queue: [],
18
- setOnline: (isOnline) => _set(() => ({ isOnline })),
19
- setSwStatus: (swStatus, swError) => _set(() => ({ swStatus, swError })),
20
- registerResource: (url, entry) => _set((s) => ({ resources: { ...s.resources, [url]: entry } })),
21
- updateResource: (url, update) => _set((s) => ({
17
+ setOnline: (e) => g(() => ({ isOnline: e })),
18
+ setSwStatus: (e, t) => g(() => ({ swStatus: e, swError: t })),
19
+ registerResource: (e, t) => g((n) => ({ resources: { ...n.resources, [e]: t } })),
20
+ updateResource: (e, t) => g((n) => ({
22
21
  resources: {
23
- ...s.resources,
24
- [url]: s.resources[url] ? { ...s.resources[url], ...update } : s.resources[url]
22
+ ...n.resources,
23
+ [e]: n.resources[e] ? { ...n.resources[e], ...t } : n.resources[e]
25
24
  }
26
25
  })),
27
- unregisterResource: (url) => _set((s) => {
28
- const { [url]: _removed, ...rest } = s.resources;
29
- return { resources: rest };
26
+ unregisterResource: (e) => g((t) => {
27
+ const { [e]: n, ...r } = t.resources;
28
+ return { resources: r };
30
29
  }),
31
- addQueueItem: (item) => _set((s) => ({ queue: [...s.queue, item] })),
32
- updateQueueItem: (id, update) => _set((s) => ({
33
- queue: s.queue.map((item) => item.id === id ? { ...item, ...update } : item)
30
+ addQueueItem: (e) => g((t) => ({ queue: [...t.queue, e] })),
31
+ updateQueueItem: (e, t) => g((n) => ({
32
+ queue: n.queue.map((r) => r.id === e ? { ...r, ...t } : r)
34
33
  })),
35
- removeQueueItem: (id) => _set((s) => ({ queue: s.queue.filter((item) => item.id !== id) })),
36
- hydrateQueue: (items) => _set(() => ({ queue: items }))
34
+ removeQueueItem: (e) => g((t) => ({ queue: t.queue.filter((n) => n.id !== e) })),
35
+ hydrateQueue: (e) => g(() => ({ queue: e }))
37
36
  };
38
- function _getState() {
39
- return _state;
37
+ function G() {
38
+ return y;
40
39
  }
41
- function _subscribe(listener) {
42
- _listeners.add(listener);
43
- return () => {
44
- _listeners.delete(listener);
40
+ function K(e) {
41
+ return D.add(e), () => {
42
+ D.delete(e);
45
43
  };
46
44
  }
47
- const useEidosStore = {
48
- getState: _getState,
49
- subscribe: _subscribe,
45
+ const o = {
46
+ getState: G,
47
+ subscribe: K,
50
48
  // Test/devtools helper — merges partial state, preserves action methods.
51
- setState: (partial) => {
52
- const update = typeof partial === "function" ? partial(_state) : partial;
53
- _state = { ..._state, ...update };
54
- _notify();
49
+ setState: (e) => {
50
+ const t = typeof e == "function" ? e(y) : e;
51
+ y = { ...y, ...t }, W();
55
52
  }
56
53
  };
57
- let _registration = null;
58
- let _pendingMessages = [];
59
- function getSwRegistration() {
60
- return _registration;
61
- }
62
- async function registerServiceWorker(swPath) {
63
- if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
64
- useEidosStore.getState().setSwStatus("unsupported");
54
+ let w = null, Q = [];
55
+ function V() {
56
+ return w;
57
+ }
58
+ async function Y(e) {
59
+ if (typeof navigator > "u" || !("serviceWorker" in navigator)) {
60
+ o.getState().setSwStatus("unsupported");
65
61
  return;
66
62
  }
67
- const store = useEidosStore.getState();
68
- store.setSwStatus("registering");
63
+ const t = o.getState();
64
+ t.setSwStatus("registering");
69
65
  try {
70
- _registration = await navigator.serviceWorker.register(swPath, { scope: "/" });
71
- await waitForActivation(_registration);
72
- store.setSwStatus("active");
73
- navigator.serviceWorker.addEventListener("message", onSwMessage);
74
- window.addEventListener("online", () => store.setOnline(true));
75
- window.addEventListener("offline", () => store.setOnline(false));
76
- flushPendingMessages();
77
- } catch (err) {
78
- store.setSwStatus("error", String(err));
66
+ w = await navigator.serviceWorker.register(e, { scope: "/" }), await z(w), t.setSwStatus("active"), navigator.serviceWorker.addEventListener("message", J), window.addEventListener("online", () => t.setOnline(!0)), window.addEventListener("offline", () => t.setOnline(!1)), Z();
67
+ } catch (n) {
68
+ t.setSwStatus("error", String(n));
79
69
  }
80
70
  }
81
- function waitForActivation(reg) {
82
- return new Promise((resolve) => {
83
- if (reg.active) {
84
- resolve();
71
+ function z(e) {
72
+ return new Promise((t) => {
73
+ if (e.active) {
74
+ t();
85
75
  return;
86
76
  }
87
- const sw = reg.installing ?? reg.waiting;
88
- if (!sw) {
89
- resolve();
77
+ const n = e.installing ?? e.waiting;
78
+ if (!n) {
79
+ t();
90
80
  return;
91
81
  }
92
- const timer = setTimeout(resolve, 1e4);
93
- sw.addEventListener("statechange", function handler() {
94
- if (sw.state === "activated") {
95
- clearTimeout(timer);
96
- sw.removeEventListener("statechange", handler);
97
- resolve();
98
- }
82
+ const r = setTimeout(t, 1e4);
83
+ n.addEventListener("statechange", function s() {
84
+ n.state === "activated" && (clearTimeout(r), n.removeEventListener("statechange", s), t());
99
85
  });
100
86
  });
101
87
  }
102
- function sendToWorker(message) {
103
- const sw = _registration == null ? void 0 : _registration.active;
104
- if (sw) {
105
- sw.postMessage(message);
106
- } else {
107
- _pendingMessages.push(message);
108
- }
88
+ function q(e) {
89
+ const t = w == null ? void 0 : w.active;
90
+ t ? t.postMessage(e) : Q.push(e);
109
91
  }
110
- let _bgSyncHandler = null;
111
- function registerBgSyncHandler(fn) {
112
- _bgSyncHandler = fn;
92
+ let O = null;
93
+ function X(e) {
94
+ O = e;
113
95
  }
114
- function isBgSyncSupported() {
96
+ function we() {
115
97
  try {
116
- return typeof navigator !== "undefined" && "serviceWorker" in navigator && _registration !== null && "sync" in _registration;
98
+ return typeof navigator < "u" && "serviceWorker" in navigator && w !== null && "sync" in w;
117
99
  } catch {
118
- return false;
100
+ return !1;
119
101
  }
120
102
  }
121
- function onSwMessage(event) {
122
- const data = event.data;
123
- if (!(data == null ? void 0 : data.type)) return;
124
- const store = useEidosStore.getState();
125
- const { type, url } = data;
126
- if (type === "EIDOS_BACKGROUND_SYNC") {
127
- _bgSyncHandler == null ? void 0 : _bgSyncHandler();
103
+ function J(e) {
104
+ const t = e.data;
105
+ if (!(t != null && t.type)) return;
106
+ const n = o.getState(), { type: r, url: s } = t;
107
+ if (r === "EIDOS_BACKGROUND_SYNC") {
108
+ O == null || O();
128
109
  return;
129
110
  }
130
- if (!url) return;
131
- switch (type) {
132
- case "EIDOS_CACHE_HIT": {
133
- const current = store.resources[url];
134
- store.updateResource(url, {
135
- status: "fresh",
136
- lastEvent: "cache-hit",
137
- cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
138
- });
139
- break;
140
- }
141
- case "EIDOS_CACHE_UPDATED": {
142
- store.updateResource(url, {
143
- status: "fresh",
144
- lastEvent: "cache-updated",
145
- cachedAt: Date.now()
146
- });
147
- break;
148
- }
149
- case "EIDOS_NETWORK_ERROR": {
150
- store.updateResource(url, {
151
- status: "error",
152
- lastEvent: "network-error"
153
- });
154
- break;
111
+ if (s)
112
+ switch (r) {
113
+ case "EIDOS_CACHE_HIT": {
114
+ const i = n.resources[s];
115
+ n.updateResource(s, {
116
+ status: "fresh",
117
+ lastEvent: "cache-hit",
118
+ cacheHits: ((i == null ? void 0 : i.cacheHits) ?? 0) + 1
119
+ });
120
+ break;
121
+ }
122
+ case "EIDOS_CACHE_UPDATED": {
123
+ n.updateResource(s, {
124
+ status: "fresh",
125
+ lastEvent: "cache-updated",
126
+ cachedAt: Date.now()
127
+ });
128
+ break;
129
+ }
130
+ case "EIDOS_NETWORK_ERROR": {
131
+ n.updateResource(s, {
132
+ status: "error",
133
+ lastEvent: "network-error"
134
+ });
135
+ break;
136
+ }
155
137
  }
156
- }
157
138
  }
158
- function setOfflineSimulation(enabled) {
159
- sendToWorker({ type: "EIDOS_SIMULATE_OFFLINE", enabled });
160
- useEidosStore.getState().setOnline(!enabled);
139
+ function ge(e) {
140
+ q({ type: "EIDOS_SIMULATE_OFFLINE", enabled: e }), o.getState().setOnline(!e);
141
+ }
142
+ function Z() {
143
+ const e = w == null ? void 0 : w.active;
144
+ if (e) {
145
+ for (const t of Q) e.postMessage(t);
146
+ Q = [];
147
+ }
161
148
  }
162
- function flushPendingMessages() {
163
- const sw = _registration == null ? void 0 : _registration.active;
164
- if (!sw) return;
165
- for (const msg of _pendingMessages) sw.postMessage(msg);
166
- _pendingMessages = [];
149
+ const R = /* @__PURE__ */ new Map();
150
+ let x = null;
151
+ function ye(e) {
152
+ x = e;
167
153
  }
168
- const _registry = /* @__PURE__ */ new Map();
169
- function isPattern(url) {
170
- return url.includes("*") || /:[^/]+/.test(url);
154
+ function S(e) {
155
+ return e.includes("*") || /:[^/]+/.test(e);
171
156
  }
172
- function patternToRegexStr(pattern) {
173
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
174
- return "^" + escaped.replace(/\*\*/g, ".+").replace(/\*/g, "[^/]+").replace(/:[^/]+/g, "[^/]+") + "$";
157
+ function ee(e) {
158
+ return "^" + e.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".+").replace(/\*/g, "[^/]+").replace(/:[^/]+/g, "[^/]+") + "$";
175
159
  }
176
- function _patternError(url, method) {
160
+ function b(e, t) {
177
161
  return new Error(
178
- `[eidos] resource('${url}') is a URL pattern — ${method}() is not supported on pattern handles. The SW intercepts matching requests automatically; call fetch(specificUrl) directly in your app code.`
162
+ `[eidos] resource('${e}') is a URL pattern — ${t}() is not supported on pattern handles. The SW intercepts matching requests automatically; call fetch(specificUrl) directly in your app code.`
179
163
  );
180
164
  }
181
- function resource(url, config) {
182
- if (_registry.has(url)) {
183
- return _registry.get(url);
184
- }
185
- const strategy = deriveStrategy(url, config);
186
- const regexStr = isPattern(url) ? patternToRegexStr(url) : void 0;
187
- const entry = {
188
- url,
189
- config,
190
- strategy,
165
+ function Se(e, t) {
166
+ if (R.has(e))
167
+ return R.get(e);
168
+ const n = te(e, t), r = S(e) ? ee(e) : void 0, s = {
169
+ url: e,
170
+ config: t,
171
+ strategy: n,
191
172
  status: "idle",
192
173
  cacheHits: 0,
193
174
  cacheMisses: 0
194
175
  };
195
- useEidosStore.getState().registerResource(url, entry);
196
- sendToWorker({
176
+ o.getState().registerResource(e, s), q({
197
177
  type: "EIDOS_REGISTER_RESOURCE",
198
- url,
199
- strategy: strategy.swStrategy,
200
- cacheName: strategy.cacheName,
201
- ...regexStr !== void 0 && { pattern: regexStr }
178
+ url: e,
179
+ strategy: n.swStrategy,
180
+ cacheName: n.cacheName,
181
+ ...r !== void 0 && { pattern: r }
202
182
  });
203
- const handle = {
204
- url,
205
- config,
206
- strategy,
183
+ const i = {
184
+ url: e,
185
+ config: t,
186
+ strategy: n,
207
187
  fetch: async () => {
208
- if (isPattern(url)) throw _patternError(url, "fetch");
209
- const store = useEidosStore.getState();
210
- store.updateResource(url, { status: "fetching", fetchedAt: Date.now() });
211
- const cache = await caches.open(strategy.cacheName).catch(() => null);
188
+ if (S(e)) throw b(e, "fetch");
189
+ const a = o.getState();
190
+ a.updateResource(e, { status: "fetching", fetchedAt: Date.now() });
191
+ const c = await caches.open(n.cacheName).catch(() => null);
212
192
  try {
213
- if (strategy.swStrategy !== "network-first") {
214
- const cached = cache ? await cache.match(url).catch(() => null) : null;
215
- const current = useEidosStore.getState().resources[url];
216
- const expired = config.maxAge !== void 0 && (current == null ? void 0 : current.cachedAt) !== void 0 && Date.now() - current.cachedAt > config.maxAge;
217
- if (cached && !expired) {
218
- store.updateResource(url, {
193
+ if (n.swStrategy !== "network-first") {
194
+ const d = c ? await c.match(e).catch(() => null) : null, f = o.getState().resources[e], E = t.maxAge !== void 0 && (f == null ? void 0 : f.cachedAt) !== void 0 && Date.now() - f.cachedAt > t.maxAge;
195
+ if (d && !E)
196
+ return a.updateResource(e, {
219
197
  status: "fresh",
220
198
  lastEvent: "cache-hit",
221
- cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
222
- });
223
- if (strategy.swStrategy === "stale-while-revalidate") {
224
- fetch(url).then(async (resp) => {
225
- if (resp.ok && cache) {
226
- await cache.put(url, resp.clone());
227
- useEidosStore.getState().updateResource(url, {
228
- cachedAt: Date.now(),
229
- lastEvent: "cache-updated"
230
- });
231
- }
232
- }).catch(() => {
233
- });
234
- }
235
- return cached;
236
- }
237
- const storeEntry = useEidosStore.getState().resources[url];
238
- store.updateResource(url, {
239
- cacheMisses: ((storeEntry == null ? void 0 : storeEntry.cacheMisses) ?? 0) + 1
199
+ cacheHits: ((f == null ? void 0 : f.cacheHits) ?? 0) + 1
200
+ }), n.swStrategy === "stale-while-revalidate" && fetch(e).then(async (P) => {
201
+ P.ok && c && (await c.put(e, P.clone()), o.getState().updateResource(e, {
202
+ cachedAt: Date.now(),
203
+ lastEvent: "cache-updated"
204
+ }));
205
+ }).catch(() => {
206
+ }), d;
207
+ const I = o.getState().resources[e];
208
+ a.updateResource(e, {
209
+ cacheMisses: ((I == null ? void 0 : I.cacheMisses) ?? 0) + 1
240
210
  });
241
211
  }
242
- const response = await fetch(url);
243
- if (response.ok) {
244
- if (cache) await cache.put(url, response.clone());
245
- store.updateResource(url, {
212
+ const u = await fetch(e);
213
+ if (u.ok)
214
+ return c && await c.put(e, u.clone()), a.updateResource(e, {
246
215
  status: "fresh",
247
216
  cachedAt: Date.now(),
248
217
  lastEvent: "cache-updated"
249
- });
250
- return response;
251
- }
252
- store.updateResource(url, { status: response.status === 503 ? "offline" : "error" });
253
- const isOffline = response.headers.get("X-Eidos-Offline") === "true";
218
+ }), u;
219
+ a.updateResource(e, { status: u.status === 503 ? "offline" : "error" });
220
+ const l = u.headers.get("X-Eidos-Offline") === "true";
254
221
  throw new Error(
255
- isOffline ? `offline: no cached response for ${url}` : `${response.status} ${response.statusText}`
222
+ l ? `offline: no cached response for ${e}` : `${u.status} ${u.statusText}`
256
223
  );
257
- } catch (err) {
258
- const fallback = cache ? await cache.match(url).catch(() => null) : null;
259
- if (fallback) {
260
- const current = useEidosStore.getState().resources[url];
261
- store.updateResource(url, {
224
+ } catch (u) {
225
+ const l = c ? await c.match(e).catch(() => null) : null;
226
+ if (l) {
227
+ const d = o.getState().resources[e];
228
+ return a.updateResource(e, {
262
229
  status: "fresh",
263
230
  lastEvent: "cache-hit",
264
- cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
265
- });
266
- return fallback;
231
+ cacheHits: ((d == null ? void 0 : d.cacheHits) ?? 0) + 1
232
+ }), l;
267
233
  }
268
- store.updateResource(url, { status: "error" });
269
- throw err;
234
+ throw a.updateResource(e, { status: "error" }), u;
270
235
  }
271
236
  },
272
237
  json: async () => {
273
- if (isPattern(url)) throw _patternError(url, "json");
274
- const res = await handle.fetch();
275
- return res.json();
238
+ if (S(e)) throw b(e, "json");
239
+ return (await i.fetch()).json();
276
240
  },
277
241
  query: () => {
278
- if (isPattern(url)) throw _patternError(url, "query");
242
+ if (S(e)) throw b(e, "query");
279
243
  return {
280
- queryKey: ["eidos", url],
281
- queryFn: () => handle.json()
244
+ queryKey: ["eidos", e],
245
+ queryFn: () => i.json()
282
246
  };
283
247
  },
284
248
  prefetch: async () => {
285
- if (isPattern(url)) throw _patternError(url, "prefetch");
286
- await handle.fetch();
249
+ if (S(e)) throw b(e, "prefetch");
250
+ await i.fetch();
287
251
  },
288
252
  invalidate: async () => {
289
- sendToWorker({ type: "EIDOS_CLEAR_CACHE", url });
290
- const cache = await caches.open(strategy.cacheName).catch(() => null);
291
- if (cache) {
292
- const keys = await cache.keys();
293
- const patternRe = regexStr ? new RegExp(regexStr) : null;
294
- const isCrossOrigin = url.startsWith("http");
253
+ q({ type: "EIDOS_CLEAR_CACHE", url: e });
254
+ const a = await caches.open(n.cacheName).catch(() => null);
255
+ if (a) {
256
+ const c = await a.keys(), u = r ? new RegExp(r) : null, l = e.startsWith("http");
295
257
  await Promise.all(
296
- keys.filter((r) => {
297
- const rUrl = r.url;
298
- const p = new URL(rUrl).pathname;
299
- if (patternRe) {
300
- return patternRe.test(isCrossOrigin ? rUrl : p);
301
- }
302
- return isCrossOrigin ? rUrl === url : rUrl === url || p === url;
303
- }).map((r) => cache.delete(r))
258
+ c.filter((d) => {
259
+ const f = d.url, E = new URL(f).pathname;
260
+ return u ? u.test(l ? f : E) : l ? f === e : f === e || E === e;
261
+ }).map((d) => a.delete(d))
304
262
  );
305
263
  }
306
- if (!isPattern(url)) {
307
- useEidosStore.getState().updateResource(url, {
308
- status: "stale",
309
- cachedAt: void 0,
310
- lastEvent: "cache-cleared",
311
- cacheHits: 0,
312
- cacheMisses: 0
313
- });
314
- }
264
+ S(e) || o.getState().updateResource(e, {
265
+ status: "stale",
266
+ cachedAt: void 0,
267
+ lastEvent: "cache-cleared",
268
+ cacheHits: 0,
269
+ cacheMisses: 0
270
+ }), x == null || x(["eidos", e]);
315
271
  },
316
272
  unregister: () => {
317
- _registry.delete(url);
318
- sendToWorker({ type: "EIDOS_UNREGISTER_RESOURCE", url });
319
- useEidosStore.getState().unregisterResource(url);
273
+ R.delete(e), q({ type: "EIDOS_UNREGISTER_RESOURCE", url: e }), o.getState().unregisterResource(e);
320
274
  }
321
275
  };
322
- _registry.set(url, handle);
323
- return handle;
276
+ return R.set(e, i), i;
324
277
  }
325
- function deriveStrategy(url, config) {
326
- const explicit = config.strategy;
327
- if (config.offline) return buildStrategy(explicit ?? "stale-while-revalidate", url, config.cacheName);
328
- return buildStrategy(explicit ?? "network-first", url, config.cacheName);
278
+ function te(e, t) {
279
+ const n = t.strategy;
280
+ return t.offline ? T(n ?? "stale-while-revalidate", e, t.cacheName) : T(n ?? "network-first", e, t.cacheName);
329
281
  }
330
- const STRATEGY_META = {
282
+ const ne = {
331
283
  "stale-while-revalidate": {
332
284
  name: "StaleWhileRevalidate",
333
285
  reasoning: "offline: true signals resilience. SWR returns cached data instantly while revalidating in the background — the best tradeoff between speed and freshness for offline-capable resources.",
@@ -374,383 +326,296 @@ new NetworkFirst({
374
326
  })`
375
327
  }
376
328
  };
377
- function buildStrategy(swStrategy, _url, cacheName) {
329
+ function T(e, t, n) {
378
330
  return {
379
- ...STRATEGY_META[swStrategy],
380
- swStrategy,
381
- cacheName: cacheName ?? "eidos-resources-v1"
331
+ ...ne[e],
332
+ swStrategy: e,
333
+ cacheName: n ?? "eidos-resources-v1"
382
334
  };
383
335
  }
384
- const DB_NAME = "eidos";
385
- const DB_VERSION = 1;
386
- const QUEUE_STORE = "action-queue";
387
- let _db = null;
388
- function openDB() {
389
- if (_db) return Promise.resolve(_db);
390
- return new Promise((resolve, reject) => {
391
- const req = indexedDB.open(DB_NAME, DB_VERSION);
392
- req.onupgradeneeded = (event) => {
393
- const db = event.target.result;
394
- if (!db.objectStoreNames.contains(QUEUE_STORE)) {
395
- const store = db.createObjectStore(QUEUE_STORE, { keyPath: "id" });
396
- store.createIndex("status", "status", { unique: false });
397
- store.createIndex("actionId", "actionId", { unique: false });
336
+ const se = "eidos", re = 1, h = "action-queue";
337
+ let A = null;
338
+ function m() {
339
+ return A ? Promise.resolve(A) : new Promise((e, t) => {
340
+ const n = indexedDB.open(se, re);
341
+ n.onupgradeneeded = (r) => {
342
+ const s = r.target.result;
343
+ if (!s.objectStoreNames.contains(h)) {
344
+ const i = s.createObjectStore(h, { keyPath: "id" });
345
+ i.createIndex("status", "status", { unique: !1 }), i.createIndex("actionId", "actionId", { unique: !1 });
398
346
  }
399
- };
400
- req.onsuccess = () => {
401
- _db = req.result;
402
- resolve(req.result);
403
- };
404
- req.onerror = () => reject(req.error);
347
+ }, n.onsuccess = () => {
348
+ A = n.result, e(n.result);
349
+ }, n.onerror = () => t(n.error);
405
350
  });
406
351
  }
407
- async function idbAddToQueue(item) {
408
- const db = await openDB();
409
- return new Promise((resolve, reject) => {
410
- const tx = db.transaction(QUEUE_STORE, "readwrite");
411
- tx.objectStore(QUEUE_STORE).add(item);
412
- tx.oncomplete = () => resolve();
413
- tx.onerror = () => reject(tx.error);
352
+ async function ae(e) {
353
+ const t = await m();
354
+ return new Promise((n, r) => {
355
+ const s = t.transaction(h, "readwrite");
356
+ s.objectStore(h).add(e), s.oncomplete = () => n(), s.onerror = () => r(s.error);
414
357
  });
415
358
  }
416
- async function idbGetQueue() {
417
- const db = await openDB();
418
- return new Promise((resolve, reject) => {
419
- const tx = db.transaction(QUEUE_STORE, "readonly");
420
- const req = tx.objectStore(QUEUE_STORE).getAll();
421
- req.onsuccess = () => resolve(req.result);
422
- req.onerror = () => reject(req.error);
359
+ async function ie() {
360
+ const e = await m();
361
+ return new Promise((t, n) => {
362
+ const s = e.transaction(h, "readonly").objectStore(h).getAll();
363
+ s.onsuccess = () => t(s.result), s.onerror = () => n(s.error);
423
364
  });
424
365
  }
425
- async function idbUpdateQueueItem(id, update) {
426
- const db = await openDB();
427
- return new Promise((resolve, reject) => {
428
- const tx = db.transaction(QUEUE_STORE, "readwrite");
429
- const store = tx.objectStore(QUEUE_STORE);
430
- const get = store.get(id);
431
- get.onsuccess = () => {
432
- if (get.result) {
433
- store.put({ ...get.result, ...update });
434
- }
435
- };
436
- tx.oncomplete = () => resolve();
437
- tx.onerror = () => reject(tx.error);
366
+ async function k(e, t) {
367
+ const n = await m();
368
+ return new Promise((r, s) => {
369
+ const i = n.transaction(h, "readwrite"), a = i.objectStore(h), c = a.get(e);
370
+ c.onsuccess = () => {
371
+ c.result && a.put({ ...c.result, ...t });
372
+ }, i.oncomplete = () => r(), i.onerror = () => s(i.error);
438
373
  });
439
374
  }
440
- async function idbRemoveFromQueue(id) {
441
- const db = await openDB();
442
- return new Promise((resolve, reject) => {
443
- const tx = db.transaction(QUEUE_STORE, "readwrite");
444
- tx.objectStore(QUEUE_STORE).delete(id);
445
- tx.oncomplete = () => resolve();
446
- tx.onerror = () => reject(tx.error);
375
+ async function oe(e) {
376
+ const t = await m();
377
+ return new Promise((n, r) => {
378
+ const s = t.transaction(h, "readwrite");
379
+ s.objectStore(h).delete(e), s.oncomplete = () => n(), s.onerror = () => r(s.error);
447
380
  });
448
381
  }
449
- async function idbGetPendingItems() {
450
- const db = await openDB();
451
- return new Promise((resolve, reject) => {
452
- const tx = db.transaction(QUEUE_STORE, "readonly");
453
- const index = tx.objectStore(QUEUE_STORE).index("status");
454
- const results = [];
455
- let done = 0;
456
- function finish(err) {
457
- if (err) {
458
- reject(err);
382
+ async function ce() {
383
+ const e = await m();
384
+ return new Promise((t, n) => {
385
+ const s = e.transaction(h, "readonly").objectStore(h).index("status"), i = [];
386
+ let a = 0;
387
+ function c(d) {
388
+ if (d) {
389
+ n(d);
459
390
  return;
460
391
  }
461
- if (++done === 2) resolve(results);
392
+ ++a === 2 && t(i);
462
393
  }
463
- const pendingReq = index.openCursor(IDBKeyRange.only("pending"));
464
- pendingReq.onsuccess = (e) => {
465
- const cursor = e.target.result;
466
- if (cursor) {
467
- results.push(cursor.value);
468
- cursor.continue();
469
- } else finish();
470
- };
471
- pendingReq.onerror = () => finish(pendingReq.error);
472
- const failedReq = index.openCursor(IDBKeyRange.only("failed"));
473
- failedReq.onsuccess = (e) => {
474
- const cursor = e.target.result;
475
- if (cursor) {
476
- results.push(cursor.value);
477
- cursor.continue();
478
- } else finish();
479
- };
480
- failedReq.onerror = () => finish(failedReq.error);
394
+ const u = s.openCursor(IDBKeyRange.only("pending"));
395
+ u.onsuccess = (d) => {
396
+ const f = d.target.result;
397
+ f ? (i.push(f.value), f.continue()) : c();
398
+ }, u.onerror = () => c(u.error);
399
+ const l = s.openCursor(IDBKeyRange.only("failed"));
400
+ l.onsuccess = (d) => {
401
+ const f = d.target.result;
402
+ f ? (i.push(f.value), f.continue()) : c();
403
+ }, l.onerror = () => c(l.error);
481
404
  });
482
405
  }
483
- async function idbClearQueue() {
484
- const db = await openDB();
485
- return new Promise((resolve, reject) => {
486
- const tx = db.transaction(QUEUE_STORE, "readwrite");
487
- tx.objectStore(QUEUE_STORE).clear();
488
- tx.oncomplete = () => resolve();
489
- tx.onerror = () => reject(tx.error);
406
+ async function ue() {
407
+ const e = await m();
408
+ return new Promise((t, n) => {
409
+ const r = e.transaction(h, "readwrite");
410
+ r.objectStore(h).clear(), r.oncomplete = () => t(), r.onerror = () => n(r.error);
490
411
  });
491
412
  }
492
- const _actionRegistry = /* @__PURE__ */ new Map();
493
- function uid() {
413
+ const H = /* @__PURE__ */ new Map();
414
+ function L() {
494
415
  return crypto.randomUUID();
495
416
  }
496
- function action(fn, config) {
497
- const actionId = config.name || fn.name || uid();
498
- _actionRegistry.set(actionId, fn);
499
- const wrapped = async (...args) => {
500
- const { isOnline } = useEidosStore.getState();
501
- if (config.reliability === "neverLose") {
502
- if (!isOnline) {
503
- return persistAndQueue(actionId, actionId, args, config);
504
- }
417
+ function me(e, t) {
418
+ const n = t.name || e.name || L();
419
+ H.set(n, e);
420
+ const r = async (...s) => {
421
+ const { isOnline: i } = o.getState();
422
+ if (t.reliability === "neverLose") {
423
+ if (!i)
424
+ return j(n, n, s, t);
505
425
  try {
506
- return await fn(...args);
426
+ return await e(...s);
507
427
  } catch {
508
- return persistAndQueue(actionId, actionId, args, config);
428
+ return j(n, n, s, t);
509
429
  }
510
430
  }
511
- return fn(...args);
431
+ return e(...s);
512
432
  };
513
- Object.defineProperty(wrapped, "id", { value: actionId, writable: false });
514
- Object.defineProperty(wrapped, "config", { value: config, writable: false });
515
- return wrapped;
516
- }
517
- async function persistAndQueue(actionId, actionName, args, config) {
518
- const id = uid();
519
- const item = {
520
- id,
521
- actionId,
522
- actionName,
523
- args,
433
+ return Object.defineProperty(r, "id", { value: n, writable: !1 }), Object.defineProperty(r, "config", { value: t, writable: !1 }), r;
434
+ }
435
+ async function j(e, t, n, r) {
436
+ const s = L(), i = {
437
+ id: s,
438
+ actionId: e,
439
+ actionName: t,
440
+ args: n,
524
441
  queuedAt: Date.now(),
525
442
  retryCount: 0,
526
- maxRetries: config.maxRetries ?? 3,
443
+ maxRetries: r.maxRetries ?? 3,
527
444
  status: "pending"
528
445
  };
529
- await idbAddToQueue(item);
530
- useEidosStore.getState().addQueueItem(item);
446
+ await ae(i), o.getState().addQueueItem(i);
531
447
  try {
532
- const reg = getSwRegistration();
533
- if (reg && "sync" in reg) {
534
- await reg.sync.register("eidos-queue-replay");
535
- }
448
+ const a = V();
449
+ a && "sync" in a && await a.sync.register("eidos-queue-replay");
536
450
  } catch {
537
451
  }
538
452
  return {
539
- queued: true,
540
- id,
541
- message: `"${actionName}" queued — will execute when online`
453
+ queued: !0,
454
+ id: s,
455
+ message: `"${t}" queued — will execute when online`
542
456
  };
543
457
  }
544
- function backoffMs(retryCount) {
545
- const base = Math.min(2e3 * 2 ** retryCount, 3e5);
546
- return base * (0.8 + Math.random() * 0.4);
458
+ function de(e) {
459
+ return Math.min(2e3 * 2 ** e, 3e5) * (0.8 + Math.random() * 0.4);
547
460
  }
548
- let _replaying = false;
549
- async function replayQueue() {
550
- const store = useEidosStore.getState();
551
- if (!store.isOnline || _replaying) {
461
+ let _ = !1;
462
+ async function C() {
463
+ const e = o.getState();
464
+ if (!e.isOnline || _)
552
465
  return { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0 };
553
- }
554
- _replaying = true;
466
+ _ = !0;
555
467
  try {
556
- return await _doReplayQueue(store);
468
+ return await fe(e);
557
469
  } finally {
558
- _replaying = false;
470
+ _ = !1;
559
471
  }
560
472
  }
561
- async function _doReplayQueue(store) {
562
- const candidates = await idbGetPendingItems();
563
- const now = Date.now();
564
- const pending = candidates.filter(
565
- (item) => !item.nextRetryAt || item.nextRetryAt <= now
566
- );
567
- const result = { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0 };
568
- const outcomes = await Promise.allSettled(
569
- pending.map(async (item) => {
570
- const fn = _actionRegistry.get(item.actionId);
571
- if (!fn) return "skipped";
572
- store.updateQueueItem(item.id, { status: "replaying" });
573
- await idbUpdateQueueItem(item.id, { status: "replaying" });
473
+ async function fe(e) {
474
+ const t = await ce(), n = Date.now(), r = t.filter(
475
+ (a) => !a.nextRetryAt || a.nextRetryAt <= n
476
+ ), s = { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0 }, i = await Promise.allSettled(
477
+ r.map(async (a) => {
478
+ const c = H.get(a.actionId);
479
+ if (!c) return "skipped";
480
+ e.updateQueueItem(a.id, { status: "replaying" }), await k(a.id, { status: "replaying" });
574
481
  try {
575
- await fn(...item.args);
576
- const completedAt = Date.now();
577
- store.updateQueueItem(item.id, { status: "succeeded", completedAt });
578
- await idbUpdateQueueItem(item.id, { status: "succeeded", completedAt });
579
- setTimeout(() => {
580
- store.removeQueueItem(item.id);
581
- idbRemoveFromQueue(item.id);
582
- }, 3e3);
583
- return "succeeded";
584
- } catch (err) {
585
- const retryCount = item.retryCount + 1;
586
- if (retryCount >= item.maxRetries) {
587
- store.updateQueueItem(item.id, { status: "failed", error: String(err), retryCount });
588
- await idbUpdateQueueItem(item.id, { status: "failed", error: String(err), retryCount });
589
- return "failed";
590
- } else {
591
- const nextRetryAt = Date.now() + backoffMs(retryCount);
592
- store.updateQueueItem(item.id, { status: "pending", retryCount, nextRetryAt });
593
- await idbUpdateQueueItem(item.id, { status: "pending", retryCount, nextRetryAt });
594
- return "retrying";
482
+ await c(...a.args);
483
+ const u = Date.now();
484
+ return e.updateQueueItem(a.id, { status: "succeeded", completedAt: u }), await k(a.id, { status: "succeeded", completedAt: u }), setTimeout(() => {
485
+ e.removeQueueItem(a.id), oe(a.id);
486
+ }, 3e3), "succeeded";
487
+ } catch (u) {
488
+ const l = a.retryCount + 1;
489
+ if (l >= a.maxRetries)
490
+ return e.updateQueueItem(a.id, { status: "failed", error: String(u), retryCount: l }), await k(a.id, { status: "failed", error: String(u), retryCount: l }), "failed";
491
+ {
492
+ const d = Date.now() + de(l);
493
+ return e.updateQueueItem(a.id, { status: "pending", retryCount: l, nextRetryAt: d }), await k(a.id, { status: "pending", retryCount: l, nextRetryAt: d }), "retrying";
595
494
  }
596
495
  }
597
496
  })
598
497
  );
599
- for (const o of outcomes) {
600
- const outcome = o.status === "fulfilled" ? o.value : "failed";
601
- if (outcome === "skipped") {
602
- result.skipped++;
603
- } else {
604
- result.attempted++;
605
- result[outcome]++;
606
- }
498
+ for (const a of i) {
499
+ const c = a.status === "fulfilled" ? a.value : "failed";
500
+ c === "skipped" ? s.skipped++ : (s.attempted++, s[c]++);
607
501
  }
608
- return result;
609
- }
610
- async function clearQueue() {
611
- await idbClearQueue();
612
- useEidosStore.getState().hydrateQueue([]);
613
- }
614
- let _initialized = false;
615
- async function initEidos(config = {}) {
616
- if (_initialized) return;
617
- _initialized = true;
618
- const swPath = config.swPath ?? "/eidos-sw.js";
619
- const autoReplay = config.autoReplay ?? true;
502
+ return s;
503
+ }
504
+ async function ve() {
505
+ await ue(), o.getState().hydrateQueue([]);
506
+ }
507
+ let M = !1;
508
+ async function le(e = {}) {
509
+ if (M) return;
510
+ M = !0;
511
+ const t = e.swPath ?? "/eidos-sw.js", n = e.autoReplay ?? !0;
620
512
  try {
621
- const persisted = await idbGetQueue();
622
- if (persisted.length > 0) {
623
- useEidosStore.getState().hydrateQueue(persisted);
624
- }
513
+ const r = await ie();
514
+ r.length > 0 && o.getState().hydrateQueue(r);
625
515
  } catch {
626
516
  }
627
517
  try {
628
- await registerServiceWorker(swPath);
518
+ await Y(t);
629
519
  } catch {
630
520
  }
631
- registerBgSyncHandler(() => {
632
- if (useEidosStore.getState().isOnline) {
633
- setTimeout(replayQueue, 200);
634
- }
635
- });
636
- if (autoReplay) {
637
- let prevIsOnline = useEidosStore.getState().isOnline;
638
- useEidosStore.subscribe(() => {
639
- const { isOnline } = useEidosStore.getState();
640
- const justCameOnline = isOnline && !prevIsOnline;
641
- prevIsOnline = isOnline;
642
- if (justCameOnline) {
643
- setTimeout(replayQueue, 600);
644
- }
521
+ if (X(() => {
522
+ o.getState().isOnline && setTimeout(C, 200);
523
+ }), n) {
524
+ let r = o.getState().isOnline;
525
+ o.subscribe(() => {
526
+ const { isOnline: a } = o.getState(), c = a && !r;
527
+ r = a, c && setTimeout(C, 600);
645
528
  });
646
- const store = useEidosStore.getState();
647
- const hasPending = store.queue.some((q) => q.status === "pending" || q.status === "failed");
648
- if (store.isOnline && hasPending) {
649
- setTimeout(replayQueue, 1200);
650
- }
529
+ const s = o.getState(), i = s.queue.some((a) => a.status === "pending" || a.status === "failed");
530
+ s.isOnline && i && setTimeout(C, 1200);
651
531
  }
652
532
  }
653
- function EidosProvider({ children, swPath, autoReplay }) {
654
- useEffect(() => {
655
- initEidos({ swPath, autoReplay });
656
- }, []);
657
- return /* @__PURE__ */ jsx(Fragment, { children });
658
- }
659
- function useStore(selector) {
660
- const fn = selector ?? ((s) => s);
661
- return useSyncExternalStore(useEidosStore.subscribe, () => fn(useEidosStore.getState()));
662
- }
663
- function useEidos() {
664
- return useStore();
665
- }
666
- function useEidosResource(url) {
667
- return useStore((s) => s.resources[url]);
668
- }
669
- function useEidosQueue() {
670
- return useStore((s) => s.queue);
671
- }
672
- function useEidosAction(id) {
673
- return useStore((s) => s.queue.find((item) => item.id === id));
674
- }
675
- function useEidosStatus() {
676
- const isOnline = useStore((s) => s.isOnline);
677
- const swStatus = useStore((s) => s.swStatus);
678
- const swError = useStore((s) => s.swError);
679
- return { isOnline, swStatus, swError };
680
- }
681
- function useEidosQueueStats() {
682
- const pending = useStore((s) => s.queue.filter((q) => q.status === "pending").length);
683
- const failed = useStore((s) => s.queue.filter((q) => q.status === "failed").length);
684
- const replaying = useStore((s) => s.queue.filter((q) => q.status === "replaying").length);
685
- const total = useStore((s) => s.queue.length);
686
- return { pending, failed, replaying, total };
687
- }
688
- function useEidosOnDrain(callback) {
689
- const total = useStore((s) => s.queue.length);
690
- const prevRef = useRef(0);
691
- const callbackRef = useRef(callback);
692
- callbackRef.current = callback;
693
- useEffect(() => {
694
- if (prevRef.current > 0 && total === 0) {
695
- callbackRef.current();
696
- }
697
- prevRef.current = total;
698
- }, [total]);
533
+ function Ee({ children: e, swPath: t, autoReplay: n }) {
534
+ return U(() => {
535
+ le({ swPath: t, autoReplay: n });
536
+ }, []), /* @__PURE__ */ B(F, { children: e });
537
+ }
538
+ function p(e) {
539
+ const t = e ?? ((n) => n);
540
+ return $(o.subscribe, () => t(o.getState()));
541
+ }
542
+ function Re() {
543
+ return p();
544
+ }
545
+ function be(e) {
546
+ return p((t) => t.resources[e]);
547
+ }
548
+ function ke() {
549
+ return p((e) => e.queue);
550
+ }
551
+ function qe(e) {
552
+ return p((t) => t.queue.find((n) => n.id === e));
553
+ }
554
+ function Oe() {
555
+ const e = p((r) => r.isOnline), t = p((r) => r.swStatus), n = p((r) => r.swError);
556
+ return { isOnline: e, swStatus: t, swError: n };
557
+ }
558
+ function xe() {
559
+ const e = p((s) => s.queue.filter((i) => i.status === "pending").length), t = p((s) => s.queue.filter((i) => i.status === "failed").length), n = p((s) => s.queue.filter((i) => i.status === "replaying").length), r = p((s) => s.queue.length);
560
+ return { pending: e, failed: t, replaying: n, total: r };
561
+ }
562
+ function Ie(e) {
563
+ const t = p((s) => s.queue.length), n = N(0), r = N(e);
564
+ r.current = e, U(() => {
565
+ n.current > 0 && t === 0 && r.current(), n.current = t;
566
+ }, [t]);
699
567
  }
700
- const VERSION = "1.0.12";
701
- function readable(selector) {
568
+ const Ae = "1.0.12";
569
+ function v(e) {
702
570
  return {
703
- subscribe(run) {
704
- run(selector(useEidosStore.getState()));
705
- return useEidosStore.subscribe(() => run(selector(useEidosStore.getState())));
571
+ subscribe(t) {
572
+ return t(e(o.getState())), o.subscribe(() => t(e(o.getState())));
706
573
  },
707
574
  getState() {
708
- return selector(useEidosStore.getState());
575
+ return e(o.getState());
709
576
  }
710
577
  };
711
578
  }
712
- const eidosStore = readable((s) => s);
713
- const eidosQueue = readable((s) => s.queue);
714
- const eidosStatus = readable((s) => ({
715
- isOnline: s.isOnline,
716
- swStatus: s.swStatus,
717
- swError: s.swError
718
- }));
719
- const eidosQueueStats = readable((s) => ({
720
- pending: s.queue.filter((q) => q.status === "pending").length,
721
- failed: s.queue.filter((q) => q.status === "failed").length,
722
- replaying: s.queue.filter((q) => q.status === "replaying").length,
723
- total: s.queue.length
724
- }));
725
- function eidosResource(url) {
726
- return readable((s) => s.resources[url]);
727
- }
728
- function eidosAction(id) {
729
- return readable((s) => s.queue.find((item) => item.id === id));
579
+ const _e = v((e) => e), Ce = v((e) => e.queue), De = v((e) => ({
580
+ isOnline: e.isOnline,
581
+ swStatus: e.swStatus,
582
+ swError: e.swError
583
+ })), Qe = v((e) => {
584
+ let t = 0, n = 0, r = 0;
585
+ for (const s of e.queue)
586
+ s.status === "pending" ? t++ : s.status === "failed" ? n++ : s.status === "replaying" && r++;
587
+ return { pending: t, failed: n, replaying: r, total: e.queue.length };
588
+ });
589
+ function Pe(e) {
590
+ return v((t) => t.resources[e]);
591
+ }
592
+ function Ne(e) {
593
+ return v((t) => t.queue.find((n) => n.id === e));
730
594
  }
731
595
  export {
732
- EidosProvider,
733
- VERSION,
734
- action,
735
- clearQueue,
736
- eidosAction,
737
- eidosQueue,
738
- eidosQueueStats,
739
- eidosResource,
740
- eidosStatus,
741
- eidosStore,
742
- initEidos,
743
- isBgSyncSupported,
744
- replayQueue,
745
- resource,
746
- setOfflineSimulation,
747
- useEidos,
748
- useEidosAction,
749
- useEidosOnDrain,
750
- useEidosQueue,
751
- useEidosQueueStats,
752
- useEidosResource,
753
- useEidosStatus,
754
- useEidosStore
596
+ Ee as EidosProvider,
597
+ Ae as VERSION,
598
+ me as action,
599
+ ve as clearQueue,
600
+ Ne as eidosAction,
601
+ Ce as eidosQueue,
602
+ Qe as eidosQueueStats,
603
+ Pe as eidosResource,
604
+ De as eidosStatus,
605
+ _e as eidosStore,
606
+ le as initEidos,
607
+ we as isBgSyncSupported,
608
+ C as replayQueue,
609
+ Se as resource,
610
+ ge as setOfflineSimulation,
611
+ ye as setQueryInvalidator,
612
+ Re as useEidos,
613
+ qe as useEidosAction,
614
+ Ie as useEidosOnDrain,
615
+ ke as useEidosQueue,
616
+ xe as useEidosQueueStats,
617
+ be as useEidosResource,
618
+ Oe as useEidosStatus,
619
+ o as useEidosStore
755
620
  };
756
621
  //# sourceMappingURL=eidos.es.js.map