@sweidos/eidos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,880 @@
1
+ import require$$0, { useEffect } from "react";
2
+ import { jsx, Fragment } from "react/jsx-runtime";
3
+ const __vite_import_meta_env__$1 = {};
4
+ const createStoreImpl = (createState) => {
5
+ let state;
6
+ const listeners = /* @__PURE__ */ new Set();
7
+ const setState = (partial, replace) => {
8
+ const nextState = typeof partial === "function" ? partial(state) : partial;
9
+ if (!Object.is(nextState, state)) {
10
+ const previousState = state;
11
+ state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
12
+ listeners.forEach((listener) => listener(state, previousState));
13
+ }
14
+ };
15
+ const getState = () => state;
16
+ const getInitialState = () => initialState;
17
+ const subscribe = (listener) => {
18
+ listeners.add(listener);
19
+ return () => listeners.delete(listener);
20
+ };
21
+ const destroy = () => {
22
+ if ((__vite_import_meta_env__$1 ? "production" : void 0) !== "production") {
23
+ console.warn(
24
+ "[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."
25
+ );
26
+ }
27
+ listeners.clear();
28
+ };
29
+ const api = { setState, getState, getInitialState, subscribe, destroy };
30
+ const initialState = state = createState(setState, getState, api);
31
+ return api;
32
+ };
33
+ const createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
34
+ function getDefaultExportFromCjs(x) {
35
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
36
+ }
37
+ var withSelector = { exports: {} };
38
+ var withSelector_production = {};
39
+ var shim = { exports: {} };
40
+ var useSyncExternalStoreShim_production = {};
41
+ /**
42
+ * @license React
43
+ * use-sync-external-store-shim.production.js
44
+ *
45
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
46
+ *
47
+ * This source code is licensed under the MIT license found in the
48
+ * LICENSE file in the root directory of this source tree.
49
+ */
50
+ var hasRequiredUseSyncExternalStoreShim_production;
51
+ function requireUseSyncExternalStoreShim_production() {
52
+ if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
53
+ hasRequiredUseSyncExternalStoreShim_production = 1;
54
+ var React = require$$0;
55
+ function is(x, y) {
56
+ return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
57
+ }
58
+ var objectIs = "function" === typeof Object.is ? Object.is : is, useState = React.useState, useEffect2 = React.useEffect, useLayoutEffect = React.useLayoutEffect, useDebugValue2 = React.useDebugValue;
59
+ function useSyncExternalStore$2(subscribe, getSnapshot) {
60
+ var value = getSnapshot(), _useState = useState({ inst: { value, getSnapshot } }), inst = _useState[0].inst, forceUpdate = _useState[1];
61
+ useLayoutEffect(
62
+ function() {
63
+ inst.value = value;
64
+ inst.getSnapshot = getSnapshot;
65
+ checkIfSnapshotChanged(inst) && forceUpdate({ inst });
66
+ },
67
+ [subscribe, value, getSnapshot]
68
+ );
69
+ useEffect2(
70
+ function() {
71
+ checkIfSnapshotChanged(inst) && forceUpdate({ inst });
72
+ return subscribe(function() {
73
+ checkIfSnapshotChanged(inst) && forceUpdate({ inst });
74
+ });
75
+ },
76
+ [subscribe]
77
+ );
78
+ useDebugValue2(value);
79
+ return value;
80
+ }
81
+ function checkIfSnapshotChanged(inst) {
82
+ var latestGetSnapshot = inst.getSnapshot;
83
+ inst = inst.value;
84
+ try {
85
+ var nextValue = latestGetSnapshot();
86
+ return !objectIs(inst, nextValue);
87
+ } catch (error) {
88
+ return true;
89
+ }
90
+ }
91
+ function useSyncExternalStore$1(subscribe, getSnapshot) {
92
+ return getSnapshot();
93
+ }
94
+ var shim2 = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
95
+ useSyncExternalStoreShim_production.useSyncExternalStore = void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim2;
96
+ return useSyncExternalStoreShim_production;
97
+ }
98
+ var useSyncExternalStoreShim_development = {};
99
+ /**
100
+ * @license React
101
+ * use-sync-external-store-shim.development.js
102
+ *
103
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
104
+ *
105
+ * This source code is licensed under the MIT license found in the
106
+ * LICENSE file in the root directory of this source tree.
107
+ */
108
+ var hasRequiredUseSyncExternalStoreShim_development;
109
+ function requireUseSyncExternalStoreShim_development() {
110
+ if (hasRequiredUseSyncExternalStoreShim_development) return useSyncExternalStoreShim_development;
111
+ hasRequiredUseSyncExternalStoreShim_development = 1;
112
+ "production" !== process.env.NODE_ENV && function() {
113
+ function is(x, y) {
114
+ return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
115
+ }
116
+ function useSyncExternalStore$2(subscribe, getSnapshot) {
117
+ didWarnOld18Alpha || void 0 === React.startTransition || (didWarnOld18Alpha = true, console.error(
118
+ "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
119
+ ));
120
+ var value = getSnapshot();
121
+ if (!didWarnUncachedGetSnapshot) {
122
+ var cachedValue = getSnapshot();
123
+ objectIs(value, cachedValue) || (console.error(
124
+ "The result of getSnapshot should be cached to avoid an infinite loop"
125
+ ), didWarnUncachedGetSnapshot = true);
126
+ }
127
+ cachedValue = useState({
128
+ inst: { value, getSnapshot }
129
+ });
130
+ var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
131
+ useLayoutEffect(
132
+ function() {
133
+ inst.value = value;
134
+ inst.getSnapshot = getSnapshot;
135
+ checkIfSnapshotChanged(inst) && forceUpdate({ inst });
136
+ },
137
+ [subscribe, value, getSnapshot]
138
+ );
139
+ useEffect2(
140
+ function() {
141
+ checkIfSnapshotChanged(inst) && forceUpdate({ inst });
142
+ return subscribe(function() {
143
+ checkIfSnapshotChanged(inst) && forceUpdate({ inst });
144
+ });
145
+ },
146
+ [subscribe]
147
+ );
148
+ useDebugValue2(value);
149
+ return value;
150
+ }
151
+ function checkIfSnapshotChanged(inst) {
152
+ var latestGetSnapshot = inst.getSnapshot;
153
+ inst = inst.value;
154
+ try {
155
+ var nextValue = latestGetSnapshot();
156
+ return !objectIs(inst, nextValue);
157
+ } catch (error) {
158
+ return true;
159
+ }
160
+ }
161
+ function useSyncExternalStore$1(subscribe, getSnapshot) {
162
+ return getSnapshot();
163
+ }
164
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
165
+ var React = require$$0, objectIs = "function" === typeof Object.is ? Object.is : is, useState = React.useState, useEffect2 = React.useEffect, useLayoutEffect = React.useLayoutEffect, useDebugValue2 = React.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim2 = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
166
+ useSyncExternalStoreShim_development.useSyncExternalStore = void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim2;
167
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
168
+ }();
169
+ return useSyncExternalStoreShim_development;
170
+ }
171
+ var hasRequiredShim;
172
+ function requireShim() {
173
+ if (hasRequiredShim) return shim.exports;
174
+ hasRequiredShim = 1;
175
+ if (process.env.NODE_ENV === "production") {
176
+ shim.exports = requireUseSyncExternalStoreShim_production();
177
+ } else {
178
+ shim.exports = requireUseSyncExternalStoreShim_development();
179
+ }
180
+ return shim.exports;
181
+ }
182
+ /**
183
+ * @license React
184
+ * use-sync-external-store-shim/with-selector.production.js
185
+ *
186
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
187
+ *
188
+ * This source code is licensed under the MIT license found in the
189
+ * LICENSE file in the root directory of this source tree.
190
+ */
191
+ var hasRequiredWithSelector_production;
192
+ function requireWithSelector_production() {
193
+ if (hasRequiredWithSelector_production) return withSelector_production;
194
+ hasRequiredWithSelector_production = 1;
195
+ var React = require$$0, shim2 = requireShim();
196
+ function is(x, y) {
197
+ return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
198
+ }
199
+ var objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore = shim2.useSyncExternalStore, useRef = React.useRef, useEffect2 = React.useEffect, useMemo = React.useMemo, useDebugValue2 = React.useDebugValue;
200
+ withSelector_production.useSyncExternalStoreWithSelector = function(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
201
+ var instRef = useRef(null);
202
+ if (null === instRef.current) {
203
+ var inst = { hasValue: false, value: null };
204
+ instRef.current = inst;
205
+ } else inst = instRef.current;
206
+ instRef = useMemo(
207
+ function() {
208
+ function memoizedSelector(nextSnapshot) {
209
+ if (!hasMemo) {
210
+ hasMemo = true;
211
+ memoizedSnapshot = nextSnapshot;
212
+ nextSnapshot = selector(nextSnapshot);
213
+ if (void 0 !== isEqual && inst.hasValue) {
214
+ var currentSelection = inst.value;
215
+ if (isEqual(currentSelection, nextSnapshot))
216
+ return memoizedSelection = currentSelection;
217
+ }
218
+ return memoizedSelection = nextSnapshot;
219
+ }
220
+ currentSelection = memoizedSelection;
221
+ if (objectIs(memoizedSnapshot, nextSnapshot)) return currentSelection;
222
+ var nextSelection = selector(nextSnapshot);
223
+ if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))
224
+ return memoizedSnapshot = nextSnapshot, currentSelection;
225
+ memoizedSnapshot = nextSnapshot;
226
+ return memoizedSelection = nextSelection;
227
+ }
228
+ var hasMemo = false, memoizedSnapshot, memoizedSelection, maybeGetServerSnapshot = void 0 === getServerSnapshot ? null : getServerSnapshot;
229
+ return [
230
+ function() {
231
+ return memoizedSelector(getSnapshot());
232
+ },
233
+ null === maybeGetServerSnapshot ? void 0 : function() {
234
+ return memoizedSelector(maybeGetServerSnapshot());
235
+ }
236
+ ];
237
+ },
238
+ [getSnapshot, getServerSnapshot, selector, isEqual]
239
+ );
240
+ var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);
241
+ useEffect2(
242
+ function() {
243
+ inst.hasValue = true;
244
+ inst.value = value;
245
+ },
246
+ [value]
247
+ );
248
+ useDebugValue2(value);
249
+ return value;
250
+ };
251
+ return withSelector_production;
252
+ }
253
+ var withSelector_development = {};
254
+ /**
255
+ * @license React
256
+ * use-sync-external-store-shim/with-selector.development.js
257
+ *
258
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
259
+ *
260
+ * This source code is licensed under the MIT license found in the
261
+ * LICENSE file in the root directory of this source tree.
262
+ */
263
+ var hasRequiredWithSelector_development;
264
+ function requireWithSelector_development() {
265
+ if (hasRequiredWithSelector_development) return withSelector_development;
266
+ hasRequiredWithSelector_development = 1;
267
+ "production" !== process.env.NODE_ENV && function() {
268
+ function is(x, y) {
269
+ return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
270
+ }
271
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
272
+ var React = require$$0, shim2 = requireShim(), objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore = shim2.useSyncExternalStore, useRef = React.useRef, useEffect2 = React.useEffect, useMemo = React.useMemo, useDebugValue2 = React.useDebugValue;
273
+ withSelector_development.useSyncExternalStoreWithSelector = function(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
274
+ var instRef = useRef(null);
275
+ if (null === instRef.current) {
276
+ var inst = { hasValue: false, value: null };
277
+ instRef.current = inst;
278
+ } else inst = instRef.current;
279
+ instRef = useMemo(
280
+ function() {
281
+ function memoizedSelector(nextSnapshot) {
282
+ if (!hasMemo) {
283
+ hasMemo = true;
284
+ memoizedSnapshot = nextSnapshot;
285
+ nextSnapshot = selector(nextSnapshot);
286
+ if (void 0 !== isEqual && inst.hasValue) {
287
+ var currentSelection = inst.value;
288
+ if (isEqual(currentSelection, nextSnapshot))
289
+ return memoizedSelection = currentSelection;
290
+ }
291
+ return memoizedSelection = nextSnapshot;
292
+ }
293
+ currentSelection = memoizedSelection;
294
+ if (objectIs(memoizedSnapshot, nextSnapshot))
295
+ return currentSelection;
296
+ var nextSelection = selector(nextSnapshot);
297
+ if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))
298
+ return memoizedSnapshot = nextSnapshot, currentSelection;
299
+ memoizedSnapshot = nextSnapshot;
300
+ return memoizedSelection = nextSelection;
301
+ }
302
+ var hasMemo = false, memoizedSnapshot, memoizedSelection, maybeGetServerSnapshot = void 0 === getServerSnapshot ? null : getServerSnapshot;
303
+ return [
304
+ function() {
305
+ return memoizedSelector(getSnapshot());
306
+ },
307
+ null === maybeGetServerSnapshot ? void 0 : function() {
308
+ return memoizedSelector(maybeGetServerSnapshot());
309
+ }
310
+ ];
311
+ },
312
+ [getSnapshot, getServerSnapshot, selector, isEqual]
313
+ );
314
+ var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);
315
+ useEffect2(
316
+ function() {
317
+ inst.hasValue = true;
318
+ inst.value = value;
319
+ },
320
+ [value]
321
+ );
322
+ useDebugValue2(value);
323
+ return value;
324
+ };
325
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
326
+ }();
327
+ return withSelector_development;
328
+ }
329
+ if (process.env.NODE_ENV === "production") {
330
+ withSelector.exports = requireWithSelector_production();
331
+ } else {
332
+ withSelector.exports = requireWithSelector_development();
333
+ }
334
+ var withSelectorExports = withSelector.exports;
335
+ const useSyncExternalStoreExports = /* @__PURE__ */ getDefaultExportFromCjs(withSelectorExports);
336
+ const __vite_import_meta_env__ = {};
337
+ const { useDebugValue } = require$$0;
338
+ const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports;
339
+ let didWarnAboutEqualityFn = false;
340
+ const identity = (arg) => arg;
341
+ function useStore(api, selector = identity, equalityFn) {
342
+ if ((__vite_import_meta_env__ ? "production" : void 0) !== "production" && equalityFn && !didWarnAboutEqualityFn) {
343
+ console.warn(
344
+ "[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"
345
+ );
346
+ didWarnAboutEqualityFn = true;
347
+ }
348
+ const slice = useSyncExternalStoreWithSelector(
349
+ api.subscribe,
350
+ api.getState,
351
+ api.getServerState || api.getInitialState,
352
+ selector,
353
+ equalityFn
354
+ );
355
+ useDebugValue(slice);
356
+ return slice;
357
+ }
358
+ const createImpl = (createState) => {
359
+ if ((__vite_import_meta_env__ ? "production" : void 0) !== "production" && typeof createState !== "function") {
360
+ console.warn(
361
+ "[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`."
362
+ );
363
+ }
364
+ const api = typeof createState === "function" ? createStore(createState) : createState;
365
+ const useBoundStore = (selector, equalityFn) => useStore(api, selector, equalityFn);
366
+ Object.assign(useBoundStore, api);
367
+ return useBoundStore;
368
+ };
369
+ const create = (createState) => createState ? createImpl(createState) : createImpl;
370
+ const useEidosStore = create((set) => ({
371
+ isOnline: typeof navigator !== "undefined" ? navigator.onLine : true,
372
+ swStatus: "idle",
373
+ swError: void 0,
374
+ resources: {},
375
+ queue: [],
376
+ setOnline: (isOnline) => set({ isOnline }),
377
+ setSwStatus: (swStatus, swError) => set({ swStatus, swError }),
378
+ registerResource: (url, entry) => set((s) => ({ resources: { ...s.resources, [url]: entry } })),
379
+ updateResource: (url, update) => set((s) => ({
380
+ resources: {
381
+ ...s.resources,
382
+ [url]: s.resources[url] ? { ...s.resources[url], ...update } : s.resources[url]
383
+ }
384
+ })),
385
+ unregisterResource: (url) => set((s) => {
386
+ const { [url]: _removed, ...rest } = s.resources;
387
+ return { resources: rest };
388
+ }),
389
+ addQueueItem: (item) => set((s) => ({ queue: [...s.queue, item] })),
390
+ updateQueueItem: (id, update) => set((s) => ({
391
+ queue: s.queue.map((item) => item.id === id ? { ...item, ...update } : item)
392
+ })),
393
+ removeQueueItem: (id) => set((s) => ({ queue: s.queue.filter((item) => item.id !== id) })),
394
+ hydrateQueue: (items) => set({ queue: items })
395
+ }));
396
+ let _registration = null;
397
+ async function registerServiceWorker(swPath) {
398
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
399
+ useEidosStore.getState().setSwStatus("unsupported");
400
+ return;
401
+ }
402
+ const store = useEidosStore.getState();
403
+ store.setSwStatus("registering");
404
+ try {
405
+ _registration = await navigator.serviceWorker.register(swPath, { scope: "/" });
406
+ await waitForActivation(_registration);
407
+ store.setSwStatus("active");
408
+ navigator.serviceWorker.addEventListener("message", onSwMessage);
409
+ window.addEventListener("online", () => store.setOnline(true));
410
+ window.addEventListener("offline", () => store.setOnline(false));
411
+ flushResourceRegistrations();
412
+ } catch (err) {
413
+ store.setSwStatus("error", String(err));
414
+ }
415
+ }
416
+ function waitForActivation(reg) {
417
+ return new Promise((resolve) => {
418
+ if (reg.active) {
419
+ resolve();
420
+ return;
421
+ }
422
+ const sw = reg.installing ?? reg.waiting;
423
+ if (!sw) {
424
+ resolve();
425
+ return;
426
+ }
427
+ sw.addEventListener("statechange", function handler() {
428
+ if (sw.state === "activated") {
429
+ sw.removeEventListener("statechange", handler);
430
+ resolve();
431
+ }
432
+ });
433
+ });
434
+ }
435
+ function sendToWorker(message) {
436
+ const sw = _registration == null ? void 0 : _registration.active;
437
+ if (sw) sw.postMessage(message);
438
+ }
439
+ function onSwMessage(event) {
440
+ const data = event.data;
441
+ if (!(data == null ? void 0 : data.type)) return;
442
+ const store = useEidosStore.getState();
443
+ const { type, url } = data;
444
+ if (!url) return;
445
+ switch (type) {
446
+ case "EIDOS_CACHE_HIT": {
447
+ const current = store.resources[url];
448
+ store.updateResource(url, {
449
+ status: "fresh",
450
+ lastEvent: "cache-hit",
451
+ cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
452
+ });
453
+ break;
454
+ }
455
+ case "EIDOS_CACHE_UPDATED": {
456
+ store.updateResource(url, {
457
+ status: "fresh",
458
+ lastEvent: "cache-updated",
459
+ cachedAt: Date.now()
460
+ });
461
+ break;
462
+ }
463
+ case "EIDOS_NETWORK_ERROR": {
464
+ store.updateResource(url, {
465
+ status: "error",
466
+ lastEvent: "network-error"
467
+ });
468
+ break;
469
+ }
470
+ }
471
+ }
472
+ function setOfflineSimulation(enabled) {
473
+ sendToWorker({ type: "EIDOS_SIMULATE_OFFLINE", enabled });
474
+ useEidosStore.getState().setOnline(!enabled);
475
+ }
476
+ function flushResourceRegistrations() {
477
+ const { resources } = useEidosStore.getState();
478
+ Object.values(resources).forEach((entry) => {
479
+ sendToWorker({
480
+ type: "EIDOS_REGISTER_RESOURCE",
481
+ url: entry.url,
482
+ strategy: entry.strategy.swStrategy,
483
+ cacheName: entry.strategy.cacheName
484
+ });
485
+ });
486
+ }
487
+ const _registry = /* @__PURE__ */ new Map();
488
+ function resource(url, config) {
489
+ if (_registry.has(url)) return _registry.get(url);
490
+ const strategy = deriveStrategy(url, config);
491
+ const entry = {
492
+ url,
493
+ config,
494
+ strategy,
495
+ status: "idle",
496
+ cacheHits: 0,
497
+ cacheMisses: 0
498
+ };
499
+ useEidosStore.getState().registerResource(url, entry);
500
+ sendToWorker({
501
+ type: "EIDOS_REGISTER_RESOURCE",
502
+ url,
503
+ strategy: strategy.swStrategy,
504
+ cacheName: strategy.cacheName
505
+ });
506
+ const handle = {
507
+ url,
508
+ config,
509
+ strategy,
510
+ fetch: async () => {
511
+ const store = useEidosStore.getState();
512
+ store.updateResource(url, { status: "fetching", fetchedAt: Date.now() });
513
+ try {
514
+ const cache = await caches.open(strategy.cacheName).catch(() => null);
515
+ const cached = cache ? await cache.match(url).catch(() => null) : null;
516
+ if (cached) {
517
+ const current2 = useEidosStore.getState().resources[url];
518
+ store.updateResource(url, {
519
+ status: "fresh",
520
+ lastEvent: "cache-hit",
521
+ cacheHits: ((current2 == null ? void 0 : current2.cacheHits) ?? 0) + 1
522
+ });
523
+ if (strategy.swStrategy === "stale-while-revalidate") {
524
+ fetch(url).then(async (resp) => {
525
+ if (resp.ok && cache) {
526
+ await cache.put(url, resp.clone());
527
+ useEidosStore.getState().updateResource(url, {
528
+ cachedAt: Date.now(),
529
+ lastEvent: "cache-updated"
530
+ });
531
+ }
532
+ }).catch(() => {
533
+ });
534
+ }
535
+ return cached;
536
+ }
537
+ const current = useEidosStore.getState().resources[url];
538
+ store.updateResource(url, {
539
+ cacheMisses: ((current == null ? void 0 : current.cacheMisses) ?? 0) + 1
540
+ });
541
+ const response = await fetch(url);
542
+ if (response.ok) {
543
+ if (cache) await cache.put(url, response.clone());
544
+ store.updateResource(url, {
545
+ status: "fresh",
546
+ cachedAt: Date.now(),
547
+ lastEvent: "cache-updated"
548
+ });
549
+ return response;
550
+ }
551
+ store.updateResource(url, { status: response.status === 503 ? "offline" : "error" });
552
+ const isOffline = response.headers.get("X-Eidos-Offline") === "true";
553
+ throw new Error(
554
+ isOffline ? `offline: no cached response for ${url}` : `${response.status} ${response.statusText}`
555
+ );
556
+ } catch (err) {
557
+ const cache = await caches.open(strategy.cacheName).catch(() => null);
558
+ const fallback = cache ? await cache.match(url).catch(() => null) : null;
559
+ if (fallback) {
560
+ const current = useEidosStore.getState().resources[url];
561
+ store.updateResource(url, {
562
+ status: "fresh",
563
+ lastEvent: "cache-hit",
564
+ cacheHits: ((current == null ? void 0 : current.cacheHits) ?? 0) + 1
565
+ });
566
+ return fallback;
567
+ }
568
+ store.updateResource(url, { status: "error" });
569
+ throw err;
570
+ }
571
+ },
572
+ json: async () => {
573
+ const res = await handle.fetch();
574
+ return res.json();
575
+ },
576
+ query: () => ({
577
+ queryKey: ["eidos", url],
578
+ queryFn: () => handle.json()
579
+ }),
580
+ prefetch: async () => {
581
+ await handle.fetch();
582
+ },
583
+ invalidate: async () => {
584
+ sendToWorker({ type: "EIDOS_CLEAR_CACHE", url });
585
+ const cache = await caches.open(strategy.cacheName).catch(() => null);
586
+ if (cache) {
587
+ const keys = await cache.keys();
588
+ await Promise.all(
589
+ keys.filter((r) => new URL(r.url).pathname === url).map((r) => cache.delete(r))
590
+ );
591
+ }
592
+ useEidosStore.getState().updateResource(url, {
593
+ status: "stale",
594
+ cachedAt: void 0,
595
+ lastEvent: "cache-cleared",
596
+ cacheHits: 0,
597
+ cacheMisses: 0
598
+ });
599
+ }
600
+ };
601
+ _registry.set(url, handle);
602
+ return handle;
603
+ }
604
+ function deriveStrategy(url, config) {
605
+ const explicit = config.strategy;
606
+ if (config.offline) return buildStrategy(explicit ?? "stale-while-revalidate");
607
+ return buildStrategy(explicit ?? "network-first");
608
+ }
609
+ const STRATEGY_META = {
610
+ "stale-while-revalidate": {
611
+ name: "StaleWhileRevalidate",
612
+ 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.",
613
+ behavior: [
614
+ "Cache hit → return immediately, kick off background revalidation",
615
+ "Cache miss → fetch from network, cache the response, return it",
616
+ "Offline → return cached version if available, 503 if not",
617
+ "Reconnect → next request triggers a background refresh"
618
+ ],
619
+ equivalentCode: `// Workbox equivalent
620
+ new StaleWhileRevalidate({
621
+ cacheName: 'eidos-resources-v1',
622
+ plugins: [new ExpirationPlugin({ maxEntries: 60 })],
623
+ })`
624
+ },
625
+ "cache-first": {
626
+ name: "CacheFirst",
627
+ reasoning: "cache-first maximises speed and offline availability. Network is consulted only on cache miss. Best for static or infrequently-updated data.",
628
+ behavior: [
629
+ "Cache hit → return immediately, no network request made",
630
+ "Cache miss → fetch from network, cache the response, return it",
631
+ "Offline → return cached version, 503 if cache is empty",
632
+ "Cache never expires unless explicitly invalidated"
633
+ ],
634
+ equivalentCode: `// Workbox equivalent
635
+ new CacheFirst({
636
+ cacheName: 'eidos-resources-v1',
637
+ plugins: [new ExpirationPlugin({ maxEntries: 60 })],
638
+ })`
639
+ },
640
+ "network-first": {
641
+ name: "NetworkFirst",
642
+ reasoning: "network-first prioritises fresh data. Cache acts as a safety net when offline. Best for frequently-updated resources where stale data causes problems.",
643
+ behavior: [
644
+ "Always try network first",
645
+ "Network success → update cache, return fresh response",
646
+ "Network failure → fall back to cached version",
647
+ "Offline with empty cache → return 503 error response"
648
+ ],
649
+ equivalentCode: `// Workbox equivalent
650
+ new NetworkFirst({
651
+ cacheName: 'eidos-resources-v1',
652
+ networkTimeoutSeconds: 3,
653
+ })`
654
+ }
655
+ };
656
+ function buildStrategy(swStrategy, _url) {
657
+ return {
658
+ ...STRATEGY_META[swStrategy],
659
+ swStrategy,
660
+ cacheName: "eidos-resources-v1"
661
+ };
662
+ }
663
+ const DB_NAME = "eidos";
664
+ const DB_VERSION = 1;
665
+ const QUEUE_STORE = "action-queue";
666
+ let _db = null;
667
+ function openDB() {
668
+ if (_db) return Promise.resolve(_db);
669
+ return new Promise((resolve, reject) => {
670
+ const req = indexedDB.open(DB_NAME, DB_VERSION);
671
+ req.onupgradeneeded = (event) => {
672
+ const db = event.target.result;
673
+ if (!db.objectStoreNames.contains(QUEUE_STORE)) {
674
+ const store = db.createObjectStore(QUEUE_STORE, { keyPath: "id" });
675
+ store.createIndex("status", "status", { unique: false });
676
+ store.createIndex("actionId", "actionId", { unique: false });
677
+ }
678
+ };
679
+ req.onsuccess = () => {
680
+ _db = req.result;
681
+ resolve(req.result);
682
+ };
683
+ req.onerror = () => reject(req.error);
684
+ });
685
+ }
686
+ async function idbAddToQueue(item) {
687
+ const db = await openDB();
688
+ return new Promise((resolve, reject) => {
689
+ const tx = db.transaction(QUEUE_STORE, "readwrite");
690
+ tx.objectStore(QUEUE_STORE).add(item);
691
+ tx.oncomplete = () => resolve();
692
+ tx.onerror = () => reject(tx.error);
693
+ });
694
+ }
695
+ async function idbGetQueue() {
696
+ const db = await openDB();
697
+ return new Promise((resolve, reject) => {
698
+ const tx = db.transaction(QUEUE_STORE, "readonly");
699
+ const req = tx.objectStore(QUEUE_STORE).getAll();
700
+ req.onsuccess = () => resolve(req.result);
701
+ req.onerror = () => reject(req.error);
702
+ });
703
+ }
704
+ async function idbUpdateQueueItem(id, update) {
705
+ const db = await openDB();
706
+ return new Promise((resolve, reject) => {
707
+ const tx = db.transaction(QUEUE_STORE, "readwrite");
708
+ const store = tx.objectStore(QUEUE_STORE);
709
+ const get = store.get(id);
710
+ get.onsuccess = () => {
711
+ if (get.result) store.put({ ...get.result, ...update });
712
+ };
713
+ tx.oncomplete = () => resolve();
714
+ tx.onerror = () => reject(tx.error);
715
+ });
716
+ }
717
+ async function idbRemoveFromQueue(id) {
718
+ const db = await openDB();
719
+ return new Promise((resolve, reject) => {
720
+ const tx = db.transaction(QUEUE_STORE, "readwrite");
721
+ tx.objectStore(QUEUE_STORE).delete(id);
722
+ tx.oncomplete = () => resolve();
723
+ tx.onerror = () => reject(tx.error);
724
+ });
725
+ }
726
+ const _actionRegistry = /* @__PURE__ */ new Map();
727
+ function uid() {
728
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
729
+ }
730
+ function action(fn, config) {
731
+ const actionId = config.name ?? fn.name ?? uid();
732
+ _actionRegistry.set(actionId, fn);
733
+ const wrapped = async (...args) => {
734
+ const { isOnline } = useEidosStore.getState();
735
+ if (config.reliability === "neverLose") {
736
+ if (!isOnline) {
737
+ return persistAndQueue(actionId, fn.name || actionId, args, config);
738
+ }
739
+ try {
740
+ return await fn(...args);
741
+ } catch {
742
+ return persistAndQueue(actionId, fn.name || actionId, args, config);
743
+ }
744
+ }
745
+ return fn(...args);
746
+ };
747
+ Object.defineProperty(wrapped, "id", { value: actionId, writable: false });
748
+ Object.defineProperty(wrapped, "config", { value: config, writable: false });
749
+ return wrapped;
750
+ }
751
+ async function persistAndQueue(actionId, actionName, args, config) {
752
+ const id = uid();
753
+ const item = {
754
+ id,
755
+ actionId,
756
+ actionName,
757
+ args,
758
+ queuedAt: Date.now(),
759
+ retryCount: 0,
760
+ maxRetries: config.maxRetries ?? 3,
761
+ status: "pending"
762
+ };
763
+ await idbAddToQueue(item);
764
+ useEidosStore.getState().addQueueItem(item);
765
+ return {
766
+ queued: true,
767
+ id,
768
+ message: `"${actionName}" queued — will execute when online`
769
+ };
770
+ }
771
+ async function replayQueue() {
772
+ const store = useEidosStore.getState();
773
+ if (!store.isOnline) return;
774
+ const queue = await idbGetQueue();
775
+ const pending = queue.filter(
776
+ (item) => item.status === "pending" || item.status === "failed"
777
+ );
778
+ for (const item of pending) {
779
+ const fn = _actionRegistry.get(item.actionId);
780
+ if (!fn) continue;
781
+ store.updateQueueItem(item.id, { status: "replaying" });
782
+ await idbUpdateQueueItem(item.id, { status: "replaying" });
783
+ try {
784
+ await fn(...item.args);
785
+ const completedAt = Date.now();
786
+ store.updateQueueItem(item.id, { status: "succeeded", completedAt });
787
+ await idbUpdateQueueItem(item.id, { status: "succeeded", completedAt });
788
+ setTimeout(() => {
789
+ store.removeQueueItem(item.id);
790
+ idbRemoveFromQueue(item.id);
791
+ }, 3e3);
792
+ } catch (err) {
793
+ const retryCount = item.retryCount + 1;
794
+ if (retryCount >= item.maxRetries) {
795
+ store.updateQueueItem(item.id, {
796
+ status: "failed",
797
+ error: String(err),
798
+ retryCount
799
+ });
800
+ await idbUpdateQueueItem(item.id, {
801
+ status: "failed",
802
+ error: String(err),
803
+ retryCount
804
+ });
805
+ } else {
806
+ store.updateQueueItem(item.id, { status: "pending", retryCount });
807
+ await idbUpdateQueueItem(item.id, { status: "pending", retryCount });
808
+ }
809
+ }
810
+ }
811
+ }
812
+ let _initialized = false;
813
+ async function initEidos(config = {}) {
814
+ if (_initialized) return;
815
+ _initialized = true;
816
+ const swPath = config.swPath ?? "/eidos-sw.js";
817
+ const autoReplay = config.autoReplay ?? true;
818
+ try {
819
+ const persisted = await idbGetQueue();
820
+ if (persisted.length > 0) {
821
+ useEidosStore.getState().hydrateQueue(persisted);
822
+ }
823
+ } catch {
824
+ }
825
+ try {
826
+ await registerServiceWorker(swPath);
827
+ } catch {
828
+ }
829
+ if (autoReplay) {
830
+ let prevIsOnline = useEidosStore.getState().isOnline;
831
+ useEidosStore.subscribe((state) => {
832
+ const justCameOnline = state.isOnline && !prevIsOnline;
833
+ prevIsOnline = state.isOnline;
834
+ if (justCameOnline) {
835
+ setTimeout(replayQueue, 600);
836
+ }
837
+ });
838
+ const store = useEidosStore.getState();
839
+ const hasPending = store.queue.some((q) => q.status === "pending" || q.status === "failed");
840
+ if (store.isOnline && hasPending) {
841
+ setTimeout(replayQueue, 1200);
842
+ }
843
+ }
844
+ }
845
+ function EidosProvider({ children, swPath, autoReplay }) {
846
+ useEffect(() => {
847
+ initEidos({ swPath, autoReplay });
848
+ }, []);
849
+ return /* @__PURE__ */ jsx(Fragment, { children });
850
+ }
851
+ function useEidos() {
852
+ return useEidosStore();
853
+ }
854
+ function useEidosResource(url) {
855
+ return useEidosStore((s) => s.resources[url]);
856
+ }
857
+ function useEidosQueue() {
858
+ return useEidosStore((s) => s.queue);
859
+ }
860
+ function useEidosStatus() {
861
+ return useEidosStore((s) => ({
862
+ isOnline: s.isOnline,
863
+ swStatus: s.swStatus,
864
+ swError: s.swError
865
+ }));
866
+ }
867
+ export {
868
+ EidosProvider,
869
+ action,
870
+ initEidos,
871
+ replayQueue,
872
+ resource,
873
+ setOfflineSimulation,
874
+ useEidos,
875
+ useEidosQueue,
876
+ useEidosResource,
877
+ useEidosStatus,
878
+ useEidosStore
879
+ };
880
+ //# sourceMappingURL=eidos.es.js.map