@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/idb.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { ActionQueueItem } from './types';
2
+ import { QueueStorage } from './queue-storage';
3
+ export declare function idbAddToQueue(item: ActionQueueItem): Promise<void>;
4
+ export declare function idbGetQueue(): Promise<ActionQueueItem[]>;
5
+ export declare function idbUpdateQueueItem(id: string, update: Partial<ActionQueueItem>): Promise<void>;
6
+ export declare function idbRemoveFromQueue(id: string): Promise<void>;
7
+ export declare function idbGetPendingItems(): Promise<ActionQueueItem[]>;
8
+ export declare function idbClearQueue(): Promise<void>;
9
+ /** IndexedDB-backed QueueStorage implementation (default for browser environments). */
10
+ export declare const idbQueueStorage: QueueStorage;
package/dist/index.d.ts CHANGED
@@ -1,647 +1,20 @@
1
- import { JSX } from 'react';
2
- import { ReactNode } from 'react';
3
-
4
- export declare function action<TArgs extends any[], TReturn>(fn: ActionFn<TArgs, TReturn>, config: ActionConfig<TArgs>): ActionHandle<TArgs, TReturn>;
5
-
6
- export declare type ActionConfig<TArgs extends any[] = any[]> = (ActionConfigBase<TArgs> & {
7
- /** Call directly, no persistence on failure. */
8
- reliability: 'best-effort';
9
- }) | (ActionConfigBase<TArgs> & {
10
- /** Persist to IndexedDB before executing; replay on reconnect. */
11
- reliability: 'neverLose';
12
- /**
13
- * Required for `neverLose` queued items must survive a page reload
14
- * and be matched back to this action on replay. `fn.name` is not
15
- * reliable (minifiers rename it, arrow functions may be anonymous).
16
- */
17
- name: string;
18
- });
19
-
20
- declare interface ActionConfigBase<TArgs extends any[] = any[]> {
21
- /** Max retry attempts before marking as failed. Default: 3. */
22
- maxRetries?: number;
23
- /** Human-readable name for the action (used in devtools). */
24
- name?: string;
25
- /**
26
- * Prefixes the registered action id (`namespace::name`). Use to avoid
27
- * collisions when two actions share a name (e.g. across micro-frontends,
28
- * or two `createOrder` actions in different modules) — without a
29
- * namespace, the second registration silently overwrites the first.
30
- */
31
- namespace?: string;
32
- /**
33
- * Replay order when multiple queued actions are pending.
34
- * `'high'` items replay before `'normal'`, which replay before `'low'`.
35
- * Each tier completes fully before the next tier begins.
36
- * Default: `'normal'`.
37
- */
38
- priority?: 'high' | 'normal' | 'low';
39
- /**
40
- * Called immediately before the async function executes, with the same args
41
- * plus a trailing `ActionContext`. Use to apply an optimistic UI update (add
42
- * item, mark as pending, etc.) and to capture `idempotencyKey` for later
43
- * `handle.cancel(idempotencyKey)` calls. Called on every invocation —
44
- * online, offline, and during queue replay.
45
- */
46
- onOptimistic?: (...args: [...TArgs, ActionContext]) => void;
47
- /**
48
- * Called when the action permanently fails and will not be retried.
49
- * - `best-effort`: called on first throw.
50
- * - `neverLose`: called when `maxRetries` is exhausted (status → `'failed'`).
51
- * Use to revert the optimistic update.
52
- */
53
- onRollback?: (...args: [...TArgs, ActionContext]) => void;
54
- /**
55
- * Declarative conflict-resolution strategy used during queue replay when
56
- * the server responds with a 4xx status (conflict, gone, unprocessable,
57
- * etc.). If not provided, 4xx errors are treated identically to other
58
- * errors (retried until `maxRetries` is exhausted, then `onRollback` is
59
- * called). See `ConflictConfig`.
60
- */
61
- conflict?: ConflictConfig;
62
- /**
63
- * When `true`, each invocation gets an `AbortController` whose `signal` is
64
- * passed via `ActionContext.signal`. Forward it to `fetch`/etc. so
65
- * `handle.cancel(idempotencyKey)` can abort an in-flight call, or remove a
66
- * not-yet-replayed queued item.
67
- */
68
- cancellable?: boolean;
69
- }
70
-
71
- /**
72
- * Passed as an extra argument after the declared params to `neverLose` actions,
73
- * on every invocation (initial call, offline queue, and replay). The same
74
- * `idempotencyKey` is reused across all retries of one logical invocation —
75
- * forward it to your server (e.g. as an `Idempotency-Key` header) so a retry
76
- * that reaches the server after a dropped response doesn't double-execute.
77
- */
78
- export declare interface ActionContext {
79
- idempotencyKey: string;
80
- /** 0 on the first attempt, incremented on each replay retry. */
81
- attempt: number;
82
- /** Set when `config.cancellable` is true. Forward to `fetch`/etc. for cancellation support. */
83
- signal?: AbortSignal;
84
- }
85
-
86
- /**
87
- * Every action function receives its declared args plus a trailing
88
- * `ActionContext` — on every invocation (online, offline, and replay).
89
- */
90
- export declare type ActionFn<TArgs extends unknown[], TReturn> = (...args: [...TArgs, ActionContext]) => Promise<TReturn>;
91
-
92
- export declare interface ActionHandle<TArgs extends any[], TReturn> {
93
- (...args: TArgs): Promise<TReturn | QueuedResult>;
94
- readonly id: string;
95
- readonly config: ActionConfig;
96
- /**
97
- * Cancel an invocation by its `idempotencyKey` (from `ActionContext` /
98
- * `onOptimistic`). Aborts the in-flight call if `cancellable: true` and
99
- * still running, otherwise removes a not-yet-replayed queued item.
100
- * Returns `true` if something was cancelled/removed.
101
- */
102
- cancel: (idempotencyKey: string) => Promise<boolean>;
103
- }
104
-
105
- export declare interface ActionQueueItem {
106
- /** Shape version this item was persisted with. Items from before v2 are migrated on load. */
107
- schemaVersion: number;
108
- id: string;
109
- /** ID of the registered action (maps to the function in the registry). */
110
- actionId: string;
111
- actionName: string;
112
- /**
113
- * Stable per-invocation key, generated once and reused across every retry/replay
114
- * of this item. Pass to your server as an idempotency key so retries that reach
115
- * the server after a dropped response don't double-execute.
116
- */
117
- idempotencyKey: string;
118
- args: unknown[];
119
- queuedAt: number;
120
- retryCount: number;
121
- maxRetries: number;
122
- status: 'pending' | 'replaying' | 'succeeded' | 'failed';
123
- /** Replay priority. High items replay before normal, normal before low. Default: 'normal'. */
124
- priority?: 'high' | 'normal' | 'low';
125
- error?: string;
126
- completedAt?: number;
127
- /** Earliest timestamp at which this item should be retried (exponential backoff). */
128
- nextRetryAt?: number;
129
- }
130
-
131
- /** A handle returned by either `resource()` or `resourcePattern()`. */
132
- export declare type AnyResourceHandle = ResourceHandle<any> | PatternResourceHandle;
133
-
134
- /** Minimal subset of @react-native-async-storage/async-storage (or any compatible key-value store). */
135
- export declare interface AsyncStorageLike {
136
- getItem(key: string): Promise<string | null>;
137
- setItem(key: string, value: string): Promise<void>;
138
- removeItem(key: string): Promise<void>;
139
- }
140
-
141
- /**
142
- * QueueStorage implementation backed by any AsyncStorage-compatible API.
143
- * Pass the AsyncStorage singleton from @react-native-async-storage/async-storage
144
- * (or MMKV, SQLite, or any store that satisfies AsyncStorageLike).
145
- */
146
- export declare class AsyncStorageQueueStorage implements QueueStorage {
147
- private readonly storage;
148
- constructor(storage: AsyncStorageLike);
149
- private readAll;
150
- private writeAll;
151
- add(item: ActionQueueItem): Promise<void>;
152
- getAll(): Promise<ActionQueueItem[]>;
153
- getPending(): Promise<ActionQueueItem[]>;
154
- update(id: string, patch: Partial<ActionQueueItem>): Promise<void>;
155
- remove(id: string): Promise<void>;
156
- clear(): Promise<void>;
157
- }
158
-
159
- export declare type CacheStrategy = 'cache-first' | 'stale-while-revalidate' | 'network-first';
160
-
161
- /**
162
- * Cancel an invocation by its `idempotencyKey` (from `ActionContext` /
163
- * `onOptimistic`). Aborts the in-flight call if `cancellable: true` and
164
- * still running, otherwise removes a not-yet-replayed queued item.
165
- * Returns `true` if something was cancelled/removed.
166
- *
167
- * Shared by every `ActionHandle.cancel()` and by devtools, which can't
168
- * address a specific handle from a queue item alone.
169
- */
170
- export declare function cancelByIdempotencyKey(idempotencyKey: string): Promise<boolean>;
171
-
172
- /** Remove all items from the action queue (storage + in-memory store). */
173
- export declare function clearQueue(): Promise<void>;
174
-
175
- export declare interface ConflictConfig {
176
- /**
177
- * - `'serverWins'`: drop the queued item, keeping the server's state.
178
- * - `'clientWins'`: keep retrying — the client's write should eventually
179
- * be accepted (e.g. once the server-side conflict is cleared).
180
- * - `'merge'` / `'custom'`: call `resolve` to decide.
181
- */
182
- strategy: 'serverWins' | 'clientWins' | 'merge' | 'custom';
183
- /** Required for `'merge'` and `'custom'`. */
184
- resolve?: (ctx: ConflictContext) => ConflictResolution;
185
- }
186
-
187
- /**
188
- * Passed to `ConflictConfig.resolve` (for `'merge'`/`'custom'` strategies)
189
- * when a queued action's replay receives a 4xx response.
190
- */
191
- export declare interface ConflictContext {
192
- /** Whatever `fn` threw — typically a `Response` or an error with `.status`. */
193
- error: unknown;
194
- /** The original arguments the action was queued with. */
195
- args: any[];
196
- /** Number of replay attempts so far (0 on first replay). */
197
- attempt: number;
198
- idempotencyKey: string;
199
- }
200
-
201
- /**
202
- * Outcome of `ConflictConfig.resolve`:
203
- * - `'retry'`: keep the item queued, retry per normal backoff.
204
- * - `'skip'`: silently remove the item (no `onRollback`).
205
- * - `{ resolved: args }`: replace the queued args and retry immediately
206
- * on the next replay pass.
207
- */
208
- export declare type ConflictResolution = 'retry' | 'skip' | {
209
- resolved: any[];
210
- };
211
-
212
- /**
213
- * Live state for a single queue item by ID. Returns `undefined` once the item
214
- * is removed from the queue (after a successful replay or `clearQueue()`).
215
- * @example
216
- * // Svelte
217
- * const item = eidosAction(queuedResult.id)
218
- * $: status = $item?.status // 'pending' | 'replaying' | 'succeeded' | 'failed' | undefined
219
- */
220
- export declare function eidosAction(id: string): EidosReadable<ActionQueueItem | undefined>;
221
-
222
- export declare interface EidosConfig {
223
- /** Path to the eidos service worker. Defaults to '/eidos-sw.js'. */
224
- swPath?: string;
225
- /** Automatically replay the action queue on reconnect. Default: true. */
226
- autoReplay?: boolean;
227
- /**
228
- * Opt-in reliability telemetry. Called with a snapshot of cumulative
229
- * `neverLose` queue outcome counters (`ReliabilityStats`) every
230
- * `reliabilityReportInterval` ms — wire this up to your analytics backend.
231
- * Not called if omitted.
232
- */
233
- onReliabilityReport?: (stats: ReliabilityStats) => void;
234
- /** Interval (ms) between `onReliabilityReport` calls. Default: 60000. */
235
- reliabilityReportInterval?: number;
236
- }
237
-
238
- /**
239
- * Mount once at the root of your application.
240
- * Registers the service worker and initialises the Eidos runtime.
241
- *
242
- * @example
243
- * <EidosProvider swPath="/eidos-sw.js">
244
- * <App />
245
- * </EidosProvider>
246
- */
247
- export declare function EidosProvider({ children, swPath, autoReplay }: EidosProviderProps): JSX.Element;
248
-
249
- declare interface EidosProviderProps extends EidosConfig {
250
- children: ReactNode;
251
- }
252
-
253
- /** The action queue. Re-notifies on every queue mutation. */
254
- export declare const eidosQueue: EidosReadable<ActionQueueItem[]>;
255
-
256
- /**
257
- * Queue counts. Re-emits only when a count actually changes, not on every
258
- * queue mutation (e.g. a status transition that doesn't change counts is skipped).
259
- */
260
- export declare const eidosQueueStats: EidosReadable<{
261
- pending: number;
262
- failed: number;
263
- replaying: number;
264
- total: number;
265
- }>;
266
-
267
- export declare interface EidosReadable<T> {
268
- /** Subscribe to value changes. Returns an unsubscribe function. */
269
- subscribe(run: (value: T) => void): () => void;
270
- /** Read the current value synchronously without subscribing. */
271
- getState(): T;
272
- }
273
-
274
- /**
275
- * Cumulative, session-scoped `neverLose` queue outcome counters — opt-in
276
- * reliability telemetry. Re-emits only when a counter changes. See
277
- * `EidosConfig.onReliabilityReport` to forward these to an analytics backend.
278
- */
279
- export declare const eidosReliabilityStats: EidosReadable<ReliabilityStats>;
280
-
281
- /**
282
- * Live cache state for a single registered resource URL.
283
- * @example
284
- * // Svelte
285
- * const entry = eidosResource('/api/products')
286
- * $: hits = $entry?.cacheHits ?? 0
287
- */
288
- export declare function eidosResource(url: string): EidosReadable<ResourceEntry | undefined>;
289
-
290
- export declare interface EidosState {
291
- isOnline: boolean;
292
- swStatus: 'idle' | 'registering' | 'active' | 'error' | 'unsupported';
293
- swError?: string;
294
- resources: Record<string, ResourceEntry>;
295
- queue: ActionQueueItem[];
296
- reliability: ReliabilityStats;
297
- }
298
-
299
- /**
300
- * Online status + SW lifecycle.
301
- * Only re-emits when isOnline, swStatus, or swError actually changes.
302
- */
303
- export declare const eidosStatus: EidosReadable<{
304
- isOnline: boolean;
305
- swStatus: EidosStore['swStatus'];
306
- swError: string | undefined;
307
- }>;
308
-
309
- export declare interface EidosStore extends EidosState, ResourceActions, QueueActions, ReliabilityActions {
310
- setOnline: (online: boolean) => void;
311
- setSwStatus: (status: EidosState['swStatus'], error?: string) => void;
312
- }
313
-
314
- /** Full Eidos state snapshot. Prefer the narrower stores below. */
315
- export declare const eidosStore: EidosReadable<EidosStore>;
316
-
317
- export declare interface GeneratedStrategy {
318
- name: string;
319
- swStrategy: CacheStrategy;
320
- cacheName: string;
321
- /** One-line rationale for why this strategy was chosen. */
322
- reasoning: string;
323
- /** Human-readable description of each behavioral step. */
324
- behavior: string[];
325
- /** Pseudocode showing the equivalent Workbox config. */
326
- equivalentCode: string;
327
- }
328
-
329
- export declare function _getQueueStorage(): QueueStorage | null;
330
-
331
- declare function _getState(): EidosStore;
332
-
333
- export declare function getSwRegistration(): ServiceWorkerRegistration | null;
334
-
335
- export declare function initEidos(config?: EidosConfig): Promise<void>;
336
-
337
- export declare function isBgSyncSupported(): boolean;
338
-
339
- declare type Listener = () => void;
340
-
341
- /**
342
- * Calls `callback` once each time the action queue drains from non-empty → 0.
343
- * Framework-agnostic equivalent of `useEidosOnDrain` for Svelte/Vue/vanilla.
344
- * Returns an unsubscribe function.
345
- *
346
- * @example
347
- * // Svelte
348
- * onMount(() => onQueueDrain(() => toast.success('All offline actions synced!')))
349
- */
350
- export declare function onQueueDrain(callback: () => void): () => void;
351
-
352
- /**
353
- * Handle for a URL pattern (`/api/products/*`, `/api/users/:id`, `**`).
354
- * The SW intercepts all matching requests automatically — there is no single
355
- * URL to fetch/cache directly, so only cache-management methods are exposed.
356
- * Returned by `resourcePattern()`.
357
- */
358
- export declare interface PatternResourceHandle {
359
- readonly url: string;
360
- readonly config: ResourceConfig;
361
- readonly strategy: GeneratedStrategy;
362
- /** Clears all cache entries matching this pattern. */
363
- invalidate: () => Promise<void>;
364
- /** Remove from registry and SW. Required before re-registering the same pattern with different config. */
365
- unregister: () => void;
366
- }
367
-
368
- declare interface PushHandlers {
369
- onNotificationClick?: (data: unknown) => void;
370
- onSubscriptionExpired?: (sub: PushSubscriptionJSON) => void;
371
- }
372
-
373
- declare type QueryInvalidator = (queryKey: [string, string]) => void;
374
-
375
- declare interface QueueActions {
376
- addQueueItem: (item: ActionQueueItem) => void;
377
- updateQueueItem: (id: string, update: Partial<ActionQueueItem>) => void;
378
- batchUpdateQueueItems: (updates: Array<{
379
- id: string;
380
- update: Partial<ActionQueueItem>;
381
- }>) => void;
382
- removeQueueItem: (id: string) => void;
383
- hydrateQueue: (items: ActionQueueItem[]) => void;
384
- }
385
-
386
- export declare interface QueuedResult {
387
- readonly queued: true;
388
- readonly id: string;
389
- readonly message: string;
390
- }
391
-
392
- export declare interface QueueStorage {
393
- add(item: ActionQueueItem): Promise<void>;
394
- getAll(): Promise<ActionQueueItem[]>;
395
- getPending(): Promise<ActionQueueItem[]>;
396
- update(id: string, patch: Partial<ActionQueueItem>): Promise<void>;
397
- remove(id: string): Promise<void>;
398
- clear(): Promise<void>;
399
- }
400
-
401
- export declare function registerPushCallbacks(handlers: PushHandlers): void;
402
-
403
- declare interface ReliabilityActions {
404
- recordReliabilityEvent: (event: keyof ReliabilityStats) => void;
405
- resetReliabilityStats: () => void;
406
- }
407
-
408
- /**
409
- * Cumulative, session-scoped counters for `neverLose` queue outcomes — opt-in
410
- * telemetry surfaced via `eidosReliabilityStats` / `useEidosReliabilityStats()`
411
- * and `EidosConfig.onReliabilityReport`. Reset on page reload (not persisted).
412
- */
413
- export declare interface ReliabilityStats {
414
- [key: string]: number;
415
- /** Actions persisted to the queue (offline, or online call that threw). */
416
- queued: number;
417
- /** Queue items that executed successfully (first attempt or a retry). */
418
- succeeded: number;
419
- /** Queue items that exhausted `maxRetries` and moved to `'failed'`. */
420
- failed: number;
421
- /** Replay attempts that failed but will retry (haven't exhausted `maxRetries`). */
422
- retried: number;
423
- /** Queue items dropped by a `serverWins`/`merge`/`custom` conflict resolution. */
424
- conflicted: number;
425
- /** Queue items removed via `handle.cancel(idempotencyKey)` before replay completed. */
426
- cancelled: number;
427
- }
428
-
429
- export declare function replayQueue(): Promise<ReplayResult>;
430
-
431
- /** Summary returned by replayQueue(). */
432
- export declare interface ReplayResult {
433
- /** Items where the registered function was found and called. */
434
- attempted: number;
435
- /** Items that resolved successfully. */
436
- succeeded: number;
437
- /** Items that failed and have no retries remaining (status: 'failed'). */
438
- failed: number;
439
- /** Items that failed but will be retried later (nextRetryAt set). */
440
- retrying: number;
441
- /** Items whose actionId had no registered function — likely not yet imported. */
442
- skipped: number;
443
- /** Items that received a 4xx response and were dropped via `conflict: { strategy: 'serverWins' }` (or `resolve()` returning `'skip'`). */
444
- conflicted: number;
445
- /** Items removed via `handle.cancel(idempotencyKey)` before/during replay. */
446
- cancelled: number;
447
- }
448
-
449
- /**
450
- * Reset a `'failed'` queue item back to `'pending'` so the next
451
- * `replayQueue()` retries it — clears `error`/`nextRetryAt` and resets
452
- * `retryCount` to 0. Returns `true` if the item existed and was failed.
453
- * Used by devtools' per-item "Retry" action.
454
- */
455
- export declare function requeueItem(id: string): Promise<boolean>;
456
-
457
- export declare function _resetEidos(): void;
458
-
459
- /**
460
- * Registers a concrete-URL resource. For URL patterns (`/api/products/*`,
461
- * `/api/users/:id`, `**`), use `resourcePattern()` instead.
462
- */
463
- export declare function resource<T = unknown>(url: string, config: ResourceConfig): ResourceHandle<T>;
464
-
465
- declare interface ResourceActions {
466
- registerResource: (url: string, entry: ResourceEntry) => void;
467
- updateResource: (url: string, update: Partial<ResourceEntry>) => void;
468
- unregisterResource: (url: string) => void;
469
- }
470
-
471
- export declare interface ResourceConfig {
472
- /** Make this resource available when the device is offline. */
473
- offline: boolean;
474
- /** Override the auto-selected caching strategy. */
475
- strategy?: CacheStrategy;
476
- /** Custom cache bucket name. Defaults to 'eidos-resources-v1'. */
477
- cacheName?: string;
478
- /**
479
- * Cache schema version. Bump when the response shape changes so old
480
- * cached entries (a different shape) aren't served from a stale bucket.
481
- * Appended to `cacheName` as a suffix (e.g. `eidos-resources-v1-v2`).
482
- * Old-versioned buckets are left in Cache Storage — clear them via
483
- * `caches.delete()` if needed.
484
- */
485
- version?: string | number;
486
- /** Max age of cached response in milliseconds. Expired entries trigger a network fetch. */
487
- maxAge?: number;
488
- }
489
-
490
- export declare interface ResourceEntry {
491
- url: string;
492
- config: ResourceConfig;
493
- strategy: GeneratedStrategy;
494
- status: 'idle' | 'fetching' | 'fresh' | 'stale' | 'error' | 'offline';
495
- cachedAt?: number;
496
- fetchedAt?: number;
497
- cacheHits: number;
498
- cacheMisses: number;
499
- lastEvent?: 'cache-hit' | 'cache-updated' | 'network-error' | 'cache-cleared';
500
- }
501
-
502
- export declare interface ResourceHandle<T = unknown> {
503
- readonly url: string;
504
- readonly config: ResourceConfig;
505
- readonly strategy: GeneratedStrategy;
506
- fetch: () => Promise<Response>;
507
- json: () => Promise<T>;
508
- /** Returns a TanStack Query-compatible options object. */
509
- query: () => {
510
- queryKey: [string, string];
511
- queryFn: () => Promise<T>;
512
- };
513
- prefetch: () => Promise<void>;
514
- invalidate: () => Promise<void>;
515
- /** Remove from registry and SW. Required before re-registering the same URL with different config. */
516
- unregister: () => void;
517
- }
518
-
519
- /**
520
- * Registers a URL pattern (`/api/products/*`, `/api/users/:id`, `**`). The SW
521
- * intercepts all matching requests automatically — there is no single URL to
522
- * fetch/cache directly, so the returned handle only supports cache management
523
- * (`invalidate`/`unregister`). For a fetchable resource, use `resource()`.
524
- */
525
- export declare function resourcePattern(url: string, config: ResourceConfig): PatternResourceHandle;
526
-
527
- export declare function sendToWorker(message: Record<string, unknown>): void;
528
-
529
- export declare function setOfflineSimulation(enabled: boolean): void;
530
-
531
- /* Excluded from this release type: setQueryInvalidator */
532
-
533
- /** Override the default IndexedDB queue with a custom storage backend (e.g. AsyncStorage for React Native). */
534
- export declare function setQueueStorage(s: QueueStorage): void;
535
-
536
- declare function _subscribe(listener: Listener): () => void;
537
-
538
- /**
539
- * Subscribe to online/offline transitions and trigger replayQueue() on
540
- * reconnect, plus replay any pending items left over from a previous session.
541
- *
542
- * Shared by the web (runtime.ts) and React Native (runtime-rn.ts) init paths.
543
- *
544
- * WHY subscribe to the store instead of window.addEventListener('online'):
545
- * setOfflineSimulation() updates the store directly but never fires a real
546
- * browser `online` event. Watching the store catches both:
547
- * • Real network reconnects (sw-bridge updates store on window.online)
548
- * • Simulation toggled off (setOfflineSimulation(false) → store.setOnline(true))
549
- *
550
- * Returns an unsubscribe function.
551
- */
552
- export declare function subscribeReplayOnReconnect(): () => void;
553
-
554
- /** Full Eidos store — prefer the narrower hooks below for performance. */
555
- export declare function useEidos(): EidosStore;
556
-
557
- /**
558
- * Live state for a single queue item by ID. Only re-renders when that specific
559
- * item changes — cheaper than `useEidosQueue().find(id)` which re-renders on
560
- * any queue mutation.
561
- */
562
- export declare function useEidosAction(id: string): ActionQueueItem | undefined;
563
-
564
- export declare function useEidosOnDrain(callback: () => void): void;
565
-
566
- /** The current action queue. */
567
- export declare function useEidosQueue(): ActionQueueItem[];
568
-
569
- /**
570
- * Queue counts — single subscription, single loop. Re-renders only when a
571
- * count changes, not on every queue mutation. Use for badges and status bars
572
- * instead of `useEidosQueue()` when you only need numbers, not full items.
573
- */
574
- export declare function useEidosQueueStats(): {
575
- pending: number;
576
- failed: number;
577
- replaying: number;
578
- total: number;
579
- };
580
-
581
- /**
582
- * Calls `callback` once each time the action queue drains from non-empty → 0.
583
- * Stable callback reference not required — always calls the latest version.
584
- * Use for "all offline actions synced!" toasts.
585
- *
586
- * @example
587
- * useEidosOnDrain(() => toast.success('All offline actions synced!'))
588
- */
589
- /**
590
- * Cumulative, session-scoped `neverLose` queue outcome counters — opt-in
591
- * reliability telemetry for dashboards/devtools. Re-renders only when a
592
- * counter changes.
593
- */
594
- export declare function useEidosReliabilityStats(): ReliabilityStats;
595
-
596
- /** Live state for a single registered resource URL. */
597
- export declare function useEidosResource(url: string): ResourceEntry;
598
-
599
- /** All registered resources — only re-renders when the resources map changes, not on queue mutations. */
600
- export declare function useEidosResources(): Record<string, ResourceEntry>;
601
-
602
- /**
603
- * Online + SW status — cheap subscription, safe to use in header components.
604
- * Three separate primitive selectors so each only triggers a re-render when
605
- * its own value changes (no object-reference churn from a combined selector).
606
- */
607
- export declare function useEidosStatus(): {
608
- isOnline: boolean;
609
- swStatus: "idle" | "error" | "registering" | "active" | "unsupported";
610
- swError: string | undefined;
611
- };
612
-
613
- export declare const useEidosStore: {
614
- getState: typeof _getState;
615
- subscribe: typeof _subscribe;
616
- setState: (partial: Partial<EidosStore> | ((s: EidosStore) => Partial<EidosStore>)) => void;
617
- };
618
-
619
- export declare const VERSION = "2.2.0";
620
-
621
- /**
622
- * Bulk-prefetch an array of resource handles concurrently, warming the cache
623
- * for each one. Useful on login / app init when you know which resources the
624
- * user will need offline.
625
- *
626
- * Pattern handles (containing `*`, `**`, or `:param`) are silently skipped —
627
- * they match multiple URLs so there is no single URL to prefetch.
628
- *
629
- * @example
630
- * import { warmCache } from '@sweidos/eidos'
631
- *
632
- * // In EidosProvider's onReady, or after login:
633
- * const { warmed, failed } = await warmCache([products, userProfile, settings])
634
- */
635
- export declare function warmCache(handles: ResourceHandle[]): Promise<WarmCacheResult>;
636
-
637
- /** Summary returned by warmCache(). */
638
- export declare interface WarmCacheResult {
639
- /** Resources that were prefetched successfully. */
640
- warmed: number;
641
- /** Resources whose prefetch threw (network error, offline, etc.). */
642
- failed: number;
643
- /** The raw errors, in input order, for failed handles. */
644
- errors: unknown[];
645
- }
646
-
647
- export { }
1
+ export { resource, resourcePattern, warmCache, setQueryInvalidator } from './resource';
2
+ export { action, replayQueue, clearQueue, cancelByIdempotencyKey, requeueItem } from './action';
3
+ export { initEidos, _resetEidos } from './runtime';
4
+ export type { EidosConfig } from './runtime';
5
+ export { subscribeReplayOnReconnect } from './replay';
6
+ export { setQueueStorage, _getQueueStorage } from './queue-storage';
7
+ export type { QueueStorage } from './queue-storage';
8
+ export { AsyncStorageQueueStorage } from './async-storage-adapter';
9
+ export type { AsyncStorageLike } from './async-storage-adapter';
10
+ export { EidosProvider } from './react/Provider';
11
+ export { useEidos, useEidosResources, useEidosResource, useEidosQueue, useEidosAction, useEidosQueueStats, useEidosStatus, useEidosOnDrain, useEidosReliabilityStats, } from './react/hooks';
12
+ export { VERSION } from './version';
13
+ export { setOfflineSimulation, isBgSyncSupported, getSwRegistration, sendToWorker, registerPushCallbacks, triggerSwUpdate, } from './sw-bridge';
14
+ export { eidosDebug } from './debug';
15
+ export type { EidosDebugSnapshot } from './debug';
16
+ export { useEidosStore } from './store';
17
+ export type { EidosStore } from './store';
18
+ export { eidosStore, eidosQueue, eidosStatus, eidosQueueStats, eidosResource, eidosAction, onQueueDrain, eidosReliabilityStats, } from './stores';
19
+ export type { EidosReadable } from './stores';
20
+ export type { ResourceConfig, ResourceHandle, PatternResourceHandle, AnyResourceHandle, ResourceEntry, GeneratedStrategy, WarmCacheResult, ActionConfig, ActionContext, ActionFn, ActionHandle, ActionQueueItem, QueuedResult, ReplayResult, EidosState, ReliabilityStats, ConflictContext, ConflictResolution, ConflictConfig, CacheStrategy, } from './types';