@sweidos/eidos 1.0.19 → 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,338 +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);
161
141
  }
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 = [];
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
+ }
167
148
  }
168
- const _registry = /* @__PURE__ */ new Map();
169
- let _queryInvalidator = null;
170
- function setQueryInvalidator(fn) {
171
- _queryInvalidator = fn;
149
+ const R = /* @__PURE__ */ new Map();
150
+ let x = null;
151
+ function ye(e) {
152
+ x = e;
172
153
  }
173
- function isPattern(url) {
174
- return url.includes("*") || /:[^/]+/.test(url);
154
+ function S(e) {
155
+ return e.includes("*") || /:[^/]+/.test(e);
175
156
  }
176
- function patternToRegexStr(pattern) {
177
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
178
- return "^" + escaped.replace(/\*\*/g, ".+").replace(/\*/g, "[^/]+").replace(/:[^/]+/g, "[^/]+") + "$";
157
+ function ee(e) {
158
+ return "^" + e.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".+").replace(/\*/g, "[^/]+").replace(/:[^/]+/g, "[^/]+") + "$";
179
159
  }
180
- function _patternError(url, method) {
160
+ function b(e, t) {
181
161
  return new Error(
182
- `[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.`
183
163
  );
184
164
  }
185
- function resource(url, config) {
186
- if (_registry.has(url)) {
187
- return _registry.get(url);
188
- }
189
- const strategy = deriveStrategy(url, config);
190
- const regexStr = isPattern(url) ? patternToRegexStr(url) : void 0;
191
- const entry = {
192
- url,
193
- config,
194
- 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,
195
172
  status: "idle",
196
173
  cacheHits: 0,
197
174
  cacheMisses: 0
198
175
  };
199
- useEidosStore.getState().registerResource(url, entry);
200
- sendToWorker({
176
+ o.getState().registerResource(e, s), q({
201
177
  type: "EIDOS_REGISTER_RESOURCE",
202
- url,
203
- strategy: strategy.swStrategy,
204
- cacheName: strategy.cacheName,
205
- ...regexStr !== void 0 && { pattern: regexStr }
178
+ url: e,
179
+ strategy: n.swStrategy,
180
+ cacheName: n.cacheName,
181
+ ...r !== void 0 && { pattern: r }
206
182
  });
207
- const handle = {
208
- url,
209
- config,
210
- strategy,
183
+ const i = {
184
+ url: e,
185
+ config: t,
186
+ strategy: n,
211
187
  fetch: async () => {
212
- if (isPattern(url)) throw _patternError(url, "fetch");
213
- const store = useEidosStore.getState();
214
- store.updateResource(url, { status: "fetching", fetchedAt: Date.now() });
215
- 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);
216
192
  try {
217
- if (strategy.swStrategy !== "network-first") {
218
- const cached = cache ? await cache.match(url).catch(() => null) : null;
219
- const current = useEidosStore.getState().resources[url];
220
- const expired = config.maxAge !== void 0 && (current == null ? void 0 : current.cachedAt) !== void 0 && Date.now() - current.cachedAt > config.maxAge;
221
- if (cached && !expired) {
222
- 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, {
223
197
  status: "fresh",
224
198
  lastEvent: "cache-hit",
225
- cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
226
- });
227
- if (strategy.swStrategy === "stale-while-revalidate") {
228
- fetch(url).then(async (resp) => {
229
- if (resp.ok && cache) {
230
- await cache.put(url, resp.clone());
231
- useEidosStore.getState().updateResource(url, {
232
- cachedAt: Date.now(),
233
- lastEvent: "cache-updated"
234
- });
235
- }
236
- }).catch(() => {
237
- });
238
- }
239
- return cached;
240
- }
241
- const storeEntry = useEidosStore.getState().resources[url];
242
- store.updateResource(url, {
243
- 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
244
210
  });
245
211
  }
246
- const response = await fetch(url);
247
- if (response.ok) {
248
- if (cache) await cache.put(url, response.clone());
249
- 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, {
250
215
  status: "fresh",
251
216
  cachedAt: Date.now(),
252
217
  lastEvent: "cache-updated"
253
- });
254
- return response;
255
- }
256
- store.updateResource(url, { status: response.status === 503 ? "offline" : "error" });
257
- 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";
258
221
  throw new Error(
259
- isOffline ? `offline: no cached response for ${url}` : `${response.status} ${response.statusText}`
222
+ l ? `offline: no cached response for ${e}` : `${u.status} ${u.statusText}`
260
223
  );
261
- } catch (err) {
262
- const fallback = cache ? await cache.match(url).catch(() => null) : null;
263
- if (fallback) {
264
- const current = useEidosStore.getState().resources[url];
265
- 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, {
266
229
  status: "fresh",
267
230
  lastEvent: "cache-hit",
268
- cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
269
- });
270
- return fallback;
231
+ cacheHits: ((d == null ? void 0 : d.cacheHits) ?? 0) + 1
232
+ }), l;
271
233
  }
272
- store.updateResource(url, { status: "error" });
273
- throw err;
234
+ throw a.updateResource(e, { status: "error" }), u;
274
235
  }
275
236
  },
276
237
  json: async () => {
277
- if (isPattern(url)) throw _patternError(url, "json");
278
- const res = await handle.fetch();
279
- return res.json();
238
+ if (S(e)) throw b(e, "json");
239
+ return (await i.fetch()).json();
280
240
  },
281
241
  query: () => {
282
- if (isPattern(url)) throw _patternError(url, "query");
242
+ if (S(e)) throw b(e, "query");
283
243
  return {
284
- queryKey: ["eidos", url],
285
- queryFn: () => handle.json()
244
+ queryKey: ["eidos", e],
245
+ queryFn: () => i.json()
286
246
  };
287
247
  },
288
248
  prefetch: async () => {
289
- if (isPattern(url)) throw _patternError(url, "prefetch");
290
- await handle.fetch();
249
+ if (S(e)) throw b(e, "prefetch");
250
+ await i.fetch();
291
251
  },
292
252
  invalidate: async () => {
293
- sendToWorker({ type: "EIDOS_CLEAR_CACHE", url });
294
- const cache = await caches.open(strategy.cacheName).catch(() => null);
295
- if (cache) {
296
- const keys = await cache.keys();
297
- const patternRe = regexStr ? new RegExp(regexStr) : null;
298
- 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");
299
257
  await Promise.all(
300
- keys.filter((r) => {
301
- const rUrl = r.url;
302
- const p = new URL(rUrl).pathname;
303
- if (patternRe) {
304
- return patternRe.test(isCrossOrigin ? rUrl : p);
305
- }
306
- return isCrossOrigin ? rUrl === url : rUrl === url || p === url;
307
- }).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))
308
262
  );
309
263
  }
310
- if (!isPattern(url)) {
311
- useEidosStore.getState().updateResource(url, {
312
- status: "stale",
313
- cachedAt: void 0,
314
- lastEvent: "cache-cleared",
315
- cacheHits: 0,
316
- cacheMisses: 0
317
- });
318
- }
319
- _queryInvalidator == null ? void 0 : _queryInvalidator(["eidos", url]);
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]);
320
271
  },
321
272
  unregister: () => {
322
- _registry.delete(url);
323
- sendToWorker({ type: "EIDOS_UNREGISTER_RESOURCE", url });
324
- useEidosStore.getState().unregisterResource(url);
273
+ R.delete(e), q({ type: "EIDOS_UNREGISTER_RESOURCE", url: e }), o.getState().unregisterResource(e);
325
274
  }
326
275
  };
327
- _registry.set(url, handle);
328
- return handle;
276
+ return R.set(e, i), i;
329
277
  }
330
- function deriveStrategy(url, config) {
331
- const explicit = config.strategy;
332
- if (config.offline) return buildStrategy(explicit ?? "stale-while-revalidate", url, config.cacheName);
333
- 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);
334
281
  }
335
- const STRATEGY_META = {
282
+ const ne = {
336
283
  "stale-while-revalidate": {
337
284
  name: "StaleWhileRevalidate",
338
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.",
@@ -379,384 +326,296 @@ new NetworkFirst({
379
326
  })`
380
327
  }
381
328
  };
382
- function buildStrategy(swStrategy, _url, cacheName) {
329
+ function T(e, t, n) {
383
330
  return {
384
- ...STRATEGY_META[swStrategy],
385
- swStrategy,
386
- cacheName: cacheName ?? "eidos-resources-v1"
331
+ ...ne[e],
332
+ swStrategy: e,
333
+ cacheName: n ?? "eidos-resources-v1"
387
334
  };
388
335
  }
389
- const DB_NAME = "eidos";
390
- const DB_VERSION = 1;
391
- const QUEUE_STORE = "action-queue";
392
- let _db = null;
393
- function openDB() {
394
- if (_db) return Promise.resolve(_db);
395
- return new Promise((resolve, reject) => {
396
- const req = indexedDB.open(DB_NAME, DB_VERSION);
397
- req.onupgradeneeded = (event) => {
398
- const db = event.target.result;
399
- if (!db.objectStoreNames.contains(QUEUE_STORE)) {
400
- const store = db.createObjectStore(QUEUE_STORE, { keyPath: "id" });
401
- store.createIndex("status", "status", { unique: false });
402
- 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 });
403
346
  }
404
- };
405
- req.onsuccess = () => {
406
- _db = req.result;
407
- resolve(req.result);
408
- };
409
- req.onerror = () => reject(req.error);
347
+ }, n.onsuccess = () => {
348
+ A = n.result, e(n.result);
349
+ }, n.onerror = () => t(n.error);
410
350
  });
411
351
  }
412
- async function idbAddToQueue(item) {
413
- const db = await openDB();
414
- return new Promise((resolve, reject) => {
415
- const tx = db.transaction(QUEUE_STORE, "readwrite");
416
- tx.objectStore(QUEUE_STORE).add(item);
417
- tx.oncomplete = () => resolve();
418
- 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);
419
357
  });
420
358
  }
421
- async function idbGetQueue() {
422
- const db = await openDB();
423
- return new Promise((resolve, reject) => {
424
- const tx = db.transaction(QUEUE_STORE, "readonly");
425
- const req = tx.objectStore(QUEUE_STORE).getAll();
426
- req.onsuccess = () => resolve(req.result);
427
- 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);
428
364
  });
429
365
  }
430
- async function idbUpdateQueueItem(id, update) {
431
- const db = await openDB();
432
- return new Promise((resolve, reject) => {
433
- const tx = db.transaction(QUEUE_STORE, "readwrite");
434
- const store = tx.objectStore(QUEUE_STORE);
435
- const get = store.get(id);
436
- get.onsuccess = () => {
437
- if (get.result) {
438
- store.put({ ...get.result, ...update });
439
- }
440
- };
441
- tx.oncomplete = () => resolve();
442
- 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);
443
373
  });
444
374
  }
445
- async function idbRemoveFromQueue(id) {
446
- const db = await openDB();
447
- return new Promise((resolve, reject) => {
448
- const tx = db.transaction(QUEUE_STORE, "readwrite");
449
- tx.objectStore(QUEUE_STORE).delete(id);
450
- tx.oncomplete = () => resolve();
451
- 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);
452
380
  });
453
381
  }
454
- async function idbGetPendingItems() {
455
- const db = await openDB();
456
- return new Promise((resolve, reject) => {
457
- const tx = db.transaction(QUEUE_STORE, "readonly");
458
- const index = tx.objectStore(QUEUE_STORE).index("status");
459
- const results = [];
460
- let done = 0;
461
- function finish(err) {
462
- if (err) {
463
- 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);
464
390
  return;
465
391
  }
466
- if (++done === 2) resolve(results);
392
+ ++a === 2 && t(i);
467
393
  }
468
- const pendingReq = index.openCursor(IDBKeyRange.only("pending"));
469
- pendingReq.onsuccess = (e) => {
470
- const cursor = e.target.result;
471
- if (cursor) {
472
- results.push(cursor.value);
473
- cursor.continue();
474
- } else finish();
475
- };
476
- pendingReq.onerror = () => finish(pendingReq.error);
477
- const failedReq = index.openCursor(IDBKeyRange.only("failed"));
478
- failedReq.onsuccess = (e) => {
479
- const cursor = e.target.result;
480
- if (cursor) {
481
- results.push(cursor.value);
482
- cursor.continue();
483
- } else finish();
484
- };
485
- 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);
486
404
  });
487
405
  }
488
- async function idbClearQueue() {
489
- const db = await openDB();
490
- return new Promise((resolve, reject) => {
491
- const tx = db.transaction(QUEUE_STORE, "readwrite");
492
- tx.objectStore(QUEUE_STORE).clear();
493
- tx.oncomplete = () => resolve();
494
- 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);
495
411
  });
496
412
  }
497
- const _actionRegistry = /* @__PURE__ */ new Map();
498
- function uid() {
413
+ const H = /* @__PURE__ */ new Map();
414
+ function L() {
499
415
  return crypto.randomUUID();
500
416
  }
501
- function action(fn, config) {
502
- const actionId = config.name || fn.name || uid();
503
- _actionRegistry.set(actionId, fn);
504
- const wrapped = async (...args) => {
505
- const { isOnline } = useEidosStore.getState();
506
- if (config.reliability === "neverLose") {
507
- if (!isOnline) {
508
- return persistAndQueue(actionId, actionId, args, config);
509
- }
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);
510
425
  try {
511
- return await fn(...args);
426
+ return await e(...s);
512
427
  } catch {
513
- return persistAndQueue(actionId, actionId, args, config);
428
+ return j(n, n, s, t);
514
429
  }
515
430
  }
516
- return fn(...args);
431
+ return e(...s);
517
432
  };
518
- Object.defineProperty(wrapped, "id", { value: actionId, writable: false });
519
- Object.defineProperty(wrapped, "config", { value: config, writable: false });
520
- return wrapped;
521
- }
522
- async function persistAndQueue(actionId, actionName, args, config) {
523
- const id = uid();
524
- const item = {
525
- id,
526
- actionId,
527
- actionName,
528
- 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,
529
441
  queuedAt: Date.now(),
530
442
  retryCount: 0,
531
- maxRetries: config.maxRetries ?? 3,
443
+ maxRetries: r.maxRetries ?? 3,
532
444
  status: "pending"
533
445
  };
534
- await idbAddToQueue(item);
535
- useEidosStore.getState().addQueueItem(item);
446
+ await ae(i), o.getState().addQueueItem(i);
536
447
  try {
537
- const reg = getSwRegistration();
538
- if (reg && "sync" in reg) {
539
- await reg.sync.register("eidos-queue-replay");
540
- }
448
+ const a = V();
449
+ a && "sync" in a && await a.sync.register("eidos-queue-replay");
541
450
  } catch {
542
451
  }
543
452
  return {
544
- queued: true,
545
- id,
546
- message: `"${actionName}" queued — will execute when online`
453
+ queued: !0,
454
+ id: s,
455
+ message: `"${t}" queued — will execute when online`
547
456
  };
548
457
  }
549
- function backoffMs(retryCount) {
550
- const base = Math.min(2e3 * 2 ** retryCount, 3e5);
551
- 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);
552
460
  }
553
- let _replaying = false;
554
- async function replayQueue() {
555
- const store = useEidosStore.getState();
556
- if (!store.isOnline || _replaying) {
461
+ let _ = !1;
462
+ async function C() {
463
+ const e = o.getState();
464
+ if (!e.isOnline || _)
557
465
  return { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0 };
558
- }
559
- _replaying = true;
466
+ _ = !0;
560
467
  try {
561
- return await _doReplayQueue(store);
468
+ return await fe(e);
562
469
  } finally {
563
- _replaying = false;
470
+ _ = !1;
564
471
  }
565
472
  }
566
- async function _doReplayQueue(store) {
567
- const candidates = await idbGetPendingItems();
568
- const now = Date.now();
569
- const pending = candidates.filter(
570
- (item) => !item.nextRetryAt || item.nextRetryAt <= now
571
- );
572
- const result = { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0 };
573
- const outcomes = await Promise.allSettled(
574
- pending.map(async (item) => {
575
- const fn = _actionRegistry.get(item.actionId);
576
- if (!fn) return "skipped";
577
- store.updateQueueItem(item.id, { status: "replaying" });
578
- 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" });
579
481
  try {
580
- await fn(...item.args);
581
- const completedAt = Date.now();
582
- store.updateQueueItem(item.id, { status: "succeeded", completedAt });
583
- await idbUpdateQueueItem(item.id, { status: "succeeded", completedAt });
584
- setTimeout(() => {
585
- store.removeQueueItem(item.id);
586
- idbRemoveFromQueue(item.id);
587
- }, 3e3);
588
- return "succeeded";
589
- } catch (err) {
590
- const retryCount = item.retryCount + 1;
591
- if (retryCount >= item.maxRetries) {
592
- store.updateQueueItem(item.id, { status: "failed", error: String(err), retryCount });
593
- await idbUpdateQueueItem(item.id, { status: "failed", error: String(err), retryCount });
594
- return "failed";
595
- } else {
596
- const nextRetryAt = Date.now() + backoffMs(retryCount);
597
- store.updateQueueItem(item.id, { status: "pending", retryCount, nextRetryAt });
598
- await idbUpdateQueueItem(item.id, { status: "pending", retryCount, nextRetryAt });
599
- 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";
600
494
  }
601
495
  }
602
496
  })
603
497
  );
604
- for (const o of outcomes) {
605
- const outcome = o.status === "fulfilled" ? o.value : "failed";
606
- if (outcome === "skipped") {
607
- result.skipped++;
608
- } else {
609
- result.attempted++;
610
- result[outcome]++;
611
- }
498
+ for (const a of i) {
499
+ const c = a.status === "fulfilled" ? a.value : "failed";
500
+ c === "skipped" ? s.skipped++ : (s.attempted++, s[c]++);
612
501
  }
613
- return result;
614
- }
615
- async function clearQueue() {
616
- await idbClearQueue();
617
- useEidosStore.getState().hydrateQueue([]);
618
- }
619
- let _initialized = false;
620
- async function initEidos(config = {}) {
621
- if (_initialized) return;
622
- _initialized = true;
623
- const swPath = config.swPath ?? "/eidos-sw.js";
624
- 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;
625
512
  try {
626
- const persisted = await idbGetQueue();
627
- if (persisted.length > 0) {
628
- useEidosStore.getState().hydrateQueue(persisted);
629
- }
513
+ const r = await ie();
514
+ r.length > 0 && o.getState().hydrateQueue(r);
630
515
  } catch {
631
516
  }
632
517
  try {
633
- await registerServiceWorker(swPath);
518
+ await Y(t);
634
519
  } catch {
635
520
  }
636
- registerBgSyncHandler(() => {
637
- if (useEidosStore.getState().isOnline) {
638
- setTimeout(replayQueue, 200);
639
- }
640
- });
641
- if (autoReplay) {
642
- let prevIsOnline = useEidosStore.getState().isOnline;
643
- useEidosStore.subscribe(() => {
644
- const { isOnline } = useEidosStore.getState();
645
- const justCameOnline = isOnline && !prevIsOnline;
646
- prevIsOnline = isOnline;
647
- if (justCameOnline) {
648
- setTimeout(replayQueue, 600);
649
- }
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);
650
528
  });
651
- const store = useEidosStore.getState();
652
- const hasPending = store.queue.some((q) => q.status === "pending" || q.status === "failed");
653
- if (store.isOnline && hasPending) {
654
- setTimeout(replayQueue, 1200);
655
- }
529
+ const s = o.getState(), i = s.queue.some((a) => a.status === "pending" || a.status === "failed");
530
+ s.isOnline && i && setTimeout(C, 1200);
656
531
  }
657
532
  }
658
- function EidosProvider({ children, swPath, autoReplay }) {
659
- useEffect(() => {
660
- initEidos({ swPath, autoReplay });
661
- }, []);
662
- return /* @__PURE__ */ jsx(Fragment, { children });
663
- }
664
- function useStore(selector) {
665
- const fn = selector ?? ((s) => s);
666
- return useSyncExternalStore(useEidosStore.subscribe, () => fn(useEidosStore.getState()));
667
- }
668
- function useEidos() {
669
- return useStore();
670
- }
671
- function useEidosResource(url) {
672
- return useStore((s) => s.resources[url]);
673
- }
674
- function useEidosQueue() {
675
- return useStore((s) => s.queue);
676
- }
677
- function useEidosAction(id) {
678
- return useStore((s) => s.queue.find((item) => item.id === id));
679
- }
680
- function useEidosStatus() {
681
- const isOnline = useStore((s) => s.isOnline);
682
- const swStatus = useStore((s) => s.swStatus);
683
- const swError = useStore((s) => s.swError);
684
- return { isOnline, swStatus, swError };
685
- }
686
- function useEidosQueueStats() {
687
- const pending = useStore((s) => s.queue.filter((q) => q.status === "pending").length);
688
- const failed = useStore((s) => s.queue.filter((q) => q.status === "failed").length);
689
- const replaying = useStore((s) => s.queue.filter((q) => q.status === "replaying").length);
690
- const total = useStore((s) => s.queue.length);
691
- return { pending, failed, replaying, total };
692
- }
693
- function useEidosOnDrain(callback) {
694
- const total = useStore((s) => s.queue.length);
695
- const prevRef = useRef(0);
696
- const callbackRef = useRef(callback);
697
- callbackRef.current = callback;
698
- useEffect(() => {
699
- if (prevRef.current > 0 && total === 0) {
700
- callbackRef.current();
701
- }
702
- prevRef.current = total;
703
- }, [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]);
704
567
  }
705
- const VERSION = "1.0.12";
706
- function readable(selector) {
568
+ const Ae = "1.0.12";
569
+ function v(e) {
707
570
  return {
708
- subscribe(run) {
709
- run(selector(useEidosStore.getState()));
710
- return useEidosStore.subscribe(() => run(selector(useEidosStore.getState())));
571
+ subscribe(t) {
572
+ return t(e(o.getState())), o.subscribe(() => t(e(o.getState())));
711
573
  },
712
574
  getState() {
713
- return selector(useEidosStore.getState());
575
+ return e(o.getState());
714
576
  }
715
577
  };
716
578
  }
717
- const eidosStore = readable((s) => s);
718
- const eidosQueue = readable((s) => s.queue);
719
- const eidosStatus = readable((s) => ({
720
- isOnline: s.isOnline,
721
- swStatus: s.swStatus,
722
- swError: s.swError
723
- }));
724
- const eidosQueueStats = readable((s) => ({
725
- pending: s.queue.filter((q) => q.status === "pending").length,
726
- failed: s.queue.filter((q) => q.status === "failed").length,
727
- replaying: s.queue.filter((q) => q.status === "replaying").length,
728
- total: s.queue.length
729
- }));
730
- function eidosResource(url) {
731
- return readable((s) => s.resources[url]);
732
- }
733
- function eidosAction(id) {
734
- 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));
735
594
  }
736
595
  export {
737
- EidosProvider,
738
- VERSION,
739
- action,
740
- clearQueue,
741
- eidosAction,
742
- eidosQueue,
743
- eidosQueueStats,
744
- eidosResource,
745
- eidosStatus,
746
- eidosStore,
747
- initEidos,
748
- isBgSyncSupported,
749
- replayQueue,
750
- resource,
751
- setOfflineSimulation,
752
- setQueryInvalidator,
753
- useEidos,
754
- useEidosAction,
755
- useEidosOnDrain,
756
- useEidosQueue,
757
- useEidosQueueStats,
758
- useEidosResource,
759
- useEidosStatus,
760
- 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
761
620
  };
762
621
  //# sourceMappingURL=eidos.es.js.map