@sweidos/eidos 1.0.34 → 1.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.
Files changed (48) hide show
  1. package/README.md +96 -89
  2. package/dist/action.js +119 -86
  3. package/dist/async-storage-adapter.js +15 -12
  4. package/dist/devtools.js +953 -555
  5. package/dist/eidos.cjs +15 -0
  6. package/dist/idb.js +59 -56
  7. package/dist/index.d.ts +37 -15
  8. package/dist/index.js +42 -41
  9. package/dist/nextjs.js +1 -10
  10. package/dist/query.cjs +131 -0
  11. package/dist/query.js +121 -41
  12. package/dist/queue-storage.js +5 -4
  13. package/dist/react/Devtools.d.ts +1 -1
  14. package/dist/react/Provider.js +11 -7
  15. package/dist/react/hooks.js +48 -38
  16. package/dist/react-native.js +47 -53
  17. package/dist/replay.js +15 -0
  18. package/dist/resource.js +77 -79
  19. package/dist/runtime.js +22 -28
  20. package/dist/store-slices.js +43 -0
  21. package/dist/store.js +32 -49
  22. package/dist/stores.js +25 -22
  23. package/dist/sveltekit.js +22 -6
  24. package/dist/sw-bridge.js +48 -46
  25. package/dist/testing.cjs +165 -0
  26. package/dist/testing.js +140 -70
  27. package/dist/version.js +4 -3
  28. package/dist/vite.cjs +48 -0
  29. package/dist/vite.js +45 -29
  30. package/package.json +48 -27
  31. package/dist/action.js.map +0 -1
  32. package/dist/async-storage-adapter.js.map +0 -1
  33. package/dist/eidos.cjs.js +0 -14
  34. package/dist/eidos.cjs.js.map +0 -1
  35. package/dist/idb.js.map +0 -1
  36. package/dist/index.js.map +0 -1
  37. package/dist/query.cjs.js +0 -48
  38. package/dist/queue-storage.js.map +0 -1
  39. package/dist/react/Provider.js.map +0 -1
  40. package/dist/react/hooks.js.map +0 -1
  41. package/dist/resource.js.map +0 -1
  42. package/dist/runtime.js.map +0 -1
  43. package/dist/store.js.map +0 -1
  44. package/dist/stores.js.map +0 -1
  45. package/dist/sw-bridge.js.map +0 -1
  46. package/dist/testing.cjs.js +0 -86
  47. package/dist/version.js.map +0 -1
  48. package/dist/vite.cjs.js +0 -31
package/README.md CHANGED
@@ -12,10 +12,10 @@
12
12
  Declare what your app needs offline. Eidos picks the cache strategy, registers the Service Worker, and persists your action queue to IndexedDB — automatically.
13
13
 
14
14
  ```ts
15
- import { resource, action } from '@sweidos/eidos'
15
+ import { resource, action } from '@sweidos/eidos';
16
16
 
17
- const products = resource('/api/products', { offline: true })
18
- const createOrder = action(orderApi.create, { reliability: 'neverLose' })
17
+ const products = resource('/api/products', { offline: true });
18
+ const createOrder = action(orderApi.create, { reliability: 'neverLose' });
19
19
  ```
20
20
 
21
21
  No service worker file to write. No cache strategy to configure. No retry logic to implement.
@@ -60,12 +60,12 @@ npm install @sweidos/eidos
60
60
 
61
61
  ```ts
62
62
  // vite.config.ts
63
- import { eidos } from '@sweidos/eidos/vite'
64
- import { defineConfig } from 'vite'
63
+ import { eidos } from '@sweidos/eidos/vite';
64
+ import { defineConfig } from 'vite';
65
65
 
66
66
  export default defineConfig({
67
67
  plugins: [eidos()],
68
- })
68
+ });
69
69
  ```
70
70
 
71
71
  > **Without Vite** — copy manually: `cp node_modules/@sweidos/eidos/dist/eidos-sw.js public/`
@@ -74,39 +74,39 @@ export default defineConfig({
74
74
 
75
75
  ```tsx
76
76
  // main.tsx
77
- import { EidosProvider } from '@sweidos/eidos'
78
- import { createRoot } from 'react-dom/client'
79
- import { App } from './App'
77
+ import { EidosProvider } from '@sweidos/eidos';
78
+ import { createRoot } from 'react-dom/client';
79
+ import { App } from './App';
80
80
 
81
81
  createRoot(document.getElementById('root')!).render(
82
82
  <EidosProvider swPath="/eidos-sw.js">
83
83
  <App />
84
- </EidosProvider>
85
- )
84
+ </EidosProvider>,
85
+ );
86
86
  ```
87
87
 
88
88
  ```ts
89
89
  // src/lib/eidos.ts ← module scope required for queue replay after reload
90
- import { resource, action } from '@sweidos/eidos'
90
+ import { resource, action } from '@sweidos/eidos';
91
91
 
92
- export const products = resource('/api/products', { offline: true })
92
+ export const products = resource('/api/products', { offline: true });
93
93
 
94
94
  export const createOrder = action(
95
95
  async (payload: OrderPayload) => {
96
- const res = await fetch('/api/orders', { method: 'POST', body: JSON.stringify(payload) })
97
- return res.json()
96
+ const res = await fetch('/api/orders', { method: 'POST', body: JSON.stringify(payload) });
97
+ return res.json();
98
98
  },
99
99
  { reliability: 'neverLose', name: 'createOrder' },
100
- )
100
+ );
101
101
  ```
102
102
 
103
103
  ```tsx
104
104
  // In components — works the same online and offline
105
- const result = await createOrder({ productId: 1, qty: 2 })
105
+ const result = await createOrder({ productId: 1, qty: 2 });
106
106
 
107
107
  if ('queued' in result) {
108
108
  // Saved to IndexedDB — replays automatically on reconnect
109
- console.log(result.message)
109
+ console.log(result.message);
110
110
  }
111
111
  ```
112
112
 
@@ -114,35 +114,35 @@ if ('queued' in result) {
114
114
 
115
115
  ## What you get
116
116
 
117
- | Feature | Description |
118
- |---------|-------------|
119
- | **Auto strategy selection** | `offline: true` → StaleWhileRevalidate. No config needed. Override when you want. |
120
- | **Persistent action queue** | Failed writes go to IndexedDB and replay with exponential backoff on reconnect. |
121
- | **Request deduplication** | Concurrent `resource.fetch()` calls share one in-flight request. |
122
- | **Optimistic updates** | `onOptimistic` / `onRollback` callbacks for instant UI feedback. |
123
- | **Conflict resolution** | `onConflict` decides per 4xx whether to retry or drop a queued action. |
124
- | **Queue prioritization** | `priority: 'high' | 'normal' | 'low'` — high items replay before normal. |
125
- | **Cache warming** | `warmCache(handles[])` bulk-prefetches resources on login/init. |
126
- | **URL patterns** | `/api/products/*`, `/api/users/:id`, `**` wildcards — SW intercepts all matches. |
127
- | **Background Sync** | Registers a `sync` tag so queued actions replay even after tab close. |
128
- | **Devtools panel** | `<EidosDevtools />` — live queue, cache state, offline toggle, no CSS import. |
129
- | **Testing helpers** | `mockOffline`, `drainQueue`, `resetEidos`, `getCachedEntry` for Vitest/Jest. |
130
- | **OpenAPI codegen** | `npx eidos-gen openapi.json` generates typed `resource()` + `action()` declarations. |
117
+ | Feature | Description |
118
+ | --------------------------- | ------------------------------------------------------------------------------------ |
119
+ | **Auto strategy selection** | `offline: true` → StaleWhileRevalidate. No config needed. Override when you want. |
120
+ | **Persistent action queue** | Failed writes go to IndexedDB and replay with exponential backoff on reconnect. |
121
+ | **Request deduplication** | Concurrent `resource.fetch()` calls share one in-flight request. |
122
+ | **Optimistic updates** | `onOptimistic` / `onRollback` callbacks for instant UI feedback. |
123
+ | **Conflict resolution** | `onConflict` decides per 4xx whether to retry or drop a queued action. |
124
+ | **Queue prioritization** | `priority: 'high' \| 'normal' \| 'low'` — high items replay before normal. |
125
+ | **Cache warming** | `warmCache(handles[])` bulk-prefetches resources on login/init. |
126
+ | **URL patterns** | `/api/products/*`, `/api/users/:id`, `**` wildcards — SW intercepts all matches. |
127
+ | **Background Sync** | Registers a `sync` tag so queued actions replay even after tab close. |
128
+ | **Devtools panel** | `<EidosDevtools />` — live queue, cache state, offline toggle, no CSS import. |
129
+ | **Testing helpers** | `mockOffline`, `drainQueue`, `resetEidos`, `getCachedEntry` for Vitest/Jest. |
130
+ | **OpenAPI codegen** | `npx eidos-gen openapi.json` generates typed `resource()` + `action()` declarations. |
131
131
 
132
132
  ---
133
133
 
134
134
  ## Framework support
135
135
 
136
- | Framework | Import path | Notes |
137
- |-----------|-------------|-------|
138
- | **React** | `@sweidos/eidos` | Hooks + `EidosProvider` |
139
- | **Next.js App Router** | `@sweidos/eidos/nextjs` | Pre-marked `'use client'` — no wrapper needed |
140
- | **SvelteKit** | `@sweidos/eidos/sveltekit` | `initEidosSvelteKit()` in `onMount`, framework-agnostic stores |
141
- | **Vue** | `@sweidos/eidos` | Framework-agnostic stores via `eidosStatus.subscribe()` |
142
- | **React Native** | `@sweidos/eidos/react-native` | AsyncStorage-backed queue, same `action()` API |
143
- | **Vanilla JS** | `@sweidos/eidos` | `eidosStatus`, `eidosQueue`, `eidosQueueStats` stores |
144
- | **Vite** | `@sweidos/eidos/vite` | Plugin auto-copies `eidos-sw.js` on every build |
145
- | **TanStack Query** | `@sweidos/eidos/query` | `useEidosQuery`, `useEidosMutation`, `withEidosQueryClient` |
136
+ | Framework | Import path | Notes |
137
+ | ---------------------- | ----------------------------- | -------------------------------------------------------------- |
138
+ | **React** | `@sweidos/eidos` | Hooks + `EidosProvider` |
139
+ | **Next.js App Router** | `@sweidos/eidos/nextjs` | Pre-marked `'use client'` — no wrapper needed |
140
+ | **SvelteKit** | `@sweidos/eidos/sveltekit` | `initEidosSvelteKit()` in `onMount`, framework-agnostic stores |
141
+ | **Vue** | `@sweidos/eidos` | Framework-agnostic stores via `eidosStatus.subscribe()` |
142
+ | **React Native** | `@sweidos/eidos/react-native` | AsyncStorage-backed queue, same `action()` API |
143
+ | **Vanilla JS** | `@sweidos/eidos` | `eidosStatus`, `eidosQueue`, `eidosQueueStats` stores |
144
+ | **Vite** | `@sweidos/eidos/vite` | Plugin auto-copies `eidos-sw.js` on every build |
145
+ | **TanStack Query** | `@sweidos/eidos/query` | `useEidosQuery`, `useEidosMutation`, `withEidosQueryClient` |
146
146
 
147
147
  ---
148
148
 
@@ -169,11 +169,11 @@ products.query() // { queryKey, queryFn } for useQuery
169
169
 
170
170
  **Auto-selected strategy:**
171
171
 
172
- | Config | Strategy | Use when |
173
- |--------|----------|----------|
174
- | `offline: true` | StaleWhileRevalidate | Default — fast + background refresh |
175
- | `offline: true, strategy: 'cache-first'` | CacheFirst | Static assets, config data |
176
- | `offline: true, strategy: 'network-first'` | NetworkFirst | Always-fresh with offline fallback |
172
+ | Config | Strategy | Use when |
173
+ | ------------------------------------------ | -------------------- | ----------------------------------- |
174
+ | `offline: true` | StaleWhileRevalidate | Default — fast + background refresh |
175
+ | `offline: true, strategy: 'cache-first'` | CacheFirst | Static assets, config data |
176
+ | `offline: true, strategy: 'network-first'` | NetworkFirst | Always-fresh with offline fallback |
177
177
 
178
178
  URL patterns work on any handle: `/api/products/*`, `/api/users/:id`, `**`
179
179
 
@@ -194,11 +194,11 @@ const createOrder = action(async (payload: OrderPayload) => { ... }, {
194
194
  ### React hooks
195
195
 
196
196
  ```ts
197
- const { isOnline, swStatus } = useEidosStatus()
198
- const { pending, failed } = useEidosQueueStats()
199
- const entry = useEidosResource('/api/products')
200
- const item = useEidosAction(queuedResult.id)
201
- useEidosOnDrain(() => toast('All offline actions synced!'))
197
+ const { isOnline, swStatus } = useEidosStatus();
198
+ const { pending, failed } = useEidosQueueStats();
199
+ const entry = useEidosResource('/api/products');
200
+ const item = useEidosAction(queuedResult.id);
201
+ useEidosOnDrain(() => toast('All offline actions synced!'));
202
202
  ```
203
203
 
204
204
  ### Framework-agnostic stores
@@ -217,18 +217,18 @@ eidosResource('/api/products').getState() // ResourceEntry | undefined
217
217
 
218
218
  ```ts
219
219
  // main.tsx — register once
220
- withEidosQueryClient(queryClient)
220
+ withEidosQueryClient(queryClient);
221
221
 
222
222
  // In components
223
- const { data, isPending } = useEidosQuery<Product[]>(products)
223
+ const { data, isPending } = useEidosQuery<Product[]>(products);
224
224
 
225
225
  const mutation = useEidosMutation(createOrder, {
226
226
  invalidates: [products], // clears cache + invalidates TQ on success
227
227
  onSuccess(data) {
228
- if ('queued' in data) toast('Saved offline')
229
- else toast(`Order #${data.id} created`)
228
+ if ('queued' in data) toast('Saved offline');
229
+ else toast(`Order #${data.id} created`);
230
230
  },
231
- })
231
+ });
232
232
  ```
233
233
 
234
234
  ---
@@ -237,25 +237,30 @@ const mutation = useEidosMutation(createOrder, {
237
237
 
238
238
  ```ts
239
239
  import {
240
- mockOffline, mockOnline, drainQueue,
241
- waitForQueueDrain, getCachedEntry,
242
- clearEidosCache, resetEidos, getEidosState,
243
- } from '@sweidos/eidos/testing'
244
-
245
- beforeEach(() => resetEidos())
240
+ mockOffline,
241
+ mockOnline,
242
+ drainQueue,
243
+ waitForQueueDrain,
244
+ getCachedEntry,
245
+ clearEidosCache,
246
+ resetEidos,
247
+ getEidosState,
248
+ } from '@sweidos/eidos/testing';
249
+
250
+ beforeEach(() => resetEidos());
246
251
 
247
252
  it('queues action while offline', async () => {
248
- mockOffline()
249
- await createOrder({ productId: 1, qty: 2 })
250
- expect(getEidosState().queue).toHaveLength(1)
251
- })
253
+ mockOffline();
254
+ await createOrder({ productId: 1, qty: 2 });
255
+ expect(getEidosState().queue).toHaveLength(1);
256
+ });
252
257
 
253
258
  it('replays on reconnect', async () => {
254
- mockOffline()
255
- await createOrder({ productId: 1, qty: 2 })
256
- const result = await drainQueue()
257
- expect(result.succeeded).toBe(1)
258
- })
259
+ mockOffline();
260
+ await createOrder({ productId: 1, qty: 2 });
261
+ const result = await drainQueue();
262
+ expect(result.succeeded).toBe(1);
263
+ });
259
264
  ```
260
265
 
261
266
  ---
@@ -274,10 +279,12 @@ Handles path params, `$ref` resolution, request/response types, DELETE body omis
274
279
  ## Devtools
275
280
 
276
281
  ```tsx
277
- import { EidosDevtools } from '@sweidos/eidos/devtools'
282
+ import { EidosDevtools } from '@sweidos/eidos/devtools';
278
283
 
279
284
  // Drop anywhere — bottom-right floating panel, no CSS import
280
- {process.env.NODE_ENV === 'development' && <EidosDevtools />}
285
+ {
286
+ process.env.NODE_ENV === 'development' && <EidosDevtools />;
287
+ }
281
288
  ```
282
289
 
283
290
  Panel shows: live queue state · cache entries · SW status · offline simulation toggle.
@@ -296,30 +303,30 @@ Panel shows: live queue state · cache entries · SW status · offline simulatio
296
303
 
297
304
  ## Known limitations
298
305
 
299
- | Limitation | Detail |
300
- |------------|--------|
301
- | GET-only caching | SW intercepts `GET` only. Mutations go through `action()`. |
302
- | Module-scope actions | `action()` must be at module scope so functions are registered before a reload triggers replay. |
303
- | Single SW | Assumes one SW at the configured `swPath`. |
304
- | React Native resources | In-memory only — no Cache API or SW in RN. Action queue fully persists. |
306
+ | Limitation | Detail |
307
+ | ---------------------- | ----------------------------------------------------------------------------------------------- |
308
+ | GET-only caching | SW intercepts `GET` only. Mutations go through `action()`. |
309
+ | Module-scope actions | `action()` must be at module scope so functions are registered before a reload triggers replay. |
310
+ | Single SW | Assumes one SW at the configured `swPath`. |
311
+ | React Native resources | In-memory only — no Cache API or SW in RN. Action queue fully persists. |
305
312
 
306
313
  ---
307
314
 
308
315
  ## How it compares
309
316
 
310
- | | **Eidos** | Workbox | RTK Query / TanStack Query |
311
- |---|---|---|---|
312
- | Service worker setup | Generated for you — `resource()`/`action()` declarations drive the SW | Hand-write `routing` + `strategies` config | None — no SW |
313
- | Caching strategy | Auto-derived from intent (`offline: true` → SWR, etc.), inspectable via devtools | Manually chosen per route | Configurable `staleTime`/`gcTime`, no Cache Storage integration |
314
- | Offline writes | `action()` + `reliability: 'neverLose'` → IndexedDB queue, auto-replay, exponential backoff | Background Sync plugin, you wire the queue | No built-in offline mutation queue |
315
- | Framework support | React, Svelte, Vue, Next.js, React Native, vanilla JS | Framework-agnostic (SW only) | Per-library (RTK Query = Redux, TanStack = many) |
316
- | TanStack Query bridge | `@sweidos/eidos/query` — drop-in `useEidosQuery`/`useEidosMutation` | — | Native |
317
- | Bundle size (core, gzip) | ~9 kB | ~3-6 kB (modular) | ~13 kB (TanStack Query core) |
317
+ | | **Eidos** | Workbox | RTK Query / TanStack Query |
318
+ | -------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------- |
319
+ | Service worker setup | Generated for you — `resource()`/`action()` declarations drive the SW | Hand-write `routing` + `strategies` config | None — no SW |
320
+ | Caching strategy | Auto-derived from intent (`offline: true` → SWR, etc.), inspectable via devtools | Manually chosen per route | Configurable `staleTime`/`gcTime`, no Cache Storage integration |
321
+ | Offline writes | `action()` + `reliability: 'neverLose'` → IndexedDB queue, auto-replay, exponential backoff | Background Sync plugin, you wire the queue | No built-in offline mutation queue |
322
+ | Framework support | React, Svelte, Vue, Next.js, React Native, vanilla JS | Framework-agnostic (SW only) | Per-library (RTK Query = Redux, TanStack = many) |
323
+ | TanStack Query bridge | `@sweidos/eidos/query` — drop-in `useEidosQuery`/`useEidosMutation` | — | Native |
324
+ | Bundle size (core, brotli) | ~5.4 kB | ~3-6 kB (modular) | ~13 kB (TanStack Query core) |
318
325
 
319
326
  Eidos isn't a replacement for TanStack Query — `@sweidos/eidos/query` is a thin
320
327
  adapter so you keep TQ's cache/devtools while Eidos owns the offline layer
321
328
  (SW caching + IndexedDB write queue). Workbox is a lower-level toolkit Eidos
322
- generates strategies *for*; Eidos picks and configures the strategy from your
329
+ generates strategies _for_; Eidos picks and configures the strategy from your
323
330
  `resource()`/`action()` declarations instead of you writing `workbox-*` config
324
331
  by hand.
325
332
 
package/dist/action.js CHANGED
@@ -1,69 +1,66 @@
1
- import { useEidosStore as d } from "./store.js";
2
- import { getSwRegistration as b } from "./sw-bridge.js";
3
- import { idbClearQueue as g, idbRemoveFromQueue as Q, idbUpdateQueueItem as h, idbGetPendingItems as I, idbGetQueue as R, idbAddToQueue as k } from "./idb.js";
4
- import { _getQueueStorage as v } from "./queue-storage.js";
5
- const l = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), S = {
6
- add: (e) => k(e),
7
- getAll: () => R(),
8
- getPending: () => I(),
9
- update: (e, t) => h(e, t),
10
- remove: (e) => Q(e),
11
- clear: () => g()
12
- };
13
- function o() {
14
- return v() ?? S;
1
+ import { useEidosStore as s } from "./store.js";
2
+ import { getSwRegistration as w } from "./sw-bridge.js";
3
+ import { idbQueueStorage as g } from "./idb.js";
4
+ import { _getQueueStorage as m } from "./queue-storage.js";
5
+ var d = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
6
+ function u() {
7
+ return m() ?? g;
15
8
  }
16
- function m() {
9
+ function y() {
17
10
  return crypto.randomUUID();
18
11
  }
19
- function U(e, t) {
20
- const r = t.name || e.name || m();
21
- l.set(r, e), t.onRollback && f.set(r, t.onRollback), t.onConflict && y.set(r, t.onConflict);
22
- const u = async (...a) => {
23
- var i, s;
24
- const { isOnline: n } = d.getState();
25
- if ((i = t.onOptimistic) == null || i.call(t, ...a), t.reliability === "neverLose") {
26
- if (!n)
27
- return p(r, r, a, t);
12
+ function C(e, t) {
13
+ const r = t.name || e.name || y();
14
+ d.set(r, e), t.onRollback && p.set(r, t.onRollback), t.onConflict && f.set(r, t.onConflict);
15
+ const a = async (...i) => {
16
+ const { isOnline: n } = s.getState();
17
+ if (t.onOptimistic?.(...i), t.reliability === "neverLose") {
18
+ if (!n) return l(r, r, i, t);
28
19
  try {
29
- return await e(...a);
20
+ return await e(...i);
30
21
  } catch {
31
- return p(r, r, a, t);
22
+ return l(r, r, i, t);
32
23
  }
33
24
  }
34
25
  try {
35
- return await e(...a);
36
- } catch (w) {
37
- throw (s = t.onRollback) == null || s.call(t, ...a), w;
26
+ return await e(...i);
27
+ } catch (o) {
28
+ throw t.onRollback?.(...i), o;
38
29
  }
39
30
  };
40
- return Object.defineProperty(u, "id", { value: r, writable: !1 }), Object.defineProperty(u, "config", { value: t, writable: !1 }), u;
31
+ return Object.defineProperty(a, "id", {
32
+ value: r,
33
+ writable: !1
34
+ }), Object.defineProperty(a, "config", {
35
+ value: t,
36
+ writable: !1
37
+ }), a;
41
38
  }
42
- async function p(e, t, r, u) {
43
- const a = m(), n = {
44
- id: a,
39
+ async function l(e, t, r, a) {
40
+ const i = y(), n = {
41
+ id: i,
45
42
  actionId: e,
46
43
  actionName: t,
47
44
  args: r,
48
45
  queuedAt: Date.now(),
49
46
  retryCount: 0,
50
- maxRetries: u.maxRetries ?? 3,
47
+ maxRetries: a.maxRetries ?? 3,
51
48
  status: "pending",
52
- priority: u.priority ?? "normal"
49
+ priority: a.priority ?? "normal"
53
50
  };
54
- await o().add(n), d.getState().addQueueItem(n);
51
+ await u().add(n), s.getState().addQueueItem(n);
55
52
  try {
56
- const i = b();
57
- i && "sync" in i && await i.sync.register("eidos-queue-replay");
53
+ const o = w();
54
+ o && "sync" in o && await o.sync.register("eidos-queue-replay");
58
55
  } catch {
59
56
  }
60
57
  return {
61
58
  queued: !0,
62
- id: a,
59
+ id: i,
63
60
  message: `"${t}" queued — will execute when online`
64
61
  };
65
62
  }
66
- function x(e) {
63
+ function h(e) {
67
64
  if (e instanceof Response) return e.status >= 400 && e.status < 500;
68
65
  if (typeof e == "object" && e !== null) {
69
66
  const t = e.status;
@@ -71,76 +68,112 @@ function x(e) {
71
68
  }
72
69
  return !1;
73
70
  }
74
- function C(e) {
71
+ function R(e) {
75
72
  return Math.min(2e3 * 2 ** e, 3e5) * (0.8 + Math.random() * 0.4);
76
73
  }
77
- let c = !1;
78
- async function j() {
79
- const e = d.getState();
80
- if (!e.isOnline || c)
81
- return { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0, conflicted: 0 };
74
+ var c = !1;
75
+ async function _() {
76
+ const e = s.getState();
77
+ if (!e.isOnline || c) return {
78
+ attempted: 0,
79
+ succeeded: 0,
80
+ failed: 0,
81
+ retrying: 0,
82
+ skipped: 0,
83
+ conflicted: 0
84
+ };
82
85
  c = !0;
83
86
  try {
84
- return await M(e);
87
+ return await Q(e);
85
88
  } finally {
86
89
  c = !1;
87
90
  }
88
91
  }
89
- async function _(e, t) {
90
- var u;
91
- const r = l.get(e.actionId);
92
+ async function b(e, t) {
93
+ const r = d.get(e.actionId);
92
94
  if (!r) return "skipped";
93
95
  try {
94
96
  await r(...e.args);
95
97
  const a = Date.now();
96
- return t.updateQueueItem(e.id, { status: "succeeded", completedAt: a }), await o().update(e.id, { status: "succeeded", completedAt: a }), setTimeout(() => {
97
- t.removeQueueItem(e.id), o().remove(e.id);
98
+ return t.updateQueueItem(e.id, {
99
+ status: "succeeded",
100
+ completedAt: a
101
+ }), await u().update(e.id, {
102
+ status: "succeeded",
103
+ completedAt: a
104
+ }), setTimeout(() => {
105
+ t.removeQueueItem(e.id), u().remove(e.id);
98
106
  }, 3e3), "succeeded";
99
107
  } catch (a) {
100
- if (x(a)) {
101
- const i = y.get(e.actionId);
102
- if (i && i(a, e.args) === "skip")
103
- return t.removeQueueItem(e.id), await o().remove(e.id), "conflicted";
108
+ if (h(a)) {
109
+ const n = f.get(e.actionId);
110
+ if (n && n(a, e.args) === "skip")
111
+ return t.removeQueueItem(e.id), await u().remove(e.id), "conflicted";
104
112
  }
105
- const n = e.retryCount + 1;
106
- if (n >= e.maxRetries)
107
- return t.updateQueueItem(e.id, { status: "failed", error: String(a), retryCount: n }), await o().update(e.id, { status: "failed", error: String(a), retryCount: n }), (u = f.get(e.actionId)) == null || u(...e.args), "failed";
113
+ const i = e.retryCount + 1;
114
+ if (i >= e.maxRetries)
115
+ return t.updateQueueItem(e.id, {
116
+ status: "failed",
117
+ error: String(a),
118
+ retryCount: i
119
+ }), await u().update(e.id, {
120
+ status: "failed",
121
+ error: String(a),
122
+ retryCount: i
123
+ }), p.get(e.actionId)?.(...e.args), "failed";
108
124
  {
109
- const i = Date.now() + C(n);
110
- return t.updateQueueItem(e.id, { status: "pending", retryCount: n, nextRetryAt: i }), await o().update(e.id, { status: "pending", retryCount: n, nextRetryAt: i }), "retrying";
125
+ const n = Date.now() + R(i);
126
+ return t.updateQueueItem(e.id, {
127
+ status: "pending",
128
+ retryCount: i,
129
+ nextRetryAt: n
130
+ }), await u().update(e.id, {
131
+ status: "pending",
132
+ retryCount: i,
133
+ nextRetryAt: n
134
+ }), "retrying";
111
135
  }
112
136
  }
113
137
  }
114
- async function A(e, t, r) {
138
+ async function I(e, t, r) {
115
139
  if (e.length === 0) return;
116
- const u = e.filter((n) => l.has(n.actionId));
117
- if (r.skipped += e.length - u.length, u.length > 0) {
118
- t.batchUpdateQueueItems(u.map((n) => ({ id: n.id, update: { status: "replaying" } })));
119
- for (const n of u)
120
- o().update(n.id, { status: "replaying" });
140
+ const a = e.filter((n) => d.has(n.actionId));
141
+ if (r.skipped += e.length - a.length, a.length > 0) {
142
+ t.batchUpdateQueueItems(a.map((n) => ({
143
+ id: n.id,
144
+ update: { status: "replaying" }
145
+ })));
146
+ for (const n of a) u().update(n.id, { status: "replaying" });
121
147
  }
122
- const a = await Promise.allSettled(u.map((n) => _(n, t)));
123
- for (const n of a) {
124
- const i = n.status === "fulfilled" ? n.value : "failed";
125
- i === "skipped" ? r.skipped++ : i === "conflicted" ? r.conflicted++ : (r.attempted++, r[i]++);
148
+ const i = await Promise.allSettled(a.map((n) => b(n, t)));
149
+ for (const n of i) {
150
+ const o = n.status === "fulfilled" ? n.value : "failed";
151
+ o === "skipped" ? r.skipped++ : o === "conflicted" ? r.conflicted++ : (r.attempted++, r[o]++);
126
152
  }
127
153
  }
128
- async function M(e) {
129
- const t = await o().getPending(), r = Date.now(), u = t.filter(
130
- (n) => n.retryCount < n.maxRetries && (!n.nextRetryAt || n.nextRetryAt <= r)
131
- ), a = { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0, conflicted: 0 };
132
- for (const n of ["high", "normal", "low"]) {
133
- const i = u.filter((s) => (s.priority ?? "normal") === n);
134
- await A(i, e, a);
135
- }
136
- return a;
154
+ async function Q(e) {
155
+ const t = await u().getPending(), r = Date.now(), a = t.filter((n) => n.retryCount < n.maxRetries && (!n.nextRetryAt || n.nextRetryAt <= r)), i = {
156
+ attempted: 0,
157
+ succeeded: 0,
158
+ failed: 0,
159
+ retrying: 0,
160
+ skipped: 0,
161
+ conflicted: 0
162
+ };
163
+ for (const n of [
164
+ "high",
165
+ "normal",
166
+ "low"
167
+ ]) await I(a.filter((o) => (o.priority ?? "normal") === n), e, i);
168
+ return i;
137
169
  }
138
- async function T() {
139
- await o().clear(), d.getState().hydrateQueue([]);
170
+ async function A() {
171
+ await u().clear(), s.getState().hydrateQueue([]);
140
172
  }
141
173
  export {
142
- U as action,
143
- T as clearQueue,
144
- j as replayQueue
174
+ C as action,
175
+ A as clearQueue,
176
+ _ as replayQueue
145
177
  };
146
- //# sourceMappingURL=action.js.map
178
+
179
+ //# sourceMappingURL=action.js.map
@@ -1,5 +1,4 @@
1
- const i = "@eidos:queue";
2
- class l {
1
+ var i = "@eidos:queue", l = class {
3
2
  constructor(t) {
4
3
  this.storage = t;
5
4
  }
@@ -15,28 +14,32 @@ class l {
15
14
  await this.storage.setItem(i, JSON.stringify(t));
16
15
  }
17
16
  async add(t) {
18
- const e = await this.readAll();
19
- e.push(t), await this.writeAll(e);
17
+ const a = await this.readAll();
18
+ a.push(t), await this.writeAll(a);
20
19
  }
21
20
  async getAll() {
22
21
  return this.readAll();
23
22
  }
24
23
  async getPending() {
25
- return (await this.readAll()).filter((e) => e.status === "pending" || e.status === "failed");
24
+ return (await this.readAll()).filter((t) => t.status === "pending" || t.status === "failed");
26
25
  }
27
- async update(t, e) {
28
- const a = await this.readAll(), s = a.findIndex((r) => r.id === t);
29
- s !== -1 && (a[s] = { ...a[s], ...e }), await this.writeAll(a);
26
+ async update(t, a) {
27
+ const e = await this.readAll(), s = e.findIndex((r) => r.id === t);
28
+ s !== -1 && (e[s] = {
29
+ ...e[s],
30
+ ...a
31
+ }), await this.writeAll(e);
30
32
  }
31
33
  async remove(t) {
32
- const e = await this.readAll();
33
- await this.writeAll(e.filter((a) => a.id !== t));
34
+ const a = await this.readAll();
35
+ await this.writeAll(a.filter((e) => e.id !== t));
34
36
  }
35
37
  async clear() {
36
38
  await this.storage.removeItem(i);
37
39
  }
38
- }
40
+ };
39
41
  export {
40
42
  l as AsyncStorageQueueStorage
41
43
  };
42
- //# sourceMappingURL=async-storage-adapter.js.map
44
+
45
+ //# sourceMappingURL=async-storage-adapter.js.map