@sweidos/eidos 1.0.20 → 1.0.22

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 DELETED
@@ -1,621 +0,0 @@
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,
13
- swStatus: "idle",
14
- swError: void 0,
15
- resources: {},
16
- queue: [],
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) => ({
21
- resources: {
22
- ...n.resources,
23
- [e]: n.resources[e] ? { ...n.resources[e], ...t } : n.resources[e]
24
- }
25
- })),
26
- unregisterResource: (e) => g((t) => {
27
- const { [e]: n, ...r } = t.resources;
28
- return { resources: r };
29
- }),
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)
33
- })),
34
- removeQueueItem: (e) => g((t) => ({ queue: t.queue.filter((n) => n.id !== e) })),
35
- hydrateQueue: (e) => g(() => ({ queue: e }))
36
- };
37
- function G() {
38
- return y;
39
- }
40
- function K(e) {
41
- return D.add(e), () => {
42
- D.delete(e);
43
- };
44
- }
45
- const o = {
46
- getState: G,
47
- subscribe: K,
48
- // Test/devtools helper — merges partial state, preserves action methods.
49
- setState: (e) => {
50
- const t = typeof e == "function" ? e(y) : e;
51
- y = { ...y, ...t }, W();
52
- }
53
- };
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");
61
- return;
62
- }
63
- const t = o.getState();
64
- t.setSwStatus("registering");
65
- try {
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));
69
- }
70
- }
71
- function z(e) {
72
- return new Promise((t) => {
73
- if (e.active) {
74
- t();
75
- return;
76
- }
77
- const n = e.installing ?? e.waiting;
78
- if (!n) {
79
- t();
80
- return;
81
- }
82
- const r = setTimeout(t, 1e4);
83
- n.addEventListener("statechange", function s() {
84
- n.state === "activated" && (clearTimeout(r), n.removeEventListener("statechange", s), t());
85
- });
86
- });
87
- }
88
- function q(e) {
89
- const t = w == null ? void 0 : w.active;
90
- t ? t.postMessage(e) : Q.push(e);
91
- }
92
- let O = null;
93
- function X(e) {
94
- O = e;
95
- }
96
- function we() {
97
- try {
98
- return typeof navigator < "u" && "serviceWorker" in navigator && w !== null && "sync" in w;
99
- } catch {
100
- return !1;
101
- }
102
- }
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();
109
- return;
110
- }
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
- }
137
- }
138
- }
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
- }
148
- }
149
- const R = /* @__PURE__ */ new Map();
150
- let x = null;
151
- function ye(e) {
152
- x = e;
153
- }
154
- function S(e) {
155
- return e.includes("*") || /:[^/]+/.test(e);
156
- }
157
- function ee(e) {
158
- return "^" + e.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".+").replace(/\*/g, "[^/]+").replace(/:[^/]+/g, "[^/]+") + "$";
159
- }
160
- function b(e, t) {
161
- return new Error(
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.`
163
- );
164
- }
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,
172
- status: "idle",
173
- cacheHits: 0,
174
- cacheMisses: 0
175
- };
176
- o.getState().registerResource(e, s), q({
177
- type: "EIDOS_REGISTER_RESOURCE",
178
- url: e,
179
- strategy: n.swStrategy,
180
- cacheName: n.cacheName,
181
- ...r !== void 0 && { pattern: r }
182
- });
183
- const i = {
184
- url: e,
185
- config: t,
186
- strategy: n,
187
- fetch: async () => {
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);
192
- try {
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, {
197
- status: "fresh",
198
- lastEvent: "cache-hit",
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
210
- });
211
- }
212
- const u = await fetch(e);
213
- if (u.ok)
214
- return c && await c.put(e, u.clone()), a.updateResource(e, {
215
- status: "fresh",
216
- cachedAt: Date.now(),
217
- lastEvent: "cache-updated"
218
- }), u;
219
- a.updateResource(e, { status: u.status === 503 ? "offline" : "error" });
220
- const l = u.headers.get("X-Eidos-Offline") === "true";
221
- throw new Error(
222
- l ? `offline: no cached response for ${e}` : `${u.status} ${u.statusText}`
223
- );
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, {
229
- status: "fresh",
230
- lastEvent: "cache-hit",
231
- cacheHits: ((d == null ? void 0 : d.cacheHits) ?? 0) + 1
232
- }), l;
233
- }
234
- throw a.updateResource(e, { status: "error" }), u;
235
- }
236
- },
237
- json: async () => {
238
- if (S(e)) throw b(e, "json");
239
- return (await i.fetch()).json();
240
- },
241
- query: () => {
242
- if (S(e)) throw b(e, "query");
243
- return {
244
- queryKey: ["eidos", e],
245
- queryFn: () => i.json()
246
- };
247
- },
248
- prefetch: async () => {
249
- if (S(e)) throw b(e, "prefetch");
250
- await i.fetch();
251
- },
252
- invalidate: async () => {
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");
257
- await Promise.all(
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))
262
- );
263
- }
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]);
271
- },
272
- unregister: () => {
273
- R.delete(e), q({ type: "EIDOS_UNREGISTER_RESOURCE", url: e }), o.getState().unregisterResource(e);
274
- }
275
- };
276
- return R.set(e, i), i;
277
- }
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);
281
- }
282
- const ne = {
283
- "stale-while-revalidate": {
284
- name: "StaleWhileRevalidate",
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.",
286
- behavior: [
287
- "Cache hit → return immediately, kick off background revalidation",
288
- "Cache miss → fetch from network, cache the response, return it",
289
- "Offline → return cached version if available, 503 if not",
290
- "Reconnect → next request triggers a background refresh"
291
- ],
292
- equivalentCode: `// Workbox equivalent
293
- new StaleWhileRevalidate({
294
- cacheName: 'eidos-resources-v1',
295
- plugins: [new ExpirationPlugin({ maxEntries: 60 })],
296
- })`
297
- },
298
- "cache-first": {
299
- name: "CacheFirst",
300
- reasoning: "cache-first maximises speed and offline availability. Network is consulted only on cache miss. Best for static or infrequently-updated data.",
301
- behavior: [
302
- "Cache hit → return immediately, no network request made",
303
- "Cache miss → fetch from network, cache the response, return it",
304
- "Offline → return cached version, 503 if cache is empty",
305
- "Cache never expires unless explicitly invalidated"
306
- ],
307
- equivalentCode: `// Workbox equivalent
308
- new CacheFirst({
309
- cacheName: 'eidos-resources-v1',
310
- plugins: [new ExpirationPlugin({ maxEntries: 60 })],
311
- })`
312
- },
313
- "network-first": {
314
- name: "NetworkFirst",
315
- reasoning: "network-first prioritises fresh data. Cache acts as a safety net when offline. Best for frequently-updated resources where stale data causes problems.",
316
- behavior: [
317
- "Always try network first",
318
- "Network success → update cache, return fresh response",
319
- "Network failure → fall back to cached version",
320
- "Offline with empty cache → return 503 error response"
321
- ],
322
- equivalentCode: `// Workbox equivalent
323
- new NetworkFirst({
324
- cacheName: 'eidos-resources-v1',
325
- networkTimeoutSeconds: 3,
326
- })`
327
- }
328
- };
329
- function T(e, t, n) {
330
- return {
331
- ...ne[e],
332
- swStrategy: e,
333
- cacheName: n ?? "eidos-resources-v1"
334
- };
335
- }
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 });
346
- }
347
- }, n.onsuccess = () => {
348
- A = n.result, e(n.result);
349
- }, n.onerror = () => t(n.error);
350
- });
351
- }
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);
357
- });
358
- }
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);
364
- });
365
- }
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);
373
- });
374
- }
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);
380
- });
381
- }
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);
390
- return;
391
- }
392
- ++a === 2 && t(i);
393
- }
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);
404
- });
405
- }
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);
411
- });
412
- }
413
- const H = /* @__PURE__ */ new Map();
414
- function L() {
415
- return crypto.randomUUID();
416
- }
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);
425
- try {
426
- return await e(...s);
427
- } catch {
428
- return j(n, n, s, t);
429
- }
430
- }
431
- return e(...s);
432
- };
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,
441
- queuedAt: Date.now(),
442
- retryCount: 0,
443
- maxRetries: r.maxRetries ?? 3,
444
- status: "pending"
445
- };
446
- await ae(i), o.getState().addQueueItem(i);
447
- try {
448
- const a = V();
449
- a && "sync" in a && await a.sync.register("eidos-queue-replay");
450
- } catch {
451
- }
452
- return {
453
- queued: !0,
454
- id: s,
455
- message: `"${t}" queued — will execute when online`
456
- };
457
- }
458
- function de(e) {
459
- return Math.min(2e3 * 2 ** e, 3e5) * (0.8 + Math.random() * 0.4);
460
- }
461
- let _ = !1;
462
- async function C() {
463
- const e = o.getState();
464
- if (!e.isOnline || _)
465
- return { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0 };
466
- _ = !0;
467
- try {
468
- return await fe(e);
469
- } finally {
470
- _ = !1;
471
- }
472
- }
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" });
481
- try {
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";
494
- }
495
- }
496
- })
497
- );
498
- for (const a of i) {
499
- const c = a.status === "fulfilled" ? a.value : "failed";
500
- c === "skipped" ? s.skipped++ : (s.attempted++, s[c]++);
501
- }
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;
512
- try {
513
- const r = await ie();
514
- r.length > 0 && o.getState().hydrateQueue(r);
515
- } catch {
516
- }
517
- try {
518
- await Y(t);
519
- } catch {
520
- }
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);
528
- });
529
- const s = o.getState(), i = s.queue.some((a) => a.status === "pending" || a.status === "failed");
530
- s.isOnline && i && setTimeout(C, 1200);
531
- }
532
- }
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]);
567
- }
568
- const Ae = "1.0.12";
569
- function v(e) {
570
- return {
571
- subscribe(t) {
572
- return t(e(o.getState())), o.subscribe(() => t(e(o.getState())));
573
- },
574
- getState() {
575
- return e(o.getState());
576
- }
577
- };
578
- }
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));
594
- }
595
- export {
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
620
- };
621
- //# sourceMappingURL=eidos.es.js.map