@threadbase-sh/streamer 1.36.2 → 1.36.3

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.cjs CHANGED
@@ -6899,6 +6899,10 @@ var StreamerServer = class {
6899
6899
  // Set by onConversationChanged while a scan is in-flight; getScanner() does
6900
6900
  // a single rescan after the current one completes instead of restarting it.
6901
6901
  scannerStale = false;
6902
+ // Single-flight guard for the background disk reconcile: a burst of list
6903
+ // polls during active session writes shares one rescan instead of queueing
6904
+ // a full rescan per request.
6905
+ conversationReconcileInFlight = null;
6902
6906
  // Single-flight + TTL guard around scanner.refreshFile (see refreshFileGuarded).
6903
6907
  // A live file's mtime is always newer than the snapshot, so an unguarded
6904
6908
  // refresh fires on every request and re-parses the whole file from byte 0.
@@ -7916,9 +7920,9 @@ var StreamerServer = class {
7916
7920
  * the automatic freshness path when the directory watcher marked the scanner
7917
7921
  * stale or shouldRefreshProjectsFromHdd detected disk drift.
7918
7922
  */
7919
- async reconcileConversationsCacheFromDisk() {
7923
+ async reconcileConversationsCacheFromDisk(onProgress) {
7920
7924
  if (!this.cache) return;
7921
- const scanner = await this.rescanForRefresh();
7925
+ const scanner = await this.rescanForRefresh(onProgress);
7922
7926
  const metas = [...scanner.getMetadataCache().values()];
7923
7927
  try {
7924
7928
  this.cache.upsertFromScannerMeta(metas);
@@ -7946,6 +7950,18 @@ var StreamerServer = class {
7946
7950
  );
7947
7951
  }
7948
7952
  }
7953
+ // Reconcile the cache from disk without blocking the caller. Single-flighted
7954
+ // so a burst of list polls during active session writes shares one rescan
7955
+ // rather than queueing a full rescan each; tracked so close() awaits the
7956
+ // in-flight cache write before shutting the DB.
7957
+ startBackgroundConversationReconcile() {
7958
+ if (this.conversationReconcileInFlight) return;
7959
+ const task = this.reconcileConversationsCacheFromDisk().finally(() => {
7960
+ this.conversationReconcileInFlight = null;
7961
+ });
7962
+ this.conversationReconcileInFlight = task;
7963
+ this.trackCacheWrite(task);
7964
+ }
7949
7965
  shouldAutoReconcileConversationList() {
7950
7966
  if (!this.cache) return false;
7951
7967
  if (this.scannerStale) return true;
@@ -7963,13 +7979,19 @@ var StreamerServer = class {
7963
7979
  const providerFilter = url.searchParams.get("provider") ?? void 0;
7964
7980
  const bustCache = url.searchParams.get("refresh") === "1";
7965
7981
  if (this.cache && (bustCache || this.shouldAutoReconcileConversationList())) {
7966
- if (bustCache) {
7982
+ const canServeStale = !bustCache && this.cache.listConversations({ limit: 0, offset: 0 }).total > 0;
7983
+ if (canServeStale) {
7984
+ this.startBackgroundConversationReconcile();
7985
+ } else {
7986
+ const shouldEmitProgress = createScanProgressThrottle();
7967
7987
  await this.withWarmup(
7968
7988
  "conversation_refresh",
7969
- () => this.reconcileConversationsCacheFromDisk()
7989
+ () => this.reconcileConversationsCacheFromDisk((scanned, total2) => {
7990
+ if (shouldEmitProgress(scanned, total2)) {
7991
+ this.wsHub.broadcast({ type: "scan_progress", scanned, total: total2 });
7992
+ }
7993
+ })
7970
7994
  );
7971
- } else {
7972
- await this.reconcileConversationsCacheFromDisk();
7973
7995
  }
7974
7996
  }
7975
7997
  if (this.cache) {
@@ -8205,7 +8227,7 @@ var StreamerServer = class {
8205
8227
  // getFreshScanner() this does NOT discard the warm scanner. scannerReady is
8206
8228
  // only ever reassigned to a live scan promise (never nulled mid-scan), so the
8207
8229
  // getScanner() anti-infinite-loop guard is preserved.
8208
- async rescanForRefresh() {
8230
+ async rescanForRefresh(onProgress) {
8209
8231
  if (this.scannerReady) await this.scannerReady;
8210
8232
  this.scannerStale = false;
8211
8233
  if (!this.scanner) {
@@ -8216,7 +8238,8 @@ var StreamerServer = class {
8216
8238
  this.scannerReady = scanner.scan({
8217
8239
  ...this.scanProfiles ? { profiles: this.scanProfiles } : {},
8218
8240
  ...this.codexScanOpts(),
8219
- fullRescan: true
8241
+ fullRescan: true,
8242
+ ...onProgress ? { onProgress } : {}
8220
8243
  });
8221
8244
  await this.scannerReady;
8222
8245
  return scanner;