async-storage-sync 1.0.5 → 1.0.7
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/README.md +6 -2
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +90 -19
- package/dist/index.mjs +90 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,10 +61,12 @@ console.log(`${pending.length} forms waiting to sync`);
|
|
|
61
61
|
|
|
62
62
|
- `autoSync: true` (default): when the app starts, the package checks connectivity and attempts sync if online.
|
|
63
63
|
- `autoSync: true` also listens for reconnect events and retries pending items automatically.
|
|
64
|
+
- `autoSyncCollections` (optional): when set, auto-sync on reconnect targets only those collections.
|
|
64
65
|
- `autoSync: false`: no automatic syncing; call sync methods manually when you choose.
|
|
65
66
|
- Manual methods:
|
|
66
67
|
- `store.flushWithResult()` → sync all pending and return summary counts
|
|
67
|
-
- `store.
|
|
68
|
+
- `store.syncWithResult(collection)` → sync one collection and return summary counts
|
|
69
|
+
- `store.syncManyWithResult(collections)` → sync only selected collections and return merged summary counts
|
|
68
70
|
- `store.syncById(collection, id)` → sync one record
|
|
69
71
|
- Sync destination is controlled by your config: `serverUrl + endpoint`.
|
|
70
72
|
|
|
@@ -88,7 +90,8 @@ console.log(`${pending.length} forms waiting to sync`);
|
|
|
88
90
|
| `store.deleteById(collection, id)` | Delete one record by internal `_id` |
|
|
89
91
|
| `store.deleteCollection(collection)` | Delete all records in one collection |
|
|
90
92
|
| `store.flushWithResult()` | Sync all pending and return detailed summary (`attempted`, `synced`, `failed`, `retried`, `remainingPending`, `items`) |
|
|
91
|
-
| `store.
|
|
93
|
+
| `store.syncWithResult(collection)` | Sync collection and return detailed summary (same format as `flushWithResult()`) |
|
|
94
|
+
| `store.syncManyWithResult(collections)` | Sync selected collections and return one merged summary (same format as `flushWithResult()`) |
|
|
92
95
|
| `store.syncById(collection, id)` | Sync one specific record by internal `_id` |
|
|
93
96
|
| `store.requeueFailed()` | Move `failed` records back to pending queue for retry |
|
|
94
97
|
| `store.onSynced(callback)` | Event callback for successful sync of each item |
|
|
@@ -176,6 +179,7 @@ initSyncQueue({
|
|
|
176
179
|
credentials: Record<string, string>, // (required) merged into request headers
|
|
177
180
|
endpoint?: '/submit', // route to POST data
|
|
178
181
|
autoSync?: false, // auto-sync on reconnect
|
|
182
|
+
autoSyncCollections?: ['invoices', 'payments'], // optional: only these collections auto-sync on reconnect
|
|
179
183
|
onSyncSuccess?: 'keep', // after sync: keep|delete|ttl
|
|
180
184
|
ttl?: 7 * 24 * 60 * 60 * 1000, // if ttl mode, keep duration
|
|
181
185
|
duplicateStrategy?: 'append', // append or overwrite
|
package/dist/index.d.mts
CHANGED
|
@@ -13,6 +13,7 @@ interface InitConfig {
|
|
|
13
13
|
*/
|
|
14
14
|
payloadTransformer?: (record: Record<string, unknown>) => Record<string, unknown>;
|
|
15
15
|
autoSync?: boolean;
|
|
16
|
+
autoSyncCollections?: string[];
|
|
16
17
|
endpoint?: string;
|
|
17
18
|
onSyncSuccess?: OnSyncSuccess;
|
|
18
19
|
ttl?: number;
|
|
@@ -80,7 +81,8 @@ declare class AsyncStorageSync {
|
|
|
80
81
|
getById<T extends Record<string, unknown>>(name: string, id: string): Promise<StoredRecord<T> | null>;
|
|
81
82
|
deleteById(name: string, id: string): Promise<void>;
|
|
82
83
|
deleteCollection(name: string): Promise<void>;
|
|
83
|
-
|
|
84
|
+
syncWithResult(name: string): Promise<FlushResult>;
|
|
85
|
+
syncManyWithResult(names: string[]): Promise<FlushResult>;
|
|
84
86
|
syncById(_name: string, id: string): Promise<void>;
|
|
85
87
|
flushWithResult(): Promise<FlushResult>;
|
|
86
88
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ interface InitConfig {
|
|
|
13
13
|
*/
|
|
14
14
|
payloadTransformer?: (record: Record<string, unknown>) => Record<string, unknown>;
|
|
15
15
|
autoSync?: boolean;
|
|
16
|
+
autoSyncCollections?: string[];
|
|
16
17
|
endpoint?: string;
|
|
17
18
|
onSyncSuccess?: OnSyncSuccess;
|
|
18
19
|
ttl?: number;
|
|
@@ -80,7 +81,8 @@ declare class AsyncStorageSync {
|
|
|
80
81
|
getById<T extends Record<string, unknown>>(name: string, id: string): Promise<StoredRecord<T> | null>;
|
|
81
82
|
deleteById(name: string, id: string): Promise<void>;
|
|
82
83
|
deleteCollection(name: string): Promise<void>;
|
|
83
|
-
|
|
84
|
+
syncWithResult(name: string): Promise<FlushResult>;
|
|
85
|
+
syncManyWithResult(names: string[]): Promise<FlushResult>;
|
|
84
86
|
syncById(_name: string, id: string): Promise<void>;
|
|
85
87
|
flushWithResult(): Promise<FlushResult>;
|
|
86
88
|
/**
|
package/dist/index.js
CHANGED
|
@@ -221,9 +221,49 @@ var SyncEngine = class {
|
|
|
221
221
|
clearTimeout(this.debounceTimer);
|
|
222
222
|
}
|
|
223
223
|
this.debounceTimer = setTimeout(() => {
|
|
224
|
-
void this.
|
|
224
|
+
void this.flushAutoSyncTargetWithResult();
|
|
225
225
|
}, DEBOUNCE_MS);
|
|
226
226
|
}
|
|
227
|
+
async flushAutoSyncTargetWithResult() {
|
|
228
|
+
const configuredCollections = this.config.autoSyncCollections?.map((name) => name.trim()).filter((name) => name.length > 0);
|
|
229
|
+
if (!configuredCollections || configuredCollections.length === 0) {
|
|
230
|
+
return this.flushWithResult();
|
|
231
|
+
}
|
|
232
|
+
return this.flushCollectionsWithResult(configuredCollections);
|
|
233
|
+
}
|
|
234
|
+
createEmptyResult() {
|
|
235
|
+
return {
|
|
236
|
+
attempted: 0,
|
|
237
|
+
synced: 0,
|
|
238
|
+
failed: 0,
|
|
239
|
+
retried: 0,
|
|
240
|
+
deferred: 0,
|
|
241
|
+
networkErrors: 0,
|
|
242
|
+
remainingPending: 0,
|
|
243
|
+
skippedAlreadyFlushing: false,
|
|
244
|
+
items: []
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
mergeResult(target, source) {
|
|
248
|
+
target.attempted += source.attempted;
|
|
249
|
+
target.synced += source.synced;
|
|
250
|
+
target.failed += source.failed;
|
|
251
|
+
target.retried += source.retried;
|
|
252
|
+
target.deferred += source.deferred;
|
|
253
|
+
target.networkErrors += source.networkErrors;
|
|
254
|
+
target.items.push(...source.items);
|
|
255
|
+
target.remainingPending = source.remainingPending;
|
|
256
|
+
target.skippedAlreadyFlushing = target.skippedAlreadyFlushing || source.skippedAlreadyFlushing;
|
|
257
|
+
}
|
|
258
|
+
async flushCollectionsWithResult(collectionNames) {
|
|
259
|
+
const result = this.createEmptyResult();
|
|
260
|
+
for (const collectionName of collectionNames) {
|
|
261
|
+
const collectionResult = await this.flushCollectionWithResult(collectionName);
|
|
262
|
+
this.mergeResult(result, collectionResult);
|
|
263
|
+
}
|
|
264
|
+
result.remainingPending = this.queue.getPending().length;
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
227
267
|
async flushWithResult() {
|
|
228
268
|
if (this.isFlushing) {
|
|
229
269
|
console.log("[SyncEngine] flush() skipped \u2014 already flushing");
|
|
@@ -240,17 +280,7 @@ var SyncEngine = class {
|
|
|
240
280
|
};
|
|
241
281
|
}
|
|
242
282
|
this.isFlushing = true;
|
|
243
|
-
const result =
|
|
244
|
-
attempted: 0,
|
|
245
|
-
synced: 0,
|
|
246
|
-
failed: 0,
|
|
247
|
-
retried: 0,
|
|
248
|
-
deferred: 0,
|
|
249
|
-
networkErrors: 0,
|
|
250
|
-
remainingPending: 0,
|
|
251
|
-
skippedAlreadyFlushing: false,
|
|
252
|
-
items: []
|
|
253
|
-
};
|
|
283
|
+
const result = this.createEmptyResult();
|
|
254
284
|
try {
|
|
255
285
|
const pending = this.queue.getPending();
|
|
256
286
|
console.log("[SyncEngine] flush() \u2014 pending items:", pending.length);
|
|
@@ -281,10 +311,48 @@ var SyncEngine = class {
|
|
|
281
311
|
this.isFlushing = false;
|
|
282
312
|
}
|
|
283
313
|
}
|
|
284
|
-
async
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
314
|
+
async flushCollectionWithResult(collectionName) {
|
|
315
|
+
if (this.isFlushing) {
|
|
316
|
+
return {
|
|
317
|
+
attempted: 0,
|
|
318
|
+
synced: 0,
|
|
319
|
+
failed: 0,
|
|
320
|
+
retried: 0,
|
|
321
|
+
deferred: 0,
|
|
322
|
+
networkErrors: 0,
|
|
323
|
+
remainingPending: this.queue.getPendingForCollection(collectionName).length,
|
|
324
|
+
skippedAlreadyFlushing: true,
|
|
325
|
+
items: []
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
this.isFlushing = true;
|
|
329
|
+
const result = this.createEmptyResult();
|
|
330
|
+
try {
|
|
331
|
+
const pending = this.queue.getPendingForCollection(collectionName);
|
|
332
|
+
if (pending.length === 0) {
|
|
333
|
+
result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
336
|
+
for (const item of pending) {
|
|
337
|
+
result.attempted += 1;
|
|
338
|
+
const itemResult = await this.syncItem(item);
|
|
339
|
+
result.items.push(itemResult);
|
|
340
|
+
if (itemResult.status === "synced") {
|
|
341
|
+
result.synced += 1;
|
|
342
|
+
} else if (itemResult.status === "failed") {
|
|
343
|
+
result.failed += 1;
|
|
344
|
+
} else if (itemResult.status === "retried") {
|
|
345
|
+
result.retried += 1;
|
|
346
|
+
} else if (itemResult.status === "deferred-backoff") {
|
|
347
|
+
result.deferred += 1;
|
|
348
|
+
} else if (itemResult.status === "network-error") {
|
|
349
|
+
result.networkErrors += 1;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
|
|
353
|
+
return result;
|
|
354
|
+
} finally {
|
|
355
|
+
this.isFlushing = false;
|
|
288
356
|
}
|
|
289
357
|
}
|
|
290
358
|
async flushRecord(recordId) {
|
|
@@ -471,7 +539,7 @@ var _AsyncStorageSync = class _AsyncStorageSync {
|
|
|
471
539
|
console.log("[AsyncStorageSync] autoSync enabled \u2014 starting sync engine");
|
|
472
540
|
instance.engine.start();
|
|
473
541
|
} else {
|
|
474
|
-
console.log("[AsyncStorageSync] autoSync disabled \u2014 call
|
|
542
|
+
console.log("[AsyncStorageSync] autoSync disabled \u2014 call flushWithResult() or syncWithResult(collection) manually");
|
|
475
543
|
}
|
|
476
544
|
_AsyncStorageSync.instance = instance;
|
|
477
545
|
return instance;
|
|
@@ -556,8 +624,11 @@ var _AsyncStorageSync = class _AsyncStorageSync {
|
|
|
556
624
|
async deleteCollection(name) {
|
|
557
625
|
await this.driver.remove(collectionKey(name));
|
|
558
626
|
}
|
|
559
|
-
async
|
|
560
|
-
|
|
627
|
+
async syncWithResult(name) {
|
|
628
|
+
return this.engine.flushCollectionWithResult(name);
|
|
629
|
+
}
|
|
630
|
+
async syncManyWithResult(names) {
|
|
631
|
+
return this.engine.flushCollectionsWithResult(names);
|
|
561
632
|
}
|
|
562
633
|
async syncById(_name, id) {
|
|
563
634
|
await this.engine.flushRecord(id);
|
package/dist/index.mjs
CHANGED
|
@@ -199,9 +199,49 @@ var SyncEngine = class {
|
|
|
199
199
|
clearTimeout(this.debounceTimer);
|
|
200
200
|
}
|
|
201
201
|
this.debounceTimer = setTimeout(() => {
|
|
202
|
-
void this.
|
|
202
|
+
void this.flushAutoSyncTargetWithResult();
|
|
203
203
|
}, DEBOUNCE_MS);
|
|
204
204
|
}
|
|
205
|
+
async flushAutoSyncTargetWithResult() {
|
|
206
|
+
const configuredCollections = this.config.autoSyncCollections?.map((name) => name.trim()).filter((name) => name.length > 0);
|
|
207
|
+
if (!configuredCollections || configuredCollections.length === 0) {
|
|
208
|
+
return this.flushWithResult();
|
|
209
|
+
}
|
|
210
|
+
return this.flushCollectionsWithResult(configuredCollections);
|
|
211
|
+
}
|
|
212
|
+
createEmptyResult() {
|
|
213
|
+
return {
|
|
214
|
+
attempted: 0,
|
|
215
|
+
synced: 0,
|
|
216
|
+
failed: 0,
|
|
217
|
+
retried: 0,
|
|
218
|
+
deferred: 0,
|
|
219
|
+
networkErrors: 0,
|
|
220
|
+
remainingPending: 0,
|
|
221
|
+
skippedAlreadyFlushing: false,
|
|
222
|
+
items: []
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
mergeResult(target, source) {
|
|
226
|
+
target.attempted += source.attempted;
|
|
227
|
+
target.synced += source.synced;
|
|
228
|
+
target.failed += source.failed;
|
|
229
|
+
target.retried += source.retried;
|
|
230
|
+
target.deferred += source.deferred;
|
|
231
|
+
target.networkErrors += source.networkErrors;
|
|
232
|
+
target.items.push(...source.items);
|
|
233
|
+
target.remainingPending = source.remainingPending;
|
|
234
|
+
target.skippedAlreadyFlushing = target.skippedAlreadyFlushing || source.skippedAlreadyFlushing;
|
|
235
|
+
}
|
|
236
|
+
async flushCollectionsWithResult(collectionNames) {
|
|
237
|
+
const result = this.createEmptyResult();
|
|
238
|
+
for (const collectionName of collectionNames) {
|
|
239
|
+
const collectionResult = await this.flushCollectionWithResult(collectionName);
|
|
240
|
+
this.mergeResult(result, collectionResult);
|
|
241
|
+
}
|
|
242
|
+
result.remainingPending = this.queue.getPending().length;
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
205
245
|
async flushWithResult() {
|
|
206
246
|
if (this.isFlushing) {
|
|
207
247
|
console.log("[SyncEngine] flush() skipped \u2014 already flushing");
|
|
@@ -218,17 +258,7 @@ var SyncEngine = class {
|
|
|
218
258
|
};
|
|
219
259
|
}
|
|
220
260
|
this.isFlushing = true;
|
|
221
|
-
const result =
|
|
222
|
-
attempted: 0,
|
|
223
|
-
synced: 0,
|
|
224
|
-
failed: 0,
|
|
225
|
-
retried: 0,
|
|
226
|
-
deferred: 0,
|
|
227
|
-
networkErrors: 0,
|
|
228
|
-
remainingPending: 0,
|
|
229
|
-
skippedAlreadyFlushing: false,
|
|
230
|
-
items: []
|
|
231
|
-
};
|
|
261
|
+
const result = this.createEmptyResult();
|
|
232
262
|
try {
|
|
233
263
|
const pending = this.queue.getPending();
|
|
234
264
|
console.log("[SyncEngine] flush() \u2014 pending items:", pending.length);
|
|
@@ -259,10 +289,48 @@ var SyncEngine = class {
|
|
|
259
289
|
this.isFlushing = false;
|
|
260
290
|
}
|
|
261
291
|
}
|
|
262
|
-
async
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
292
|
+
async flushCollectionWithResult(collectionName) {
|
|
293
|
+
if (this.isFlushing) {
|
|
294
|
+
return {
|
|
295
|
+
attempted: 0,
|
|
296
|
+
synced: 0,
|
|
297
|
+
failed: 0,
|
|
298
|
+
retried: 0,
|
|
299
|
+
deferred: 0,
|
|
300
|
+
networkErrors: 0,
|
|
301
|
+
remainingPending: this.queue.getPendingForCollection(collectionName).length,
|
|
302
|
+
skippedAlreadyFlushing: true,
|
|
303
|
+
items: []
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
this.isFlushing = true;
|
|
307
|
+
const result = this.createEmptyResult();
|
|
308
|
+
try {
|
|
309
|
+
const pending = this.queue.getPendingForCollection(collectionName);
|
|
310
|
+
if (pending.length === 0) {
|
|
311
|
+
result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
for (const item of pending) {
|
|
315
|
+
result.attempted += 1;
|
|
316
|
+
const itemResult = await this.syncItem(item);
|
|
317
|
+
result.items.push(itemResult);
|
|
318
|
+
if (itemResult.status === "synced") {
|
|
319
|
+
result.synced += 1;
|
|
320
|
+
} else if (itemResult.status === "failed") {
|
|
321
|
+
result.failed += 1;
|
|
322
|
+
} else if (itemResult.status === "retried") {
|
|
323
|
+
result.retried += 1;
|
|
324
|
+
} else if (itemResult.status === "deferred-backoff") {
|
|
325
|
+
result.deferred += 1;
|
|
326
|
+
} else if (itemResult.status === "network-error") {
|
|
327
|
+
result.networkErrors += 1;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
|
|
331
|
+
return result;
|
|
332
|
+
} finally {
|
|
333
|
+
this.isFlushing = false;
|
|
266
334
|
}
|
|
267
335
|
}
|
|
268
336
|
async flushRecord(recordId) {
|
|
@@ -449,7 +517,7 @@ var _AsyncStorageSync = class _AsyncStorageSync {
|
|
|
449
517
|
console.log("[AsyncStorageSync] autoSync enabled \u2014 starting sync engine");
|
|
450
518
|
instance.engine.start();
|
|
451
519
|
} else {
|
|
452
|
-
console.log("[AsyncStorageSync] autoSync disabled \u2014 call
|
|
520
|
+
console.log("[AsyncStorageSync] autoSync disabled \u2014 call flushWithResult() or syncWithResult(collection) manually");
|
|
453
521
|
}
|
|
454
522
|
_AsyncStorageSync.instance = instance;
|
|
455
523
|
return instance;
|
|
@@ -534,8 +602,11 @@ var _AsyncStorageSync = class _AsyncStorageSync {
|
|
|
534
602
|
async deleteCollection(name) {
|
|
535
603
|
await this.driver.remove(collectionKey(name));
|
|
536
604
|
}
|
|
537
|
-
async
|
|
538
|
-
|
|
605
|
+
async syncWithResult(name) {
|
|
606
|
+
return this.engine.flushCollectionWithResult(name);
|
|
607
|
+
}
|
|
608
|
+
async syncManyWithResult(names) {
|
|
609
|
+
return this.engine.flushCollectionsWithResult(names);
|
|
539
610
|
}
|
|
540
611
|
async syncById(_name, id) {
|
|
541
612
|
await this.engine.flushRecord(id);
|
package/package.json
CHANGED