@mustafaaksoy41/react-native-offline-queue 0.1.2

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +673 -0
  3. package/lib/commonjs/adapters/index.js +128 -0
  4. package/lib/commonjs/adapters/index.js.map +1 -0
  5. package/lib/commonjs/components/OfflineProvider.js +51 -0
  6. package/lib/commonjs/components/OfflineProvider.js.map +1 -0
  7. package/lib/commonjs/components/OfflineSyncPrompt.js +37 -0
  8. package/lib/commonjs/components/OfflineSyncPrompt.js.map +1 -0
  9. package/lib/commonjs/core/OfflineManager.js +308 -0
  10. package/lib/commonjs/core/OfflineManager.js.map +1 -0
  11. package/lib/commonjs/core/StorageAdapter.js +31 -0
  12. package/lib/commonjs/core/StorageAdapter.js.map +1 -0
  13. package/lib/commonjs/core/types.js +15 -0
  14. package/lib/commonjs/core/types.js.map +1 -0
  15. package/lib/commonjs/global.d.js +2 -0
  16. package/lib/commonjs/global.d.js.map +1 -0
  17. package/lib/commonjs/hooks/useOfflineMutation.js +61 -0
  18. package/lib/commonjs/hooks/useOfflineMutation.js.map +1 -0
  19. package/lib/commonjs/hooks/useOfflineQueue.js +21 -0
  20. package/lib/commonjs/hooks/useOfflineQueue.js.map +1 -0
  21. package/lib/commonjs/hooks/useOfflineSyncInterceptor.js +42 -0
  22. package/lib/commonjs/hooks/useOfflineSyncInterceptor.js.map +1 -0
  23. package/lib/commonjs/hooks/useSyncProgress.js +33 -0
  24. package/lib/commonjs/hooks/useSyncProgress.js.map +1 -0
  25. package/lib/commonjs/index.js +134 -0
  26. package/lib/commonjs/index.js.map +1 -0
  27. package/lib/commonjs/package.json +1 -0
  28. package/lib/module/adapters/index.js +121 -0
  29. package/lib/module/adapters/index.js.map +1 -0
  30. package/lib/module/components/OfflineProvider.js +43 -0
  31. package/lib/module/components/OfflineProvider.js.map +1 -0
  32. package/lib/module/components/OfflineSyncPrompt.js +31 -0
  33. package/lib/module/components/OfflineSyncPrompt.js.map +1 -0
  34. package/lib/module/core/OfflineManager.js +304 -0
  35. package/lib/module/core/OfflineManager.js.map +1 -0
  36. package/lib/module/core/StorageAdapter.js +25 -0
  37. package/lib/module/core/StorageAdapter.js.map +1 -0
  38. package/lib/module/core/types.js +11 -0
  39. package/lib/module/core/types.js.map +1 -0
  40. package/lib/module/global.d.js +2 -0
  41. package/lib/module/global.d.js.map +1 -0
  42. package/lib/module/hooks/useOfflineMutation.js +57 -0
  43. package/lib/module/hooks/useOfflineMutation.js.map +1 -0
  44. package/lib/module/hooks/useOfflineQueue.js +17 -0
  45. package/lib/module/hooks/useOfflineQueue.js.map +1 -0
  46. package/lib/module/hooks/useOfflineSyncInterceptor.js +38 -0
  47. package/lib/module/hooks/useOfflineSyncInterceptor.js.map +1 -0
  48. package/lib/module/hooks/useSyncProgress.js +29 -0
  49. package/lib/module/hooks/useSyncProgress.js.map +1 -0
  50. package/lib/module/index.js +20 -0
  51. package/lib/module/index.js.map +1 -0
  52. package/lib/module/package.json +1 -0
  53. package/lib/typescript/adapters/index.d.ts +12 -0
  54. package/lib/typescript/adapters/index.d.ts.map +1 -0
  55. package/lib/typescript/components/OfflineProvider.d.ts +13 -0
  56. package/lib/typescript/components/OfflineProvider.d.ts.map +1 -0
  57. package/lib/typescript/components/OfflineSyncPrompt.d.ts +11 -0
  58. package/lib/typescript/components/OfflineSyncPrompt.d.ts.map +1 -0
  59. package/lib/typescript/core/OfflineManager.d.ts +53 -0
  60. package/lib/typescript/core/OfflineManager.d.ts.map +1 -0
  61. package/lib/typescript/core/StorageAdapter.d.ts +21 -0
  62. package/lib/typescript/core/StorageAdapter.d.ts.map +1 -0
  63. package/lib/typescript/core/types.d.ts +23 -0
  64. package/lib/typescript/core/types.d.ts.map +1 -0
  65. package/lib/typescript/hooks/useOfflineMutation.d.ts +8 -0
  66. package/lib/typescript/hooks/useOfflineMutation.d.ts.map +1 -0
  67. package/lib/typescript/hooks/useOfflineQueue.d.ts +8 -0
  68. package/lib/typescript/hooks/useOfflineQueue.d.ts.map +1 -0
  69. package/lib/typescript/hooks/useOfflineSyncInterceptor.d.ts +9 -0
  70. package/lib/typescript/hooks/useOfflineSyncInterceptor.d.ts.map +1 -0
  71. package/lib/typescript/hooks/useSyncProgress.d.ts +23 -0
  72. package/lib/typescript/hooks/useSyncProgress.d.ts.map +1 -0
  73. package/lib/typescript/index.d.ts +11 -0
  74. package/lib/typescript/index.d.ts.map +1 -0
  75. package/package.json +73 -0
  76. package/src/adapters/index.ts +141 -0
  77. package/src/components/OfflineProvider.tsx +52 -0
  78. package/src/components/OfflineSyncPrompt.tsx +32 -0
  79. package/src/core/OfflineManager.ts +338 -0
  80. package/src/core/StorageAdapter.ts +42 -0
  81. package/src/core/types.ts +33 -0
  82. package/src/global.d.ts +1 -0
  83. package/src/hooks/useOfflineMutation.ts +63 -0
  84. package/src/hooks/useOfflineQueue.ts +17 -0
  85. package/src/hooks/useOfflineSyncInterceptor.ts +39 -0
  86. package/src/hooks/useSyncProgress.ts +32 -0
  87. package/src/index.ts +17 -0
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+
3
+ import { MemoryStorageAdapter, isRecordAdapter } from './StorageAdapter';
4
+ import { INITIAL_SYNC_PROGRESS } from './types';
5
+ import { getMMKVAdapter, getAsyncStorageAdapter, getRealmAdapter } from '../adapters';
6
+ // Simple UUID string generator
7
+ function generateUUID() {
8
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
9
+ const r = Math.random() * 16 | 0,
10
+ v = c === 'x' ? r : r & 0x3 | 0x8;
11
+ return v.toString(16);
12
+ });
13
+ }
14
+ class OfflineManagerClass {
15
+ queue = [];
16
+ storage = new MemoryStorageAdapter();
17
+ storageKey = 'REACT_NATIVE_OFFLINE_QUEUE_STATE';
18
+ useRecordAdapter = false;
19
+
20
+ // Queue listeners (for useOfflineQueue / useSyncExternalStore)
21
+ queueListeners = new Set();
22
+
23
+ // Progress listeners (for useSyncProgress)
24
+ progressListeners = new Set();
25
+
26
+ // Per-action handler registry
27
+ actionHandlers = new Map();
28
+ isInitialized = false;
29
+ syncMode = 'manual';
30
+ isSyncing = false;
31
+
32
+ // ─── Sync Progress State ───
33
+ _syncProgress = {
34
+ ...INITIAL_SYNC_PROGRESS
35
+ };
36
+ get syncProgress() {
37
+ return this._syncProgress;
38
+ }
39
+
40
+ // ─── Configuration ───
41
+ async configure(config) {
42
+ if (config.storageType) {
43
+ if (config.storageType === 'mmkv') {
44
+ this.storage = getMMKVAdapter();
45
+ this.useRecordAdapter = false;
46
+ } else if (config.storageType === 'async-storage') {
47
+ this.storage = getAsyncStorageAdapter();
48
+ this.useRecordAdapter = false;
49
+ } else if (config.storageType === 'realm') {
50
+ this.storage = getRealmAdapter(config.realmOptions);
51
+ this.useRecordAdapter = true;
52
+ } else {
53
+ this.storage = new MemoryStorageAdapter();
54
+ this.useRecordAdapter = false;
55
+ }
56
+ } else if (config.storage) {
57
+ this.storage = config.storage;
58
+ this.useRecordAdapter = isRecordAdapter(config.storage);
59
+ }
60
+ if (config.storageKey) {
61
+ this.storageKey = config.storageKey;
62
+ }
63
+ if (config.syncMode) {
64
+ this.syncMode = config.syncMode;
65
+ }
66
+ if (config.onSyncAction) {
67
+ this.onSyncAction = config.onSyncAction;
68
+ }
69
+ if (config.onOnlineRestore) {
70
+ this.onOnlineRestore = config.onOnlineRestore;
71
+ }
72
+ await this.loadQueue();
73
+ this.isInitialized = true;
74
+ }
75
+
76
+ // ─── Storage (supports both adapter types) ───
77
+ async loadQueue() {
78
+ try {
79
+ if (this.useRecordAdapter) {
80
+ const adapter = this.storage;
81
+ this.queue = await adapter.getAll();
82
+ } else {
83
+ const adapter = this.storage;
84
+ const data = await adapter.getItem(this.storageKey);
85
+ if (data) {
86
+ this.queue = JSON.parse(data) || [];
87
+ }
88
+ }
89
+ this.notifyQueueListeners();
90
+ } catch (e) {
91
+ console.warn('[OfflineManager] Failed to load queue from storage', e);
92
+ }
93
+ }
94
+ async saveQueue() {
95
+ try {
96
+ if (!this.useRecordAdapter) {
97
+ const adapter = this.storage;
98
+ await adapter.setItem(this.storageKey, JSON.stringify(this.queue));
99
+ }
100
+ // Record adapter saves per-operation, no need for full queue write
101
+ } catch (e) {
102
+ console.warn('[OfflineManager] Failed to save queue to storage', e);
103
+ }
104
+ }
105
+
106
+ // ─── Queue Subscriptions (useSyncExternalStore) ───
107
+ subscribeQueue = listener => {
108
+ this.queueListeners.add(listener);
109
+ return () => this.queueListeners.delete(listener);
110
+ };
111
+
112
+ // Backward compatibility alias
113
+ subscribe = this.subscribeQueue;
114
+ notifyQueueListeners() {
115
+ this.queueListeners.forEach(l => l());
116
+ }
117
+
118
+ // ─── Progress Subscriptions (useSyncExternalStore) ───
119
+ subscribeProgress = listener => {
120
+ this.progressListeners.add(listener);
121
+ return () => this.progressListeners.delete(listener);
122
+ };
123
+ updateProgress(partial) {
124
+ this._syncProgress = {
125
+ ...this._syncProgress,
126
+ ...partial
127
+ };
128
+ this.progressListeners.forEach(l => l());
129
+ }
130
+ updateProgressItem(id, update) {
131
+ this._syncProgress = {
132
+ ...this._syncProgress,
133
+ items: this._syncProgress.items.map(item => item.action.id === id ? {
134
+ ...item,
135
+ ...update
136
+ } : item)
137
+ };
138
+ this.progressListeners.forEach(l => l());
139
+ }
140
+
141
+ // ─── Queue CRUD ───
142
+ async push(actionName, payload) {
143
+ const action = {
144
+ id: generateUUID(),
145
+ actionName,
146
+ payload,
147
+ createdAt: Date.now(),
148
+ retryCount: 0
149
+ };
150
+ this.queue = [...this.queue, action];
151
+ if (this.useRecordAdapter) {
152
+ await this.storage.insert(action);
153
+ } else {
154
+ await this.saveQueue();
155
+ }
156
+ this.notifyQueueListeners();
157
+ return action;
158
+ }
159
+ async remove(id) {
160
+ this.queue = this.queue.filter(a => a.id !== id);
161
+ if (this.useRecordAdapter) {
162
+ await this.storage.remove(id);
163
+ } else {
164
+ await this.saveQueue();
165
+ }
166
+ this.notifyQueueListeners();
167
+ }
168
+ async clear() {
169
+ this.queue = [];
170
+ if (this.useRecordAdapter) {
171
+ await this.storage.clear();
172
+ } else {
173
+ await this.saveQueue();
174
+ }
175
+ this.notifyQueueListeners();
176
+ this.updateProgress({
177
+ ...INITIAL_SYNC_PROGRESS
178
+ });
179
+ }
180
+ getQueue() {
181
+ return this.queue;
182
+ }
183
+
184
+ // ─── Per-Action Handler Registry ───
185
+ registerHandler(actionName, handler) {
186
+ this.actionHandlers.set(actionName, handler);
187
+ }
188
+ unregisterHandler(actionName) {
189
+ this.actionHandlers.delete(actionName);
190
+ }
191
+ getHandler(actionName) {
192
+ return this.actionHandlers.get(actionName);
193
+ }
194
+
195
+ // ─── The Central Sync Mechanism (with progress tracking) ───
196
+ async flushQueue() {
197
+ if (this.queue.length === 0 || this.isSyncing) {
198
+ return;
199
+ }
200
+ const hasAnyHandler = this.onSyncAction || this.actionHandlers.size > 0;
201
+ if (!hasAnyHandler) {
202
+ console.warn('[OfflineManager] No handlers registered and no onSyncAction configured.');
203
+ return;
204
+ }
205
+ this.isSyncing = true;
206
+ this.notifyQueueListeners();
207
+ const currentQueue = [...this.queue];
208
+
209
+ // Initialize progress tracking for this sync session
210
+ const progressItems = currentQueue.map(action => ({
211
+ action,
212
+ status: 'pending'
213
+ }));
214
+ this.updateProgress({
215
+ isActive: true,
216
+ totalCount: currentQueue.length,
217
+ completedCount: 0,
218
+ failedCount: 0,
219
+ currentAction: null,
220
+ items: progressItems
221
+ });
222
+ let completedCount = 0;
223
+ let failedCount = 0;
224
+ for (const action of currentQueue) {
225
+ // Mark current item as "syncing"
226
+ this.updateProgress({
227
+ currentAction: action
228
+ });
229
+ this.updateProgressItem(action.id, {
230
+ status: 'syncing'
231
+ });
232
+ try {
233
+ // Per-action handler takes priority, then fallback to onSyncAction
234
+ const handler = this.actionHandlers.get(action.actionName);
235
+ if (handler) {
236
+ await handler(action.payload);
237
+ } else if (this.onSyncAction) {
238
+ await this.onSyncAction(action);
239
+ } else {
240
+ throw new Error(`No handler registered for action: ${action.actionName}`);
241
+ }
242
+
243
+ // Success → remove from queue + mark in progress
244
+ await this.remove(action.id);
245
+ completedCount++;
246
+ this.updateProgressItem(action.id, {
247
+ status: 'success'
248
+ });
249
+ this.updateProgress({
250
+ completedCount
251
+ });
252
+ } catch (error) {
253
+ console.warn(`[OfflineManager] Action ${action.actionName} failed to sync.`, error);
254
+
255
+ // Mark as failed in progress
256
+ failedCount++;
257
+ this.updateProgressItem(action.id, {
258
+ status: 'failed',
259
+ error: error?.message || 'Unknown error'
260
+ });
261
+ this.updateProgress({
262
+ failedCount
263
+ });
264
+
265
+ // Update retry count on the queue item
266
+ const target = this.queue.find(a => a.id === action.id);
267
+ if (target) {
268
+ target.retryCount += 1;
269
+ }
270
+ if (this.useRecordAdapter) {
271
+ await this.storage.update(action.id, {
272
+ retryCount: target?.retryCount || 0
273
+ });
274
+ } else {
275
+ await this.saveQueue();
276
+ }
277
+ this.notifyQueueListeners();
278
+ }
279
+ }
280
+ this.isSyncing = false;
281
+ this.updateProgress({
282
+ isActive: false,
283
+ currentAction: null
284
+ });
285
+ this.notifyQueueListeners();
286
+ }
287
+
288
+ // ─── Called by OfflineProvider when internet restores ───
289
+ handleOnlineRestore() {
290
+ if (this.queue.length === 0) return;
291
+ if (this.syncMode === 'auto') {
292
+ this.flushQueue();
293
+ } else if (this.syncMode === 'manual' && this.onOnlineRestore) {
294
+ this.onOnlineRestore({
295
+ pendingCount: this.queue.length,
296
+ syncNow: () => this.flushQueue(),
297
+ discardQueue: () => this.clear()
298
+ });
299
+ }
300
+ // If manual + no onOnlineRestore → silent (nothing happens)
301
+ }
302
+ }
303
+ export const OfflineManager = new OfflineManagerClass();
304
+ //# sourceMappingURL=OfflineManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["MemoryStorageAdapter","isRecordAdapter","INITIAL_SYNC_PROGRESS","getMMKVAdapter","getAsyncStorageAdapter","getRealmAdapter","generateUUID","replace","c","r","Math","random","v","toString","OfflineManagerClass","queue","storage","storageKey","useRecordAdapter","queueListeners","Set","progressListeners","actionHandlers","Map","isInitialized","syncMode","isSyncing","_syncProgress","syncProgress","configure","config","storageType","realmOptions","onSyncAction","onOnlineRestore","loadQueue","adapter","getAll","data","getItem","JSON","parse","notifyQueueListeners","e","console","warn","saveQueue","setItem","stringify","subscribeQueue","listener","add","delete","subscribe","forEach","l","subscribeProgress","updateProgress","partial","updateProgressItem","id","update","items","map","item","action","push","actionName","payload","createdAt","Date","now","retryCount","insert","remove","filter","a","clear","getQueue","registerHandler","handler","set","unregisterHandler","getHandler","get","flushQueue","length","hasAnyHandler","size","currentQueue","progressItems","status","isActive","totalCount","completedCount","failedCount","currentAction","Error","error","message","target","find","handleOnlineRestore","pendingCount","syncNow","discardQueue","OfflineManager"],"sourceRoot":"../../../src","sources":["core/OfflineManager.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ // Key-Value adapter (MMKV, AsyncStorage, Memory)
4
+ // Stores entire queue as a single JSON string
5
+
6
+ // Record-based adapter (Realm, SQLite, WatermelonDB)
7
+ // Each queue item is a separate database record — much faster for large queues
8
+
9
+ // Type guard to check which adapter type is being used
10
+ export function isRecordAdapter(adapter) {
11
+ return 'insert' in adapter && 'getAll' in adapter;
12
+ }
13
+ export class MemoryStorageAdapter {
14
+ store = {};
15
+ getItem(key) {
16
+ return this.store[key] || null;
17
+ }
18
+ setItem(key, value) {
19
+ this.store[key] = value;
20
+ }
21
+ removeItem(key) {
22
+ delete this.store[key];
23
+ }
24
+ }
25
+ //# sourceMappingURL=StorageAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["isRecordAdapter","adapter","MemoryStorageAdapter","store","getItem","key","setItem","value","removeItem"],"sourceRoot":"../../../src","sources":["core/StorageAdapter.ts"],"mappings":";;AAEA;AACA;;AAOA;AACA;;AASA;AACA,OAAO,SAASA,eAAeA,CAC7BC,OAA8C,EACb;EACjC,OAAO,QAAQ,IAAIA,OAAO,IAAI,QAAQ,IAAIA,OAAO;AACnD;AAEA,OAAO,MAAMC,oBAAoB,CAA2B;EAClDC,KAAK,GAA2B,CAAC,CAAC;EAE1CC,OAAOA,CAACC,GAAW,EAAiB;IAClC,OAAO,IAAI,CAACF,KAAK,CAACE,GAAG,CAAC,IAAI,IAAI;EAChC;EAEAC,OAAOA,CAACD,GAAW,EAAEE,KAAa,EAAQ;IACxC,IAAI,CAACJ,KAAK,CAACE,GAAG,CAAC,GAAGE,KAAK;EACzB;EAEAC,UAAUA,CAACH,GAAW,EAAQ;IAC5B,OAAO,IAAI,CAACF,KAAK,CAACE,GAAG,CAAC;EACxB;AACF","ignoreList":[]}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ export const INITIAL_SYNC_PROGRESS = {
4
+ isActive: false,
5
+ totalCount: 0,
6
+ completedCount: 0,
7
+ failedCount: 0,
8
+ currentAction: null,
9
+ items: []
10
+ };
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["INITIAL_SYNC_PROGRESS","isActive","totalCount","completedCount","failedCount","currentAction","items"],"sourceRoot":"../../../src","sources":["core/types.ts"],"mappings":";;AAyBA,OAAO,MAAMA,qBAAmC,GAAG;EACjDC,QAAQ,EAAE,KAAK;EACfC,UAAU,EAAE,CAAC;EACbC,cAAc,EAAE,CAAC;EACjBC,WAAW,EAAE,CAAC;EACdC,aAAa,EAAE,IAAI;EACnBC,KAAK,EAAE;AACT,CAAC","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=global.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["global.d.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ import { useEffect, useRef } from 'react';
4
+ import { OfflineManager } from '../core/OfflineManager';
5
+ import { useNetworkStatus } from '../components/OfflineProvider';
6
+ export function useOfflineMutation(actionName, options) {
7
+ const {
8
+ isOnline
9
+ } = useNetworkStatus();
10
+ const handlerRef = useRef(options?.handler);
11
+ handlerRef.current = options?.handler;
12
+
13
+ // Register per-action handler (persists even after unmount)
14
+ useEffect(() => {
15
+ if (handlerRef.current) {
16
+ OfflineManager.registerHandler(actionName, payload => handlerRef.current(payload));
17
+ }
18
+ }, [actionName]);
19
+ const mutateOffline = async payload => {
20
+ // Resolve which handler to use: per-action handler > global onSyncAction
21
+ const handler = handlerRef.current || OfflineManager.getHandler(actionName);
22
+ const globalHandler = OfflineManager.onSyncAction;
23
+ const hasHandler = handler || globalHandler;
24
+ if (isOnline && hasHandler) {
25
+ // ── ONLINE: Execute directly, skip the queue ──
26
+ if (__DEV__) console.log(`[OfflineQueue] mutate: ${actionName} (direct)`);
27
+ try {
28
+ if (handler) {
29
+ await handler(payload);
30
+ } else if (globalHandler) {
31
+ await globalHandler({
32
+ id: '',
33
+ actionName,
34
+ payload,
35
+ createdAt: Date.now(),
36
+ retryCount: 0
37
+ });
38
+ }
39
+ options?.onOptimisticSuccess?.(payload);
40
+ } catch (error) {
41
+ console.warn(`[OfflineQueue] mutate: ${actionName} failed, falling back to queue`, error);
42
+ await OfflineManager.push(actionName, payload);
43
+ options?.onOptimisticSuccess?.(payload);
44
+ options?.onError?.(error, payload);
45
+ }
46
+ } else {
47
+ // ── OFFLINE: Add to queue + optimistic update ──
48
+ if (__DEV__) console.log(`[OfflineQueue] mutate: ${actionName} (queued)`);
49
+ await OfflineManager.push(actionName, payload);
50
+ options?.onOptimisticSuccess?.(payload);
51
+ }
52
+ };
53
+ return {
54
+ mutateOffline
55
+ };
56
+ }
57
+ //# sourceMappingURL=useOfflineMutation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useEffect","useRef","OfflineManager","useNetworkStatus","useOfflineMutation","actionName","options","isOnline","handlerRef","handler","current","registerHandler","payload","mutateOffline","getHandler","globalHandler","onSyncAction","hasHandler","__DEV__","console","log","id","createdAt","Date","now","retryCount","onOptimisticSuccess","error","warn","push","onError"],"sourceRoot":"../../../src","sources":["hooks/useOfflineMutation.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AACzC,SAASC,cAAc,QAAQ,wBAAwB;AACvD,SAASC,gBAAgB,QAAQ,+BAA+B;AAEhE,OAAO,SAASC,kBAAkBA,CAChCC,UAAkB,EAClBC,OAIC,EACD;EACA,MAAM;IAAEC;EAAS,CAAC,GAAGJ,gBAAgB,CAAC,CAAC;EACvC,MAAMK,UAAU,GAAGP,MAAM,CAACK,OAAO,EAAEG,OAAO,CAAC;EAC3CD,UAAU,CAACE,OAAO,GAAGJ,OAAO,EAAEG,OAAO;;EAErC;EACAT,SAAS,CAAC,MAAM;IACd,IAAIQ,UAAU,CAACE,OAAO,EAAE;MACtBR,cAAc,CAACS,eAAe,CAACN,UAAU,EAAGO,OAAY,IACtDJ,UAAU,CAACE,OAAO,CAAEE,OAAO,CAC7B,CAAC;IACH;EACF,CAAC,EAAE,CAACP,UAAU,CAAC,CAAC;EAEhB,MAAMQ,aAAa,GAAG,MAAOD,OAAiB,IAAK;IACjD;IACA,MAAMH,OAAO,GAAGD,UAAU,CAACE,OAAO,IAAIR,cAAc,CAACY,UAAU,CAACT,UAAU,CAAC;IAC3E,MAAMU,aAAa,GAAGb,cAAc,CAACc,YAAY;IACjD,MAAMC,UAAU,GAAGR,OAAO,IAAIM,aAAa;IAE3C,IAAIR,QAAQ,IAAIU,UAAU,EAAE;MAC1B;MACA,IAAIC,OAAO,EAAEC,OAAO,CAACC,GAAG,CAAC,0BAA0Bf,UAAU,WAAW,CAAC;MACzE,IAAI;QACF,IAAII,OAAO,EAAE;UACX,MAAMA,OAAO,CAACG,OAAO,CAAC;QACxB,CAAC,MAAM,IAAIG,aAAa,EAAE;UACxB,MAAMA,aAAa,CAAC;YAClBM,EAAE,EAAE,EAAE;YACNhB,UAAU;YACVO,OAAO;YACPU,SAAS,EAAEC,IAAI,CAACC,GAAG,CAAC,CAAC;YACrBC,UAAU,EAAE;UACd,CAAC,CAAC;QACJ;QACAnB,OAAO,EAAEoB,mBAAmB,GAAGd,OAAO,CAAC;MACzC,CAAC,CAAC,OAAOe,KAAU,EAAE;QACnBR,OAAO,CAACS,IAAI,CAAC,0BAA0BvB,UAAU,gCAAgC,EAAEsB,KAAK,CAAC;QACzF,MAAMzB,cAAc,CAAC2B,IAAI,CAACxB,UAAU,EAAEO,OAAO,CAAC;QAC9CN,OAAO,EAAEoB,mBAAmB,GAAGd,OAAO,CAAC;QACvCN,OAAO,EAAEwB,OAAO,GAAGH,KAAK,EAAEf,OAAO,CAAC;MACpC;IACF,CAAC,MAAM;MACL;MACA,IAAIM,OAAO,EAAEC,OAAO,CAACC,GAAG,CAAC,0BAA0Bf,UAAU,WAAW,CAAC;MACzE,MAAMH,cAAc,CAAC2B,IAAI,CAACxB,UAAU,EAAEO,OAAO,CAAC;MAC9CN,OAAO,EAAEoB,mBAAmB,GAAGd,OAAO,CAAC;IACzC;EACF,CAAC;EAED,OAAO;IAAEC;EAAc,CAAC;AAC1B","ignoreList":[]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ import { useSyncExternalStore } from 'react';
4
+ import { OfflineManager } from '../core/OfflineManager';
5
+ const subscribe = listener => OfflineManager.subscribe(listener);
6
+ const getSnapshot = () => OfflineManager.getQueue();
7
+ export function useOfflineQueue() {
8
+ const queue = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
9
+ return {
10
+ queue,
11
+ pendingCount: queue.length,
12
+ isSyncing: OfflineManager.isSyncing,
13
+ syncNow: () => OfflineManager.flushQueue(),
14
+ clearQueue: () => OfflineManager.clear()
15
+ };
16
+ }
17
+ //# sourceMappingURL=useOfflineQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useSyncExternalStore","OfflineManager","subscribe","listener","getSnapshot","getQueue","useOfflineQueue","queue","pendingCount","length","isSyncing","syncNow","flushQueue","clearQueue","clear"],"sourceRoot":"../../../src","sources":["hooks/useOfflineQueue.ts"],"mappings":";;AAAA,SAASA,oBAAoB,QAAQ,OAAO;AAC5C,SAASC,cAAc,QAAQ,wBAAwB;AAEvD,MAAMC,SAAS,GAAIC,QAAoB,IAAKF,cAAc,CAACC,SAAS,CAACC,QAAQ,CAAC;AAC9E,MAAMC,WAAW,GAAGA,CAAA,KAAMH,cAAc,CAACI,QAAQ,CAAC,CAAC;AAEnD,OAAO,SAASC,eAAeA,CAAA,EAAG;EAChC,MAAMC,KAAK,GAAGP,oBAAoB,CAACE,SAAS,EAAEE,WAAW,EAAEA,WAAW,CAAC;EAEvE,OAAO;IACLG,KAAK;IACLC,YAAY,EAAED,KAAK,CAACE,MAAM;IAC1BC,SAAS,EAAET,cAAc,CAACS,SAAS;IACnCC,OAAO,EAAEA,CAAA,KAAMV,cAAc,CAACW,UAAU,CAAC,CAAC;IAC1CC,UAAU,EAAEA,CAAA,KAAMZ,cAAc,CAACa,KAAK,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { useNetworkStatus } from '../components/OfflineProvider';
5
+ import { useOfflineQueue } from './useOfflineQueue';
6
+ export function useOfflineSyncInterceptor({
7
+ onPromptNeeded
8
+ }) {
9
+ const {
10
+ isOnline
11
+ } = useNetworkStatus();
12
+ const {
13
+ pendingCount,
14
+ syncNow,
15
+ clearQueue
16
+ } = useOfflineQueue();
17
+ const onPromptNeededRef = useRef(onPromptNeeded);
18
+ useEffect(() => {
19
+ onPromptNeededRef.current = onPromptNeeded;
20
+ });
21
+ const [hasPrompted, setHasPrompted] = useState(false);
22
+ useEffect(() => {
23
+ if (isOnline && pendingCount > 0 && !hasPrompted) {
24
+ setHasPrompted(true);
25
+ onPromptNeededRef.current({
26
+ pendingCount,
27
+ syncNow: async () => {
28
+ await syncNow();
29
+ },
30
+ discardQueue: clearQueue
31
+ });
32
+ } else if (!isOnline || pendingCount === 0) {
33
+ // Reset prompt state when offline or when queue is cleared
34
+ setHasPrompted(false);
35
+ }
36
+ }, [isOnline, pendingCount, hasPrompted, syncNow, clearQueue]);
37
+ }
38
+ //# sourceMappingURL=useOfflineSyncInterceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useEffect","useRef","useState","useNetworkStatus","useOfflineQueue","useOfflineSyncInterceptor","onPromptNeeded","isOnline","pendingCount","syncNow","clearQueue","onPromptNeededRef","current","hasPrompted","setHasPrompted","discardQueue"],"sourceRoot":"../../../src","sources":["hooks/useOfflineSyncInterceptor.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AACnD,SAASC,gBAAgB,QAAQ,+BAA+B;AAChE,SAASC,eAAe,QAAQ,mBAAmB;AAUnD,OAAO,SAASC,yBAAyBA,CAAC;EAAEC;AAAmC,CAAC,EAAE;EAChF,MAAM;IAAEC;EAAS,CAAC,GAAGJ,gBAAgB,CAAC,CAAC;EACvC,MAAM;IAAEK,YAAY;IAAEC,OAAO;IAAEC;EAAW,CAAC,GAAGN,eAAe,CAAC,CAAC;EAE/D,MAAMO,iBAAiB,GAAGV,MAAM,CAACK,cAAc,CAAC;EAChDN,SAAS,CAAC,MAAM;IACdW,iBAAiB,CAACC,OAAO,GAAGN,cAAc;EAC5C,CAAC,CAAC;EAEF,MAAM,CAACO,WAAW,EAAEC,cAAc,CAAC,GAAGZ,QAAQ,CAAC,KAAK,CAAC;EAErDF,SAAS,CAAC,MAAM;IACd,IAAIO,QAAQ,IAAIC,YAAY,GAAG,CAAC,IAAI,CAACK,WAAW,EAAE;MAChDC,cAAc,CAAC,IAAI,CAAC;MACpBH,iBAAiB,CAACC,OAAO,CAAC;QACxBJ,YAAY;QACZC,OAAO,EAAE,MAAAA,CAAA,KAAY;UACnB,MAAMA,OAAO,CAAC,CAAC;QACjB,CAAC;QACDM,YAAY,EAAEL;MAChB,CAAC,CAAC;IACJ,CAAC,MAAM,IAAI,CAACH,QAAQ,IAAIC,YAAY,KAAK,CAAC,EAAE;MAC1C;MACAM,cAAc,CAAC,KAAK,CAAC;IACvB;EACF,CAAC,EAAE,CAACP,QAAQ,EAAEC,YAAY,EAAEK,WAAW,EAAEJ,OAAO,EAAEC,UAAU,CAAC,CAAC;AAChE","ignoreList":[]}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ import { useSyncExternalStore } from 'react';
4
+ import { OfflineManager } from '../core/OfflineManager';
5
+ const subscribeProgress = listener => OfflineManager.subscribeProgress(listener);
6
+ const getProgressSnapshot = () => OfflineManager.syncProgress;
7
+
8
+ /**
9
+ * Live sync progress tracker.
10
+ * Use this inside a BottomSheet, Modal, or any UI to show per-item sync status.
11
+ *
12
+ * Returns:
13
+ * - isActive: whether a sync session is currently running
14
+ * - totalCount: total items in this sync batch
15
+ * - completedCount: successfully synced so far
16
+ * - failedCount: items that failed
17
+ * - currentAction: the action currently being synced
18
+ * - items: full list with per-item status (pending | syncing | success | failed)
19
+ * - percentage: 0-100 completion percentage
20
+ */
21
+ export function useSyncProgress() {
22
+ const progress = useSyncExternalStore(subscribeProgress, getProgressSnapshot, getProgressSnapshot);
23
+ const percentage = progress.totalCount > 0 ? Math.round((progress.completedCount + progress.failedCount) / progress.totalCount * 100) : 0;
24
+ return {
25
+ ...progress,
26
+ percentage
27
+ };
28
+ }
29
+ //# sourceMappingURL=useSyncProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useSyncExternalStore","OfflineManager","subscribeProgress","listener","getProgressSnapshot","syncProgress","useSyncProgress","progress","percentage","totalCount","Math","round","completedCount","failedCount"],"sourceRoot":"../../../src","sources":["hooks/useSyncProgress.ts"],"mappings":";;AAAA,SAASA,oBAAoB,QAAQ,OAAO;AAC5C,SAASC,cAAc,QAAQ,wBAAwB;AAEvD,MAAMC,iBAAiB,GAAIC,QAAoB,IAAKF,cAAc,CAACC,iBAAiB,CAACC,QAAQ,CAAC;AAC9F,MAAMC,mBAAmB,GAAGA,CAAA,KAAMH,cAAc,CAACI,YAAY;;AAE7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAAA,EAAG;EAChC,MAAMC,QAAQ,GAAGP,oBAAoB,CAACE,iBAAiB,EAAEE,mBAAmB,EAAEA,mBAAmB,CAAC;EAElG,MAAMI,UAAU,GACdD,QAAQ,CAACE,UAAU,GAAG,CAAC,GACnBC,IAAI,CAACC,KAAK,CAAE,CAACJ,QAAQ,CAACK,cAAc,GAAGL,QAAQ,CAACM,WAAW,IAAIN,QAAQ,CAACE,UAAU,GAAI,GAAG,CAAC,GAC1F,CAAC;EAEP,OAAO;IACL,GAAGF,QAAQ;IACXC;EACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ // Core
4
+ export * from './core/types';
5
+ export * from './core/StorageAdapter';
6
+ export { OfflineManager } from './core/OfflineManager';
7
+
8
+ // Adapters
9
+ export { getMMKVAdapter, getAsyncStorageAdapter, getRealmAdapter } from './adapters';
10
+
11
+ // Components
12
+ export * from './components/OfflineProvider';
13
+ export * from './components/OfflineSyncPrompt';
14
+
15
+ // Hooks
16
+ export * from './hooks/useOfflineQueue';
17
+ export * from './hooks/useOfflineMutation';
18
+ export * from './hooks/useOfflineSyncInterceptor';
19
+ export * from './hooks/useSyncProgress';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["OfflineManager","getMMKVAdapter","getAsyncStorageAdapter","getRealmAdapter"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA;AACA,cAAc,cAAc;AAC5B,cAAc,uBAAuB;AACrC,SAASA,cAAc,QAAmC,uBAAuB;;AAEjF;AACA,SAASC,cAAc,EAAEC,sBAAsB,EAAEC,eAAe,QAAkC,YAAY;;AAE9G;AACA,cAAc,8BAA8B;AAC5C,cAAc,gCAAgC;;AAE9C;AACA,cAAc,yBAAyB;AACvC,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC;AACjD,cAAc,yBAAyB","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,12 @@
1
+ import type { StorageAdapter } from '../core/StorageAdapter';
2
+ import type { RecordStorageAdapter } from '../core/StorageAdapter';
3
+ export declare const getMMKVAdapter: () => StorageAdapter;
4
+ export declare const getAsyncStorageAdapter: () => StorageAdapter;
5
+ export interface RealmAdapterOptions {
6
+ /** Pass your existing Realm instance to share it with your app */
7
+ realmInstance?: any;
8
+ /** Custom schema name (default: 'OfflineQueueItem') */
9
+ schemaName?: string;
10
+ }
11
+ export declare const getRealmAdapter: (options?: RealmAdapterOptions) => RecordStorageAdapter;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAKnE,eAAO,MAAM,cAAc,QAAO,cAcjC,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAO,cAazC,CAAC;AAiBF,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,GAAI,UAAU,mBAAmB,KAAG,oBAgF/D,CAAC"}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { type OfflineManagerConfig } from '../core/OfflineManager';
3
+ interface OfflineContextValue {
4
+ isOnline: boolean | null;
5
+ }
6
+ export declare const useNetworkStatus: () => OfflineContextValue;
7
+ export interface OfflineProviderProps {
8
+ children: React.ReactNode;
9
+ config: OfflineManagerConfig;
10
+ }
11
+ export declare const OfflineProvider: React.FC<OfflineProviderProps>;
12
+ export {};
13
+ //# sourceMappingURL=OfflineProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OfflineProvider.d.ts","sourceRoot":"","sources":["../../../src/components/OfflineProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiE,MAAM,OAAO,CAAC;AAEtF,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnF,UAAU,mBAAmB;IACzB,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5B;AAID,eAAO,MAAM,gBAAgB,2BAAmC,CAAC;AAEjE,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,oBAAoB,CAAC;CAChC;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAkC1D,CAAC"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ export interface OfflineSyncPromptProps {
3
+ children: (props: {
4
+ pendingCount: number;
5
+ isSyncing: boolean;
6
+ syncNow: () => Promise<void>;
7
+ cancel: () => Promise<void>;
8
+ }) => React.ReactNode;
9
+ }
10
+ export declare const OfflineSyncPrompt: React.FC<OfflineSyncPromptProps>;
11
+ //# sourceMappingURL=OfflineSyncPrompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OfflineSyncPrompt.d.ts","sourceRoot":"","sources":["../../../src/components/OfflineSyncPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,OAAO,CAAC;QACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;KAC/B,KAAK,KAAK,CAAC,SAAS,CAAC;CACzB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAkB9D,CAAC"}