cry-synced-db-client 0.1.104 → 0.1.106

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/index.js CHANGED
@@ -2348,7 +2348,7 @@ var _SyncEngine = class _SyncEngine {
2348
2348
  let sentCount = 0;
2349
2349
  let conflictsResolved = 0;
2350
2350
  const collectionStats = {};
2351
- this.callOnSyncStart({ calledFrom });
2351
+ this.callOnSyncStart({ calledFrom, initialSync: false });
2352
2352
  try {
2353
2353
  this.deps.cancelRestUploadTimer();
2354
2354
  await this.deps.awaitRestUpload();
@@ -3360,6 +3360,7 @@ var SyncedDb = class _SyncedDb {
3360
3360
  this.onSyncEnd = config.onSyncEnd;
3361
3361
  this.onDexieSyncStart = config.onDexieSyncStart;
3362
3362
  this.onDexieSyncEnd = config.onDexieSyncEnd;
3363
+ this.onSyncProgress = config.onSyncProgress;
3363
3364
  this.onServerSyncStart = config.onServerSyncStart;
3364
3365
  this.onServerSyncEnd = config.onServerSyncEnd;
3365
3366
  this.onConflictResolved = config.onConflictResolved;
@@ -3475,7 +3476,7 @@ var SyncedDb = class _SyncedDb {
3475
3476
  dexieDb: this.dexieDb,
3476
3477
  restInterface: this.restInterface,
3477
3478
  callbacks: {
3478
- onSyncStart: config.onSyncStart,
3479
+ onSyncStart: config.onSyncStart ? (info) => config.onSyncStart(__spreadProps(__spreadValues({}, info), { initialSync: !this._lastFullSyncDate })) : void 0,
3479
3480
  onSyncEnd: config.onSyncEnd,
3480
3481
  onServerSyncStart: config.onServerSyncStart,
3481
3482
  onServerSyncEnd: config.onServerSyncEnd,
@@ -3583,11 +3584,15 @@ var SyncedDb = class _SyncedDb {
3583
3584
  }
3584
3585
  if (newlyAllowed.length > 0) {
3585
3586
  const dexieStart = Date.now();
3587
+ let totalItems = 0;
3586
3588
  this.safeCallback(this.onDexieSyncStart, { calledFrom: "setSyncOnlyTheseCollections", collectionCount: newlyAllowed.length });
3587
- for (const name of newlyAllowed) {
3588
- await this.loadCollectionToInMem(name);
3589
+ for (let i = 0; i < newlyAllowed.length; i++) {
3590
+ const name = newlyAllowed[i];
3591
+ const items = await this.loadCollectionToInMem(name);
3592
+ totalItems += items;
3593
+ this.safeCallback(this.onSyncProgress, { collection: name, loaded: i + 1, total: newlyAllowed.length, items });
3589
3594
  }
3590
- this.safeCallback(this.onDexieSyncEnd, { calledFrom: "setSyncOnlyTheseCollections", collectionCount: newlyAllowed.length, durationMs: Date.now() - dexieStart });
3595
+ this.safeCallback(this.onDexieSyncEnd, { calledFrom: "setSyncOnlyTheseCollections", collectionCount: newlyAllowed.length, totalItems, durationMs: Date.now() - dexieStart });
3591
3596
  }
3592
3597
  if (newlyAllowed.length > 0 && this.connectionManager.canSync()) {
3593
3598
  this.sync("setSyncOnlyTheseCollections").catch(() => {
@@ -3623,14 +3628,19 @@ var SyncedDb = class _SyncedDb {
3623
3628
  "BroadcastChannel API is not available. Cross-tab synchronization disabled."
3624
3629
  );
3625
3630
  }
3631
+ await this._loadLastFullSync();
3626
3632
  await this.pendingChanges.recoverPendingWrites();
3627
3633
  const allowedColls = [...this.collections.keys()].filter((n) => this.isSyncAllowed(n));
3628
3634
  const dexieStart = Date.now();
3635
+ let totalItems = 0;
3629
3636
  this.safeCallback(this.onDexieSyncStart, { calledFrom: "init", collectionCount: allowedColls.length });
3630
- for (const name of allowedColls) {
3631
- await this.loadCollectionToInMem(name);
3637
+ for (let i = 0; i < allowedColls.length; i++) {
3638
+ const name = allowedColls[i];
3639
+ const items = await this.loadCollectionToInMem(name);
3640
+ totalItems += items;
3641
+ this.safeCallback(this.onSyncProgress, { collection: name, loaded: i + 1, total: allowedColls.length, items });
3632
3642
  }
3633
- this.safeCallback(this.onDexieSyncEnd, { calledFrom: "init", collectionCount: allowedColls.length, durationMs: Date.now() - dexieStart });
3643
+ this.safeCallback(this.onDexieSyncEnd, { calledFrom: "init", collectionCount: allowedColls.length, totalItems, durationMs: Date.now() - dexieStart });
3634
3644
  this.leaderElection.init();
3635
3645
  this.crossTabSync.init();
3636
3646
  (_a = this.wakeSync) == null ? void 0 : _a.init();
@@ -3675,6 +3685,40 @@ var SyncedDb = class _SyncedDb {
3675
3685
  }
3676
3686
  this.initialized = true;
3677
3687
  }
3688
+ /**
3689
+ * Flush all debounced pending writes to Dexie.
3690
+ * Resolves when all data is persisted to IndexedDB.
3691
+ * Does NOT upload to server — call sync() for that.
3692
+ */
3693
+ async flush() {
3694
+ await this.pendingChanges.flushAll();
3695
+ }
3696
+ /**
3697
+ * Returns when all collections were last successfully synced
3698
+ * from the server, or undefined if never.
3699
+ * Value is persisted in Dexie and survives page reload.
3700
+ * Only set when syncOnlyCollections is null (all collections active).
3701
+ * Cleared on dropDatabase.
3702
+ */
3703
+ lastSuccessfulServerSync() {
3704
+ return this._lastFullSyncDate;
3705
+ }
3706
+ /** @internal Update after successful full sync */
3707
+ async _setLastFullSync(date) {
3708
+ this._lastFullSyncDate = date;
3709
+ await this.dexieDb.setSyncMeta("__lastFullSync", date.toISOString());
3710
+ }
3711
+ /** @internal Load cached value from Dexie */
3712
+ async _loadLastFullSync() {
3713
+ const meta = await this.dexieDb.getSyncMeta("__lastFullSync");
3714
+ if (meta == null ? void 0 : meta.lastSyncTs) {
3715
+ this._lastFullSyncDate = new Date(meta.lastSyncTs);
3716
+ }
3717
+ }
3718
+ /** @internal Clear on dropDatabase */
3719
+ _clearLastFullSync() {
3720
+ this._lastFullSyncDate = void 0;
3721
+ }
3678
3722
  async close() {
3679
3723
  var _a, _b;
3680
3724
  this.leaderElection.setClosing(true);
@@ -4176,6 +4220,12 @@ var SyncedDb = class _SyncedDb {
4176
4220
  this.syncing = true;
4177
4221
  try {
4178
4222
  await this.syncEngine.sync(calledFrom);
4223
+ if (!this.syncOnlyCollections) {
4224
+ const now = /* @__PURE__ */ new Date();
4225
+ this._setLastFullSync(now).catch((err) => {
4226
+ console.error("Failed to persist lastFullSync:", err);
4227
+ });
4228
+ }
4179
4229
  } finally {
4180
4230
  this.syncing = false;
4181
4231
  this.syncLock = false;
@@ -4317,6 +4367,7 @@ var SyncedDb = class _SyncedDb {
4317
4367
  await this.dexieDb.clearDirtyChanges(collectionName);
4318
4368
  }
4319
4369
  this.syncMetaCache.clear();
4370
+ this._clearLastFullSync();
4320
4371
  }
4321
4372
  // ==================== Object Metadata ====================
4322
4373
  getObjectMetadata(collection, _id) {
@@ -4406,6 +4457,7 @@ var SyncedDb = class _SyncedDb {
4406
4457
  if (meta) {
4407
4458
  this.syncMetaCache.set(name, meta);
4408
4459
  }
4460
+ return allItems.length;
4409
4461
  }
4410
4462
  assertCollection(name) {
4411
4463
  if (!this.collections.has(name)) {
@@ -41,6 +41,7 @@ export declare class SyncedDb implements I_SyncedDb {
41
41
  private readonly onSyncEnd?;
42
42
  private readonly onDexieSyncStart?;
43
43
  private readonly onDexieSyncEnd?;
44
+ private readonly onSyncProgress?;
44
45
  private readonly onServerSyncStart?;
45
46
  private readonly onServerSyncEnd?;
46
47
  private readonly onConflictResolved?;
@@ -70,6 +71,27 @@ export declare class SyncedDb implements I_SyncedDb {
70
71
  */
71
72
  simulateExternalBroadcast(payload: MetaUpdateBroadcast): void;
72
73
  init(): Promise<void>;
74
+ /**
75
+ * Flush all debounced pending writes to Dexie.
76
+ * Resolves when all data is persisted to IndexedDB.
77
+ * Does NOT upload to server — call sync() for that.
78
+ */
79
+ flush(): Promise<void>;
80
+ private _lastFullSyncDate?;
81
+ /**
82
+ * Returns when all collections were last successfully synced
83
+ * from the server, or undefined if never.
84
+ * Value is persisted in Dexie and survives page reload.
85
+ * Only set when syncOnlyCollections is null (all collections active).
86
+ * Cleared on dropDatabase.
87
+ */
88
+ lastSuccessfulServerSync(): Date | undefined;
89
+ /** @internal Update after successful full sync */
90
+ _setLastFullSync(date: Date): Promise<void>;
91
+ /** @internal Load cached value from Dexie */
92
+ private _loadLastFullSync;
93
+ /** @internal Clear on dropDatabase */
94
+ private _clearLastFullSync;
73
95
  close(): Promise<void>;
74
96
  isOnline(): boolean;
75
97
  forceOffline(forced: boolean): void;
@@ -210,6 +210,7 @@ export interface I_InMemManager {
210
210
  export interface SyncEngineCallbacks {
211
211
  onSyncStart?: (info: {
212
212
  calledFrom?: string;
213
+ initialSync: boolean;
213
214
  }) => void;
214
215
  onSyncEnd?: (info: SyncInfo) => void;
215
216
  onServerSyncStart?: (info: {
@@ -293,9 +293,10 @@ export interface SyncedDbConfig {
293
293
  debounceRestWritesMs?: number;
294
294
  /** Callback ki se pokliče, ko SyncedDb sam preide v offline stanje (npr. ob sync napaki) */
295
295
  onForcedOffline?: (reason: string) => void;
296
- /** Callback at the start of each sync cycle */
296
+ /** Callback at the start of each sync cycle. initialSync=true if no full sync has completed yet. */
297
297
  onSyncStart?: (info: {
298
298
  calledFrom?: string;
299
+ initialSync: boolean;
299
300
  }) => void;
300
301
  /** Callback at the end of each sync cycle */
301
302
  onSyncEnd?: (info: SyncInfo) => void;
@@ -308,8 +309,16 @@ export interface SyncedDbConfig {
308
309
  onDexieSyncEnd?: (info: {
309
310
  calledFrom?: string;
310
311
  collectionCount: number;
312
+ totalItems: number;
311
313
  durationMs: number;
312
314
  }) => void;
315
+ /** Callback after each collection is loaded during full sync (Dexie→inMem). Fires only during init/setSyncOnlyTheseCollections. */
316
+ onSyncProgress?: (info: {
317
+ collection: string;
318
+ loaded: number;
319
+ total: number;
320
+ items: number;
321
+ }) => void;
313
322
  /** Callback when server download starts (findNewerManyStream) */
314
323
  onServerSyncStart?: (info: {
315
324
  calledFrom?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cry-synced-db-client",
3
- "version": "0.1.104",
3
+ "version": "0.1.106",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",