cry-synced-db-client 0.1.102 → 0.1.105
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,6 +2348,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2348
2348
|
let sentCount = 0;
|
|
2349
2349
|
let conflictsResolved = 0;
|
|
2350
2350
|
const collectionStats = {};
|
|
2351
|
+
this.callOnSyncStart({ calledFrom, initialSync: false });
|
|
2351
2352
|
try {
|
|
2352
2353
|
this.deps.cancelRestUploadTimer();
|
|
2353
2354
|
await this.deps.awaitRestUpload();
|
|
@@ -2373,6 +2374,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2373
2374
|
configMap.set(collectionName, config);
|
|
2374
2375
|
}
|
|
2375
2376
|
this.callOnFindNewerManyCall(syncSpecs, calledFrom);
|
|
2377
|
+
this.callbackSafe(this.callbacks.onServerSyncStart, { calledFrom, collectionCount: syncSpecs.length });
|
|
2376
2378
|
const findNewerManyStartTime = Date.now();
|
|
2377
2379
|
const collectionState = /* @__PURE__ */ new Map();
|
|
2378
2380
|
for (const [name] of configMap) {
|
|
@@ -2414,8 +2416,22 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2414
2416
|
};
|
|
2415
2417
|
}
|
|
2416
2418
|
this.callOnFindNewerManyResult(syncSpecs, {}, findNewerManyStartTime, true, calledFrom);
|
|
2419
|
+
this.callbackSafe(this.callbacks.onServerSyncEnd, {
|
|
2420
|
+
calledFrom,
|
|
2421
|
+
collectionCount: syncSpecs.length,
|
|
2422
|
+
receivedCount,
|
|
2423
|
+
durationMs: Date.now() - findNewerManyStartTime,
|
|
2424
|
+
success: true
|
|
2425
|
+
});
|
|
2417
2426
|
} catch (err) {
|
|
2418
2427
|
this.callOnFindNewerManyResult(syncSpecs, {}, findNewerManyStartTime, false, calledFrom, err);
|
|
2428
|
+
this.callbackSafe(this.callbacks.onServerSyncEnd, {
|
|
2429
|
+
calledFrom,
|
|
2430
|
+
collectionCount: syncSpecs.length,
|
|
2431
|
+
receivedCount,
|
|
2432
|
+
durationMs: Date.now() - findNewerManyStartTime,
|
|
2433
|
+
success: false
|
|
2434
|
+
});
|
|
2419
2435
|
throw err;
|
|
2420
2436
|
}
|
|
2421
2437
|
const uploadStats = await this.uploadDirtyItems(calledFrom);
|
|
@@ -2430,7 +2446,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2430
2446
|
};
|
|
2431
2447
|
}
|
|
2432
2448
|
}
|
|
2433
|
-
this.
|
|
2449
|
+
this.callOnSyncEnd({
|
|
2434
2450
|
durationMs: Date.now() - startTime,
|
|
2435
2451
|
receivedCount,
|
|
2436
2452
|
sentCount,
|
|
@@ -2443,7 +2459,7 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2443
2459
|
const reason = err instanceof Error ? err.message : String(err);
|
|
2444
2460
|
console.error("Sync failed, going offline:", err);
|
|
2445
2461
|
this.deps.goOffline(`Sync failed: ${reason}`);
|
|
2446
|
-
this.
|
|
2462
|
+
this.callOnSyncEnd({
|
|
2447
2463
|
durationMs: Date.now() - startTime,
|
|
2448
2464
|
receivedCount,
|
|
2449
2465
|
sentCount,
|
|
@@ -2798,12 +2814,31 @@ var _SyncEngine = class _SyncEngine {
|
|
|
2798
2814
|
// ============================================================
|
|
2799
2815
|
// Callback Wrappers
|
|
2800
2816
|
// ============================================================
|
|
2801
|
-
|
|
2802
|
-
|
|
2817
|
+
/** Safe callback invocation — swallows errors */
|
|
2818
|
+
callbackSafe(fn, info) {
|
|
2819
|
+
if (fn) {
|
|
2803
2820
|
try {
|
|
2804
|
-
|
|
2821
|
+
fn(info);
|
|
2805
2822
|
} catch (err) {
|
|
2806
|
-
console.error("
|
|
2823
|
+
console.error("Callback failed:", err);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
callOnSyncStart(info) {
|
|
2828
|
+
if (this.callbacks.onSyncStart) {
|
|
2829
|
+
try {
|
|
2830
|
+
this.callbacks.onSyncStart(info);
|
|
2831
|
+
} catch (err) {
|
|
2832
|
+
console.error("onSyncStart callback failed:", err);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
callOnSyncEnd(info) {
|
|
2837
|
+
if (this.callbacks.onSyncEnd) {
|
|
2838
|
+
try {
|
|
2839
|
+
this.callbacks.onSyncEnd(info);
|
|
2840
|
+
} catch (err) {
|
|
2841
|
+
console.error("onSyncEnd callback failed:", err);
|
|
2807
2842
|
}
|
|
2808
2843
|
}
|
|
2809
2844
|
}
|
|
@@ -3321,7 +3356,12 @@ var SyncedDb = class _SyncedDb {
|
|
|
3321
3356
|
const windowId = (_a = config._testWindowId) != null ? _a : this.getOrCreateWindowId();
|
|
3322
3357
|
this.defaultReturnDeleted = (_b = config.returnDeleted) != null ? _b : false;
|
|
3323
3358
|
this.defaultReturnArchived = (_c = config.returnArchived) != null ? _c : false;
|
|
3324
|
-
this.
|
|
3359
|
+
this.onSyncStart = config.onSyncStart;
|
|
3360
|
+
this.onSyncEnd = config.onSyncEnd;
|
|
3361
|
+
this.onDexieSyncStart = config.onDexieSyncStart;
|
|
3362
|
+
this.onDexieSyncEnd = config.onDexieSyncEnd;
|
|
3363
|
+
this.onServerSyncStart = config.onServerSyncStart;
|
|
3364
|
+
this.onServerSyncEnd = config.onServerSyncEnd;
|
|
3325
3365
|
this.onConflictResolved = config.onConflictResolved;
|
|
3326
3366
|
this.onWsNotification = config.onWsNotification;
|
|
3327
3367
|
this.onCrossTabSync = config.onCrossTabSync;
|
|
@@ -3435,7 +3475,10 @@ var SyncedDb = class _SyncedDb {
|
|
|
3435
3475
|
dexieDb: this.dexieDb,
|
|
3436
3476
|
restInterface: this.restInterface,
|
|
3437
3477
|
callbacks: {
|
|
3438
|
-
|
|
3478
|
+
onSyncStart: config.onSyncStart ? (info) => config.onSyncStart(__spreadProps(__spreadValues({}, info), { initialSync: !this._lastFullSyncDate })) : void 0,
|
|
3479
|
+
onSyncEnd: config.onSyncEnd,
|
|
3480
|
+
onServerSyncStart: config.onServerSyncStart,
|
|
3481
|
+
onServerSyncEnd: config.onServerSyncEnd,
|
|
3439
3482
|
onConflictResolved: config.onConflictResolved,
|
|
3440
3483
|
onServerWriteRequest: config.onServerWriteRequest,
|
|
3441
3484
|
onServerWriteResult: config.onServerWriteResult,
|
|
@@ -3538,8 +3581,14 @@ var SyncedDb = class _SyncedDb {
|
|
|
3538
3581
|
newlyAllowed.push(name);
|
|
3539
3582
|
}
|
|
3540
3583
|
}
|
|
3541
|
-
|
|
3542
|
-
|
|
3584
|
+
if (newlyAllowed.length > 0) {
|
|
3585
|
+
const dexieStart = Date.now();
|
|
3586
|
+
let totalItems = 0;
|
|
3587
|
+
this.safeCallback(this.onDexieSyncStart, { calledFrom: "setSyncOnlyTheseCollections", collectionCount: newlyAllowed.length });
|
|
3588
|
+
for (const name of newlyAllowed) {
|
|
3589
|
+
totalItems += await this.loadCollectionToInMem(name);
|
|
3590
|
+
}
|
|
3591
|
+
this.safeCallback(this.onDexieSyncEnd, { calledFrom: "setSyncOnlyTheseCollections", collectionCount: newlyAllowed.length, totalItems, durationMs: Date.now() - dexieStart });
|
|
3543
3592
|
}
|
|
3544
3593
|
if (newlyAllowed.length > 0 && this.connectionManager.canSync()) {
|
|
3545
3594
|
this.sync("setSyncOnlyTheseCollections").catch(() => {
|
|
@@ -3575,11 +3624,16 @@ var SyncedDb = class _SyncedDb {
|
|
|
3575
3624
|
"BroadcastChannel API is not available. Cross-tab synchronization disabled."
|
|
3576
3625
|
);
|
|
3577
3626
|
}
|
|
3627
|
+
await this._loadLastFullSync();
|
|
3578
3628
|
await this.pendingChanges.recoverPendingWrites();
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
}
|
|
3629
|
+
const allowedColls = [...this.collections.keys()].filter((n) => this.isSyncAllowed(n));
|
|
3630
|
+
const dexieStart = Date.now();
|
|
3631
|
+
let totalItems = 0;
|
|
3632
|
+
this.safeCallback(this.onDexieSyncStart, { calledFrom: "init", collectionCount: allowedColls.length });
|
|
3633
|
+
for (const name of allowedColls) {
|
|
3634
|
+
totalItems += await this.loadCollectionToInMem(name);
|
|
3635
|
+
}
|
|
3636
|
+
this.safeCallback(this.onDexieSyncEnd, { calledFrom: "init", collectionCount: allowedColls.length, totalItems, durationMs: Date.now() - dexieStart });
|
|
3583
3637
|
this.leaderElection.init();
|
|
3584
3638
|
this.crossTabSync.init();
|
|
3585
3639
|
(_a = this.wakeSync) == null ? void 0 : _a.init();
|
|
@@ -3624,6 +3678,40 @@ var SyncedDb = class _SyncedDb {
|
|
|
3624
3678
|
}
|
|
3625
3679
|
this.initialized = true;
|
|
3626
3680
|
}
|
|
3681
|
+
/**
|
|
3682
|
+
* Flush all debounced pending writes to Dexie.
|
|
3683
|
+
* Resolves when all data is persisted to IndexedDB.
|
|
3684
|
+
* Does NOT upload to server — call sync() for that.
|
|
3685
|
+
*/
|
|
3686
|
+
async flush() {
|
|
3687
|
+
await this.pendingChanges.flushAll();
|
|
3688
|
+
}
|
|
3689
|
+
/**
|
|
3690
|
+
* Returns when all collections were last successfully synced
|
|
3691
|
+
* from the server, or undefined if never.
|
|
3692
|
+
* Value is persisted in Dexie and survives page reload.
|
|
3693
|
+
* Only set when syncOnlyCollections is null (all collections active).
|
|
3694
|
+
* Cleared on dropDatabase.
|
|
3695
|
+
*/
|
|
3696
|
+
lastSuccessfulServerSync() {
|
|
3697
|
+
return this._lastFullSyncDate;
|
|
3698
|
+
}
|
|
3699
|
+
/** @internal Update after successful full sync */
|
|
3700
|
+
async _setLastFullSync(date) {
|
|
3701
|
+
this._lastFullSyncDate = date;
|
|
3702
|
+
await this.dexieDb.setSyncMeta("__lastFullSync", date.toISOString());
|
|
3703
|
+
}
|
|
3704
|
+
/** @internal Load cached value from Dexie */
|
|
3705
|
+
async _loadLastFullSync() {
|
|
3706
|
+
const meta = await this.dexieDb.getSyncMeta("__lastFullSync");
|
|
3707
|
+
if (meta == null ? void 0 : meta.lastSyncTs) {
|
|
3708
|
+
this._lastFullSyncDate = new Date(meta.lastSyncTs);
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
/** @internal Clear on dropDatabase */
|
|
3712
|
+
_clearLastFullSync() {
|
|
3713
|
+
this._lastFullSyncDate = void 0;
|
|
3714
|
+
}
|
|
3627
3715
|
async close() {
|
|
3628
3716
|
var _a, _b;
|
|
3629
3717
|
this.leaderElection.setClosing(true);
|
|
@@ -4125,6 +4213,10 @@ var SyncedDb = class _SyncedDb {
|
|
|
4125
4213
|
this.syncing = true;
|
|
4126
4214
|
try {
|
|
4127
4215
|
await this.syncEngine.sync(calledFrom);
|
|
4216
|
+
if (!this.syncOnlyCollections) {
|
|
4217
|
+
this._setLastFullSync(/* @__PURE__ */ new Date()).catch(() => {
|
|
4218
|
+
});
|
|
4219
|
+
}
|
|
4128
4220
|
} finally {
|
|
4129
4221
|
this.syncing = false;
|
|
4130
4222
|
this.syncLock = false;
|
|
@@ -4266,6 +4358,7 @@ var SyncedDb = class _SyncedDb {
|
|
|
4266
4358
|
await this.dexieDb.clearDirtyChanges(collectionName);
|
|
4267
4359
|
}
|
|
4268
4360
|
this.syncMetaCache.clear();
|
|
4361
|
+
this._clearLastFullSync();
|
|
4269
4362
|
}
|
|
4270
4363
|
// ==================== Object Metadata ====================
|
|
4271
4364
|
getObjectMetadata(collection, _id) {
|
|
@@ -4330,6 +4423,16 @@ var SyncedDb = class _SyncedDb {
|
|
|
4330
4423
|
* Accumulates all items first, then does a single initCollection
|
|
4331
4424
|
* call to minimize reactive update overhead.
|
|
4332
4425
|
*/
|
|
4426
|
+
/** Safe callback invocation — swallows errors */
|
|
4427
|
+
safeCallback(fn, info) {
|
|
4428
|
+
if (fn) {
|
|
4429
|
+
try {
|
|
4430
|
+
fn(info);
|
|
4431
|
+
} catch (err) {
|
|
4432
|
+
console.error("Callback failed:", err);
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4333
4436
|
async loadCollectionToInMem(name) {
|
|
4334
4437
|
const allItems = [];
|
|
4335
4438
|
await this.dexieDb.forEachBatch(name, 2e3, async (chunk) => {
|
|
@@ -4345,6 +4448,7 @@ var SyncedDb = class _SyncedDb {
|
|
|
4345
4448
|
if (meta) {
|
|
4346
4449
|
this.syncMetaCache.set(name, meta);
|
|
4347
4450
|
}
|
|
4451
|
+
return allItems.length;
|
|
4348
4452
|
}
|
|
4349
4453
|
assertCollection(name) {
|
|
4350
4454
|
if (!this.collections.has(name)) {
|
|
@@ -37,7 +37,12 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
37
37
|
private beforeUnloadHandler?;
|
|
38
38
|
private readonly defaultReturnDeleted;
|
|
39
39
|
private readonly defaultReturnArchived;
|
|
40
|
-
private readonly
|
|
40
|
+
private readonly onSyncStart?;
|
|
41
|
+
private readonly onSyncEnd?;
|
|
42
|
+
private readonly onDexieSyncStart?;
|
|
43
|
+
private readonly onDexieSyncEnd?;
|
|
44
|
+
private readonly onServerSyncStart?;
|
|
45
|
+
private readonly onServerSyncEnd?;
|
|
41
46
|
private readonly onConflictResolved?;
|
|
42
47
|
private readonly onWsNotification?;
|
|
43
48
|
private readonly onCrossTabSync?;
|
|
@@ -65,6 +70,27 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
65
70
|
*/
|
|
66
71
|
simulateExternalBroadcast(payload: MetaUpdateBroadcast): void;
|
|
67
72
|
init(): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Flush all debounced pending writes to Dexie.
|
|
75
|
+
* Resolves when all data is persisted to IndexedDB.
|
|
76
|
+
* Does NOT upload to server — call sync() for that.
|
|
77
|
+
*/
|
|
78
|
+
flush(): Promise<void>;
|
|
79
|
+
private _lastFullSyncDate?;
|
|
80
|
+
/**
|
|
81
|
+
* Returns when all collections were last successfully synced
|
|
82
|
+
* from the server, or undefined if never.
|
|
83
|
+
* Value is persisted in Dexie and survives page reload.
|
|
84
|
+
* Only set when syncOnlyCollections is null (all collections active).
|
|
85
|
+
* Cleared on dropDatabase.
|
|
86
|
+
*/
|
|
87
|
+
lastSuccessfulServerSync(): Date | undefined;
|
|
88
|
+
/** @internal Update after successful full sync */
|
|
89
|
+
_setLastFullSync(date: Date): Promise<void>;
|
|
90
|
+
/** @internal Load cached value from Dexie */
|
|
91
|
+
private _loadLastFullSync;
|
|
92
|
+
/** @internal Clear on dropDatabase */
|
|
93
|
+
private _clearLastFullSync;
|
|
68
94
|
close(): Promise<void>;
|
|
69
95
|
isOnline(): boolean;
|
|
70
96
|
forceOffline(forced: boolean): void;
|
|
@@ -141,6 +167,8 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
141
167
|
* Accumulates all items first, then does a single initCollection
|
|
142
168
|
* call to minimize reactive update overhead.
|
|
143
169
|
*/
|
|
170
|
+
/** Safe callback invocation — swallows errors */
|
|
171
|
+
private safeCallback;
|
|
144
172
|
private loadCollectionToInMem;
|
|
145
173
|
private assertCollection;
|
|
146
174
|
/** Stringify an Id parameter (ObjectId → hex string). */
|
|
@@ -43,7 +43,10 @@ export declare class SyncEngine implements I_SyncEngine {
|
|
|
43
43
|
private processIncomingServerData;
|
|
44
44
|
private compareTimestamps;
|
|
45
45
|
private resolveCollectionConflict;
|
|
46
|
-
|
|
46
|
+
/** Safe callback invocation — swallows errors */
|
|
47
|
+
private callbackSafe;
|
|
48
|
+
private callOnSyncStart;
|
|
49
|
+
private callOnSyncEnd;
|
|
47
50
|
private callOnFindNewerManyCall;
|
|
48
51
|
private callOnFindNewerManyResult;
|
|
49
52
|
private callOnServerWriteRequest;
|
|
@@ -208,7 +208,22 @@ export interface I_InMemManager {
|
|
|
208
208
|
deleteObjectsMetadata(collection: string, ids: Id[]): void;
|
|
209
209
|
}
|
|
210
210
|
export interface SyncEngineCallbacks {
|
|
211
|
-
|
|
211
|
+
onSyncStart?: (info: {
|
|
212
|
+
calledFrom?: string;
|
|
213
|
+
initialSync: boolean;
|
|
214
|
+
}) => void;
|
|
215
|
+
onSyncEnd?: (info: SyncInfo) => void;
|
|
216
|
+
onServerSyncStart?: (info: {
|
|
217
|
+
calledFrom?: string;
|
|
218
|
+
collectionCount: number;
|
|
219
|
+
}) => void;
|
|
220
|
+
onServerSyncEnd?: (info: {
|
|
221
|
+
calledFrom?: string;
|
|
222
|
+
collectionCount: number;
|
|
223
|
+
receivedCount: number;
|
|
224
|
+
durationMs: number;
|
|
225
|
+
success: boolean;
|
|
226
|
+
}) => void;
|
|
212
227
|
onConflictResolved?: (report: ConflictResolutionReport) => void;
|
|
213
228
|
onServerWriteRequest?: (info: ServerWriteRequestInfo) => void;
|
|
214
229
|
onServerWriteResult?: (info: ServerWriteResultInfo) => void;
|
|
@@ -293,8 +293,38 @@ 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
|
|
297
|
-
|
|
296
|
+
/** Callback at the start of each sync cycle. initialSync=true if no full sync has completed yet. */
|
|
297
|
+
onSyncStart?: (info: {
|
|
298
|
+
calledFrom?: string;
|
|
299
|
+
initialSync: boolean;
|
|
300
|
+
}) => void;
|
|
301
|
+
/** Callback at the end of each sync cycle */
|
|
302
|
+
onSyncEnd?: (info: SyncInfo) => void;
|
|
303
|
+
/** Callback when Dexie→inMem loading starts (loadCollectionToInMem) */
|
|
304
|
+
onDexieSyncStart?: (info: {
|
|
305
|
+
calledFrom?: string;
|
|
306
|
+
collectionCount: number;
|
|
307
|
+
}) => void;
|
|
308
|
+
/** Callback when Dexie→inMem loading ends */
|
|
309
|
+
onDexieSyncEnd?: (info: {
|
|
310
|
+
calledFrom?: string;
|
|
311
|
+
collectionCount: number;
|
|
312
|
+
totalItems: number;
|
|
313
|
+
durationMs: number;
|
|
314
|
+
}) => void;
|
|
315
|
+
/** Callback when server download starts (findNewerManyStream) */
|
|
316
|
+
onServerSyncStart?: (info: {
|
|
317
|
+
calledFrom?: string;
|
|
318
|
+
collectionCount: number;
|
|
319
|
+
}) => void;
|
|
320
|
+
/** Callback when server download ends */
|
|
321
|
+
onServerSyncEnd?: (info: {
|
|
322
|
+
calledFrom?: string;
|
|
323
|
+
collectionCount: number;
|
|
324
|
+
receivedCount: number;
|
|
325
|
+
durationMs: number;
|
|
326
|
+
success: boolean;
|
|
327
|
+
}) => void;
|
|
298
328
|
/** Callback when a sync conflict is resolved (local vs server data) */
|
|
299
329
|
onConflictResolved?: (report: ConflictResolutionReport) => void;
|
|
300
330
|
/** Callback before sending data to server (updateCollections) */
|