async-storage-sync 1.0.6 → 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 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
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
 
@@ -89,6 +91,7 @@ console.log(`${pending.length} forms waiting to sync`);
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
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;
@@ -81,6 +82,7 @@ declare class AsyncStorageSync {
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;
@@ -81,6 +82,7 @@ declare class AsyncStorageSync {
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.flushWithResult();
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);
@@ -282,40 +312,48 @@ var SyncEngine = class {
282
312
  }
283
313
  }
284
314
  async flushCollectionWithResult(collectionName) {
285
- const result = {
286
- attempted: 0,
287
- synced: 0,
288
- failed: 0,
289
- retried: 0,
290
- deferred: 0,
291
- networkErrors: 0,
292
- remainingPending: 0,
293
- skippedAlreadyFlushing: false,
294
- items: []
295
- };
296
- const pending = this.queue.getPendingForCollection(collectionName);
297
- if (pending.length === 0) {
298
- result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
299
- return result;
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
+ };
300
327
  }
301
- for (const item of pending) {
302
- result.attempted += 1;
303
- const itemResult = await this.syncItem(item);
304
- result.items.push(itemResult);
305
- if (itemResult.status === "synced") {
306
- result.synced += 1;
307
- } else if (itemResult.status === "failed") {
308
- result.failed += 1;
309
- } else if (itemResult.status === "retried") {
310
- result.retried += 1;
311
- } else if (itemResult.status === "deferred-backoff") {
312
- result.deferred += 1;
313
- } else if (itemResult.status === "network-error") {
314
- result.networkErrors += 1;
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;
315
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;
316
356
  }
317
- result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
318
- return result;
319
357
  }
320
358
  async flushRecord(recordId) {
321
359
  const item = this.queue.getPendingForRecord(recordId);
@@ -501,7 +539,7 @@ var _AsyncStorageSync = class _AsyncStorageSync {
501
539
  console.log("[AsyncStorageSync] autoSync enabled \u2014 starting sync engine");
502
540
  instance.engine.start();
503
541
  } else {
504
- console.log("[AsyncStorageSync] autoSync disabled \u2014 call flush() manually");
542
+ console.log("[AsyncStorageSync] autoSync disabled \u2014 call flushWithResult() or syncWithResult(collection) manually");
505
543
  }
506
544
  _AsyncStorageSync.instance = instance;
507
545
  return instance;
@@ -589,6 +627,9 @@ var _AsyncStorageSync = class _AsyncStorageSync {
589
627
  async syncWithResult(name) {
590
628
  return this.engine.flushCollectionWithResult(name);
591
629
  }
630
+ async syncManyWithResult(names) {
631
+ return this.engine.flushCollectionsWithResult(names);
632
+ }
592
633
  async syncById(_name, id) {
593
634
  await this.engine.flushRecord(id);
594
635
  }
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.flushWithResult();
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);
@@ -260,40 +290,48 @@ var SyncEngine = class {
260
290
  }
261
291
  }
262
292
  async flushCollectionWithResult(collectionName) {
263
- const result = {
264
- attempted: 0,
265
- synced: 0,
266
- failed: 0,
267
- retried: 0,
268
- deferred: 0,
269
- networkErrors: 0,
270
- remainingPending: 0,
271
- skippedAlreadyFlushing: false,
272
- items: []
273
- };
274
- const pending = this.queue.getPendingForCollection(collectionName);
275
- if (pending.length === 0) {
276
- result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
277
- return result;
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
+ };
278
305
  }
279
- for (const item of pending) {
280
- result.attempted += 1;
281
- const itemResult = await this.syncItem(item);
282
- result.items.push(itemResult);
283
- if (itemResult.status === "synced") {
284
- result.synced += 1;
285
- } else if (itemResult.status === "failed") {
286
- result.failed += 1;
287
- } else if (itemResult.status === "retried") {
288
- result.retried += 1;
289
- } else if (itemResult.status === "deferred-backoff") {
290
- result.deferred += 1;
291
- } else if (itemResult.status === "network-error") {
292
- result.networkErrors += 1;
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;
293
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;
294
334
  }
295
- result.remainingPending = this.queue.getPendingForCollection(collectionName).length;
296
- return result;
297
335
  }
298
336
  async flushRecord(recordId) {
299
337
  const item = this.queue.getPendingForRecord(recordId);
@@ -479,7 +517,7 @@ var _AsyncStorageSync = class _AsyncStorageSync {
479
517
  console.log("[AsyncStorageSync] autoSync enabled \u2014 starting sync engine");
480
518
  instance.engine.start();
481
519
  } else {
482
- console.log("[AsyncStorageSync] autoSync disabled \u2014 call flush() manually");
520
+ console.log("[AsyncStorageSync] autoSync disabled \u2014 call flushWithResult() or syncWithResult(collection) manually");
483
521
  }
484
522
  _AsyncStorageSync.instance = instance;
485
523
  return instance;
@@ -567,6 +605,9 @@ var _AsyncStorageSync = class _AsyncStorageSync {
567
605
  async syncWithResult(name) {
568
606
  return this.engine.flushCollectionWithResult(name);
569
607
  }
608
+ async syncManyWithResult(names) {
609
+ return this.engine.flushCollectionsWithResult(names);
610
+ }
570
611
  async syncById(_name, id) {
571
612
  await this.engine.flushRecord(id);
572
613
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "async-storage-sync",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Offline-first data layer for React Native with local-first storage and automatic sync",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",