cry-synced-db-client 0.1.210 → 0.1.213

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Versions
2
2
 
3
+ ## 0.1.211 (2026-06-25)
4
+
5
+ ### Added `streamActivityTimeoutMs` to SyncedDbConfig
6
+
7
+ `findNewerManyStream` has two internal timeouts: `connectTimeout` (configurable via
8
+ `defaultTimeoutMs`) and `activityTimeout` (was hardcoded to 30s). The activity
9
+ timeout fires between stream chunk reads — if Dexie writes + Vuex reactivity for
10
+ a 2000-item chunk exceed 30s, the stream is aborted.
11
+
12
+ New fields:
13
+ - `RestProxy.defaultActivityTimeoutMs` — default for all streams (falls back to 30s)
14
+ - `SyncedDbConfig.streamActivityTimeoutMs` — threaded through SyncedDb → SyncEngine
15
+ → RestProxy.findNewerManyStream(options.activityTimeoutMs)
16
+
3
17
  ## 0.1.209 (2026-06-25)
4
18
 
5
19
  ### Removed hardcoded `{ returnDeleted: true }` from sync specs
package/dist/index.js CHANGED
@@ -3219,6 +3219,7 @@ var _SyncEngine = class _SyncEngine {
3219
3219
  let conflictsResolved = 0;
3220
3220
  const collectionStats = {};
3221
3221
  this.callOnSyncStart({ calledFrom, initialSync: false });
3222
+ const _perCollectionItems = /* @__PURE__ */ new Map();
3222
3223
  try {
3223
3224
  this.deps.cancelRestUploadTimer();
3224
3225
  await this.deps.awaitRestUpload();
@@ -3297,12 +3298,14 @@ var _SyncEngine = class _SyncEngine {
3297
3298
  if (!config) return;
3298
3299
  const state = collectionState.get(collection);
3299
3300
  state.receivedCount += items.length;
3301
+ const _tProcess = performance.now();
3300
3302
  const stats = await this.processIncomingServerData(
3301
3303
  collection,
3302
3304
  config,
3303
3305
  items,
3304
3306
  state.source
3305
3307
  );
3308
+ const _processingMs = performance.now() - _tProcess;
3306
3309
  state.conflicts += stats.conflictsResolved;
3307
3310
  if (stats.maxTs) {
3308
3311
  if (!state.maxTs || this.compareTimestamps(stats.maxTs, state.maxTs) > 0) {
@@ -3312,16 +3315,24 @@ var _SyncEngine = class _SyncEngine {
3312
3315
  if (stats.updatedIds.length > 0) {
3313
3316
  this.deps.broadcastUpdates({ [collection]: stats.updatedIds });
3314
3317
  }
3315
- if (!completedCollections.has(collection)) {
3318
+ const isNewColl = !completedCollections.has(collection);
3319
+ if (isNewColl) {
3316
3320
  completedCollections.add(collection);
3317
- this.callbackSafe(this.callbacks.onSyncProgress, {
3318
- phase: "server",
3319
- collection,
3320
- loaded: completedCollections.size,
3321
- total: syncSpecs.length,
3322
- items: items.length
3323
- });
3324
3321
  }
3322
+ _perCollectionItems.set(
3323
+ collection,
3324
+ (_perCollectionItems.get(collection) || 0) + items.length
3325
+ );
3326
+ this.callbackSafe(this.callbacks.onSyncProgress, {
3327
+ phase: "server",
3328
+ collection,
3329
+ loaded: completedCollections.size,
3330
+ total: syncSpecs.length,
3331
+ items: items.length,
3332
+ itemsCumulative: _perCollectionItems.get(collection),
3333
+ isNewCollection: isNewColl,
3334
+ processingMs: Math.round(_processingMs)
3335
+ });
3325
3336
  },
3326
3337
  {
3327
3338
  onRequestBytes: (bytes) => {
@@ -3332,7 +3343,8 @@ var _SyncEngine = class _SyncEngine {
3332
3343
  },
3333
3344
  onResponseChunkBytes: (bytes) => {
3334
3345
  responseBytes = (responseBytes != null ? responseBytes : 0) + bytes;
3335
- }
3346
+ },
3347
+ activityTimeoutMs: this.deps.streamActivityTimeoutMs
3336
3348
  }
3337
3349
  ),
3338
3350
  "findNewerManyStream"
@@ -4140,10 +4152,12 @@ var _SyncEngine = class _SyncEngine {
4140
4152
  }
4141
4153
  async processIncomingServerData(collectionName, config, serverData, source = "incremental") {
4142
4154
  if (serverData.length === 0) {
4143
- return { conflictsResolved: 0, maxTs: void 0, updatedIds: [] };
4155
+ return { conflictsResolved: 0, maxTs: void 0, updatedIds: [], dexieMs: 0, inMemMs: 0 };
4144
4156
  }
4145
4157
  let maxTs;
4146
4158
  let conflictsResolved = 0;
4159
+ let totalDexieMs = 0;
4160
+ let totalInMemMs = 0;
4147
4161
  const allUpdatedIds = [];
4148
4162
  const BATCH = _SyncEngine.SYNC_BATCH_SIZE;
4149
4163
  for (let offset = 0; offset < serverData.length; offset += BATCH) {
@@ -4202,13 +4216,22 @@ var _SyncEngine = class _SyncEngine {
4202
4216
  }
4203
4217
  }
4204
4218
  }
4219
+ let _timingDexieMs = 0;
4220
+ let _timingInMemMs = 0;
4205
4221
  if (dexieBatch.length > 0) {
4222
+ const _t0 = performance.now();
4206
4223
  await this.dexieDb.saveMany(collectionName, dexieBatch);
4224
+ _timingDexieMs = performance.now() - _t0;
4225
+ totalDexieMs += _timingDexieMs;
4207
4226
  }
4208
4227
  if (inMemSaveBatch.length > 0) {
4228
+ const _t1 = performance.now();
4209
4229
  this.deps.writeToInMemBatch(collectionName, inMemSaveBatch, "upsert", {
4210
4230
  source
4211
4231
  });
4232
+ const _inMemMs = performance.now() - _t1;
4233
+ _timingInMemMs += _inMemMs;
4234
+ totalInMemMs += _inMemMs;
4212
4235
  }
4213
4236
  if (inMemDeleteIds.length > 0) {
4214
4237
  this.deps.writeToInMemBatch(
@@ -4227,7 +4250,7 @@ var _SyncEngine = class _SyncEngine {
4227
4250
  lastSyncTs: maxTs
4228
4251
  });
4229
4252
  }
4230
- return { conflictsResolved, maxTs, updatedIds: allUpdatedIds };
4253
+ return { conflictsResolved, maxTs, updatedIds: allUpdatedIds, dexieMs: totalDexieMs, inMemMs: totalInMemMs };
4231
4254
  }
4232
4255
  // ============================================================
4233
4256
  // Private Helpers
@@ -5087,6 +5110,7 @@ var _SyncedDb = class _SyncedDb {
5087
5110
  },
5088
5111
  getInMemById: (collection, id) => this.inMemDb.getById(collection, id),
5089
5112
  withSyncTimeout: (promise, operation) => this.connectionManager.withSyncTimeout(promise, operation),
5113
+ streamActivityTimeoutMs: config.streamActivityTimeoutMs,
5090
5114
  onSyncFailed: (reason) => this.connectionManager.callOnSyncFailed(reason),
5091
5115
  flushAllPendingChanges: () => this.pendingChanges.flushAll(),
5092
5116
  cancelRestUploadTimer: () => this.pendingChanges.cancelRestUploadTimer(),
@@ -10452,16 +10476,17 @@ var RestProxy = class {
10452
10476
  this._lastRequestMs = 0;
10453
10477
  this._totalRequestMs = 0;
10454
10478
  this._requestCount = 0;
10455
- var _a, _b, _c, _d, _e;
10479
+ var _a, _b, _c, _d, _e, _f;
10456
10480
  this.endpoint = config.endpoint;
10457
10481
  this.tenant = config.tenant;
10458
10482
  this.apiKey = config.apiKey;
10459
10483
  this.defaultTimeoutMs = (_a = config.defaultTimeoutMs) != null ? _a : DEFAULT_TIMEOUT;
10460
- this.audit = (_b = config.audit) != null ? _b : {};
10461
- this.timeRequestsPrint = (_c = config.timeRequestsPrint) != null ? _c : false;
10462
- this.timeRequests = (_d = config.timeRequests) != null ? _d : this.timeRequestsPrint;
10484
+ this.defaultActivityTimeoutMs = (_b = config.defaultActivityTimeoutMs) != null ? _b : 3e4;
10485
+ this.audit = (_c = config.audit) != null ? _c : {};
10486
+ this.timeRequestsPrint = (_d = config.timeRequestsPrint) != null ? _d : false;
10487
+ this.timeRequests = (_e = config.timeRequests) != null ? _e : this.timeRequestsPrint;
10463
10488
  this.onProgressCallback = config.onProgressCallback;
10464
- this.progressChunkSize = (_e = config.progressChunkSize) != null ? _e : DEFAULT_PROGRESS_CHUNK_SIZE;
10489
+ this.progressChunkSize = (_f = config.progressChunkSize) != null ? _f : DEFAULT_PROGRESS_CHUNK_SIZE;
10465
10490
  this.globalSignal = config.signal;
10466
10491
  }
10467
10492
  /** Set global abort signal */
@@ -10638,7 +10663,7 @@ var RestProxy = class {
10638
10663
  async findNewerManyStream(spec, onChunk, options) {
10639
10664
  var _a, _b, _c, _d, _e;
10640
10665
  const connectTimeout = (_a = options == null ? void 0 : options.timeoutMs) != null ? _a : this.defaultTimeoutMs;
10641
- const activityTimeout = (_b = options == null ? void 0 : options.activityTimeoutMs) != null ? _b : 3e4;
10666
+ const activityTimeout = (_b = options == null ? void 0 : options.activityTimeoutMs) != null ? _b : this.defaultActivityTimeoutMs;
10642
10667
  const externalSignal = (_c = options == null ? void 0 : options.signal) != null ? _c : this.globalSignal;
10643
10668
  const startTime = this.timeRequests ? performance.now() : 0;
10644
10669
  const fetchStart = performance.now();
@@ -13,6 +13,17 @@ export interface RestProxyConfig {
13
13
  apiKey?: string;
14
14
  /** Default timeout in ms (default: 5000) */
15
15
  defaultTimeoutMs?: number;
16
+ /**
17
+ * Default activity timeout for streaming responses (default: 30000).
18
+ *
19
+ * Unlike `defaultTimeoutMs` which covers the initial fetch() connection,
20
+ * this timeout fires if the gap between individual chunk reads exceeds
21
+ * the limit. Streaming syncs with many large collections (e.g. initial
22
+ * sync on a new device with 60+ collections and 2000-item chunks) need
23
+ * a higher value because Dexie writes + Vuex reactivity between reads
24
+ * can delay the next read() past the default 30s.
25
+ */
26
+ defaultActivityTimeoutMs?: number;
16
27
  /** Audit info for requests */
17
28
  audit?: {
18
29
  user?: string;
@@ -64,6 +75,7 @@ export declare class RestProxy implements I_RestInterface {
64
75
  private tenant;
65
76
  private apiKey?;
66
77
  private defaultTimeoutMs;
78
+ private defaultActivityTimeoutMs;
67
79
  private audit;
68
80
  private timeRequests;
69
81
  private timeRequestsPrint;
@@ -248,6 +248,9 @@ export interface SyncEngineCallbacks {
248
248
  loaded: number;
249
249
  total: number;
250
250
  items: number;
251
+ itemsCumulative?: number;
252
+ isNewCollection?: boolean;
253
+ processingMs?: number;
251
254
  }) => void;
252
255
  onServerSyncStart?: (info: {
253
256
  calledFrom?: string;
@@ -282,6 +285,8 @@ export interface SyncEngineDeps {
282
285
  }) => void;
283
286
  getInMemById: <T extends DbEntity>(collection: string, id: Id) => T | undefined;
284
287
  withSyncTimeout: <T>(promise: Promise<T>, operation: string) => Promise<T>;
288
+ /** Activity timeout for streaming `findNewerManyStream` (ms). Default 30000. */
289
+ streamActivityTimeoutMs?: number;
285
290
  /** Notify consumers that a sync cycle failed. Does not mutate online state. */
286
291
  onSyncFailed: (reason: string) => void;
287
292
  flushAllPendingChanges: () => Promise<void>;
@@ -133,6 +133,7 @@ export interface I_RestInterface {
133
133
  findNewerManyStream<T>(spec: GetNewerSpec<T>[], onChunk: (collection: string, items: T[], specId?: string) => Promise<void>, options?: {
134
134
  timeoutMs?: number;
135
135
  signal?: AbortSignal;
136
+ activityTimeoutMs?: number;
136
137
  onRequestBytes?: (bytes: number) => void;
137
138
  onTtfbMs?: (ms: number) => void;
138
139
  onResponseChunkBytes?: (bytes: number) => void;
@@ -592,6 +592,16 @@ export interface SyncedDbConfig {
592
592
  restTimeoutMs?: number;
593
593
  /** Timeout za sync REST klice v ms (default: 120000) - daljši ker sync prenaša več podatkov */
594
594
  syncTimeoutMs?: number;
595
+ /**
596
+ * Activity timeout za streaming odgovore (default: 30000).
597
+ *
598
+ * Za razliko od `restTimeoutMs` (ki pokriva začetno fetch() povezavo),
599
+ * ta timeout sproži če je premor med posameznimi chunk read()-i daljši
600
+ * od meje. Initial sync na novi napravi (60+ kolekcij, 2000-item chunk-i)
601
+ * potrebuje višjo vrednost, ker Dexie writes + Vuex reactivity med read()-i
602
+ * lahko podaljšajo naslednji read() čez privzetih 30s.
603
+ */
604
+ streamActivityTimeoutMs?: number;
595
605
  /** Debounce čas za zapis v Dexie v ms (default: 200) */
596
606
  debounceDexieWritesMs?: number;
597
607
  /** Debounce čas za pošiljanje na REST v ms (default: 1000) - po uspešnem zapisu v Dexie */
@@ -664,6 +674,12 @@ export interface SyncedDbConfig {
664
674
  loaded: number;
665
675
  total: number;
666
676
  items: number;
677
+ /** Cumulative items for this collection across all chunks so far */
678
+ itemsCumulative?: number;
679
+ /** True only for the first chunk of a new collection */
680
+ isNewCollection?: boolean;
681
+ /** Processing time for this chunk: Dexie save + InMem write (ms) */
682
+ processingMs?: number;
667
683
  }) => void;
668
684
  /**
669
685
  * Callback when per-collection hydration status changes (hydration end,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cry-synced-db-client",
3
- "version": "0.1.210",
3
+ "version": "0.1.213",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",