@sweidos/eidos 2.2.0 → 2.3.1

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/index.js CHANGED
@@ -1,45 +1,48 @@
1
1
  import { useEidosStore as o } from "./store.js";
2
- import { getSwRegistration as i, isBgSyncSupported as s, registerPushCallbacks as t, sendToWorker as u, setOfflineSimulation as a } from "./sw-bridge.js";
3
- import { resource as d, resourcePattern as n, setQueryInvalidator as c, warmCache as p } from "./resource.js";
4
- import { _getQueueStorage as f, setQueueStorage as E } from "./queue-storage.js";
5
- import { action as Q, cancelByIdempotencyKey as y, clearQueue as g, replayQueue as R, requeueItem as b } from "./action.js";
6
- import { subscribeReplayOnReconnect as O } from "./replay.js";
7
- import { _resetEidos as P, initEidos as h } from "./runtime.js";
8
- import { AsyncStorageQueueStorage as v } from "./async-storage-adapter.js";
2
+ import { getSwRegistration as i, isBgSyncSupported as t, registerPushCallbacks as s, sendToWorker as u, setOfflineSimulation as m, triggerSwUpdate as a } from "./sw-bridge.js";
3
+ import { resource as n, resourcePattern as p, setQueryInvalidator as c, warmCache as S } from "./resource.js";
4
+ import { _getQueueStorage as E, setQueueStorage as l } from "./queue-storage.js";
5
+ import { action as Q, cancelByIdempotencyKey as y, clearQueue as R, replayQueue as b, requeueItem as I } from "./action.js";
6
+ import { subscribeReplayOnReconnect as w } from "./replay.js";
7
+ import { _resetEidos as D, initEidos as P } from "./runtime.js";
8
+ import { AsyncStorageQueueStorage as k } from "./async-storage-adapter.js";
9
9
  import { EidosProvider as B } from "./react/Provider.js";
10
- import { eidosAction as D, eidosQueue as _, eidosQueueStats as q, eidosReliabilityStats as x, eidosResource as K, eidosStatus as N, eidosStore as T, onQueueDrain as V } from "./stores.js";
11
- import { useEidos as j, useEidosAction as z, useEidosOnDrain as F, useEidosQueue as G, useEidosQueueStats as H, useEidosReliabilityStats as J, useEidosResource as L, useEidosResources as M, useEidosStatus as U } from "./react/hooks.js";
12
- import { VERSION as Y } from "./version.js";
10
+ import { eidosAction as _, eidosQueue as q, eidosQueueStats as x, eidosReliabilityStats as K, eidosResource as N, eidosStatus as T, eidosStore as U, onQueueDrain as V } from "./stores.js";
11
+ import { useEidos as j, useEidosAction as z, useEidosOnDrain as F, useEidosQueue as G, useEidosQueueStats as H, useEidosReliabilityStats as J, useEidosResource as L, useEidosResources as M, useEidosStatus as X } from "./react/hooks.js";
12
+ import { VERSION as Z } from "./version.js";
13
+ import { eidosDebug as ee } from "./debug.js";
13
14
  export {
14
- v as AsyncStorageQueueStorage,
15
+ k as AsyncStorageQueueStorage,
15
16
  B as EidosProvider,
16
- Y as VERSION,
17
- f as _getQueueStorage,
18
- P as _resetEidos,
17
+ Z as VERSION,
18
+ E as _getQueueStorage,
19
+ D as _resetEidos,
19
20
  Q as action,
20
21
  y as cancelByIdempotencyKey,
21
- g as clearQueue,
22
- D as eidosAction,
23
- _ as eidosQueue,
24
- q as eidosQueueStats,
25
- x as eidosReliabilityStats,
26
- K as eidosResource,
27
- N as eidosStatus,
28
- T as eidosStore,
22
+ R as clearQueue,
23
+ _ as eidosAction,
24
+ ee as eidosDebug,
25
+ q as eidosQueue,
26
+ x as eidosQueueStats,
27
+ K as eidosReliabilityStats,
28
+ N as eidosResource,
29
+ T as eidosStatus,
30
+ U as eidosStore,
29
31
  i as getSwRegistration,
30
- h as initEidos,
31
- s as isBgSyncSupported,
32
+ P as initEidos,
33
+ t as isBgSyncSupported,
32
34
  V as onQueueDrain,
33
- t as registerPushCallbacks,
34
- R as replayQueue,
35
- b as requeueItem,
36
- d as resource,
37
- n as resourcePattern,
35
+ s as registerPushCallbacks,
36
+ b as replayQueue,
37
+ I as requeueItem,
38
+ n as resource,
39
+ p as resourcePattern,
38
40
  u as sendToWorker,
39
- a as setOfflineSimulation,
41
+ m as setOfflineSimulation,
40
42
  c as setQueryInvalidator,
41
- E as setQueueStorage,
42
- O as subscribeReplayOnReconnect,
43
+ l as setQueueStorage,
44
+ w as subscribeReplayOnReconnect,
45
+ a as triggerSwUpdate,
43
46
  j as useEidos,
44
47
  z as useEidosAction,
45
48
  F as useEidosOnDrain,
@@ -48,7 +51,7 @@ export {
48
51
  J as useEidosReliabilityStats,
49
52
  L as useEidosResource,
50
53
  M as useEidosResources,
51
- U as useEidosStatus,
54
+ X as useEidosStatus,
52
55
  o as useEidosStore,
53
- p as warmCache
56
+ S as warmCache
54
57
  };
@@ -0,0 +1,2 @@
1
+ /** Decodes a base64url string (e.g. a VAPID public key) into raw bytes. */
2
+ export declare function urlBase64ToUint8Array(base64Url: string): Uint8Array;
package/dist/query.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { UseQueryOptions, UseQueryResult, UseMutationOptions, UseMutationResult, QueryClient } from '@tanstack/react-query';
2
- import { ResourceHandle, AnyResourceHandle, ActionHandle, QueuedResult } from '@sweidos/eidos';
3
-
2
+ import { ResourceHandle, AnyResourceHandle, ActionHandle, QueuedResult } from './index.ts';
4
3
  /**
5
4
  * Register a QueryClient with Eidos.
6
5
  *
@@ -0,0 +1,12 @@
1
+ import { ActionQueueItem } from './types';
2
+ export interface QueueStorage {
3
+ add(item: ActionQueueItem): Promise<void>;
4
+ getAll(): Promise<ActionQueueItem[]>;
5
+ getPending(): Promise<ActionQueueItem[]>;
6
+ update(id: string, patch: Partial<ActionQueueItem>): Promise<void>;
7
+ remove(id: string): Promise<void>;
8
+ clear(): Promise<void>;
9
+ }
10
+ /** Override the default IndexedDB queue with a custom storage backend (e.g. AsyncStorage for React Native). */
11
+ export declare function setQueueStorage(s: QueueStorage): void;
12
+ export declare function _getQueueStorage(): QueueStorage | null;
@@ -0,0 +1,32 @@
1
+ import { ActionQueueItem } from './types';
2
+ type QueueSyncMessage = {
3
+ type: 'update';
4
+ id: string;
5
+ update: Partial<ActionQueueItem>;
6
+ } | {
7
+ type: 'batchUpdate';
8
+ updates: Array<{
9
+ id: string;
10
+ update: Partial<ActionQueueItem>;
11
+ }>;
12
+ } | {
13
+ type: 'remove';
14
+ id: string;
15
+ };
16
+ /**
17
+ * Broadcasts a queue-item status change to other tabs sharing the same
18
+ * IndexedDB queue. The replay-lock holder (see `replayQueue` in action.ts)
19
+ * is the only tab that mutates queue-item status, so non-leader tabs would
20
+ * otherwise show stale status until their own store re-hydrates.
21
+ *
22
+ * No-ops in environments without BroadcastChannel (React Native, old Safari).
23
+ */
24
+ export declare function broadcastQueueSync(message: QueueSyncMessage): void;
25
+ /**
26
+ * Applies queue-item status updates broadcast by the replay-lock holder to
27
+ * this tab's store. Returns an unsubscribe function.
28
+ */
29
+ export declare function subscribeQueueSync(): () => void;
30
+ /** Test-only: reset the cached channel so each test gets a fresh instance. */
31
+ export declare function _resetQueueSyncChannel(): void;
32
+ export {};
@@ -0,0 +1,16 @@
1
+ import { ReactNode } from 'react';
2
+ import { EidosConfig } from '../runtime';
3
+ interface EidosProviderProps extends EidosConfig {
4
+ children: ReactNode;
5
+ }
6
+ /**
7
+ * Mount once at the root of your application.
8
+ * Registers the service worker and initialises the Eidos runtime.
9
+ *
10
+ * @example
11
+ * <EidosProvider swPath="/eidos-sw.js">
12
+ * <App />
13
+ * </EidosProvider>
14
+ */
15
+ export declare function EidosProvider({ children, swPath, autoReplay }: EidosProviderProps): import("react").JSX.Element;
16
+ export {};
@@ -1,5 +1,4 @@
1
1
  import { default as React } from 'react';
2
-
3
2
  export interface EidosProviderRNProps {
4
3
  children: React.ReactNode;
5
4
  /**
@@ -0,0 +1,51 @@
1
+ import { EidosStore } from '../store';
2
+ /** Full Eidos store — prefer the narrower hooks below for performance. */
3
+ export declare function useEidos(): EidosStore;
4
+ /** All registered resources — only re-renders when the resources map changes, not on queue mutations. */
5
+ export declare function useEidosResources(): Record<string, import('..').ResourceEntry>;
6
+ /** Live state for a single registered resource URL. */
7
+ export declare function useEidosResource(url: string): import('..').ResourceEntry;
8
+ /** The current action queue. */
9
+ export declare function useEidosQueue(): import('..').ActionQueueItem[];
10
+ /**
11
+ * Live state for a single queue item by ID. Only re-renders when that specific
12
+ * item changes — cheaper than `useEidosQueue().find(id)` which re-renders on
13
+ * any queue mutation.
14
+ */
15
+ export declare function useEidosAction(id: string): import('..').ActionQueueItem | undefined;
16
+ /**
17
+ * Online + SW status — cheap subscription, safe to use in header components.
18
+ * Three separate primitive selectors so each only triggers a re-render when
19
+ * its own value changes (no object-reference churn from a combined selector).
20
+ */
21
+ export declare function useEidosStatus(): {
22
+ isOnline: boolean;
23
+ swStatus: "idle" | "error" | "registering" | "active" | "unsupported";
24
+ swError: string | undefined;
25
+ };
26
+ /**
27
+ * Queue counts — single subscription, single loop. Re-renders only when a
28
+ * count changes, not on every queue mutation. Use for badges and status bars
29
+ * instead of `useEidosQueue()` when you only need numbers, not full items.
30
+ */
31
+ export declare function useEidosQueueStats(): {
32
+ pending: number;
33
+ failed: number;
34
+ replaying: number;
35
+ total: number;
36
+ };
37
+ /**
38
+ * Calls `callback` once each time the action queue drains from non-empty → 0.
39
+ * Stable callback reference not required — always calls the latest version.
40
+ * Use for "all offline actions synced!" toasts.
41
+ *
42
+ * @example
43
+ * useEidosOnDrain(() => toast.success('All offline actions synced!'))
44
+ */
45
+ /**
46
+ * Cumulative, session-scoped `neverLose` queue outcome counters — opt-in
47
+ * reliability telemetry for dashboards/devtools. Re-renders only when a
48
+ * counter changes.
49
+ */
50
+ export declare function useEidosReliabilityStats(): import('..').ReliabilityStats;
51
+ export declare function useEidosOnDrain(callback: () => void): void;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Subscribe to online/offline transitions and trigger replayQueue() on
3
+ * reconnect, plus replay any pending items left over from a previous session.
4
+ *
5
+ * Shared by the web (runtime.ts) and React Native (runtime-rn.ts) init paths.
6
+ *
7
+ * WHY subscribe to the store instead of window.addEventListener('online'):
8
+ * setOfflineSimulation() updates the store directly but never fires a real
9
+ * browser `online` event. Watching the store catches both:
10
+ * • Real network reconnects (sw-bridge updates store on window.online)
11
+ * • Simulation toggled off (setOfflineSimulation(false) → store.setOnline(true))
12
+ *
13
+ * Returns an unsubscribe function.
14
+ */
15
+ export declare function subscribeReplayOnReconnect(): () => void;
@@ -0,0 +1,32 @@
1
+ import { ResourceConfig, ResourceHandle, PatternResourceHandle, WarmCacheResult } from './types';
2
+ type QueryInvalidator = (queryKey: [string, string]) => void;
3
+ /** @internal Called by @sweidos/eidos/query. */
4
+ export declare function setQueryInvalidator(fn: QueryInvalidator): void;
5
+ /**
6
+ * Registers a concrete-URL resource. For URL patterns (`/api/products/*`,
7
+ * `/api/users/:id`, `**`), use `resourcePattern()` instead.
8
+ */
9
+ export declare function resource<T = unknown>(url: string, config: ResourceConfig): ResourceHandle<T>;
10
+ /**
11
+ * Registers a URL pattern (`/api/products/*`, `/api/users/:id`, `**`). The SW
12
+ * intercepts all matching requests automatically — there is no single URL to
13
+ * fetch/cache directly, so the returned handle only supports cache management
14
+ * (`invalidate`/`unregister`). For a fetchable resource, use `resource()`.
15
+ */
16
+ export declare function resourcePattern(url: string, config: ResourceConfig): PatternResourceHandle;
17
+ /**
18
+ * Bulk-prefetch an array of resource handles concurrently, warming the cache
19
+ * for each one. Useful on login / app init when you know which resources the
20
+ * user will need offline.
21
+ *
22
+ * Pattern handles (containing `*`, `**`, or `:param`) are silently skipped —
23
+ * they match multiple URLs so there is no single URL to prefetch.
24
+ *
25
+ * @example
26
+ * import { warmCache } from '@sweidos/eidos'
27
+ *
28
+ * // In EidosProvider's onReady, or after login:
29
+ * const { warmed, failed } = await warmCache([products, userProfile, settings])
30
+ */
31
+ export declare function warmCache(handles: ResourceHandle[]): Promise<WarmCacheResult>;
32
+ export {};
package/dist/resource.js CHANGED
@@ -1,48 +1,51 @@
1
1
  import { useEidosStore as h } from "./store.js";
2
- import { sendToWorker as p } from "./sw-bridge.js";
3
- var d = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), g = null;
4
- function _(e) {
5
- g = e;
2
+ import { sendToWorker as m } from "./sw-bridge.js";
3
+ var d = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), w = null;
4
+ function q(e) {
5
+ w = e;
6
6
  }
7
7
  function f(e) {
8
8
  return e.includes("*") || /:[^/]+/.test(e);
9
9
  }
10
- function k(e) {
10
+ function R(e) {
11
11
  return "^" + e.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".+").replace(/\*/g, "[^/]+").replace(/:[^/]+/g, "[^/]+") + "$";
12
12
  }
13
- function m(e, s) {
14
- const a = b(s), t = f(e) ? k(e) : void 0, r = {
13
+ function v(e, a) {
14
+ const s = S(a), t = f(e) ? R(e) : void 0, r = {
15
15
  url: e,
16
- config: s,
17
- strategy: a,
16
+ config: a,
17
+ strategy: s,
18
18
  status: "idle",
19
19
  cacheHits: 0,
20
20
  cacheMisses: 0
21
21
  };
22
- return h.getState().registerResource(e, r), p({
22
+ return h.getState().registerResource(e, r), m({
23
23
  type: "EIDOS_REGISTER_RESOURCE",
24
24
  url: e,
25
- strategy: a.swStrategy,
26
- cacheName: a.cacheName,
27
- ...t !== void 0 && { pattern: t }
25
+ strategy: s.swStrategy,
26
+ cacheName: s.cacheName,
27
+ ...t !== void 0 && { pattern: t },
28
+ ...a.maxAge !== void 0 && { maxAge: a.maxAge },
29
+ ...a.maxEntries !== void 0 && { maxEntries: a.maxEntries },
30
+ ...a.networkTimeoutMs !== void 0 && { networkTimeoutMs: a.networkTimeoutMs }
28
31
  }), {
29
- strategy: a,
32
+ strategy: s,
30
33
  regexStr: t
31
34
  };
32
35
  }
33
- function y(e, s, a) {
36
+ function y(e, a, s) {
34
37
  return async () => {
35
- p({
38
+ m({
36
39
  type: "EIDOS_CLEAR_CACHE",
37
40
  url: e
38
41
  });
39
- const t = await caches.open(s.cacheName).catch(() => null);
42
+ const t = await caches.open(a.cacheName).catch(() => null);
40
43
  if (t) {
41
- const r = await t.keys(), n = a ? new RegExp(a) : null, c = e.startsWith("http");
42
- await Promise.all(r.filter((i) => {
43
- const o = i.url, u = new URL(o).pathname;
44
- return n ? n.test(c ? o : u) : c ? o === e : o === e || u === e;
45
- }).map((i) => t.delete(i)));
44
+ const r = await t.keys(), n = s ? new RegExp(s) : null, i = e.startsWith("http");
45
+ await Promise.all(r.filter((c) => {
46
+ const o = c.url, u = new URL(o).pathname;
47
+ return n ? n.test(i ? o : u) : i ? o === e : o === e || u === e;
48
+ }).map((c) => t.delete(c)));
46
49
  }
47
50
  f(e) || h.getState().updateResource(e, {
48
51
  status: "stale",
@@ -50,30 +53,30 @@ function y(e, s, a) {
50
53
  lastEvent: "cache-cleared",
51
54
  cacheHits: 0,
52
55
  cacheMisses: 0
53
- }), g?.(["eidos", e]);
56
+ }), w?.(["eidos", e]);
54
57
  };
55
58
  }
56
59
  function E(e) {
57
60
  return () => {
58
- d.delete(e), p({
61
+ d.delete(e), m({
59
62
  type: "EIDOS_UNREGISTER_RESOURCE",
60
63
  url: e
61
64
  }), h.getState().unregisterResource(e);
62
65
  };
63
66
  }
64
- function A(e, s) {
67
+ function _(e, a) {
65
68
  if (f(e)) throw new Error(`[eidos] resource('${e}') is a URL pattern — use resourcePattern('${e}', config) instead. Pattern handles only support invalidate()/unregister(); the SW intercepts matching requests automatically.`);
66
69
  if (d.has(e)) return d.get(e);
67
- const { strategy: a } = m(e, s), t = {
70
+ const { strategy: s } = v(e, a), t = {
68
71
  url: e,
69
- config: s,
70
- strategy: a,
72
+ config: a,
73
+ strategy: s,
71
74
  fetch: async () => {
72
75
  const r = l.get(e);
73
- if (r) return r.then((c) => c.clone());
74
- const n = S(e, s, a);
76
+ if (r) return r.then((i) => i.clone());
77
+ const n = k(e, a, s);
75
78
  return l.set(e, n), n.finally(() => l.delete(e)).catch(() => {
76
- }), n.then((c) => c.clone());
79
+ }), n.then((i) => i.clone());
77
80
  },
78
81
  json: async () => (await t.fetch()).json(),
79
82
  query: () => ({
@@ -83,47 +86,47 @@ function A(e, s) {
83
86
  prefetch: async () => {
84
87
  await t.fetch();
85
88
  },
86
- invalidate: y(e, a, void 0),
89
+ invalidate: y(e, s, void 0),
87
90
  unregister: E(e)
88
91
  };
89
92
  return d.set(e, t), t;
90
93
  }
91
- function $(e, s) {
94
+ function T(e, a) {
92
95
  if (!f(e)) throw new Error(`[eidos] resourcePattern('${e}') is not a URL pattern — use resource('${e}', config) instead.`);
93
96
  if (d.has(e)) return d.get(e);
94
- const { strategy: a, regexStr: t } = m(e, s), r = {
97
+ const { strategy: s, regexStr: t } = v(e, a), r = {
95
98
  url: e,
96
- config: s,
97
- strategy: a,
98
- invalidate: y(e, a, t),
99
+ config: a,
100
+ strategy: s,
101
+ invalidate: y(e, s, t),
99
102
  unregister: E(e)
100
103
  };
101
104
  return d.set(e, r), r;
102
105
  }
103
- async function S(e, s, a) {
106
+ async function k(e, a, s) {
104
107
  const t = h.getState();
105
108
  t.updateResource(e, {
106
109
  status: "fetching",
107
110
  fetchedAt: Date.now()
108
111
  });
109
- const r = await caches.open(a.cacheName).catch(() => null);
112
+ const r = await caches.open(s.cacheName).catch(() => null);
110
113
  try {
111
- if (a.swStrategy !== "network-first") {
112
- const i = r ? await r.match(e).catch(() => null) : null, o = h.getState().resources[e], u = s.maxAge !== void 0 && o?.cachedAt !== void 0 && Date.now() - o.cachedAt > s.maxAge;
113
- if (i && !u)
114
+ if (s.swStrategy !== "network-first") {
115
+ const c = r ? await r.match(e).catch(() => null) : null, o = h.getState().resources[e], u = a.maxAge !== void 0 && o?.cachedAt !== void 0 && Date.now() - o.cachedAt > a.maxAge;
116
+ if (c && !u)
114
117
  return t.updateResource(e, {
115
118
  status: "fresh",
116
119
  lastEvent: "cache-hit",
117
120
  cacheHits: (o?.cacheHits ?? 0) + 1
118
- }), a.swStrategy === "stale-while-revalidate" && fetch(e, { signal: AbortSignal.timeout(5e3) }).then(async (w) => {
119
- w.ok && r && (await r.put(e, w.clone()), h.getState().updateResource(e, {
121
+ }), s.swStrategy === "stale-while-revalidate" && fetch(e, { signal: AbortSignal.timeout(a.networkTimeoutMs ?? 3e3) }).then(async (g) => {
122
+ g.ok && r && (await r.put(e, g.clone()), h.getState().updateResource(e, {
120
123
  cachedAt: Date.now(),
121
124
  lastEvent: "cache-updated"
122
125
  }));
123
126
  }).catch(() => {
124
- }), i;
125
- const R = h.getState().resources[e];
126
- t.updateResource(e, { cacheMisses: (R?.cacheMisses ?? 0) + 1 });
127
+ }), c;
128
+ const x = h.getState().resources[e];
129
+ t.updateResource(e, { cacheMisses: (x?.cacheMisses ?? 0) + 1 });
127
130
  }
128
131
  const n = await fetch(e);
129
132
  if (n.ok)
@@ -133,30 +136,30 @@ async function S(e, s, a) {
133
136
  lastEvent: "cache-updated"
134
137
  }), n;
135
138
  t.updateResource(e, { status: n.status === 503 ? "offline" : "error" });
136
- const c = n.headers.get("X-Eidos-Offline") === "true";
137
- throw new Error(c ? `offline: no cached response for ${e}` : `${n.status} ${n.statusText}`);
139
+ const i = n.headers.get("X-Eidos-Offline") === "true";
140
+ throw new Error(i ? `offline: no cached response for ${e}` : `${n.status} ${n.statusText}`);
138
141
  } catch (n) {
139
- const c = r ? await r.match(e).catch(() => null) : null;
140
- if (c) {
141
- const i = h.getState().resources[e];
142
+ const i = r ? await r.match(e).catch(() => null) : null;
143
+ if (i) {
144
+ const c = h.getState().resources[e];
142
145
  return t.updateResource(e, {
143
146
  status: "fresh",
144
147
  lastEvent: "cache-hit",
145
- cacheHits: (i?.cacheHits ?? 0) + 1
146
- }), c;
148
+ cacheHits: (c?.cacheHits ?? 0) + 1
149
+ }), i;
147
150
  }
148
151
  throw t.updateResource(e, { status: "error" }), n;
149
152
  }
150
153
  }
151
- function b(e) {
152
- const s = e.strategy;
153
- return e.offline ? v(s ?? "stale-while-revalidate", e.cacheName, e.version) : v(s ?? "network-first", e.cacheName, e.version);
154
+ function S(e) {
155
+ const a = e.strategy;
156
+ return e.offline ? p(a ?? "stale-while-revalidate", e.cacheName, e.version) : p(a ?? "network-first", e.cacheName, e.version);
154
157
  }
155
- var x = {
158
+ var A = {
156
159
  "stale-while-revalidate": "StaleWhileRevalidate",
157
160
  "cache-first": "CacheFirst",
158
161
  "network-first": "NetworkFirst"
159
- }, C = {
162
+ }, b = {
160
163
  "stale-while-revalidate": {
161
164
  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.",
162
165
  behavior: [
@@ -165,10 +168,10 @@ var x = {
165
168
  "Offline → return cached version if available, 503 if not",
166
169
  "Reconnect → next request triggers a background refresh"
167
170
  ],
168
- equivalentCode: `// Workbox equivalent
171
+ equivalentCode: `// Workbox equivalent (maxEntries/maxAge are configured via ResourceConfig)
169
172
  new StaleWhileRevalidate({
170
173
  cacheName: 'eidos-resources-v1',
171
- plugins: [new ExpirationPlugin({ maxEntries: 60 })],
174
+ plugins: [new ExpirationPlugin({ maxEntries: config.maxEntries, maxAgeSeconds: config.maxAge && config.maxAge / 1000 })],
172
175
  })`
173
176
  },
174
177
  "cache-first": {
@@ -177,12 +180,12 @@ new StaleWhileRevalidate({
177
180
  "Cache hit → return immediately, no network request made",
178
181
  "Cache miss → fetch from network, cache the response, return it",
179
182
  "Offline → return cached version, 503 if cache is empty",
180
- "Cache never expires unless explicitly invalidated"
183
+ "Cache never expires unless maxAge is set or explicitly invalidated"
181
184
  ],
182
- equivalentCode: `// Workbox equivalent
185
+ equivalentCode: `// Workbox equivalent (maxEntries/maxAge are configured via ResourceConfig)
183
186
  new CacheFirst({
184
187
  cacheName: 'eidos-resources-v1',
185
- plugins: [new ExpirationPlugin({ maxEntries: 60 })],
188
+ plugins: [new ExpirationPlugin({ maxEntries: config.maxEntries, maxAgeSeconds: config.maxAge && config.maxAge / 1000 })],
186
189
  })`
187
190
  },
188
191
  "network-first": {
@@ -196,34 +199,34 @@ new CacheFirst({
196
199
  equivalentCode: `// Workbox equivalent
197
200
  new NetworkFirst({
198
201
  cacheName: 'eidos-resources-v1',
199
- networkTimeoutSeconds: 3,
202
+ networkTimeoutSeconds: 3, // controlled via ResourceConfig.networkTimeoutMs (default 3000)
200
203
  })`
201
204
  }
202
205
  };
203
- function v(e, s, a) {
204
- const t = C[e], r = s ?? "eidos-resources-v1";
206
+ function p(e, a, s) {
207
+ const t = b[e], r = a ?? "eidos-resources-v1";
205
208
  return {
206
- name: x[e],
209
+ name: A[e],
207
210
  swStrategy: e,
208
- cacheName: a !== void 0 ? `${r}-v${a}` : r,
211
+ cacheName: s !== void 0 ? `${r}-v${s}` : r,
209
212
  reasoning: t.reasoning,
210
213
  behavior: t.behavior,
211
214
  equivalentCode: ""
212
215
  };
213
216
  }
214
- async function O(e) {
215
- const s = await Promise.allSettled(e.map((t) => t.prefetch())), a = s.filter((t) => t.status === "rejected").map((t) => t.reason);
217
+ async function M(e) {
218
+ const a = await Promise.allSettled(e.map((t) => t.prefetch())), s = a.filter((t) => t.status === "rejected").map((t) => t.reason);
216
219
  return {
217
- warmed: s.filter((t) => t.status === "fulfilled").length,
218
- failed: a.length,
219
- errors: a
220
+ warmed: a.filter((t) => t.status === "fulfilled").length,
221
+ failed: s.length,
222
+ errors: s
220
223
  };
221
224
  }
222
225
  export {
223
- A as resource,
224
- $ as resourcePattern,
225
- _ as setQueryInvalidator,
226
- O as warmCache
226
+ _ as resource,
227
+ T as resourcePattern,
228
+ q as setQueryInvalidator,
229
+ M as warmCache
227
230
  };
228
231
 
229
232
  //# sourceMappingURL=resource.js.map