mindoodb 0.0.64 → 0.0.65

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.
Files changed (51) hide show
  1. package/dist/browser/index.mjs +11 -0
  2. package/dist/core/BaseMindooDB.d.ts +19 -0
  3. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  4. package/dist/core/BaseMindooDB.js +607 -323
  5. package/dist/core/BaseMindooDB.js.map +1 -1
  6. package/dist/core/accesscontrol/tier1Evaluator.d.ts +59 -0
  7. package/dist/core/accesscontrol/tier1Evaluator.d.ts.map +1 -0
  8. package/dist/core/accesscontrol/tier1Evaluator.js +77 -0
  9. package/dist/core/accesscontrol/tier1Evaluator.js.map +1 -0
  10. package/dist/core/appendonlystores/network/IrohNetworkTransport.d.ts +58 -5
  11. package/dist/core/appendonlystores/network/IrohNetworkTransport.d.ts.map +1 -1
  12. package/dist/core/appendonlystores/network/IrohNetworkTransport.js +77 -8
  13. package/dist/core/appendonlystores/network/IrohNetworkTransport.js.map +1 -1
  14. package/dist/core/appendonlystores/network/IrohStreamIO.d.ts +32 -10
  15. package/dist/core/appendonlystores/network/IrohStreamIO.d.ts.map +1 -1
  16. package/dist/core/appendonlystores/network/IrohStreamIO.js +26 -10
  17. package/dist/core/appendonlystores/network/IrohStreamIO.js.map +1 -1
  18. package/dist/core/appendonlystores/network/irohLocator.d.ts +16 -0
  19. package/dist/core/appendonlystores/network/irohLocator.d.ts.map +1 -1
  20. package/dist/core/appendonlystores/network/irohLocator.js +36 -0
  21. package/dist/core/appendonlystores/network/irohLocator.js.map +1 -1
  22. package/dist/core/builtinDbInvariants.d.ts +12 -6
  23. package/dist/core/builtinDbInvariants.d.ts.map +1 -1
  24. package/dist/core/builtinDbInvariants.js +7 -1
  25. package/dist/core/builtinDbInvariants.js.map +1 -1
  26. package/dist/core/index.d.ts +6 -3
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/core/index.js +27 -11
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/core/peerdevices/PeerDeviceDocument.d.ts +144 -0
  31. package/dist/core/peerdevices/PeerDeviceDocument.d.ts.map +1 -0
  32. package/dist/core/peerdevices/PeerDeviceDocument.js +209 -0
  33. package/dist/core/peerdevices/PeerDeviceDocument.js.map +1 -0
  34. package/dist/core/types.d.ts +15 -0
  35. package/dist/core/types.d.ts.map +1 -1
  36. package/dist/core/userkeys/fingerprint.d.ts +12 -4
  37. package/dist/core/userkeys/fingerprint.d.ts.map +1 -1
  38. package/dist/core/userkeys/fingerprint.js +14 -5
  39. package/dist/core/userkeys/fingerprint.js.map +1 -1
  40. package/dist/iroh/index.d.ts +3 -2
  41. package/dist/iroh/index.d.ts.map +1 -1
  42. package/dist/iroh/index.js +8 -1
  43. package/dist/iroh/index.js.map +1 -1
  44. package/dist/node/server/TenantManager.d.ts +5 -0
  45. package/dist/node/server/TenantManager.d.ts.map +1 -1
  46. package/dist/node/server/TenantManager.js +35 -56
  47. package/dist/node/server/TenantManager.js.map +1 -1
  48. package/dist/node/server/nativeIrohStreamIO.d.ts.map +1 -1
  49. package/dist/node/server/nativeIrohStreamIO.js +17 -4
  50. package/dist/node/server/nativeIrohStreamIO.js.map +1 -1
  51. package/package.json +1 -1
@@ -101,7 +101,9 @@ const PREFETCH_MAX_RATE_LIMIT_DELAY_MS = 10000;
101
101
  */
102
102
  function networkErrorType(error) {
103
103
  const candidate = error;
104
- if (!candidate || candidate.name !== "NetworkError" || typeof candidate.type !== "string") {
104
+ if (!candidate ||
105
+ candidate.name !== "NetworkError" ||
106
+ typeof candidate.type !== "string") {
105
107
  return null;
106
108
  }
107
109
  return candidate.type;
@@ -117,7 +119,9 @@ function rateLimitRetryDelayMs(error, attempt) {
117
119
  return null;
118
120
  }
119
121
  const retryAfterMs = error.retryAfterMs;
120
- const requested = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) ? retryAfterMs : 0;
122
+ const requested = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs)
123
+ ? retryAfterMs
124
+ : 0;
121
125
  return Math.min(Math.max(requested, PREFETCH_RATE_LIMIT_DELAYS_MS[attempt]), PREFETCH_MAX_RATE_LIMIT_DELAY_MS);
122
126
  }
123
127
  /**
@@ -176,10 +180,9 @@ const DOC_CACHE_HEADER_VERSION = 2;
176
180
  */
177
181
  /** @internal Exported for tests only; do not import from app code. */
178
182
  exports.CUSTOM_DOC_ID_INITIAL_CHANGE_BYTES = new Uint8Array([
179
- 133, 111, 74, 131, 181, 94, 251, 69, 1, 47, 0, 8, 0, 0, 0, 0,
180
- 0, 0, 0, 192, 1, 1, 0, 0, 0, 5, 21, 14, 52, 1, 66, 2,
181
- 86, 2, 112, 2, 127, 12, 95, 97, 116, 116, 97, 99, 104, 109, 101, 110,
182
- 116, 115, 1, 127, 2, 127, 0, 127, 0,
183
+ 133, 111, 74, 131, 181, 94, 251, 69, 1, 47, 0, 8, 0, 0, 0, 0, 0, 0, 0, 192, 1,
184
+ 1, 0, 0, 0, 5, 21, 14, 52, 1, 66, 2, 86, 2, 112, 2, 127, 12, 95, 97, 116, 116,
185
+ 97, 99, 104, 109, 101, 110, 116, 115, 1, 127, 2, 127, 0, 127, 0,
183
186
  ]);
184
187
  /**
185
188
  * Returns the hard-coded initial Automerge change bytes used to seed every
@@ -513,7 +516,8 @@ class BaseMindooDB {
513
516
  this.tenant = tenant;
514
517
  this.store = store;
515
518
  this.attachmentStore = attachmentStore;
516
- this.chunkSizeBytes = attachmentConfig?.chunkSizeBytes ?? DEFAULT_CHUNK_SIZE_BYTES;
519
+ this.chunkSizeBytes =
520
+ attachmentConfig?.chunkSizeBytes ?? DEFAULT_CHUNK_SIZE_BYTES;
517
521
  this._isAdminOnlyDb = adminOnlyDb;
518
522
  this.timeTravelDate = timeTravelDate;
519
523
  this.maxCachedDocs = Math.max(1, Math.floor(documentCacheConfig?.maxEntries ?? DEFAULT_MAX_CACHED_DOCS));
@@ -529,7 +533,8 @@ class BaseMindooDB {
529
533
  : 0;
530
534
  this.cacheRestoreLimit = Math.max(1, Math.floor(documentCacheConfig?.restoreLimit ?? this.maxCachedDocs));
531
535
  this.cacheRestoreBatchSize = Math.max(1, Math.floor(documentCacheConfig?.restoreBatchSize ?? DEFAULT_RESTORE_BATCH_SIZE));
532
- this.reconcileRestoredIndexOnInit = documentCacheConfig?.reconcileRestoredIndexOnInit ?? false;
536
+ this.reconcileRestoredIndexOnInit =
537
+ documentCacheConfig?.reconcileRestoredIndexOnInit ?? false;
533
538
  this.restoreToL2 = documentCacheConfig?.restoreToL2 ?? false;
534
539
  this.warmerBatchSize = Math.max(1, Math.floor(documentCacheConfig?.warmer?.batchSize ?? DEFAULT_WARMER_BATCH_SIZE));
535
540
  this.warmerScheduler =
@@ -538,8 +543,7 @@ class BaseMindooDB {
538
543
  this.snapshotCooldownMs = Math.max(0, Math.floor(snapshotConfig?.cooldownMs ?? DEFAULT_SNAPSHOT_COOLDOWN_MS));
539
544
  // Create logger if not provided (for backward compatibility)
540
545
  this.logger =
541
- logger ||
542
- new logging_1.MindooLogger((0, logging_1.getDefaultLogLevel)(), "BaseMindooDB", true);
546
+ logger || new logging_1.MindooLogger((0, logging_1.getDefaultLogLevel)(), "BaseMindooDB", true);
543
547
  this.performanceCallback = performanceCallback;
544
548
  // Summary auto-follow: piggybacks on the coalesced change events (one
545
549
  // per sync batch / event-loop turn). Costs a docId check per event for
@@ -617,7 +621,8 @@ class BaseMindooDB {
617
621
  let signerUsernameHash = null;
618
622
  let creatorUsernameHash = null;
619
623
  if (dbId === types_1.USER_DIRECTORY_DB_ID) {
620
- signerUsernameHash = await this.resolveSignerUsernameHash(signerPublicKey);
624
+ signerUsernameHash =
625
+ await this.resolveSignerUsernameHash(signerPublicKey);
621
626
  this.signerUsernameHashByKey.set(signerPublicKey, signerUsernameHash);
622
627
  if ((0, builtinDbInvariants_1.isPersonalUserdirectoryDocId)(docId)) {
623
628
  creatorUsernameHash =
@@ -652,7 +657,8 @@ class BaseMindooDB {
652
657
  let documentUsernameHash = null;
653
658
  let signerUsernameHash = null;
654
659
  let creatorUsernameHash = null;
655
- if (dbId === types_1.USER_DIRECTORY_DB_ID && (0, builtinDbInvariants_1.isPersonalUserdirectoryDocId)(entry.docId)) {
660
+ if (dbId === types_1.USER_DIRECTORY_DB_ID &&
661
+ (0, builtinDbInvariants_1.isPersonalUserdirectoryDocId)(entry.docId)) {
656
662
  if (entryType !== "doc_create") {
657
663
  creatorUsernameHash = await this.ensurePersonalDocCreatorHash(entry.docId);
658
664
  signerUsernameHash = await this.ensureSignerUsernameHash(entry.createdByPublicKey);
@@ -675,6 +681,23 @@ class BaseMindooDB {
675
681
  creatorUsernameHash,
676
682
  });
677
683
  }
684
+ /**
685
+ * Would the builtin `directory` / `userdirectory` invariant forbid this
686
+ * entry? For callers that accept entries from somewhere other than a server
687
+ * — a peer sync — and therefore have to apply the admin/owner rules
688
+ * themselves.
689
+ *
690
+ * Deliberately the same check the load path uses, so an entry admitted here
691
+ * is one that will also materialize. The alternative, accepting on ingest
692
+ * and dropping on load, leaves the entry sitting in the store and pushes it
693
+ * on to the server at the next sync, where it is refused and fails the run.
694
+ *
695
+ * Returns false for databases without a builtin invariant, so callers can
696
+ * ask unconditionally.
697
+ */
698
+ async violatesBuiltinWriteInvariant(entry) {
699
+ return this.shouldSkipLoadedEntryForBuiltin(entry);
700
+ }
678
701
  async ensureSignerUsernameHash(signerKey) {
679
702
  if (this.signerUsernameHashByKey.has(signerKey)) {
680
703
  return this.signerUsernameHashByKey.get(signerKey) ?? null;
@@ -751,10 +774,12 @@ class BaseMindooDB {
751
774
  }
752
775
  }
753
776
  metadataVisibleAtTimeTravelDate(metadata) {
754
- return this.timeTravelDate == null || metadata.createdAt < this.timeTravelDate;
777
+ return (this.timeTravelDate == null || metadata.createdAt < this.timeTravelDate);
755
778
  }
756
779
  applyTimeTravelFilter(metadata) {
757
- return this.timeTravelDate == null ? metadata : metadata.filter((entry) => this.metadataVisibleAtTimeTravelDate(entry));
780
+ return this.timeTravelDate == null
781
+ ? metadata
782
+ : metadata.filter((entry) => this.metadataVisibleAtTimeTravelDate(entry));
758
783
  }
759
784
  mergeTimeTravelScanFilters(filters) {
760
785
  if (this.timeTravelDate == null) {
@@ -781,7 +806,9 @@ class BaseMindooDB {
781
806
  computeCachePrefix() {
782
807
  const cacheIdentity = this.store.getCacheIdentity?.() ?? this.store.getId();
783
808
  const base = `${this.tenant.getId()}/${cacheIdentity}`;
784
- return this.timeTravelDate == null ? base : `${base}/tt/${this.timeTravelDate}`;
809
+ return this.timeTravelDate == null
810
+ ? base
811
+ : `${base}/tt/${this.timeTravelDate}`;
785
812
  }
786
813
  /**
787
814
  * Attach a CacheManager so this DB participates in periodic cache flushing.
@@ -856,7 +883,8 @@ class BaseMindooDB {
856
883
  return (0, types_4.sanitizeSummaryConfig)(doc.getData()[types_4.SUMMARY_SETUP_FIELD]) ?? null;
857
884
  }
858
885
  catch (error) {
859
- if (error instanceof errors_1.DocumentNotFoundError || error instanceof errors_1.DocumentDeletedError) {
886
+ if (error instanceof errors_1.DocumentNotFoundError ||
887
+ error instanceof errors_1.DocumentDeletedError) {
860
888
  return null;
861
889
  }
862
890
  throw error;
@@ -920,7 +948,9 @@ class BaseMindooDB {
920
948
  // indexing (DirectoryTimeTravelIndex) and its change events interleave
921
949
  // with access-control evaluation; admin-only databases hold no user
922
950
  // data worth summarizing. Explicit getSummaryStore() calls still work.
923
- if (this._isAdminOnlyDb || this.store.getId() === types_1.DIRECTORY_DB_ID || this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
951
+ if (this._isAdminOnlyDb ||
952
+ this.store.getId() === types_1.DIRECTORY_DB_ID ||
953
+ this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
924
954
  return;
925
955
  }
926
956
  const hasSetupChange = changes.some((change) => change.docId === types_4.DB_SETUP_DOC_ID);
@@ -934,7 +964,9 @@ class BaseMindooDB {
934
964
  async activateSummaryFromSetupDoc() {
935
965
  try {
936
966
  const config = await this.getSummarySetup();
937
- if (config === null || this.summaryStore || !this.summaryAutoUpdateEnabled) {
967
+ if (config === null ||
968
+ this.summaryStore ||
969
+ !this.summaryAutoUpdateEnabled) {
938
970
  return;
939
971
  }
940
972
  // No explicit config: the store adopts the setup-document config on
@@ -962,7 +994,8 @@ class BaseMindooDB {
962
994
  do {
963
995
  this.summaryAutoUpdatePending = false;
964
996
  await this.summaryStore?.update();
965
- } while (this.summaryAutoUpdatePending && this.summaryAutoUpdateEnabled);
997
+ } while (this.summaryAutoUpdatePending &&
998
+ this.summaryAutoUpdateEnabled);
966
999
  }
967
1000
  catch (error) {
968
1001
  this.logger.warn(`Summary auto-update failed: ${error}`);
@@ -1011,10 +1044,11 @@ class BaseMindooDB {
1011
1044
  async getFulltextSetup() {
1012
1045
  try {
1013
1046
  const doc = await this.getDocument(types_4.DB_SETUP_DOC_ID);
1014
- return (0, types_5.sanitizeFulltextConfig)(doc.getData()[types_5.FULLTEXT_SETUP_FIELD]) ?? null;
1047
+ return ((0, types_5.sanitizeFulltextConfig)(doc.getData()[types_5.FULLTEXT_SETUP_FIELD]) ?? null);
1015
1048
  }
1016
1049
  catch (error) {
1017
- if (error instanceof errors_1.DocumentNotFoundError || error instanceof errors_1.DocumentDeletedError) {
1050
+ if (error instanceof errors_1.DocumentNotFoundError ||
1051
+ error instanceof errors_1.DocumentDeletedError) {
1018
1052
  return null;
1019
1053
  }
1020
1054
  throw error;
@@ -1034,7 +1068,7 @@ class BaseMindooDB {
1034
1068
  * resumable backfill — locally and, after sync, on every other replica.
1035
1069
  */
1036
1070
  async setFulltextSetup(config) {
1037
- const sanitized = config === null ? null : (0, types_5.sanitizeFulltextConfig)(config) ?? {};
1071
+ const sanitized = config === null ? null : ((0, types_5.sanitizeFulltextConfig)(config) ?? {});
1038
1072
  const current = await this.getFulltextSetup();
1039
1073
  if (JSON.stringify(current) === JSON.stringify(sanitized)) {
1040
1074
  return;
@@ -1061,10 +1095,11 @@ class BaseMindooDB {
1061
1095
  async getExtractionSetup() {
1062
1096
  try {
1063
1097
  const doc = await this.getDocument(types_4.DB_SETUP_DOC_ID);
1064
- return (0, types_6.sanitizeExtractionConfig)(doc.getData()[types_6.EXTRACTION_SETUP_FIELD]) ?? null;
1098
+ return ((0, types_6.sanitizeExtractionConfig)(doc.getData()[types_6.EXTRACTION_SETUP_FIELD]) ?? null);
1065
1099
  }
1066
1100
  catch (error) {
1067
- if (error instanceof errors_1.DocumentNotFoundError || error instanceof errors_1.DocumentDeletedError) {
1101
+ if (error instanceof errors_1.DocumentNotFoundError ||
1102
+ error instanceof errors_1.DocumentDeletedError) {
1068
1103
  return null;
1069
1104
  }
1070
1105
  throw error;
@@ -1080,7 +1115,7 @@ class BaseMindooDB {
1080
1115
  * without producing changefeed/sync churn.
1081
1116
  */
1082
1117
  async setExtractionSetup(config) {
1083
- const sanitized = config === null ? null : (0, types_6.sanitizeExtractionConfig)(config) ?? {};
1118
+ const sanitized = config === null ? null : ((0, types_6.sanitizeExtractionConfig)(config) ?? {});
1084
1119
  const current = await this.getExtractionSetup();
1085
1120
  if (JSON.stringify(current) === JSON.stringify(sanitized)) {
1086
1121
  return;
@@ -1155,7 +1190,9 @@ class BaseMindooDB {
1155
1190
  return;
1156
1191
  }
1157
1192
  // Same system-database exclusion as the summary auto-activation.
1158
- if (this._isAdminOnlyDb || this.store.getId() === types_1.DIRECTORY_DB_ID || this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
1193
+ if (this._isAdminOnlyDb ||
1194
+ this.store.getId() === types_1.DIRECTORY_DB_ID ||
1195
+ this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
1159
1196
  return;
1160
1197
  }
1161
1198
  const hasSetupChange = changes.some((change) => change.docId === types_4.DB_SETUP_DOC_ID);
@@ -1198,7 +1235,8 @@ class BaseMindooDB {
1198
1235
  do {
1199
1236
  this.fulltextAutoUpdatePending = false;
1200
1237
  await this.fulltextIndex?.update();
1201
- } while (this.fulltextAutoUpdatePending && this.fulltextAutoUpdateEnabled);
1238
+ } while (this.fulltextAutoUpdatePending &&
1239
+ this.fulltextAutoUpdateEnabled);
1202
1240
  }
1203
1241
  catch (error) {
1204
1242
  this.logger.warn(`Full-text auto-update failed: ${error}`);
@@ -1232,7 +1270,11 @@ class BaseMindooDB {
1232
1270
  if (this.changeListeners.size === 0) {
1233
1271
  return;
1234
1272
  }
1235
- this.pendingChangeNotifications.set(docId, { docId, isDeleted, lastModified });
1273
+ this.pendingChangeNotifications.set(docId, {
1274
+ docId,
1275
+ isDeleted,
1276
+ lastModified,
1277
+ });
1236
1278
  this.scheduleChangeNotification();
1237
1279
  }
1238
1280
  scheduleChangeNotification() {
@@ -1475,9 +1517,7 @@ class BaseMindooDB {
1475
1517
  */
1476
1518
  async flushDirtyDocToCache(store, prefix, docId, internal) {
1477
1519
  const indexEntryIdx = this.getDocIndexPosition(docId);
1478
- const changeSeq = indexEntryIdx === undefined
1479
- ? 0
1480
- : this.index[indexEntryIdx].changeSeq;
1520
+ const changeSeq = indexEntryIdx === undefined ? 0 : this.index[indexEntryIdx].changeSeq;
1481
1521
  const automergeHeads = automerge_adapter_1.Automerge.getHeads(internal.doc);
1482
1522
  // Skip the Automerge.save + L2 write when the exact same state was
1483
1523
  // already flushed (docs marked dirty by a load rather than a change).
@@ -1581,12 +1621,15 @@ class BaseMindooDB {
1581
1621
  this.processedEntryIds = checkpoint.processedEntryIds;
1582
1622
  }
1583
1623
  this.lastReconciledKeyBagFingerprint =
1584
- typeof checkpoint.keyBagFingerprint === "string" ? checkpoint.keyBagFingerprint : null;
1624
+ typeof checkpoint.keyBagFingerprint === "string"
1625
+ ? checkpoint.keyBagFingerprint
1626
+ : null;
1585
1627
  // Pending untrusted-author map. A checkpoint written before this field
1586
1628
  // existed may hide entries that were silently skipped because their
1587
1629
  // author was unknown at the time - flag it for the one-time heal scan.
1588
1630
  this.pendingUntrustedAuthors.clear();
1589
- if (checkpoint.pendingUntrustedAuthors && typeof checkpoint.pendingUntrustedAuthors === "object") {
1631
+ if (checkpoint.pendingUntrustedAuthors &&
1632
+ typeof checkpoint.pendingUntrustedAuthors === "object") {
1590
1633
  this.legacyCheckpointNeedsAuthorTrustScan = false;
1591
1634
  for (const [publicKey, docIds] of Object.entries(checkpoint.pendingUntrustedAuthors)) {
1592
1635
  if (!Array.isArray(docIds))
@@ -1617,7 +1660,8 @@ class BaseMindooDB {
1617
1660
  this.legacyCheckpointNeedsVisibilityTally = true;
1618
1661
  }
1619
1662
  this.syncScanCursors.clear();
1620
- if (checkpoint.syncScanCursors && typeof checkpoint.syncScanCursors === "object") {
1663
+ if (checkpoint.syncScanCursors &&
1664
+ typeof checkpoint.syncScanCursors === "object") {
1621
1665
  for (const [key, value] of Object.entries(checkpoint.syncScanCursors)) {
1622
1666
  if (typeof value?.sourceEpoch === "string" &&
1623
1667
  typeof value?.targetEpoch === "string" &&
@@ -1626,7 +1670,10 @@ class BaseMindooDB {
1626
1670
  this.syncScanCursors.set(key, {
1627
1671
  sourceEpoch: value.sourceEpoch,
1628
1672
  targetEpoch: value.targetEpoch,
1629
- cursor: { receiptOrder: value.cursor.receiptOrder, id: value.cursor.id },
1673
+ cursor: {
1674
+ receiptOrder: value.cursor.receiptOrder,
1675
+ id: value.cursor.id,
1676
+ },
1630
1677
  });
1631
1678
  }
1632
1679
  }
@@ -1655,7 +1702,8 @@ class BaseMindooDB {
1655
1702
  this.indexLookup.set(this.index[i].docId, i);
1656
1703
  }
1657
1704
  if (this.index.length > 0 && this.nextChangeSeq <= this.index.length) {
1658
- this.nextChangeSeq = Math.max(...this.index.map(e => e.changeSeq)) + 1;
1705
+ this.nextChangeSeq =
1706
+ Math.max(...this.index.map((e) => e.changeSeq)) + 1;
1659
1707
  }
1660
1708
  // Restore automergeHashToEntryId
1661
1709
  if (checkpoint.automergeHashToEntryId) {
@@ -1771,13 +1819,17 @@ class BaseMindooDB {
1771
1819
  lastModified: header.lastModified,
1772
1820
  decryptionKeyId: header.decryptionKeyId,
1773
1821
  isDeleted: header.isDeleted,
1774
- awaitingWitness: typeof header.awaitingWitness === "boolean" ? header.awaitingWitness : false,
1822
+ awaitingWitness: typeof header.awaitingWitness === "boolean"
1823
+ ? header.awaitingWitness
1824
+ : false,
1775
1825
  witnessed: typeof header.witnessed === "boolean" ? header.witnessed : false,
1776
1826
  };
1777
1827
  return {
1778
1828
  internal,
1779
1829
  persistedChangeSeq: typeof header.changeSeq === "number" ? header.changeSeq : 0,
1780
- persistedHeads: Array.isArray(header.automergeHeads) ? header.automergeHeads : [],
1830
+ persistedHeads: Array.isArray(header.automergeHeads)
1831
+ ? header.automergeHeads
1832
+ : [],
1781
1833
  };
1782
1834
  }
1783
1835
  /**
@@ -1791,10 +1843,12 @@ class BaseMindooDB {
1791
1843
  async getOrImportPublicKey(publicKey, trustedTime) {
1792
1844
  const directory = await this.tenant.openDirectory();
1793
1845
  let isTrusted = false;
1794
- if (trustedTime !== undefined && typeof directory.getDirectoryStateAt === "function") {
1846
+ if (trustedTime !== undefined &&
1847
+ typeof directory.getDirectoryStateAt === "function") {
1795
1848
  const node = await directory.getDirectoryStateAt(trustedTime);
1796
1849
  isTrusted =
1797
- !!(0, DirectoryStateNode_1.grantForSigningKey)(node, publicKey) || publicKey === this.getAdminPublicKey();
1850
+ !!(0, DirectoryStateNode_1.grantForSigningKey)(node, publicKey) ||
1851
+ publicKey === this.getAdminPublicKey();
1798
1852
  }
1799
1853
  else {
1800
1854
  isTrusted = await directory.validatePublicSigningKey(publicKey);
@@ -1868,7 +1922,11 @@ class BaseMindooDB {
1868
1922
  lastChunkId: a.lastChunkId,
1869
1923
  size: a.size,
1870
1924
  }))
1871
- .sort((x, y) => x.attachmentId < y.attachmentId ? -1 : x.attachmentId > y.attachmentId ? 1 : 0);
1925
+ .sort((x, y) => x.attachmentId < y.attachmentId
1926
+ ? -1
1927
+ : x.attachmentId > y.attachmentId
1928
+ ? 1
1929
+ : 0);
1872
1930
  }
1873
1931
  /**
1874
1932
  * Verify a store entry's author signature using a pre-imported CryptoKey,
@@ -2002,13 +2060,13 @@ class BaseMindooDB {
2002
2060
  // bypass this via forceChangeSeqBump: two changes within the same
2003
2061
  // millisecond would otherwise be indistinguishable here and the second
2004
2062
  // one would silently vanish from the changefeed.
2005
- if (!forceChangeSeqBump
2006
- && existingEntry.lastModified === lastModified
2007
- && existingEntry.isDeleted === isDeleted
2008
- && existingEntry.decryptionKeyId === decryptionKeyId
2009
- && existingEntry.accessState === accessState
2010
- && existingEntry.awaitingWitness === awaitingWitness
2011
- && existingEntry.witnessed === witnessed) {
2063
+ if (!forceChangeSeqBump &&
2064
+ existingEntry.lastModified === lastModified &&
2065
+ existingEntry.isDeleted === isDeleted &&
2066
+ existingEntry.decryptionKeyId === decryptionKeyId &&
2067
+ existingEntry.accessState === accessState &&
2068
+ existingEntry.awaitingWitness === awaitingWitness &&
2069
+ existingEntry.witnessed === witnessed) {
2012
2070
  return; // No change needed
2013
2071
  }
2014
2072
  // Remove from current position; positions after it are repaired lazily
@@ -2046,9 +2104,10 @@ class BaseMindooDB {
2046
2104
  ? Math.min(existingIndex, insertIndex)
2047
2105
  : insertIndex;
2048
2106
  if (shiftedFrom < this.index.length - 1) {
2049
- this.indexLookupStaleFrom = this.indexLookupStaleFrom === null
2050
- ? shiftedFrom
2051
- : Math.min(this.indexLookupStaleFrom, shiftedFrom);
2107
+ this.indexLookupStaleFrom =
2108
+ this.indexLookupStaleFrom === null
2109
+ ? shiftedFrom
2110
+ : Math.min(this.indexLookupStaleFrom, shiftedFrom);
2052
2111
  }
2053
2112
  // Reactive support: record the transition for coalesced change events.
2054
2113
  // Reached only when the index actually changed (identical replays
@@ -2246,7 +2305,8 @@ class BaseMindooDB {
2246
2305
  // not expose a fingerprint so we never silently miss a key
2247
2306
  // transition.
2248
2307
  const currentFingerprint = await this.computeCurrentKeyBagFingerprint();
2249
- const fingerprintMatches = currentFingerprint !== null && currentFingerprint === this.lastReconciledKeyBagFingerprint;
2308
+ const fingerprintMatches = currentFingerprint !== null &&
2309
+ currentFingerprint === this.lastReconciledKeyBagFingerprint;
2250
2310
  if (!fingerprintMatches || this.legacyCheckpointNeedsVisibilityTally) {
2251
2311
  this.legacyCheckpointNeedsVisibilityTally = false;
2252
2312
  await this.reconcileKeyVisibility();
@@ -2297,10 +2357,14 @@ class BaseMindooDB {
2297
2357
  if (!this.isTimeTravelMode()) {
2298
2358
  return;
2299
2359
  }
2300
- if (!this.summaryAutoUpdateEnabled || this.summarySetupProbed || this.summaryStore) {
2360
+ if (!this.summaryAutoUpdateEnabled ||
2361
+ this.summarySetupProbed ||
2362
+ this.summaryStore) {
2301
2363
  return;
2302
2364
  }
2303
- if (this._isAdminOnlyDb || this.store.getId() === types_1.DIRECTORY_DB_ID || this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
2365
+ if (this._isAdminOnlyDb ||
2366
+ this.store.getId() === types_1.DIRECTORY_DB_ID ||
2367
+ this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
2304
2368
  return;
2305
2369
  }
2306
2370
  this.summarySetupProbed = true;
@@ -2331,10 +2395,14 @@ class BaseMindooDB {
2331
2395
  * {@link handleChangesForFulltextAutoUpdate}).
2332
2396
  */
2333
2397
  probeFulltextSetupAtOpen() {
2334
- if (!this.fulltextAutoUpdateEnabled || this.fulltextSetupProbed || this.fulltextIndex) {
2398
+ if (!this.fulltextAutoUpdateEnabled ||
2399
+ this.fulltextSetupProbed ||
2400
+ this.fulltextIndex) {
2335
2401
  return;
2336
2402
  }
2337
- if (this._isAdminOnlyDb || this.store.getId() === types_1.DIRECTORY_DB_ID || this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
2403
+ if (this._isAdminOnlyDb ||
2404
+ this.store.getId() === types_1.DIRECTORY_DB_ID ||
2405
+ this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
2338
2406
  return;
2339
2407
  }
2340
2408
  if (this.isTimeTravelMode()) {
@@ -2452,15 +2520,17 @@ class BaseMindooDB {
2452
2520
  * meaning there is nothing to reconcile.
2453
2521
  */
2454
2522
  deriveDocumentVisibilityMetadata(metadata) {
2455
- const lifecycleEntries = metadata.filter((entry) => entry.entryType === "doc_create"
2456
- || entry.entryType === "doc_change"
2457
- || entry.entryType === "doc_delete"
2458
- || entry.entryType === "doc_undelete"
2459
- || entry.entryType === "doc_snapshot");
2523
+ const lifecycleEntries = metadata.filter((entry) => entry.entryType === "doc_create" ||
2524
+ entry.entryType === "doc_change" ||
2525
+ entry.entryType === "doc_delete" ||
2526
+ entry.entryType === "doc_undelete" ||
2527
+ entry.entryType === "doc_snapshot");
2460
2528
  if (lifecycleEntries.length === 0) {
2461
2529
  return null;
2462
2530
  }
2463
- lifecycleEntries.sort((left, right) => left.createdAt !== right.createdAt ? left.createdAt - right.createdAt : left.id.localeCompare(right.id));
2531
+ lifecycleEntries.sort((left, right) => left.createdAt !== right.createdAt
2532
+ ? left.createdAt - right.createdAt
2533
+ : left.id.localeCompare(right.id));
2464
2534
  const replayEntries = metadata.filter((entry) => this.isDocumentReplayEntry(entry));
2465
2535
  const entriesForLastModified = replayEntries.length > 0 ? replayEntries : lifecycleEntries;
2466
2536
  return {
@@ -2544,11 +2614,11 @@ class BaseMindooDB {
2544
2614
  const lifecycleMetadata = await this.scanAllMetadata(this.store);
2545
2615
  const metadataByDoc = new Map();
2546
2616
  for (const entry of lifecycleMetadata) {
2547
- if (entry.entryType !== "doc_create"
2548
- && entry.entryType !== "doc_change"
2549
- && entry.entryType !== "doc_delete"
2550
- && entry.entryType !== "doc_undelete"
2551
- && entry.entryType !== "doc_snapshot") {
2617
+ if (entry.entryType !== "doc_create" &&
2618
+ entry.entryType !== "doc_change" &&
2619
+ entry.entryType !== "doc_delete" &&
2620
+ entry.entryType !== "doc_undelete" &&
2621
+ entry.entryType !== "doc_snapshot") {
2552
2622
  continue;
2553
2623
  }
2554
2624
  const entries = metadataByDoc.get(entry.docId) ?? [];
@@ -2687,11 +2757,11 @@ class BaseMindooDB {
2687
2757
  // next load rebuilds from the store with the now-trusted entries.
2688
2758
  await this.purgeMaterializedDocument(docId);
2689
2759
  const metadata = await this.scanAllMetadata(this.store, { docId });
2690
- const lifecycleEntries = metadata.filter((entry) => entry.entryType === "doc_create"
2691
- || entry.entryType === "doc_change"
2692
- || entry.entryType === "doc_delete"
2693
- || entry.entryType === "doc_undelete"
2694
- || entry.entryType === "doc_snapshot");
2760
+ const lifecycleEntries = metadata.filter((entry) => entry.entryType === "doc_create" ||
2761
+ entry.entryType === "doc_change" ||
2762
+ entry.entryType === "doc_delete" ||
2763
+ entry.entryType === "doc_undelete" ||
2764
+ entry.entryType === "doc_snapshot");
2695
2765
  const visibility = this.deriveDocumentVisibilityMetadata(metadata);
2696
2766
  if (!visibility) {
2697
2767
  continue;
@@ -2722,7 +2792,10 @@ class BaseMindooDB {
2722
2792
  * directory was synced in a session that never opened this DB).
2723
2793
  */
2724
2794
  async reconcileAuthorTrustAtOpen() {
2725
- if (this.isTimeTravelMode() || this._isAdminOnlyDb || this.store.getId() === types_1.DIRECTORY_DB_ID || this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
2795
+ if (this.isTimeTravelMode() ||
2796
+ this._isAdminOnlyDb ||
2797
+ this.store.getId() === types_1.DIRECTORY_DB_ID ||
2798
+ this.store.getId() === types_1.USER_DIRECTORY_DB_ID) {
2726
2799
  return;
2727
2800
  }
2728
2801
  if (this.legacyCheckpointNeedsAuthorTrustScan) {
@@ -2775,7 +2848,7 @@ class BaseMindooDB {
2775
2848
  const headEntryIds = this.findActiveReplayHeadEntryIds(replayEntries);
2776
2849
  const hasUnappliedHead = headEntryIds.some((entryId) => {
2777
2850
  const parsed = (0, idGeneration_1.parseDocEntryId)(entryId);
2778
- return parsed !== null && !(applied?.has(parsed.automergeHash));
2851
+ return parsed !== null && !applied?.has(parsed.automergeHash);
2779
2852
  });
2780
2853
  if (!hasUnappliedHead) {
2781
2854
  continue;
@@ -2796,11 +2869,11 @@ class BaseMindooDB {
2796
2869
  async reconcileRestoredIndexWithStore() {
2797
2870
  const lifecycleMetadata = await this.scanAllMetadata(this.store);
2798
2871
  const lifecycleDocIds = Array.from(new Set(lifecycleMetadata
2799
- .filter((entry) => entry.entryType === "doc_create"
2800
- || entry.entryType === "doc_change"
2801
- || entry.entryType === "doc_delete"
2802
- || entry.entryType === "doc_undelete"
2803
- || entry.entryType === "doc_snapshot")
2872
+ .filter((entry) => entry.entryType === "doc_create" ||
2873
+ entry.entryType === "doc_change" ||
2874
+ entry.entryType === "doc_delete" ||
2875
+ entry.entryType === "doc_undelete" ||
2876
+ entry.entryType === "doc_snapshot")
2804
2877
  .map((entry) => entry.docId))).sort((left, right) => left.localeCompare(right));
2805
2878
  const missingDocIds = lifecycleDocIds.filter((docId) => !this.indexLookup.has(docId));
2806
2879
  if (missingDocIds.length === 0) {
@@ -2974,7 +3047,9 @@ class BaseMindooDB {
2974
3047
  // the index, so record it for `getInaccessibleDocumentCount`.
2975
3048
  this.noteInaccessibleDocument(docId);
2976
3049
  const existingIndex = this.getDocIndexPosition(docId);
2977
- const existing = existingIndex === undefined ? undefined : this.index[existingIndex];
3050
+ const existing = existingIndex === undefined
3051
+ ? undefined
3052
+ : this.index[existingIndex];
2978
3053
  if (existing?.accessState === "visible") {
2979
3054
  await this.purgeMaterializedDocument(docId);
2980
3055
  this.updateIndex(docId, existing.lastModified, true, representativeEntry.decryptionKeyId, "inaccessible");
@@ -2992,7 +3067,9 @@ class BaseMindooDB {
2992
3067
  const mutationEntries = allDocMetadata.filter((e) => this.isDocumentReplayEntry(e));
2993
3068
  // Snapshots compact replay history but should not change the user-visible
2994
3069
  // modification time when the original create/change/delete/undelete entries still exist.
2995
- const entriesForLastModified = mutationEntries.length > 0 ? mutationEntries : docLifecycleEntries;
3070
+ const entriesForLastModified = mutationEntries.length > 0
3071
+ ? mutationEntries
3072
+ : docLifecycleEntries;
2996
3073
  const lastModified = Math.max(...entriesForLastModified.map((e) => e.createdAt));
2997
3074
  const isDeleted = this.computeIsDeletedFromMetadata(allDocMetadata);
2998
3075
  const { awaitingWitness, witnessed } = (0, storeEntryTime_1.metadataWitnessState)(allDocMetadata);
@@ -3036,11 +3113,11 @@ class BaseMindooDB {
3036
3113
  const existingIndex = this.getDocIndexPosition(docId);
3037
3114
  const existing = existingIndex === undefined ? undefined : this.index[existingIndex];
3038
3115
  if (existing?.accessState === "visible") {
3039
- const lifecycleEntriesInBatch = entryMetadataList.filter((entry) => entry.entryType === "doc_create"
3040
- || entry.entryType === "doc_change"
3041
- || entry.entryType === "doc_delete"
3042
- || entry.entryType === "doc_undelete"
3043
- || entry.entryType === "doc_snapshot");
3116
+ const lifecycleEntriesInBatch = entryMetadataList.filter((entry) => entry.entryType === "doc_create" ||
3117
+ entry.entryType === "doc_change" ||
3118
+ entry.entryType === "doc_delete" ||
3119
+ entry.entryType === "doc_undelete" ||
3120
+ entry.entryType === "doc_snapshot");
3044
3121
  // Prefer a lifecycle entry from the failing batch for the
3045
3122
  // key id (they all share the same `decryptionKeyId` for a
3046
3123
  // doc), then fall back to any entry, then to the existing
@@ -3058,7 +3135,7 @@ class BaseMindooDB {
3058
3135
  this.cacheManager?.markDirty();
3059
3136
  }
3060
3137
  if (!this.supportsCursorScan(this.store)) {
3061
- this.processedEntryIds.push(...entryMetadataList.map(em => em.id));
3138
+ this.processedEntryIds.push(...entryMetadataList.map((em) => em.id));
3062
3139
  }
3063
3140
  return;
3064
3141
  }
@@ -3078,8 +3155,7 @@ class BaseMindooDB {
3078
3155
  });
3079
3156
  }
3080
3157
  };
3081
- const documentEntries = Array.from(entriesByDoc.entries())
3082
- .sort((a, b) => {
3158
+ const documentEntries = Array.from(entriesByDoc.entries()).sort((a, b) => {
3083
3159
  // Prefer the store's receiptOrder (unique, reflects the actual write
3084
3160
  // order) so a cold rebuild assigns changeSeqs in the same order the
3085
3161
  // live session did — `createdAt` has millisecond resolution and ties
@@ -3106,7 +3182,7 @@ class BaseMindooDB {
3106
3182
  // cursor-capable stores track progress via processedEntryCursor, so we
3107
3183
  // avoid growing an unbounded in-memory id list.
3108
3184
  if (!this.supportsCursorScan(this.store)) {
3109
- this.processedEntryIds.push(...newEntryMetadata.map(em => em.id));
3185
+ this.processedEntryIds.push(...newEntryMetadata.map((em) => em.id));
3110
3186
  }
3111
3187
  this.processedEntryCursor = nextCursor;
3112
3188
  this.cacheMetaDirty = true;
@@ -3498,10 +3574,18 @@ class BaseMindooDB {
3498
3574
  this.logger.info(`Dense sync: ${missingIds.length} entries to transfer ` +
3499
3575
  `(${allNeededArray.length - missingIds.length} already present)`);
3500
3576
  if (missingIds.length === 0) {
3501
- return { transferred: 0, scanned: allNeededArray.length, cancelled: false };
3577
+ return {
3578
+ transferred: 0,
3579
+ scanned: allNeededArray.length,
3580
+ cancelled: false,
3581
+ };
3502
3582
  }
3503
3583
  if (options?.signal?.aborted) {
3504
- return { transferred: 0, scanned: allNeededArray.length, cancelled: true };
3584
+ return {
3585
+ transferred: 0,
3586
+ scanned: allNeededArray.length,
3587
+ cancelled: true,
3588
+ };
3505
3589
  }
3506
3590
  // ── Phase 5: transfer missing entries in pages ───────────────────
3507
3591
  const pageSize = options?.pageSize ?? 500;
@@ -3510,7 +3594,13 @@ class BaseMindooDB {
3510
3594
  const rejected = [];
3511
3595
  for (let offset = 0; offset < missingIds.length; offset += pageSize) {
3512
3596
  if (options?.signal?.aborted) {
3513
- return { transferred, transferredBytes, scanned: allNeededArray.length, cancelled: true, rejected };
3597
+ return {
3598
+ transferred,
3599
+ transferredBytes,
3600
+ scanned: allNeededArray.length,
3601
+ cancelled: true,
3602
+ rejected,
3603
+ };
3514
3604
  }
3515
3605
  const batch = missingIds.slice(offset, offset + pageSize);
3516
3606
  const entries = await sourceStore.getEntries(batch);
@@ -3526,7 +3616,9 @@ class BaseMindooDB {
3526
3616
  if (receipts.length > 0 && sourceStore.applyWitnessReceipts) {
3527
3617
  await sourceStore.applyWitnessReceipts(receipts);
3528
3618
  }
3529
- const rejectedIds = batchRejected.length > 0 ? new Set(batchRejected.map((entry) => entry.id)) : null;
3619
+ const rejectedIds = batchRejected.length > 0
3620
+ ? new Set(batchRejected.map((entry) => entry.id))
3621
+ : null;
3530
3622
  if (rejectedIds) {
3531
3623
  rejected.push(...batchRejected);
3532
3624
  this.logger.warn(`Dense sync: target rejected ${batchRejected.length} of ${entries.length} entries in batch at offset ${offset}`);
@@ -3549,7 +3641,13 @@ class BaseMindooDB {
3549
3641
  }
3550
3642
  this.logger.info(`Dense sync complete: transferred ${transferred} entries` +
3551
3643
  (rejected.length > 0 ? `, ${rejected.length} rejected by target` : ""));
3552
- return { transferred, transferredBytes, scanned: allNeededArray.length, cancelled: false, rejected };
3644
+ return {
3645
+ transferred,
3646
+ transferredBytes,
3647
+ scanned: allNeededArray.length,
3648
+ cancelled: false,
3649
+ rejected,
3650
+ };
3553
3651
  }
3554
3652
  getStore() {
3555
3653
  return this.store;
@@ -3578,20 +3676,23 @@ class BaseMindooDB {
3578
3676
  continue;
3579
3677
  }
3580
3678
  const liveDoc = await this.getDocument(ledger.docId).catch(() => null);
3581
- if (liveDoc?.getAttachments().some((attachment) => attachment.attachmentId === attachmentId)) {
3679
+ if (liveDoc
3680
+ ?.getAttachments()
3681
+ .some((attachment) => attachment.attachmentId === attachmentId)) {
3582
3682
  await this.clearPendingAttachmentUploadLedger(attachmentId);
3583
3683
  result.keptCommittedUploads++;
3584
3684
  continue;
3585
3685
  }
3586
- const docEntries = await this.scanAllMetadata(this.store, { docId: ledger.docId });
3686
+ const docEntries = await this.scanAllMetadata(this.store, {
3687
+ docId: ledger.docId,
3688
+ });
3587
3689
  const mentionedByHistory = docEntries.some((entry) => entry.attachmentIds?.includes(attachmentId));
3588
3690
  if (mentionedByHistory) {
3589
3691
  await this.clearPendingAttachmentUploadLedger(attachmentId);
3590
3692
  result.keptCommittedUploads++;
3591
3693
  continue;
3592
3694
  }
3593
- const deletedChunks = await this.getEffectiveAttachmentStore()
3594
- .deleteEntriesForAttachment?.(ledger.docId, attachmentId) ?? 0;
3695
+ const deletedChunks = (await this.getEffectiveAttachmentStore().deleteEntriesForAttachment?.(ledger.docId, attachmentId)) ?? 0;
3595
3696
  await this.clearPendingAttachmentUploadLedger(attachmentId);
3596
3697
  result.reclaimedUploads++;
3597
3698
  result.reclaimedChunks += deletedChunks;
@@ -3617,7 +3718,11 @@ class BaseMindooDB {
3617
3718
  * @deprecated Use `createDocument({ signingKeyPair, signingKeyPassword, decryptionKeyId })` instead.
3618
3719
  */
3619
3720
  async createDocumentWithSigningKey(signingKeyPair, signingKeyPassword, decryptionKeyId) {
3620
- return this.createDocumentInternal({ signingKeyPair, signingKeyPassword, decryptionKeyId });
3721
+ return this.createDocumentInternal({
3722
+ signingKeyPair,
3723
+ signingKeyPassword,
3724
+ decryptionKeyId,
3725
+ });
3621
3726
  }
3622
3727
  /**
3623
3728
  * Bulk-create documents in a single append-only store write.
@@ -3655,7 +3760,8 @@ class BaseMindooDB {
3655
3760
  // in the batch must reject the whole call without side effects.
3656
3761
  for (const input of inputs) {
3657
3762
  const options = input ?? {};
3658
- if ((options.signingKeyPair !== undefined) !== (options.signingKeyPassword !== undefined)) {
3763
+ if ((options.signingKeyPair !== undefined) !==
3764
+ (options.signingKeyPassword !== undefined)) {
3659
3765
  throw new Error("createDocuments: signingKeyPair and signingKeyPassword must be provided together");
3660
3766
  }
3661
3767
  if (options.id !== undefined && !types_1.CUSTOM_DOC_ID_REGEX.test(options.id)) {
@@ -3839,7 +3945,9 @@ class BaseMindooDB {
3839
3945
  const createUsernameHash = this.usernameHashFromRecord(Object.fromEntries(initialValueEntries));
3840
3946
  // The id is settled before the write gate because it decides which rule
3841
3947
  // applies in `userdirectory`: a personal document is recognized by its id.
3842
- const docId = useCustomDocId ? options.id : this.generateUnusedDocId(options.idPrefix);
3948
+ const docId = useCustomDocId
3949
+ ? options.id
3950
+ : this.generateUnusedDocId(options.idPrefix);
3843
3951
  await this.assertBuiltinWriteAllowed("doc_create", signerPublicKey, createUsernameHash, docId);
3844
3952
  // Idempotent create: when a caller-provided id already exists locally,
3845
3953
  // return the existing document instead of producing a duplicate doc_create.
@@ -3860,7 +3968,7 @@ class BaseMindooDB {
3860
3968
  }
3861
3969
  }
3862
3970
  const keyId = await this.resolveCreateKeyId(options, docId);
3863
- this.logger.debug(`Creating document ${docId} with key ${keyId}${useCustomSigningKey ? ' using custom signing key' : ''}${useCustomDocId ? ' with caller-provided id' : ''}`);
3971
+ this.logger.debug(`Creating document ${docId} with key ${keyId}${useCustomSigningKey ? " using custom signing key" : ""}${useCustomDocId ? " with caller-provided id" : ""}`);
3864
3972
  // Build the initial Automerge document and its first change bytes.
3865
3973
  //
3866
3974
  // For UUID7 documents (and unique-by-assertion custom ids) we use the
@@ -3982,7 +4090,10 @@ class BaseMindooDB {
3982
4090
  // a later witness may stamp receivedAt, which resolveCreatorInfo picks up
3983
4091
  // on a cache miss. For the local writer, createdAt is sufficient: the
3984
4092
  // creating device is still granted.
3985
- this.creatorInfoCache.set(docId, { signingKey: createdByPublicKey, trustedTime: now });
4093
+ this.creatorInfoCache.set(docId, {
4094
+ signingKey: createdByPublicKey,
4095
+ trustedTime: now,
4096
+ });
3986
4097
  // Snapshot of attachments referenced by the freshly created doc (normally
3987
4098
  // empty; the public create API does not add attachments inline).
3988
4099
  const createAttachmentRefs = this.collectAttachmentRefs(newDoc);
@@ -4075,7 +4186,9 @@ class BaseMindooDB {
4075
4186
  : [];
4076
4187
  const signerPublicKey = await this.resolveSignerPublicKey(useCustomSigningKey ? signingKeyPair : undefined);
4077
4188
  const createUsernameHash = this.usernameHashFromRecord(Object.fromEntries(initialValueEntries));
4078
- const docId = useCustomDocId ? options.id : this.generateUnusedDocId(options.idPrefix);
4189
+ const docId = useCustomDocId
4190
+ ? options.id
4191
+ : this.generateUnusedDocId(options.idPrefix);
4079
4192
  await this.assertBuiltinWriteAllowed("doc_create", signerPublicKey, createUsernameHash, docId);
4080
4193
  const now = (0, timeSource_1.semanticNow)();
4081
4194
  const keyId = await this.resolveCreateKeyId(options, docId);
@@ -4167,7 +4280,10 @@ class BaseMindooDB {
4167
4280
  // a later witness may stamp receivedAt, which resolveCreatorInfo picks up
4168
4281
  // on a cache miss. For the local writer, createdAt is sufficient: the
4169
4282
  // creating device is still granted.
4170
- this.creatorInfoCache.set(docId, { signingKey: createdByPublicKey, trustedTime: now });
4283
+ this.creatorInfoCache.set(docId, {
4284
+ signingKey: createdByPublicKey,
4285
+ trustedTime: now,
4286
+ });
4171
4287
  const createAttachmentRefs = this.collectAttachmentRefs(finalDoc);
4172
4288
  const entryMetadata = {
4173
4289
  entryType: "doc_create",
@@ -4187,10 +4303,12 @@ class BaseMindooDB {
4187
4303
  };
4188
4304
  // Bind the metadata with the author signature (audit finding #5).
4189
4305
  entryMetadata.metadataSignature = await this.computeEntryMetadataSignature(entryMetadata, useCustomSigningKey ? { signingKeyPair, signingKeyPassword } : undefined);
4190
- const entries = [{
4306
+ const entries = [
4307
+ {
4191
4308
  ...entryMetadata,
4192
4309
  encryptedData: encryptedPayload,
4193
- }];
4310
+ },
4311
+ ];
4194
4312
  // Register the mapping BEFORE building the follow-up change entry so its
4195
4313
  // dependency resolution finds the doc_create parent.
4196
4314
  this.registerAutomergeHashMapping(docId, createHash, entryId);
@@ -4263,12 +4381,12 @@ class BaseMindooDB {
4263
4381
  // consistent: the state at `timestamp` is the deterministic merge of all
4264
4382
  // complete causal chains up to that instant.
4265
4383
  const relevantEntries = (0, DocumentDagAnalysis_1.pruneToGroundedEntries)(allEntryMetadata
4266
- .filter((em) => em.createdAt <= timestamp
4267
- && (em.entryType === "doc_create"
4268
- || em.entryType === "doc_change"
4269
- || em.entryType === "doc_delete"
4270
- || em.entryType === "doc_undelete"
4271
- || em.entryType === "doc_snapshot"))
4384
+ .filter((em) => em.createdAt <= timestamp &&
4385
+ (em.entryType === "doc_create" ||
4386
+ em.entryType === "doc_change" ||
4387
+ em.entryType === "doc_delete" ||
4388
+ em.entryType === "doc_undelete" ||
4389
+ em.entryType === "doc_snapshot"))
4272
4390
  .sort((a, b) => a.createdAt - b.createdAt));
4273
4391
  if (relevantEntries.length === 0) {
4274
4392
  this.performanceCallback?.onHistoryOperation?.({
@@ -4284,7 +4402,7 @@ class BaseMindooDB {
4284
4402
  const materializationPlan = (0, MaterializationPlanner_1.computeDocumentMaterializationPlan)(docId, relevantEntries);
4285
4403
  let startFromSnapshot = materializationPlan.snapshotEntryId !== null;
4286
4404
  const snapshotMeta = materializationPlan.snapshotEntryId
4287
- ? (metadataById.get(materializationPlan.snapshotEntryId) || null)
4405
+ ? metadataById.get(materializationPlan.snapshotEntryId) || null
4288
4406
  : null;
4289
4407
  if (startFromSnapshot && !snapshotMeta) {
4290
4408
  this.logger.warn(`Planner referenced snapshot ${materializationPlan.snapshotEntryId} not found in metadata for ${docId}; falling back to replay without snapshot`);
@@ -4363,9 +4481,9 @@ class BaseMindooDB {
4363
4481
  const firstReplayEntry = replayEntries.length > 0 ? replayEntries[0] : null;
4364
4482
  const lastReplayEntry = replayEntries.length > 0 ? replayEntries[replayEntries.length - 1] : null;
4365
4483
  const createdAt = firstReplayEntry?.createdAt ?? snapshotMeta?.createdAt ?? timestamp;
4366
- const decryptionKeyId = firstReplayEntry?.decryptionKeyId
4367
- ?? snapshotMeta?.decryptionKeyId
4368
- ?? "default";
4484
+ const decryptionKeyId = firstReplayEntry?.decryptionKeyId ??
4485
+ snapshotMeta?.decryptionKeyId ??
4486
+ "default";
4369
4487
  const isDeleted = this.computeIsDeletedFromMetadata(relevantEntries);
4370
4488
  const lastModified = lastReplayEntry?.createdAt ?? snapshotMeta?.createdAt ?? timestamp;
4371
4489
  const internalDoc = {
@@ -4396,8 +4514,8 @@ class BaseMindooDB {
4396
4514
  async ingestSealedKeyFromEntries(entries) {
4397
4515
  if (entries.length === 0)
4398
4516
  return;
4399
- const keyId = entries.find((entry) => entry.entryType === "doc_create")?.decryptionKeyId
4400
- ?? entries[0].decryptionKeyId;
4517
+ const keyId = entries.find((entry) => entry.entryType === "doc_create")
4518
+ ?.decryptionKeyId ?? entries[0].decryptionKeyId;
4401
4519
  await this.tenant.ingestSealedFromEntries?.(keyId, entries);
4402
4520
  }
4403
4521
  /**
@@ -4411,7 +4529,9 @@ class BaseMindooDB {
4411
4529
  if (!(0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId)) {
4412
4530
  return false;
4413
4531
  }
4414
- const metas = await this.scanAllMetadata(this.store, { docId: internalDoc.id });
4532
+ const metas = await this.scanAllMetadata(this.store, {
4533
+ docId: internalDoc.id,
4534
+ });
4415
4535
  await this.ingestSealedKeyFromEntries(metas);
4416
4536
  if (await this.tenant.hasDecryptionKey(internalDoc.decryptionKeyId)) {
4417
4537
  return false;
@@ -4454,10 +4574,10 @@ class BaseMindooDB {
4454
4574
  return; // Document has no history
4455
4575
  }
4456
4576
  // Load all entries
4457
- const entries = await this.store.getEntries(relevantEntries.map(em => em.id));
4577
+ const entries = await this.store.getEntries(relevantEntries.map((em) => em.id));
4458
4578
  await this.ingestSealedKeyFromEntries(entries.length > 0 ? entries : relevantEntries);
4459
4579
  // Build a map for quick lookup
4460
- const entryMap = new Map(entries.map(e => [e.id, e]));
4580
+ const entryMap = new Map(entries.map((e) => [e.id, e]));
4461
4581
  // Apply changes in order
4462
4582
  let currentDoc = null;
4463
4583
  let createdAt = null;
@@ -4494,7 +4614,11 @@ class BaseMindooDB {
4494
4614
  decryptionKeyId = entryMetadata.decryptionKeyId;
4495
4615
  }
4496
4616
  // Check document heads before applying change (for non-first entries)
4497
- const headsBefore = isFirstEntry ? null : (currentDoc ? automerge_adapter_1.Automerge.getHeads(currentDoc) : null);
4617
+ const headsBefore = isFirstEntry
4618
+ ? null
4619
+ : currentDoc
4620
+ ? automerge_adapter_1.Automerge.getHeads(currentDoc)
4621
+ : null;
4498
4622
  // Apply change using loadIncremental
4499
4623
  if (currentDoc === null) {
4500
4624
  throw new Error("currentDoc should not be null at this point");
@@ -4505,12 +4629,15 @@ class BaseMindooDB {
4505
4629
  // For lifecycle terminal entries, always yield
4506
4630
  // For other entries, only yield if heads changed
4507
4631
  let shouldYield = false;
4508
- if (isFirstEntry || entryMetadata.entryType === "doc_delete" || entryMetadata.entryType === "doc_undelete") {
4632
+ if (isFirstEntry ||
4633
+ entryMetadata.entryType === "doc_delete" ||
4634
+ entryMetadata.entryType === "doc_undelete") {
4509
4635
  shouldYield = true;
4510
4636
  }
4511
4637
  else {
4512
4638
  const headsAfter = automerge_adapter_1.Automerge.getHeads(currentDoc);
4513
- const headsChanged = headsBefore !== null && JSON.stringify(headsBefore) !== JSON.stringify(headsAfter);
4639
+ const headsChanged = headsBefore !== null &&
4640
+ JSON.stringify(headsBefore) !== JSON.stringify(headsAfter);
4514
4641
  shouldYield = headsChanged;
4515
4642
  }
4516
4643
  // Register automerge hash mapping
@@ -4739,7 +4866,7 @@ class BaseMindooDB {
4739
4866
  tt: (0, storeEntryTime_1.entryTrustedTime)(meta, now),
4740
4867
  witnessed: meta.receivedAt !== undefined,
4741
4868
  }))
4742
- .sort((a, b) => (a.tt !== b.tt ? a.tt - b.tt : a.meta.id.localeCompare(b.meta.id)));
4869
+ .sort((a, b) => a.tt !== b.tt ? a.tt - b.tt : a.meta.id.localeCompare(b.meta.id));
4743
4870
  // First trusted-time position touched by a newly-discovered entry. From here
4744
4871
  // the doc's merged state (and every later revision) may have changed, so we
4745
4872
  // re-fold and re-emit the suffix; earlier revisions are unchanged.
@@ -4870,7 +4997,8 @@ class BaseMindooDB {
4870
4997
  };
4871
4998
  }
4872
4999
  // Cache miss: reconstruct from the best in-prefix snapshot + uncovered tail.
4873
- const prefixSnapshots = docAllMeta.filter((m) => m.entryType === "doc_snapshot" && this.snapshotRootsWithin(m, prefixIds));
5000
+ const prefixSnapshots = docAllMeta.filter((m) => m.entryType === "doc_snapshot" &&
5001
+ this.snapshotRootsWithin(m, prefixIds));
4874
5002
  const planInput = [...prefix, ...prefixSnapshots];
4875
5003
  const plan = (0, MaterializationPlanner_1.computeDocumentMaterializationPlan)(docId, planInput);
4876
5004
  const metadataById = new Map(planInput.map((m) => [m.id, m]));
@@ -4908,7 +5036,8 @@ class BaseMindooDB {
4908
5036
  * use as a seed without pulling in later changes).
4909
5037
  */
4910
5038
  snapshotRootsWithin(snapshotMeta, idSet) {
4911
- const roots = snapshotMeta.snapshotHeadEntryIds && snapshotMeta.snapshotHeadEntryIds.length > 0
5039
+ const roots = snapshotMeta.snapshotHeadEntryIds &&
5040
+ snapshotMeta.snapshotHeadEntryIds.length > 0
4912
5041
  ? snapshotMeta.snapshotHeadEntryIds
4913
5042
  : snapshotMeta.dependencyIds;
4914
5043
  if (!roots || roots.length === 0) {
@@ -5059,8 +5188,7 @@ class BaseMindooDB {
5059
5188
  if (allEntryMetadata.length > 0) {
5060
5189
  await this.ingestSealedKeyFromEntries(allEntryMetadata);
5061
5190
  }
5062
- const relevantEntries = allEntryMetadata
5063
- .filter((entry) => entry.createdAt <= resolvedTimestamp && (0, DocumentDagAnalysis_1.isDagEntry)(entry));
5191
+ const relevantEntries = allEntryMetadata.filter((entry) => entry.createdAt <= resolvedTimestamp && (0, DocumentDagAnalysis_1.isDagEntry)(entry));
5064
5192
  const result = (0, DocumentDagAnalysis_1.computeDocumentDagAnalysis)(docId, relevantEntries, resolvedTimestamp);
5065
5193
  const actorIdByEntryId = await this.decodeAutomergeActorIds(relevantEntries);
5066
5194
  result.entries = result.entries.map((entry) => ({
@@ -5106,7 +5234,9 @@ class BaseMindooDB {
5106
5234
  }
5107
5235
  const decryptedPayload = await this.tenant.decryptPayload(entry.encryptedData, entry.decryptionKeyId);
5108
5236
  const decodedAutomergeChange = automerge_adapter_1.Automerge.decodeChange(decryptedPayload);
5109
- result.set(metadata.id, typeof decodedAutomergeChange.actor === "string" ? decodedAutomergeChange.actor : null);
5237
+ result.set(metadata.id, typeof decodedAutomergeChange.actor === "string"
5238
+ ? decodedAutomergeChange.actor
5239
+ : null);
5110
5240
  }
5111
5241
  return result;
5112
5242
  }
@@ -5199,8 +5329,7 @@ class BaseMindooDB {
5199
5329
  const startedAt = Date.now();
5200
5330
  const resolvedTimestamp = this.resolveDagTimestamp(timestamp);
5201
5331
  const allEntryMetadata = await this.scanAllMetadata(this.store, { docId });
5202
- const relevantEntries = allEntryMetadata
5203
- .filter((entry) => entry.createdAt <= resolvedTimestamp && (0, DocumentDagAnalysis_1.isDagEntry)(entry));
5332
+ const relevantEntries = allEntryMetadata.filter((entry) => entry.createdAt <= resolvedTimestamp && (0, DocumentDagAnalysis_1.isDagEntry)(entry));
5204
5333
  const plan = (0, DocumentDagAnalysis_1.computeBranchMaterializationPlan)(docId, relevantEntries, headEntryId);
5205
5334
  if (!plan) {
5206
5335
  this.performanceCallback?.onHistoryOperation?.({
@@ -5256,7 +5385,9 @@ class BaseMindooDB {
5256
5385
  }
5257
5386
  let decodedChange = null;
5258
5387
  if (metadata.entryType !== "doc_snapshot") {
5259
- const allEntryMetadata = await this.scanAllMetadata(this.store, { docId });
5388
+ const allEntryMetadata = await this.scanAllMetadata(this.store, {
5389
+ docId,
5390
+ });
5260
5391
  if (allEntryMetadata.length > 0) {
5261
5392
  await this.ingestSealedKeyFromEntries(allEntryMetadata);
5262
5393
  }
@@ -5330,7 +5461,9 @@ class BaseMindooDB {
5330
5461
  const docStartedAt = Date.now();
5331
5462
  yield { type: "docStart", docId };
5332
5463
  try {
5333
- const allEntryMetadata = await this.scanAllMetadata(this.store, { docId });
5464
+ const allEntryMetadata = await this.scanAllMetadata(this.store, {
5465
+ docId,
5466
+ });
5334
5467
  yield {
5335
5468
  type: "progress",
5336
5469
  scannedDocs,
@@ -5731,9 +5864,10 @@ class BaseMindooDB {
5731
5864
  if (typeof entry.receiptOrder !== "number") {
5732
5865
  continue;
5733
5866
  }
5734
- maxReceiptOrder = maxReceiptOrder === undefined
5735
- ? entry.receiptOrder
5736
- : Math.max(maxReceiptOrder, entry.receiptOrder);
5867
+ maxReceiptOrder =
5868
+ maxReceiptOrder === undefined
5869
+ ? entry.receiptOrder
5870
+ : Math.max(maxReceiptOrder, entry.receiptOrder);
5737
5871
  }
5738
5872
  return maxReceiptOrder;
5739
5873
  }
@@ -5799,7 +5933,9 @@ class BaseMindooDB {
5799
5933
  conflicts.push({
5800
5934
  docId,
5801
5935
  location: {
5802
- kind: change.entry.dependencyIds.length > 1 ? "merge-deps" : "active-heads",
5936
+ kind: change.entry.dependencyIds.length > 1
5937
+ ? "merge-deps"
5938
+ : "active-heads",
5803
5939
  entryId: change.entry.id,
5804
5940
  createdAt: change.entry.createdAt,
5805
5941
  receiptOrder: change.entry.receiptOrder,
@@ -5831,14 +5967,17 @@ class BaseMindooDB {
5831
5967
  }
5832
5968
  const pathString = (0, DocumentConflictAnalysis_1.formatDocumentConflictPath)(path);
5833
5969
  const action = this.getConflictPatchAction(patch);
5834
- const isConflictPut = action === "put" && (this.isConflictPatch(patch) || this.hasDocumentConflictAtPath(afterDoc, path));
5970
+ const isConflictPut = action === "put" &&
5971
+ (this.isConflictPatch(patch) ||
5972
+ this.hasDocumentConflictAtPath(afterDoc, path));
5835
5973
  if (isConflictPut) {
5836
5974
  const conflictPath = this.buildDocumentConflictPath(afterDoc, path, options.detail === "values");
5837
5975
  detectedPaths.set(pathString, conflictPath);
5838
5976
  activeConflictPaths.set(pathString, conflictPath);
5839
5977
  continue;
5840
5978
  }
5841
- if ((action === "put" || action === "del") && activeConflictPaths.has(pathString)) {
5979
+ if ((action === "put" || action === "del") &&
5980
+ activeConflictPaths.has(pathString)) {
5842
5981
  if (this.shouldEmitConflictObservation(change.entry, options)) {
5843
5982
  resolutions.push({
5844
5983
  type: "conflictResolved",
@@ -5854,7 +5993,8 @@ class BaseMindooDB {
5854
5993
  activeConflictPaths.delete(pathString);
5855
5994
  }
5856
5995
  }
5857
- if (detectedPaths.size > 0 && this.shouldEmitConflictObservation(change.entry, options)) {
5996
+ if (detectedPaths.size > 0 &&
5997
+ this.shouldEmitConflictObservation(change.entry, options)) {
5858
5998
  conflicts.push({
5859
5999
  docId,
5860
6000
  location: {
@@ -5874,33 +6014,37 @@ class BaseMindooDB {
5874
6014
  doc = afterDoc;
5875
6015
  entriesApplied++;
5876
6016
  const conflictPathCount = conflicts.reduce((count, conflict) => count + conflict.paths.length, 0);
5877
- if (maxConflictsPerDoc !== undefined && conflictPathCount >= maxConflictsPerDoc) {
6017
+ if (maxConflictsPerDoc !== undefined &&
6018
+ conflictPathCount >= maxConflictsPerDoc) {
5878
6019
  break;
5879
6020
  }
5880
6021
  }
5881
6022
  // If the document still has multiple active heads after replay, there may
5882
6023
  // be unresolved conflicts with no later patch to surface them. Do one final
5883
6024
  // tree scan in that bounded case so active conflicts are visible.
5884
- if (plan.activeHeadEntryIds.length > 1
5885
- && (maxConflictsPerDoc === undefined
5886
- || conflicts.reduce((count, conflict) => count + conflict.paths.length, 0) < maxConflictsPerDoc)) {
6025
+ if (plan.activeHeadEntryIds.length > 1 &&
6026
+ (maxConflictsPerDoc === undefined ||
6027
+ conflicts.reduce((count, conflict) => count + conflict.paths.length, 0) < maxConflictsPerDoc)) {
5887
6028
  const alreadyReported = new Set(conflicts.flatMap((conflict) => conflict.paths.map((path) => path.pathString)));
5888
6029
  const activeConflictPaths = this.collectDocumentConflictPaths(doc, options.detail === "values").filter((path) => !alreadyReported.has(path.pathString));
5889
6030
  const remainingBudget = maxConflictsPerDoc === undefined
5890
6031
  ? activeConflictPaths.length
5891
- : Math.max(0, maxConflictsPerDoc - conflicts.reduce((count, conflict) => count + conflict.paths.length, 0));
6032
+ : Math.max(0, maxConflictsPerDoc -
6033
+ conflicts.reduce((count, conflict) => count + conflict.paths.length, 0));
5892
6034
  const boundedActiveConflictPaths = activeConflictPaths.slice(0, remainingBudget);
5893
6035
  if (boundedActiveConflictPaths.length > 0) {
5894
6036
  const activeHeadEntries = plan.activeHeadEntryIds
5895
6037
  .map((entryId) => plan.replayById.get(entryId))
5896
6038
  .filter((entry) => entry !== undefined);
5897
- const latestActiveHeadEntry = activeHeadEntries
5898
- .sort((left, right) => {
6039
+ const latestActiveHeadEntry = activeHeadEntries.sort((left, right) => {
5899
6040
  const leftOrder = left.receiptOrder ?? left.createdAt;
5900
6041
  const rightOrder = right.receiptOrder ?? right.createdAt;
5901
- return leftOrder !== rightOrder ? rightOrder - leftOrder : right.id.localeCompare(left.id);
6042
+ return leftOrder !== rightOrder
6043
+ ? rightOrder - leftOrder
6044
+ : right.id.localeCompare(left.id);
5902
6045
  })[0];
5903
- if (options.includeUnresolvedFromBefore || this.shouldEmitConflictObservation(latestActiveHeadEntry, options)) {
6046
+ if (options.includeUnresolvedFromBefore ||
6047
+ this.shouldEmitConflictObservation(latestActiveHeadEntry, options)) {
5904
6048
  conflicts.push({
5905
6049
  docId,
5906
6050
  location: {
@@ -5932,8 +6076,8 @@ class BaseMindooDB {
5932
6076
  if (!entry) {
5933
6077
  return options.includeUnresolvedFromBefore === true;
5934
6078
  }
5935
- if (typeof entry.receiptOrder === "number"
5936
- && typeof options.since.storeReceiptOrderAsOf === "number") {
6079
+ if (typeof entry.receiptOrder === "number" &&
6080
+ typeof options.since.storeReceiptOrderAsOf === "number") {
5937
6081
  return entry.receiptOrder > options.since.storeReceiptOrderAsOf;
5938
6082
  }
5939
6083
  return entry.createdAt > options.since.takenAt;
@@ -6245,13 +6389,15 @@ class BaseMindooDB {
6245
6389
  * @returns JSON-safe scalar, array/object subset, or compact placeholder.
6246
6390
  */
6247
6391
  toJsonSafeConflictValue(value, depth = 0, seen = new WeakSet()) {
6248
- if (value === null
6249
- || typeof value === "string"
6250
- || typeof value === "number"
6251
- || typeof value === "boolean") {
6392
+ if (value === null ||
6393
+ typeof value === "string" ||
6394
+ typeof value === "number" ||
6395
+ typeof value === "boolean") {
6252
6396
  return value;
6253
6397
  }
6254
- if (value === undefined || typeof value === "function" || typeof value === "symbol") {
6398
+ if (value === undefined ||
6399
+ typeof value === "function" ||
6400
+ typeof value === "symbol") {
6255
6401
  return undefined;
6256
6402
  }
6257
6403
  if (value instanceof Uint8Array) {
@@ -6268,7 +6414,9 @@ class BaseMindooDB {
6268
6414
  }
6269
6415
  seen.add(value);
6270
6416
  if (Array.isArray(value)) {
6271
- return value.slice(0, 50).map((item) => this.toJsonSafeConflictValue(item, depth + 1, seen));
6417
+ return value
6418
+ .slice(0, 50)
6419
+ .map((item) => this.toJsonSafeConflictValue(item, depth + 1, seen));
6272
6420
  }
6273
6421
  const result = {};
6274
6422
  for (const [key, child] of Object.entries(value).slice(0, 50)) {
@@ -6379,9 +6527,9 @@ class BaseMindooDB {
6379
6527
  // and, on a time-travel instance, already reflects existence and deletion
6380
6528
  // at the cutoff (every scan feeding it is bounded by timeTravelDate). So
6381
6529
  // the scan below only has to supply dates, never lifecycle state.
6382
- const candidates = this.index.filter((entry) => entry.accessState === "visible"
6383
- && matchesLifecycle(entry.isDeleted)
6384
- && (idPrefix === undefined || (0, idGeneration_1.matchesDocIdPrefix)(entry.docId, idPrefix)));
6530
+ const candidates = this.index.filter((entry) => entry.accessState === "visible" &&
6531
+ matchesLifecycle(entry.isDeleted) &&
6532
+ (idPrefix === undefined || (0, idGeneration_1.matchesDocIdPrefix)(entry.docId, idPrefix)));
6385
6533
  if (candidates.length === 0) {
6386
6534
  return [];
6387
6535
  }
@@ -6463,11 +6611,13 @@ class BaseMindooDB {
6463
6611
  continue;
6464
6612
  }
6465
6613
  const createEntry = lifecycleEntries.find((entry) => entry.entryType === "doc_create");
6466
- if (createEntry && !(await this.tenant.hasDecryptionKey(createEntry.decryptionKeyId))) {
6614
+ if (createEntry &&
6615
+ !(await this.tenant.hasDecryptionKey(createEntry.decryptionKeyId))) {
6467
6616
  continue;
6468
6617
  }
6469
- const terminalEntries = lifecycleEntries.filter((entry) => (entry.entryType === "doc_delete" || entry.entryType === "doc_undelete")
6470
- && entry.createdAt <= timestamp);
6618
+ const terminalEntries = lifecycleEntries.filter((entry) => (entry.entryType === "doc_delete" ||
6619
+ entry.entryType === "doc_undelete") &&
6620
+ entry.createdAt <= timestamp);
6471
6621
  if (terminalEntries.length === 0) {
6472
6622
  // Fast path (the vast majority of documents): no delete/undelete ever
6473
6623
  // happened up to `timestamp`, so the document is alive and we never
@@ -6483,9 +6633,12 @@ class BaseMindooDB {
6483
6633
  // decided by id tie-break, which can disagree with causality and with
6484
6634
  // getDocumentAtTimestamp for the same instant. The extra per-doc
6485
6635
  // metadata scan is bounded by the number of ever-deleted documents.
6486
- const allEntryMetadata = await this.scanAllMetadata(this.store, { docId });
6487
- const relevantEntries = (0, DocumentDagAnalysis_1.pruneToGroundedEntries)(allEntryMetadata.filter((entry) => entry.createdAt <= timestamp
6488
- && (this.isDocumentReplayEntry(entry) || entry.entryType === "doc_snapshot")));
6636
+ const allEntryMetadata = await this.scanAllMetadata(this.store, {
6637
+ docId,
6638
+ });
6639
+ const relevantEntries = (0, DocumentDagAnalysis_1.pruneToGroundedEntries)(allEntryMetadata.filter((entry) => entry.createdAt <= timestamp &&
6640
+ (this.isDocumentReplayEntry(entry) ||
6641
+ entry.entryType === "doc_snapshot")));
6489
6642
  if (!this.computeIsDeletedFromMetadata(relevantEntries)) {
6490
6643
  docIds.push(docId);
6491
6644
  }
@@ -6517,7 +6670,8 @@ class BaseMindooDB {
6517
6670
  // One gate call per document id: inside `userdirectory` the applicable rule
6518
6671
  // depends on the id (personal documents are owned by their creator), so a
6519
6672
  // single batch-wide check would deny an owner deleting their own data.
6520
- if ((0, builtinDbInvariants_1.hasBuiltinWriteInvariant)(this.effectiveBuiltinDbId()) || this._isAdminOnlyDb) {
6673
+ if ((0, builtinDbInvariants_1.hasBuiltinWriteInvariant)(this.effectiveBuiltinDbId()) ||
6674
+ this._isAdminOnlyDb) {
6521
6675
  for (const docId of docIds) {
6522
6676
  await this.assertLifecycleMutationAllowed("doc_delete", options.signingKeyPair, options.signingKeyPassword, undefined, docId);
6523
6677
  }
@@ -6625,7 +6779,9 @@ class BaseMindooDB {
6625
6779
  mutableDoc._lastModified = now;
6626
6780
  }));
6627
6781
  if (automerge_adapter_1.Automerge.getHeads(newDoc).every((head) => headsBefore.includes(head))) {
6628
- newDoc = automerge_adapter_1.Automerge.emptyChange(newDoc, { time: now });
6782
+ newDoc = automerge_adapter_1.Automerge.emptyChange(newDoc, {
6783
+ time: now,
6784
+ });
6629
6785
  }
6630
6786
  const changeBytes = automerge_adapter_1.Automerge.getLastLocalChange(newDoc);
6631
6787
  if (!changeBytes) {
@@ -6669,7 +6825,9 @@ class BaseMindooDB {
6669
6825
  signature,
6670
6826
  originalSize: changeBytes.length,
6671
6827
  encryptedSize: encryptedPayload.length,
6672
- attachmentRefs: lifecycleAttachmentRefs.length > 0 ? lifecycleAttachmentRefs : undefined,
6828
+ attachmentRefs: lifecycleAttachmentRefs.length > 0
6829
+ ? lifecycleAttachmentRefs
6830
+ : undefined,
6673
6831
  entryVersion: types_1.CURRENT_STORE_ENTRY_VERSION,
6674
6832
  };
6675
6833
  // Bind the metadata with the author signature (audit finding #5).
@@ -6716,7 +6874,7 @@ class BaseMindooDB {
6716
6874
  * per-document flush-before-evict write storm during large batches.
6717
6875
  */
6718
6876
  async applyLifecycleEntryLocally(prepared, options) {
6719
- const { internalDoc, entryType, newDoc, automergeHash, entryId, entryMetadata, now } = prepared;
6877
+ const { internalDoc, entryType, newDoc, automergeHash, entryId, entryMetadata, now, } = prepared;
6720
6878
  const docId = internalDoc.id;
6721
6879
  this.registerAutomergeHashMapping(docId, automergeHash, entryId);
6722
6880
  // Keep the loaded document, cache, index, and sync dirty tracking in step
@@ -6726,10 +6884,12 @@ class BaseMindooDB {
6726
6884
  internalDoc.lastModified = now;
6727
6885
  // The delete/undelete entry just written is versioned and un-witnessed, so
6728
6886
  // the document is awaiting witness until pushed + stamped with a receipt.
6729
- internalDoc.awaitingWitness = (0, storeEntryTime_1.isProvisional)(entryMetadata) || (internalDoc.awaitingWitness ?? false);
6887
+ internalDoc.awaitingWitness =
6888
+ (0, storeEntryTime_1.isProvisional)(entryMetadata) || (internalDoc.awaitingWitness ?? false);
6730
6889
  // The doc is now witness-era (we just wrote a versioned entry), so it is
6731
6890
  // witnessed iff it is no longer awaiting a receipt.
6732
- internalDoc.witnessed = (0, storeEntryTime_1.isVersioned)(entryMetadata) && !internalDoc.awaitingWitness;
6891
+ internalDoc.witnessed =
6892
+ (0, storeEntryTime_1.isVersioned)(entryMetadata) && !internalDoc.awaitingWitness;
6733
6893
  // Force the changeSeq bump: a lifecycle entry was just written, so the
6734
6894
  // changefeed must re-emit the doc even if all tracked index fields happen
6735
6895
  // to match the previous state in the same millisecond.
@@ -6751,7 +6911,7 @@ class BaseMindooDB {
6751
6911
  */
6752
6912
  async deleteDocInternal(docId, signingKeyPair, signingKeyPassword, bypassPrecheck) {
6753
6913
  const useCustomSigningKey = signingKeyPair !== undefined && signingKeyPassword !== undefined;
6754
- this.logger.debug(`Deleting document ${docId}${useCustomSigningKey ? ' using custom signing key' : ''}`);
6914
+ this.logger.debug(`Deleting document ${docId}${useCustomSigningKey ? " using custom signing key" : ""}`);
6755
6915
  await this.assertLifecycleMutationAllowed("doc_delete", signingKeyPair, signingKeyPassword, undefined, docId);
6756
6916
  // Get current document
6757
6917
  const internalDoc = await this.loadDocumentInternal(docId);
@@ -6763,7 +6923,7 @@ class BaseMindooDB {
6763
6923
  }
6764
6924
  async undeleteDocInternal(docId, signingKeyPair, signingKeyPassword, bypassPrecheck) {
6765
6925
  const useCustomSigningKey = signingKeyPair !== undefined && signingKeyPassword !== undefined;
6766
- this.logger.debug(`Undeleting document ${docId}${useCustomSigningKey ? ' using custom signing key' : ''}`);
6926
+ this.logger.debug(`Undeleting document ${docId}${useCustomSigningKey ? " using custom signing key" : ""}`);
6767
6927
  const internalDoc = await this.loadDocumentInternal(docId);
6768
6928
  if (!internalDoc) {
6769
6929
  throw new errors_1.DocumentNotFoundError(docId);
@@ -6780,7 +6940,10 @@ class BaseMindooDB {
6780
6940
  return this.changeDocInternal(doc, changeFunc, options.signingKeyPair, options.signingKeyPassword, options.bypassAccessControlPrecheck);
6781
6941
  }
6782
6942
  async changeDocWithSigningKey(doc, changeFunc, signingKeyPair, signingKeyPassword) {
6783
- return this.changeDoc(doc, changeFunc, { signingKeyPair, signingKeyPassword });
6943
+ return this.changeDoc(doc, changeFunc, {
6944
+ signingKeyPair,
6945
+ signingKeyPassword,
6946
+ });
6784
6947
  }
6785
6948
  async applyTextPatch(doc, patch) {
6786
6949
  this.assertWritable("applyTextPatch");
@@ -7182,7 +7345,7 @@ class BaseMindooDB {
7182
7345
  throw new Error("changeDoc: signingKeyPair and signingKeyPassword must be provided together");
7183
7346
  }
7184
7347
  const useCustomKey = signingKeyPair !== undefined && signingKeyPassword !== undefined;
7185
- this.logger.debug(`===== ${useCustomKey ? 'changeDocWithSigningKey' : 'changeDoc'} called for document ${docId} =====`);
7348
+ this.logger.debug(`===== ${useCustomKey ? "changeDocWithSigningKey" : "changeDoc"} called for document ${docId} =====`);
7186
7349
  // Get internal document from cache or load it
7187
7350
  let internalDoc = this.getCachedDocument(docId);
7188
7351
  if (!internalDoc) {
@@ -7192,7 +7355,7 @@ class BaseMindooDB {
7192
7355
  throw new errors_1.DocumentNotFoundError(docId);
7193
7356
  }
7194
7357
  internalDoc = loadedDoc;
7195
- this.logger.debug(`Successfully loaded document ${docId} from store for ${useCustomKey ? 'changeDocWithSigningKey' : 'changeDoc'}`);
7358
+ this.logger.debug(`Successfully loaded document ${docId} from store for ${useCustomKey ? "changeDocWithSigningKey" : "changeDoc"}`);
7196
7359
  }
7197
7360
  else {
7198
7361
  this.logger.debug(`Document ${docId} found in cache`);
@@ -7210,7 +7373,7 @@ class BaseMindooDB {
7210
7373
  // Automerge.change() requires synchronous modifications, so we'll:
7211
7374
  // 1. Execute the async callback to do any async work (like signing)
7212
7375
  // 2. Apply document modifications synchronously within Automerge.change()
7213
- //
7376
+ //
7214
7377
  // We use a two-phase approach: the callback can do async work and collect
7215
7378
  // what needs to be changed, then we apply those changes in Automerge.change()
7216
7379
  const pendingChanges = new Map();
@@ -7246,16 +7409,16 @@ class BaseMindooDB {
7246
7409
  isSealed: () => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId),
7247
7410
  getRecipients: () => (0, recipients_1.resolveRecipientsFromPayload)(internalDoc.doc, internalDoc.sealedRecipients),
7248
7411
  getRecipientEpoch: () => internalDoc.sealedRecipients?.epoch ?? 0,
7249
- isEncryptedFor: (users) => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId)
7250
- && (0, recipients_1.isPayloadEncryptedFor)(internalDoc.doc, internalDoc.sealedRecipients, Array.isArray(users) ? users : [users]),
7412
+ isEncryptedFor: (users) => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId) &&
7413
+ (0, recipients_1.isPayloadEncryptedFor)(internalDoc.doc, internalDoc.sealedRecipients, Array.isArray(users) ? users : [users]),
7251
7414
  getHeads: () => automerge_adapter_1.Automerge.getHeads(internalDoc.doc),
7252
7415
  getData: () => {
7253
7416
  // Return a proxy that collects property assignments and deletions
7254
7417
  const currentData = internalDoc.doc;
7255
7418
  return new Proxy(currentData, {
7256
7419
  set: (target, prop, value) => {
7257
- throwIfCallbackInactive('set property');
7258
- if (typeof prop === 'string') {
7420
+ throwIfCallbackInactive("set property");
7421
+ if (typeof prop === "string") {
7259
7422
  // If this property was marked for deletion, remove it from deletions
7260
7423
  pendingDeletions.delete(prop);
7261
7424
  // Track the change
@@ -7266,8 +7429,8 @@ class BaseMindooDB {
7266
7429
  return true;
7267
7430
  },
7268
7431
  deleteProperty: (target, prop) => {
7269
- throwIfCallbackInactive('delete property');
7270
- if (typeof prop === 'string') {
7432
+ throwIfCallbackInactive("delete property");
7433
+ if (typeof prop === "string") {
7271
7434
  // Mark for deletion
7272
7435
  pendingDeletions.add(prop);
7273
7436
  // Remove from pending changes if it was there
@@ -7279,55 +7442,55 @@ class BaseMindooDB {
7279
7442
  },
7280
7443
  get: (target, prop) => {
7281
7444
  // If marked for deletion, return undefined
7282
- if (typeof prop === 'string' && pendingDeletions.has(prop)) {
7445
+ if (typeof prop === "string" && pendingDeletions.has(prop)) {
7283
7446
  return undefined;
7284
7447
  }
7285
7448
  // Check pending changes first, then target
7286
- if (typeof prop === 'string' && pendingChanges.has(prop)) {
7449
+ if (typeof prop === "string" && pendingChanges.has(prop)) {
7287
7450
  return pendingChanges.get(prop);
7288
7451
  }
7289
7452
  return target[prop];
7290
7453
  },
7291
7454
  has: (target, prop) => {
7292
7455
  // If marked for deletion, it doesn't exist
7293
- if (typeof prop === 'string' && pendingDeletions.has(prop)) {
7456
+ if (typeof prop === "string" && pendingDeletions.has(prop)) {
7294
7457
  return false;
7295
7458
  }
7296
7459
  // Check pending changes first, then target
7297
- if (typeof prop === 'string' && pendingChanges.has(prop)) {
7460
+ if (typeof prop === "string" && pendingChanges.has(prop)) {
7298
7461
  return true;
7299
7462
  }
7300
7463
  return prop in target;
7301
- }
7464
+ },
7302
7465
  });
7303
7466
  },
7304
7467
  // ========== Attachment Write Methods (work in changeDoc context) ==========
7305
7468
  addAttachment: async (fileData, fileName, mimeType, keyId) => {
7306
- throwIfCallbackInactive('addAttachment');
7469
+ throwIfCallbackInactive("addAttachment");
7307
7470
  const decryptionKeyId = keyId || internalDoc.decryptionKeyId;
7308
7471
  const ref = await db.addAttachmentInternal(docId, fileData, fileName, mimeType, decryptionKeyId, now);
7309
7472
  pendingAttachmentAdditions.push(ref);
7310
7473
  return ref;
7311
7474
  },
7312
7475
  addAttachmentStream: async (dataStream, fileName, mimeType, keyId) => {
7313
- throwIfCallbackInactive('addAttachmentStream');
7476
+ throwIfCallbackInactive("addAttachmentStream");
7314
7477
  const decryptionKeyId = keyId || internalDoc.decryptionKeyId;
7315
7478
  const ref = await db.addAttachmentStreamInternal(docId, dataStream, fileName, mimeType, decryptionKeyId, now);
7316
7479
  pendingAttachmentAdditions.push(ref);
7317
7480
  return ref;
7318
7481
  },
7319
7482
  removeAttachment: async (attachmentId) => {
7320
- throwIfCallbackInactive('removeAttachment');
7483
+ throwIfCallbackInactive("removeAttachment");
7321
7484
  // Check if attachment exists (either in current doc or pending additions)
7322
7485
  const payload = internalDoc.doc;
7323
7486
  const existingAttachments = payload._attachments || [];
7324
- const existsInDoc = existingAttachments.some(a => a.attachmentId === attachmentId);
7325
- const existsInPending = pendingAttachmentAdditions.some(a => a.attachmentId === attachmentId);
7487
+ const existsInDoc = existingAttachments.some((a) => a.attachmentId === attachmentId);
7488
+ const existsInPending = pendingAttachmentAdditions.some((a) => a.attachmentId === attachmentId);
7326
7489
  if (!existsInDoc && !existsInPending) {
7327
7490
  throw new Error(`Attachment ${attachmentId} not found in document ${docId}`);
7328
7491
  }
7329
7492
  // If it was added in this same changeDoc call, just remove from pending
7330
- const pendingIndex = pendingAttachmentAdditions.findIndex(a => a.attachmentId === attachmentId);
7493
+ const pendingIndex = pendingAttachmentAdditions.findIndex((a) => a.attachmentId === attachmentId);
7331
7494
  if (pendingIndex >= 0) {
7332
7495
  const [pendingRef] = pendingAttachmentAdditions.splice(pendingIndex, 1);
7333
7496
  await db.cleanupIncompleteAttachmentUpload(docId, pendingRef.attachmentId);
@@ -7362,28 +7525,33 @@ class BaseMindooDB {
7362
7525
  * this changeDoc call), or when invoked after the callback finished.
7363
7526
  */
7364
7527
  setAttachmentExtractedText: (attachmentId, result) => {
7365
- throwIfCallbackInactive('setAttachmentExtractedText');
7528
+ throwIfCallbackInactive("setAttachmentExtractedText");
7366
7529
  const payload = internalDoc.doc;
7367
7530
  const existingAttachments = payload._attachments || [];
7368
- const existsInDoc = existingAttachments.some((a) => a.attachmentId === attachmentId && !pendingAttachmentRemovals.has(attachmentId));
7531
+ const existsInDoc = existingAttachments.some((a) => a.attachmentId === attachmentId &&
7532
+ !pendingAttachmentRemovals.has(attachmentId));
7369
7533
  const existsInPending = pendingAttachmentAdditions.some((a) => a.attachmentId === attachmentId);
7370
7534
  if (!existsInDoc && !existsInPending) {
7371
7535
  throw new Error(`Attachment ${attachmentId} not found in document ${docId}`);
7372
7536
  }
7373
- const cappedText = typeof result.text === "string" && result.text.length > types_1.ATTACHMENT_EXTRACTED_TEXT_MAX_CHARS
7537
+ const cappedText = typeof result.text === "string" &&
7538
+ result.text.length > types_1.ATTACHMENT_EXTRACTED_TEXT_MAX_CHARS
7374
7539
  ? result.text.slice(0, types_1.ATTACHMENT_EXTRACTED_TEXT_MAX_CHARS)
7375
7540
  : result.text;
7376
- pendingAttachmentTextUpdates.set(attachmentId, { ...result, text: cappedText });
7541
+ pendingAttachmentTextUpdates.set(attachmentId, {
7542
+ ...result,
7543
+ text: cappedText,
7544
+ });
7377
7545
  },
7378
7546
  appendToAttachment: async (attachmentId, data) => {
7379
- throwIfCallbackInactive('appendToAttachment');
7547
+ throwIfCallbackInactive("appendToAttachment");
7380
7548
  // Find the attachment reference
7381
7549
  const payload = internalDoc.doc;
7382
7550
  const existingAttachments = payload._attachments || [];
7383
- let ref = existingAttachments.find(a => a.attachmentId === attachmentId);
7551
+ let ref = existingAttachments.find((a) => a.attachmentId === attachmentId);
7384
7552
  // Also check pending additions
7385
7553
  if (!ref) {
7386
- ref = pendingAttachmentAdditions.find(a => a.attachmentId === attachmentId);
7554
+ ref = pendingAttachmentAdditions.find((a) => a.attachmentId === attachmentId);
7387
7555
  }
7388
7556
  if (!ref) {
7389
7557
  throw new Error(`Attachment ${attachmentId} not found in document ${docId}`);
@@ -7403,7 +7571,10 @@ class BaseMindooDB {
7403
7571
  existingAppend.sizeIncrease += sizeIncrease;
7404
7572
  }
7405
7573
  else {
7406
- pendingAttachmentAppends.set(attachmentId, { lastChunkId, sizeIncrease });
7574
+ pendingAttachmentAppends.set(attachmentId, {
7575
+ lastChunkId,
7576
+ sizeIncrease,
7577
+ });
7407
7578
  }
7408
7579
  },
7409
7580
  // ========== Attachment Read Methods (also work in changeDoc context) ==========
@@ -7411,7 +7582,7 @@ class BaseMindooDB {
7411
7582
  const payload = internalDoc.doc;
7412
7583
  const existing = payload._attachments || [];
7413
7584
  // Filter out removals and add pending additions
7414
- const filtered = existing.filter(a => !pendingAttachmentRemovals.has(a.attachmentId));
7585
+ const filtered = existing.filter((a) => !pendingAttachmentRemovals.has(a.attachmentId));
7415
7586
  return [...filtered, ...pendingAttachmentAdditions];
7416
7587
  },
7417
7588
  getAttachment: async (attachmentId) => {
@@ -7459,14 +7630,14 @@ class BaseMindooDB {
7459
7630
  const attachments = automergeDoc._attachments;
7460
7631
  // Remove attachments marked for removal
7461
7632
  for (const attachmentId of pendingAttachmentRemovals) {
7462
- const index = attachments.findIndex(a => a.attachmentId === attachmentId);
7633
+ const index = attachments.findIndex((a) => a.attachmentId === attachmentId);
7463
7634
  if (index >= 0) {
7464
7635
  attachments.splice(index, 1);
7465
7636
  }
7466
7637
  }
7467
7638
  // Apply appends (update lastChunkId and size)
7468
- for (const [attachmentId, { lastChunkId, sizeIncrease }] of pendingAttachmentAppends) {
7469
- const attachment = attachments.find(a => a.attachmentId === attachmentId);
7639
+ for (const [attachmentId, { lastChunkId, sizeIncrease },] of pendingAttachmentAppends) {
7640
+ const attachment = attachments.find((a) => a.attachmentId === attachmentId);
7470
7641
  if (attachment) {
7471
7642
  attachment.lastChunkId = lastChunkId;
7472
7643
  attachment.size += sizeIncrease;
@@ -7478,7 +7649,7 @@ class BaseMindooDB {
7478
7649
  }
7479
7650
  // Apply extraction results (setAttachmentExtractedText)
7480
7651
  for (const [attachmentId, update] of pendingAttachmentTextUpdates) {
7481
- const attachment = attachments.find(a => a.attachmentId === attachmentId);
7652
+ const attachment = attachments.find((a) => a.attachmentId === attachmentId);
7482
7653
  if (!attachment) {
7483
7654
  continue; // removed in the same changeDoc call
7484
7655
  }
@@ -7525,7 +7696,9 @@ class BaseMindooDB {
7525
7696
  useCustomKey: Boolean(useCustomKey),
7526
7697
  signingKeyPair,
7527
7698
  signingKeyPassword,
7528
- successMessage: useCustomKey ? "changed with custom signing key" : "changed",
7699
+ successMessage: useCustomKey
7700
+ ? "changed with custom signing key"
7701
+ : "changed",
7529
7702
  attachmentIds: pendingAttachmentAdditions.map((ref) => ref.attachmentId),
7530
7703
  bypassPrecheck,
7531
7704
  recipients: internalDoc.sealedRecipients,
@@ -7562,13 +7735,13 @@ class BaseMindooDB {
7562
7735
  }
7563
7736
  }
7564
7737
  validateJsonPatch(patch) {
7565
- const operationCount = (patch.set?.length ?? 0)
7566
- + (patch.unset?.length ?? 0)
7567
- + (patch.listDelete?.length ?? 0)
7568
- + (patch.listInsert?.length ?? 0)
7569
- + (patch.textSplice?.length ?? 0)
7570
- + (patch.textMark?.length ?? 0)
7571
- + (patch.textUnmark?.length ?? 0);
7738
+ const operationCount = (patch.set?.length ?? 0) +
7739
+ (patch.unset?.length ?? 0) +
7740
+ (patch.listDelete?.length ?? 0) +
7741
+ (patch.listInsert?.length ?? 0) +
7742
+ (patch.textSplice?.length ?? 0) +
7743
+ (patch.textMark?.length ?? 0) +
7744
+ (patch.textUnmark?.length ?? 0);
7572
7745
  if (operationCount === 0) {
7573
7746
  throw new Error("JSON patch must include at least one operation");
7574
7747
  }
@@ -7583,7 +7756,8 @@ class BaseMindooDB {
7583
7756
  if (!Number.isInteger(operation.index) || operation.index < 0) {
7584
7757
  throw new Error("JSON listDelete index must be a non-negative integer");
7585
7758
  }
7586
- if (!Number.isInteger(operation.deleteCount) || operation.deleteCount < 0) {
7759
+ if (!Number.isInteger(operation.deleteCount) ||
7760
+ operation.deleteCount < 0) {
7587
7761
  throw new Error("JSON listDelete deleteCount must be a non-negative integer");
7588
7762
  }
7589
7763
  }
@@ -7601,10 +7775,12 @@ class BaseMindooDB {
7601
7775
  if (!Number.isInteger(operation.index) || operation.index < 0) {
7602
7776
  throw new Error("JSON textSplice index must be a non-negative integer");
7603
7777
  }
7604
- if (!Number.isInteger(operation.deleteCount) || operation.deleteCount < 0) {
7778
+ if (!Number.isInteger(operation.deleteCount) ||
7779
+ operation.deleteCount < 0) {
7605
7780
  throw new Error("JSON textSplice deleteCount must be a non-negative integer");
7606
7781
  }
7607
- if (operation.insert !== undefined && typeof operation.insert !== "string") {
7782
+ if (operation.insert !== undefined &&
7783
+ typeof operation.insert !== "string") {
7608
7784
  throw new Error("JSON textSplice insert must be a string");
7609
7785
  }
7610
7786
  }
@@ -7616,7 +7792,9 @@ class BaseMindooDB {
7616
7792
  if (!Number.isInteger(operation.length) || operation.length <= 0) {
7617
7793
  throw new Error("JSON textMark length must be a positive integer");
7618
7794
  }
7619
- if (!operation.marks || typeof operation.marks !== "object" || Array.isArray(operation.marks)) {
7795
+ if (!operation.marks ||
7796
+ typeof operation.marks !== "object" ||
7797
+ Array.isArray(operation.marks)) {
7620
7798
  throw new Error("JSON textMark marks must be an object");
7621
7799
  }
7622
7800
  }
@@ -7628,7 +7806,8 @@ class BaseMindooDB {
7628
7806
  if (!Number.isInteger(operation.length) || operation.length <= 0) {
7629
7807
  throw new Error("JSON textUnmark length must be a positive integer");
7630
7808
  }
7631
- if (!Array.isArray(operation.names) || operation.names.some((name) => typeof name !== "string" || !name)) {
7809
+ if (!Array.isArray(operation.names) ||
7810
+ operation.names.some((name) => typeof name !== "string" || !name)) {
7632
7811
  throw new Error("JSON textUnmark names must be non-empty strings");
7633
7812
  }
7634
7813
  }
@@ -7647,7 +7826,8 @@ class BaseMindooDB {
7647
7826
  this.validateRichTextSpans(patch.spans);
7648
7827
  return;
7649
7828
  }
7650
- if (!Array.isArray(patch.spansSequence) || patch.spansSequence.length === 0) {
7829
+ if (!Array.isArray(patch.spansSequence) ||
7830
+ patch.spansSequence.length === 0) {
7651
7831
  throw new Error("Rich-text patch spansSequence must be a non-empty array");
7652
7832
  }
7653
7833
  for (const spans of patch.spansSequence) {
@@ -7669,7 +7849,9 @@ class BaseMindooDB {
7669
7849
  continue;
7670
7850
  }
7671
7851
  if (span.type === "block") {
7672
- if (!span.value || typeof span.value !== "object" || Array.isArray(span.value)) {
7852
+ if (!span.value ||
7853
+ typeof span.value !== "object" ||
7854
+ Array.isArray(span.value)) {
7673
7855
  throw new Error("Rich-text block span value must be an object");
7674
7856
  }
7675
7857
  continue;
@@ -7705,7 +7887,9 @@ class BaseMindooDB {
7705
7887
  if (!Number.isInteger(markRange.length) || markRange.length <= 0) {
7706
7888
  throw new Error("Rich-text mark range length must be a positive integer");
7707
7889
  }
7708
- if (!markRange.marks || typeof markRange.marks !== "object" || Array.isArray(markRange.marks)) {
7890
+ if (!markRange.marks ||
7891
+ typeof markRange.marks !== "object" ||
7892
+ Array.isArray(markRange.marks)) {
7709
7893
  throw new Error("Rich-text mark range marks must be an object");
7710
7894
  }
7711
7895
  }
@@ -8032,7 +8216,7 @@ class BaseMindooDB {
8032
8216
  }
8033
8217
  }
8034
8218
  async persistDocumentChange(options) {
8035
- const { internalDoc, newDoc, now, headsBeforeChange, useCustomKey, signingKeyPair, signingKeyPassword, successMessage, attachmentIds, bypassPrecheck, recipients } = options;
8219
+ const { internalDoc, newDoc, now, headsBeforeChange, useCustomKey, signingKeyPair, signingKeyPassword, successMessage, attachmentIds, bypassPrecheck, recipients, } = options;
8036
8220
  const docId = internalDoc.id;
8037
8221
  this.logger.debug(`Getting change bytes from document ${docId}`);
8038
8222
  const changesSincePreviousHeads = headsBeforeChange
@@ -8063,9 +8247,10 @@ class BaseMindooDB {
8063
8247
  const { internalDoc, newDoc, now, changeBytesList, headsBeforeChange, useCustomKey, signingKeyPair, signingKeyPassword, successMessage, attachmentIds, bypassPrecheck, recipients, } = options;
8064
8248
  const docId = internalDoc.id;
8065
8249
  await this.assertCurrentSealedAccess(internalDoc);
8066
- const resolvedChangeBytesList = changeBytesList ?? (headsBeforeChange
8067
- ? automerge_adapter_1.Automerge.getChangesSince(newDoc, headsBeforeChange)
8068
- : []);
8250
+ const resolvedChangeBytesList = changeBytesList ??
8251
+ (headsBeforeChange
8252
+ ? automerge_adapter_1.Automerge.getChangesSince(newDoc, headsBeforeChange)
8253
+ : []);
8069
8254
  if (resolvedChangeBytesList.length === 0) {
8070
8255
  throw new Error("No Automerge changes to persist");
8071
8256
  }
@@ -8118,12 +8303,13 @@ class BaseMindooDB {
8118
8303
  internalDoc.lastModified = now;
8119
8304
  // The change entries just written are versioned and un-witnessed, so the
8120
8305
  // document is awaiting witness (until pushed + stamped with a receipt).
8121
- internalDoc.awaitingWitness = entries.some(storeEntryTime_1.isProvisional) || (internalDoc.awaitingWitness ?? false);
8306
+ internalDoc.awaitingWitness =
8307
+ entries.some(storeEntryTime_1.isProvisional) || (internalDoc.awaitingWitness ?? false);
8122
8308
  // `versioned` is sticky: any versioned entry (new or already reflected by a
8123
8309
  // prior awaiting/witnessed flag) keeps the doc in the witness-aware era.
8124
- const versioned = entries.some(storeEntryTime_1.isVersioned)
8125
- || internalDoc.awaitingWitness
8126
- || (internalDoc.witnessed ?? false);
8310
+ const versioned = entries.some(storeEntryTime_1.isVersioned) ||
8311
+ internalDoc.awaitingWitness ||
8312
+ (internalDoc.witnessed ?? false);
8127
8313
  internalDoc.witnessed = versioned && !internalDoc.awaitingWitness;
8128
8314
  await this.storeCachedDocument(internalDoc);
8129
8315
  // Force the changeSeq bump: new change entries were just written, so the
@@ -8139,11 +8325,15 @@ class BaseMindooDB {
8139
8325
  ? signingKeyPair?.publicKey
8140
8326
  : (await this.tenant.getCurrentUserId()).userSigningPublicKey;
8141
8327
  await this.maybeWriteSnapshotForDocument(internalDoc, useCustomKey
8142
- ? { signingKeyPair, signingKeyPassword, createdByPublicKey: createdByPublicKey ?? "" }
8328
+ ? {
8329
+ signingKeyPair,
8330
+ signingKeyPassword,
8331
+ createdByPublicKey: createdByPublicKey ?? "",
8332
+ }
8143
8333
  : { createdByPublicKey: createdByPublicKey ?? "" });
8144
8334
  }
8145
8335
  async buildDocChangeStoreEntry(options) {
8146
- const { internalDoc, changeBytes, now, useCustomKey, signingKeyPair, signingKeyPassword, attachmentIds, attachmentRefs, recipients } = options;
8336
+ const { internalDoc, changeBytes, now, useCustomKey, signingKeyPair, signingKeyPassword, attachmentIds, attachmentRefs, recipients, } = options;
8147
8337
  const docId = internalDoc.id;
8148
8338
  this.logger.debug(`Got change bytes: ${changeBytes.length} bytes`);
8149
8339
  const decodedChange = automerge_adapter_1.Automerge.decodeChange(changeBytes);
@@ -8181,7 +8371,9 @@ class BaseMindooDB {
8181
8371
  originalSize: changeBytes.length,
8182
8372
  encryptedSize: encryptedPayload.length,
8183
8373
  attachmentIds: attachmentIds && attachmentIds.length > 0 ? attachmentIds : undefined,
8184
- attachmentRefs: attachmentRefs && attachmentRefs.length > 0 ? attachmentRefs : undefined,
8374
+ attachmentRefs: attachmentRefs && attachmentRefs.length > 0
8375
+ ? attachmentRefs
8376
+ : undefined,
8185
8377
  recipients,
8186
8378
  entryVersion: types_1.CURRENT_STORE_ENTRY_VERSION,
8187
8379
  };
@@ -8259,13 +8451,19 @@ class BaseMindooDB {
8259
8451
  signature,
8260
8452
  originalSize: snapshotBytes.length,
8261
8453
  encryptedSize: encryptedPayload.length,
8262
- attachmentRefs: snapshotAttachmentRefs.length > 0 ? snapshotAttachmentRefs : undefined,
8454
+ attachmentRefs: snapshotAttachmentRefs.length > 0
8455
+ ? snapshotAttachmentRefs
8456
+ : undefined,
8263
8457
  encryptedData: encryptedPayload,
8264
8458
  };
8265
8459
  // Bind the metadata with the author signature (audit finding #5).
8266
- snapshotEntry.metadataSignature = await this.computeEntryMetadataSignature(snapshotEntry, options.signingKeyPair && options.signingKeyPassword
8267
- ? { signingKeyPair: options.signingKeyPair, signingKeyPassword: options.signingKeyPassword }
8268
- : undefined);
8460
+ snapshotEntry.metadataSignature =
8461
+ await this.computeEntryMetadataSignature(snapshotEntry, options.signingKeyPair && options.signingKeyPassword
8462
+ ? {
8463
+ signingKeyPair: options.signingKeyPair,
8464
+ signingKeyPassword: options.signingKeyPassword,
8465
+ }
8466
+ : undefined);
8269
8467
  await this.store.putEntries([snapshotEntry]);
8270
8468
  this.writesSinceSnapshotCheck.set(docId, 0);
8271
8469
  this.logger.debug(`Created snapshot for document ${docId} with ${headHashes.length} heads and ${changesSinceSnapshot} changes since previous snapshot`);
@@ -8524,7 +8722,9 @@ class BaseMindooDB {
8524
8722
  if (!serialized) {
8525
8723
  return null;
8526
8724
  }
8527
- return serialized.length > 80 ? `${serialized.slice(0, 77)}...` : serialized;
8725
+ return serialized.length > 80
8726
+ ? `${serialized.slice(0, 77)}...`
8727
+ : serialized;
8528
8728
  }
8529
8729
  catch {
8530
8730
  return String(value);
@@ -8582,10 +8782,16 @@ class BaseMindooDB {
8582
8782
  }
8583
8783
  return;
8584
8784
  }
8585
- if (this.isPlainDiffObject(beforeValue) || this.isPlainDiffObject(afterValue)) {
8586
- const beforeObject = this.isPlainDiffObject(beforeValue) ? beforeValue : {};
8785
+ if (this.isPlainDiffObject(beforeValue) ||
8786
+ this.isPlainDiffObject(afterValue)) {
8787
+ const beforeObject = this.isPlainDiffObject(beforeValue)
8788
+ ? beforeValue
8789
+ : {};
8587
8790
  const afterObject = this.isPlainDiffObject(afterValue) ? afterValue : {};
8588
- const childKeys = new Set([...Object.keys(beforeObject), ...Object.keys(afterObject)]);
8791
+ const childKeys = new Set([
8792
+ ...Object.keys(beforeObject),
8793
+ ...Object.keys(afterObject),
8794
+ ]);
8589
8795
  if (childKeys.size === 0 && basePath) {
8590
8796
  results.add(basePath);
8591
8797
  return;
@@ -8604,10 +8810,10 @@ class BaseMindooDB {
8604
8810
  * Returns true for diffable object literals and false for arrays/binary payloads.
8605
8811
  */
8606
8812
  isPlainDiffObject(value) {
8607
- return value !== null
8608
- && typeof value === "object"
8609
- && !Array.isArray(value)
8610
- && !(value instanceof Uint8Array);
8813
+ return (value !== null &&
8814
+ typeof value === "object" &&
8815
+ !Array.isArray(value) &&
8816
+ !(value instanceof Uint8Array));
8611
8817
  }
8612
8818
  /**
8613
8819
  * Extracts the terminal field name from a normalized path for loose key/path matching.
@@ -8625,7 +8831,9 @@ class BaseMindooDB {
8625
8831
  * the full decoded structure.
8626
8832
  */
8627
8833
  summarizeDecodedChange(decodedChange) {
8628
- const operations = Array.isArray(decodedChange.ops) ? decodedChange.ops : [];
8834
+ const operations = Array.isArray(decodedChange.ops)
8835
+ ? decodedChange.ops
8836
+ : [];
8629
8837
  const actionCounts = {};
8630
8838
  const touchedKeys = new Set();
8631
8839
  const summarizedOperations = operations.slice(0, 12).map((operation) => {
@@ -8660,7 +8868,9 @@ class BaseMindooDB {
8660
8868
  actorId: typeof decodedChange.actor === "string" ? decodedChange.actor : null,
8661
8869
  hash: typeof decodedChange.hash === "string" ? decodedChange.hash : null,
8662
8870
  seq: typeof decodedChange.seq === "number" ? decodedChange.seq : null,
8663
- message: typeof decodedChange.message === "string" ? decodedChange.message : null,
8871
+ message: typeof decodedChange.message === "string"
8872
+ ? decodedChange.message
8873
+ : null,
8664
8874
  dependencyHashes: Array.isArray(decodedChange.deps)
8665
8875
  ? decodedChange.deps.filter((dep) => typeof dep === "string")
8666
8876
  : [],
@@ -8686,7 +8896,9 @@ class BaseMindooDB {
8686
8896
  }
8687
8897
  const metadataById = new Map(allEntryMetadata.map((entry) => [entry.id, entry]));
8688
8898
  let startFromSnapshot = snapshotEntryId !== null;
8689
- const snapshotMeta = snapshotEntryId ? (metadataById.get(snapshotEntryId) || null) : null;
8899
+ const snapshotMeta = snapshotEntryId
8900
+ ? metadataById.get(snapshotEntryId) || null
8901
+ : null;
8690
8902
  if (startFromSnapshot && !snapshotMeta) {
8691
8903
  this.logger.warn(`Materialization referenced snapshot ${snapshotEntryId} not found in metadata for ${docId}; falling back to replay without snapshot`);
8692
8904
  startFromSnapshot = false;
@@ -8758,16 +8970,24 @@ class BaseMindooDB {
8758
8970
  this.registerAutomergeHashMapping(docId, parsed.automergeHash, entryData.id);
8759
8971
  }
8760
8972
  }
8761
- const orderedReplayEntries = [...replayEntriesForState].sort((left, right) => left.createdAt !== right.createdAt ? left.createdAt - right.createdAt : left.id.localeCompare(right.id));
8973
+ const orderedReplayEntries = [...replayEntriesForState].sort((left, right) => left.createdAt !== right.createdAt
8974
+ ? left.createdAt - right.createdAt
8975
+ : left.id.localeCompare(right.id));
8762
8976
  const firstReplayEntry = orderedReplayEntries[0] ?? null;
8763
8977
  const lastReplayEntry = orderedReplayEntries[orderedReplayEntries.length - 1] ?? null;
8764
8978
  const witnessState = (0, storeEntryTime_1.metadataWitnessState)(replayEntriesForState);
8765
8979
  return {
8766
8980
  id: docId,
8767
8981
  doc,
8768
- createdAt: firstReplayEntry?.createdAt ?? snapshotMeta?.createdAt ?? fallbackTimestamp,
8769
- lastModified: lastReplayEntry?.createdAt ?? snapshotMeta?.createdAt ?? fallbackTimestamp,
8770
- decryptionKeyId: firstReplayEntry?.decryptionKeyId ?? snapshotMeta?.decryptionKeyId ?? "default",
8982
+ createdAt: firstReplayEntry?.createdAt ??
8983
+ snapshotMeta?.createdAt ??
8984
+ fallbackTimestamp,
8985
+ lastModified: lastReplayEntry?.createdAt ??
8986
+ snapshotMeta?.createdAt ??
8987
+ fallbackTimestamp,
8988
+ decryptionKeyId: firstReplayEntry?.decryptionKeyId ??
8989
+ snapshotMeta?.decryptionKeyId ??
8990
+ "default",
8771
8991
  isDeleted: this.computeIsDeletedFromMetadata(replayEntriesForState),
8772
8992
  awaitingWitness: witnessState.awaitingWitness,
8773
8993
  witnessed: witnessState.witnessed,
@@ -8854,7 +9074,11 @@ class BaseMindooDB {
8854
9074
  const startedAt = Date.now();
8855
9075
  // Default to initial cursor if null is provided.
8856
9076
  // Prefer deterministic sequence-based cursoring; keep legacy fallback compatibility.
8857
- const actualCursor = cursor ?? { changeSeq: 0, lastModified: 0, docId: "" };
9077
+ const actualCursor = cursor ?? {
9078
+ changeSeq: 0,
9079
+ lastModified: 0,
9080
+ docId: "",
9081
+ };
8858
9082
  const idPrefix = this.normalizeIdPrefixFilter(options?.idPrefix);
8859
9083
  this.logger.debug(`Starting iteration from cursor ${JSON.stringify(actualCursor)}`);
8860
9084
  // Use a stable snapshot of the index for this generator run so concurrent
@@ -8896,7 +9120,10 @@ class BaseMindooDB {
8896
9120
  docId: entry.docId,
8897
9121
  };
8898
9122
  yieldedDocuments++;
8899
- yield { doc: this.buildInaccessibleDoc(entry), cursor: inaccessibleCursor };
9123
+ yield {
9124
+ doc: this.buildInaccessibleDoc(entry),
9125
+ cursor: inaccessibleCursor,
9126
+ };
8900
9127
  await prefetchFrom(i + 1);
8901
9128
  continue;
8902
9129
  }
@@ -9098,8 +9325,7 @@ class BaseMindooDB {
9098
9325
  // Update metadata
9099
9326
  const payload = updatedDoc;
9100
9327
  const lastEntryCreatedAt = entries.reduce((maxCreatedAt, entry) => Math.max(maxCreatedAt, entry.createdAt), cachedDoc.lastModified);
9101
- const lastModified = payload._lastModified ||
9102
- lastEntryCreatedAt;
9328
+ const lastModified = payload._lastModified || lastEntryCreatedAt;
9103
9329
  const isDeleted = this.computeIsDeletedFromMetadata(allDocMetadata);
9104
9330
  const updatedInternalDoc = {
9105
9331
  id: docId,
@@ -9550,7 +9776,8 @@ class BaseMindooDB {
9550
9776
  * re-enters the directory for them.
9551
9777
  */
9552
9778
  async resolveCreateKeyId(options, docId) {
9553
- if (options.recipients !== undefined && options.decryptionKeyId !== undefined) {
9779
+ if (options.recipients !== undefined &&
9780
+ options.decryptionKeyId !== undefined) {
9554
9781
  throw new Error("createDocument: recipients and decryptionKeyId are mutually exclusive");
9555
9782
  }
9556
9783
  if (options.recipients !== undefined) {
@@ -9588,7 +9815,10 @@ class BaseMindooDB {
9588
9815
  docId,
9589
9816
  keyId,
9590
9817
  includeSelf: options.recipientOptions?.includeSelf !== false,
9591
- userTargets: resolved.targets.map((target) => ({ kind: target.kind, id: target.id })),
9818
+ userTargets: resolved.targets.map((target) => ({
9819
+ kind: target.kind,
9820
+ id: target.id,
9821
+ })),
9592
9822
  skipped: resolved.skipped,
9593
9823
  });
9594
9824
  const recipients = await (0, recipients_1.sealToTargets)({
@@ -9662,7 +9892,8 @@ class BaseMindooDB {
9662
9892
  */
9663
9893
  async canCreate(options = {}) {
9664
9894
  const keyId = await this.resolveCreateKeyId(options);
9665
- const useCustomSigningKey = options.signingKeyPair !== undefined && options.signingKeyPassword !== undefined;
9895
+ const useCustomSigningKey = options.signingKeyPair !== undefined &&
9896
+ options.signingKeyPassword !== undefined;
9666
9897
  const signerKey = useCustomSigningKey
9667
9898
  ? options.signingKeyPair.publicKey
9668
9899
  : (await this.tenant.getCurrentUserId()).userSigningPublicKey;
@@ -9713,7 +9944,9 @@ class BaseMindooDB {
9713
9944
  }
9714
9945
  async canChangeRecipients(doc, next) {
9715
9946
  const after = { ...doc.getData() };
9716
- after[sealedTypes_1.ENCRYPT_FOR_FIELD] = { ...(0, recipients_1.readEncryptFor)(after) };
9947
+ after[sealedTypes_1.ENCRYPT_FOR_FIELD] = {
9948
+ ...(0, recipients_1.readEncryptFor)(after),
9949
+ };
9717
9950
  return this.canChange(doc, after);
9718
9951
  }
9719
9952
  async mutateRecipients(doc, mode, specs, options) {
@@ -9728,8 +9961,8 @@ class BaseMindooDB {
9728
9961
  throw new errors_1.DocumentNotFoundError(docId);
9729
9962
  }
9730
9963
  const now = (0, timeSource_1.semanticNow)();
9731
- const signer = options?.signingKeyPair?.publicKey
9732
- ?? (await this.tenant.getCurrentUserId()).userSigningPublicKey;
9964
+ const signer = options?.signingKeyPair?.publicKey ??
9965
+ (await this.tenant.getCurrentUserId()).userSigningPublicKey;
9733
9966
  const resolved = await (0, recipients_1.resolveRecipientSpecs)({
9734
9967
  tenant,
9735
9968
  specs,
@@ -9741,15 +9974,18 @@ class BaseMindooDB {
9741
9974
  now,
9742
9975
  });
9743
9976
  const currentMap = (0, recipients_1.readEncryptFor)(internalDoc.doc);
9744
- const activeIds = new Set(Object.entries(currentMap).filter(([, e]) => !e.removedAt).map(([id]) => id.split("#")[0]));
9977
+ const activeIds = new Set(Object.entries(currentMap)
9978
+ .filter(([, e]) => !e.removedAt)
9979
+ .map(([id]) => id.split("#")[0]));
9745
9980
  const addedTargets = [];
9746
9981
  const removedStableIds = [];
9747
9982
  const matchesTarget = (id, entry, target) => {
9748
9983
  const base = id.split("#")[0];
9749
- return (target.stableId === base
9750
- || target.id === base
9751
- || (!!entry.label && target.id === entry.label)
9752
- || (!!entry.keyFingerprint && target.keyFingerprint === entry.keyFingerprint));
9984
+ return (target.stableId === base ||
9985
+ target.id === base ||
9986
+ (!!entry.label && target.id === entry.label) ||
9987
+ (!!entry.keyFingerprint &&
9988
+ target.keyFingerprint === entry.keyFingerprint));
9753
9989
  };
9754
9990
  if (mode === "add" || mode === "set") {
9755
9991
  for (const target of resolved.targets) {
@@ -9785,7 +10021,9 @@ class BaseMindooDB {
9785
10021
  let generations = currentGens;
9786
10022
  let epoch = internalDoc.sealedRecipients?.epoch ?? currentGens.length;
9787
10023
  if (rotate) {
9788
- const nextDek = tenant.getCryptoAdapter().getRandomValues(new Uint8Array(32));
10024
+ const nextDek = tenant
10025
+ .getCryptoAdapter()
10026
+ .getRandomValues(new Uint8Array(32));
9789
10027
  generations = [nextDek, ...currentGens];
9790
10028
  epoch += 1;
9791
10029
  }
@@ -9811,7 +10049,9 @@ class BaseMindooDB {
9811
10049
  for (const id of removedStableIds) {
9812
10050
  remainingByStable.delete(id);
9813
10051
  for (const [stableId, target] of [...remainingByStable.entries()]) {
9814
- if (target.id === id || target.stableId === id || target.keyFingerprint === id) {
10052
+ if (target.id === id ||
10053
+ target.stableId === id ||
10054
+ target.keyFingerprint === id) {
9815
10055
  remainingByStable.delete(stableId);
9816
10056
  }
9817
10057
  }
@@ -9874,7 +10114,9 @@ class BaseMindooDB {
9874
10114
  return {
9875
10115
  epoch,
9876
10116
  rotated: rotate,
9877
- added: wrapped.getRecipients().filter((r) => addedTargets.some((t) => t.keyFingerprint === r.keyFingerprint)),
10117
+ added: wrapped
10118
+ .getRecipients()
10119
+ .filter((r) => addedTargets.some((t) => t.keyFingerprint === r.keyFingerprint)),
9878
10120
  removed: Object.entries((0, recipients_1.readEncryptFor)(internalDoc.doc))
9879
10121
  .filter(([id, e]) => e.removedAt && removedStableIds.includes(id.split("#")[0]))
9880
10122
  .map(([id, e]) => ({
@@ -10025,7 +10267,9 @@ class BaseMindooDB {
10025
10267
  // monotonicity across the entries we accept, in trusted-time order (§5.4).
10026
10268
  // A verify-only provider (no signer) routes receipts to the right scheme.
10027
10269
  const subtle = this.getSubtle();
10028
- const receiptVerifier = new Ed25519WitnessProvider_1.Ed25519WitnessProvider({ subtle }).createVerifier();
10270
+ const receiptVerifier = new Ed25519WitnessProvider_1.Ed25519WitnessProvider({
10271
+ subtle,
10272
+ }).createVerifier();
10029
10273
  const nowMs = (0, timeSource_1.semanticNow)();
10030
10274
  // Lifecycle entries only, folded in deterministic causal order. Un-witnessed
10031
10275
  // entries (versioned or legacy) order by their author time `createdAt`, NOT
@@ -10103,10 +10347,15 @@ class BaseMindooDB {
10103
10347
  // from a currently-trusted witness, carry a valid signature, and respect
10104
10348
  // per-witness monotonicity and the future-time bound. Entries with no
10105
10349
  // receipt are local/not-yet-witnessed and pass this check.
10106
- if (getTrustedWitnessKeysAt && (meta.receivedAt !== undefined || meta.receivedByPublicKey)) {
10350
+ if (getTrustedWitnessKeysAt &&
10351
+ (meta.receivedAt !== undefined || meta.receivedByPublicKey)) {
10107
10352
  try {
10108
10353
  const trustedWitnessKeys = await getTrustedWitnessKeysAt(meta.receivedAt ?? meta.createdAt);
10109
- const receiptResult = await receiptVerifier.validate(meta, { dbid, trustedWitnessKeys, nowMs });
10354
+ const receiptResult = await receiptVerifier.validate(meta, {
10355
+ dbid,
10356
+ trustedWitnessKeys,
10357
+ nowMs,
10358
+ });
10110
10359
  if (!receiptResult.ok) {
10111
10360
  quarantine(meta, "invalid_witness_receipt", receiptResult.reason ?? "invalid witness receipt");
10112
10361
  continue;
@@ -10216,7 +10465,8 @@ class BaseMindooDB {
10216
10465
  const payload = currentDoc;
10217
10466
  const isDeleted = this.computeIsDeletedFromMetadata(acceptedMeta);
10218
10467
  const lastAccepted = acceptedMeta[acceptedMeta.length - 1];
10219
- const lastModified = payload._lastModified || (lastAccepted ? lastAccepted.createdAt : (0, timeSource_1.semanticNow)());
10468
+ const lastModified = payload._lastModified ||
10469
+ (lastAccepted ? lastAccepted.createdAt : (0, timeSource_1.semanticNow)());
10220
10470
  const witnessState = (0, storeEntryTime_1.metadataWitnessState)(acceptedMeta);
10221
10471
  return {
10222
10472
  doc: {
@@ -10244,7 +10494,8 @@ class BaseMindooDB {
10244
10494
  // contract of `loadDocumentInternal` aligned with `getDocument` /
10245
10495
  // `getAllDocumentIds`.
10246
10496
  const indexEntryIdx = this.getDocIndexPosition(docId);
10247
- if (indexEntryIdx !== undefined && this.index[indexEntryIdx].accessState === "inaccessible") {
10497
+ if (indexEntryIdx !== undefined &&
10498
+ this.index[indexEntryIdx].accessState === "inaccessible") {
10248
10499
  return null;
10249
10500
  }
10250
10501
  if (this.docCache.has(docId)) {
@@ -10331,13 +10582,16 @@ class BaseMindooDB {
10331
10582
  return null;
10332
10583
  }
10333
10584
  // Log all entry types
10334
- const entryTypes = allEntryMetadata.map(em => `${em.entryType}@${em.createdAt}`).join(', ');
10585
+ const entryTypes = allEntryMetadata
10586
+ .map((em) => `${em.entryType}@${em.createdAt}`)
10587
+ .join(", ");
10335
10588
  this.logger.debug(`Entry types for ${docId}: ${entryTypes}`);
10336
- await this.tenant.ingestSealedFromEntries?.(allEntryMetadata.find((em) => em.entryType === "doc_create")?.decryptionKeyId
10337
- ?? allEntryMetadata[0].decryptionKeyId, allEntryMetadata);
10338
- const loadKeyId = allEntryMetadata.find((em) => em.entryType === "doc_create")?.decryptionKeyId
10339
- ?? allEntryMetadata[0].decryptionKeyId;
10340
- if ((0, sealedTypes_1.isSealedKeyId)(loadKeyId) && !(await this.tenant.hasDecryptionKey(loadKeyId))) {
10589
+ await this.tenant.ingestSealedFromEntries?.(allEntryMetadata.find((em) => em.entryType === "doc_create")
10590
+ ?.decryptionKeyId ?? allEntryMetadata[0].decryptionKeyId, allEntryMetadata);
10591
+ const loadKeyId = allEntryMetadata.find((em) => em.entryType === "doc_create")
10592
+ ?.decryptionKeyId ?? allEntryMetadata[0].decryptionKeyId;
10593
+ if ((0, sealedTypes_1.isSealedKeyId)(loadKeyId) &&
10594
+ !(await this.tenant.hasDecryptionKey(loadKeyId))) {
10341
10595
  this.logger.debug(`Document ${docId} is sealed and not unwrapable; treating as missing`);
10342
10596
  const existingIndex = this.getDocIndexPosition(docId);
10343
10597
  const existing = existingIndex === undefined ? undefined : this.index[existingIndex];
@@ -10398,7 +10652,7 @@ class BaseMindooDB {
10398
10652
  });
10399
10653
  let startFromSnapshot = materializationPlan.snapshotEntryId !== null;
10400
10654
  const snapshotMeta = materializationPlan.snapshotEntryId
10401
- ? (metadataById.get(materializationPlan.snapshotEntryId) || null)
10655
+ ? metadataById.get(materializationPlan.snapshotEntryId) || null
10402
10656
  : null;
10403
10657
  if (startFromSnapshot && !snapshotMeta) {
10404
10658
  this.logger.warn(`Planner referenced snapshot ${materializationPlan.snapshotEntryId} not found in metadata for ${docId}; falling back to replay without snapshot`);
@@ -10487,10 +10741,10 @@ class BaseMindooDB {
10487
10741
  // Load and apply all entries
10488
10742
  this.logger.debug(`Fetching ${entriesToLoad.length} entries from store for document ${docId}`);
10489
10743
  const entryLoadStartedAt = Date.now();
10490
- const entries = await this.fetchEntries(entriesToLoad.map(em => em.id));
10744
+ const entries = await this.fetchEntries(entriesToLoad.map((em) => em.id));
10491
10745
  entryLoadTime += Date.now() - entryLoadStartedAt;
10492
10746
  this.logger.debug(`Retrieved ${entries.length} entries from store for document ${docId}`);
10493
- this.logger.debug(`Loading document ${docId}: found ${entries.length} entries to apply (${startFromSnapshot ? 'starting from snapshot' : 'starting from scratch'})`);
10747
+ this.logger.debug(`Loading document ${docId}: found ${entries.length} entries to apply (${startFromSnapshot ? "starting from snapshot" : "starting from scratch"})`);
10494
10748
  // Log current document state before applying entries
10495
10749
  if (this.isDebugEnabled())
10496
10750
  this.logger.debug(`Document state before applying entries: heads=${JSON.stringify(automerge_adapter_1.Automerge.getHeads(doc))}`);
@@ -10608,8 +10862,10 @@ class BaseMindooDB {
10608
10862
  this.logger.debug(`Document ${docId} isDeleted: ${isDeleted}`);
10609
10863
  // The authoritative decryptionKeyId comes from the doc_create entry's metadata,
10610
10864
  // not from the Automerge payload (which does not store encryption metadata).
10611
- const createEntry = allEntryMetadata.find(em => em.entryType === "doc_create");
10612
- const decryptionKeyId = createEntry ? createEntry.decryptionKeyId : "default";
10865
+ const createEntry = allEntryMetadata.find((em) => em.entryType === "doc_create");
10866
+ const decryptionKeyId = createEntry
10867
+ ? createEntry.decryptionKeyId
10868
+ : "default";
10613
10869
  // Get lastModified from payload, or use the timestamp of the last entry
10614
10870
  const lastEntry = entries.length > 0 ? entries[entries.length - 1] : null;
10615
10871
  const lastModified = payload._lastModified ||
@@ -10659,16 +10915,16 @@ class BaseMindooDB {
10659
10915
  convertAutomergeToJS(doc) {
10660
10916
  // Check if this document has a native Automerge handle attached
10661
10917
  // The native implementation attaches metadata with Symbol.for('_am_meta')
10662
- const STATE = Symbol.for('_am_meta');
10918
+ const STATE = Symbol.for("_am_meta");
10663
10919
  const meta = doc[STATE];
10664
- if (meta && meta.handle && typeof meta.handle.materialize === 'function') {
10920
+ if (meta && meta.handle && typeof meta.handle.materialize === "function") {
10665
10921
  // Use native materialize() which properly converts Text objects to strings
10666
10922
  try {
10667
- const materialized = meta.handle.materialize('/');
10923
+ const materialized = meta.handle.materialize("/");
10668
10924
  return materialized;
10669
10925
  }
10670
10926
  catch (error) {
10671
- console.error('[MindooDB] Failed to materialize document:', error);
10927
+ console.error("[MindooDB] Failed to materialize document:", error);
10672
10928
  // Fall through to direct access
10673
10929
  }
10674
10930
  }
@@ -10680,7 +10936,9 @@ class BaseMindooDB {
10680
10936
  convertAutomergeValueToJS(value, depth) {
10681
10937
  if (value === null || value === undefined)
10682
10938
  return value;
10683
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
10939
+ if (typeof value === "string" ||
10940
+ typeof value === "number" ||
10941
+ typeof value === "boolean")
10684
10942
  return value;
10685
10943
  if (value instanceof Uint8Array)
10686
10944
  return value;
@@ -10695,10 +10953,10 @@ class BaseMindooDB {
10695
10953
  if (typeof value !== "object")
10696
10954
  return value;
10697
10955
  const record = value;
10698
- if (typeof record.length === "number"
10699
- && typeof value.concat === "function"
10700
- && record.kind === undefined
10701
- && typeof value.toString === "function") {
10956
+ if (typeof record.length === "number" &&
10957
+ typeof value.concat === "function" &&
10958
+ record.kind === undefined &&
10959
+ typeof value.toString === "function") {
10702
10960
  const asString = String(value);
10703
10961
  if (asString && asString !== "[object Object]")
10704
10962
  return asString;
@@ -10730,7 +10988,10 @@ class BaseMindooDB {
10730
10988
  get: (target, prop) => {
10731
10989
  const value = target[prop];
10732
10990
  // Recursively wrap nested objects (but not arrays or special types)
10733
- if (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Uint8Array)) {
10991
+ if (value !== null &&
10992
+ typeof value === "object" &&
10993
+ !Array.isArray(value) &&
10994
+ !(value instanceof Uint8Array)) {
10734
10995
  return createReadOnlyProxy(value);
10735
10996
  }
10736
10997
  return value;
@@ -10750,8 +11011,8 @@ class BaseMindooDB {
10750
11011
  isSealed: () => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId),
10751
11012
  getRecipients: () => (0, recipients_1.resolveRecipientsFromPayload)(internalDoc.doc, internalDoc.sealedRecipients),
10752
11013
  getRecipientEpoch: () => internalDoc.sealedRecipients?.epoch ?? 0,
10753
- isEncryptedFor: (users) => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId)
10754
- && (0, recipients_1.isPayloadEncryptedFor)(internalDoc.doc, internalDoc.sealedRecipients, Array.isArray(users) ? users : [users]),
11014
+ isEncryptedFor: (users) => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId) &&
11015
+ (0, recipients_1.isPayloadEncryptedFor)(internalDoc.doc, internalDoc.sealedRecipients, Array.isArray(users) ? users : [users]),
10755
11016
  getHeads: () => automerge_adapter_1.Automerge.getHeads(internalDoc.doc),
10756
11017
  getData: () => {
10757
11018
  // Convert Automerge document to plain JS object, converting Text
@@ -10759,7 +11020,8 @@ class BaseMindooDB {
10759
11020
  // the document's Automerge heads, so repeated getData() calls on an
10760
11021
  // unchanged doc skip the full re-materialization.
10761
11022
  const headsKey = automerge_adapter_1.Automerge.getHeads(internalDoc.doc).join(",");
10762
- if (internalDoc.jsCache === undefined || internalDoc.jsCacheHeads !== headsKey) {
11023
+ if (internalDoc.jsCache === undefined ||
11024
+ internalDoc.jsCacheHeads !== headsKey) {
10763
11025
  internalDoc.jsCache = this.convertAutomergeToJS(internalDoc.doc);
10764
11026
  internalDoc.jsCacheHeads = headsKey;
10765
11027
  }
@@ -10849,7 +11111,7 @@ class BaseMindooDB {
10849
11111
  * Get an attachment reference by ID from a document's _attachments array.
10850
11112
  */
10851
11113
  async getAttachmentRefInternal(docId, attachmentId) {
10852
- const internalDoc = this.getCachedDocument(docId) ?? await this.loadDocumentInternal(docId);
11114
+ const internalDoc = this.getCachedDocument(docId) ?? (await this.loadDocumentInternal(docId));
10853
11115
  if (!internalDoc) {
10854
11116
  throw new Error(`Document ${docId} not found while reading attachment ${attachmentId}`);
10855
11117
  }
@@ -10858,7 +11120,7 @@ class BaseMindooDB {
10858
11120
  getAttachmentRefFromDoc(internalDoc, attachmentId) {
10859
11121
  const payload = internalDoc.doc;
10860
11122
  const attachments = payload._attachments || [];
10861
- const ref = attachments.find(a => a.attachmentId === attachmentId);
11123
+ const ref = attachments.find((a) => a.attachmentId === attachmentId);
10862
11124
  if (!ref) {
10863
11125
  throw new Error(`Attachment ${attachmentId} not found in document ${internalDoc.id}`);
10864
11126
  }
@@ -10908,7 +11170,9 @@ class BaseMindooDB {
10908
11170
  async getAttachmentForRefInternal(ref) {
10909
11171
  const store = this.getEffectiveAttachmentStore();
10910
11172
  // Resolve dependency chain to get all chunk IDs in order (oldest first)
10911
- const chunkIds = await store.resolveDependencies(ref.lastChunkId, { includeStart: true });
11173
+ const chunkIds = await store.resolveDependencies(ref.lastChunkId, {
11174
+ includeStart: true,
11175
+ });
10912
11176
  this.logger.debug(`Resolved ${chunkIds.length} chunks for attachment ${ref.attachmentId}`);
10913
11177
  // Fetch all chunks
10914
11178
  const chunks = await store.getEntries(chunkIds);
@@ -11060,7 +11324,8 @@ class BaseMindooDB {
11060
11324
  encryptedData,
11061
11325
  };
11062
11326
  // Bind the metadata with the author signature (audit finding #5).
11063
- chunkEntry.metadataSignature = await this.computeEntryMetadataSignature(chunkEntry);
11327
+ chunkEntry.metadataSignature =
11328
+ await this.computeEntryMetadataSignature(chunkEntry);
11064
11329
  chunks.push(chunkEntry);
11065
11330
  prevChunkId = chunkId;
11066
11331
  }
@@ -11122,7 +11387,8 @@ class BaseMindooDB {
11122
11387
  encryptedData,
11123
11388
  };
11124
11389
  // Bind the metadata with the author signature (audit finding #5).
11125
- ledgerEntry.metadataSignature = await this.computeEntryMetadataSignature(ledgerEntry);
11390
+ ledgerEntry.metadataSignature =
11391
+ await this.computeEntryMetadataSignature(ledgerEntry);
11126
11392
  await this.putEntriesWithRetry(this.store, [ledgerEntry], `pending ledger ${attachmentId}`);
11127
11393
  }
11128
11394
  async clearPendingAttachmentUploadLedger(attachmentId) {
@@ -11130,7 +11396,9 @@ class BaseMindooDB {
11130
11396
  if (!deleteEntriesById) {
11131
11397
  return;
11132
11398
  }
11133
- await deleteEntriesById.call(this.store, [this.pendingAttachmentUploadLedgerId(attachmentId)]);
11399
+ await deleteEntriesById.call(this.store, [
11400
+ this.pendingAttachmentUploadLedgerId(attachmentId),
11401
+ ]);
11134
11402
  }
11135
11403
  async cleanupIncompleteAttachmentUpload(docId, attachmentId) {
11136
11404
  const store = this.getEffectiveAttachmentStore();
@@ -11200,7 +11468,8 @@ class BaseMindooDB {
11200
11468
  encryptedData,
11201
11469
  };
11202
11470
  // Bind the metadata with the author signature (audit finding #5).
11203
- chunkEntry.metadataSignature = await this.computeEntryMetadataSignature(chunkEntry);
11471
+ chunkEntry.metadataSignature =
11472
+ await this.computeEntryMetadataSignature(chunkEntry);
11204
11473
  pendingEntries.push(chunkEntry);
11205
11474
  pendingEncryptedBytes += encryptedData.length;
11206
11475
  chunkCount++;
@@ -11299,7 +11568,8 @@ class BaseMindooDB {
11299
11568
  encryptedData,
11300
11569
  };
11301
11570
  // Bind the metadata with the author signature (audit finding #5).
11302
- chunkEntry.metadataSignature = await this.computeEntryMetadataSignature(chunkEntry);
11571
+ chunkEntry.metadataSignature =
11572
+ await this.computeEntryMetadataSignature(chunkEntry);
11303
11573
  chunks.push(chunkEntry);
11304
11574
  prevChunkId = chunkId;
11305
11575
  }
@@ -11316,10 +11586,13 @@ class BaseMindooDB {
11316
11586
  * Accepts either a raw store or a MindooDB instance (calls getStore()).
11317
11587
  */
11318
11588
  getStoreForKind(storeKind = types_2.StoreKind.docs) {
11319
- return storeKind === types_2.StoreKind.attachments ? this.attachmentStore : this.store;
11589
+ return storeKind === types_2.StoreKind.attachments
11590
+ ? this.attachmentStore
11591
+ : this.store;
11320
11592
  }
11321
11593
  resolveStore(remote, storeKind = types_2.StoreKind.docs) {
11322
- if ('getStore' in remote && typeof remote.getStore === 'function') {
11594
+ if ("getStore" in remote &&
11595
+ typeof remote.getStore === "function") {
11323
11596
  return storeKind === types_2.StoreKind.attachments
11324
11597
  ? remote.getAttachmentStore()
11325
11598
  : remote.getStore();
@@ -11415,7 +11688,8 @@ class BaseMindooDB {
11415
11688
  },
11416
11689
  hasWriteContentRules: async (op) => {
11417
11690
  const directory = await this.tenant.openDirectory();
11418
- return (await directory.hasWriteContentRules?.(op, this.store.getId())) ?? false;
11691
+ return ((await directory.hasWriteContentRules?.(op, this.store.getId())) ??
11692
+ false);
11419
11693
  },
11420
11694
  remapAttachmentPointers: (docId, lastChunkIdByAttachmentId, signing) => this.remapAttachmentPointers(docId, lastChunkIdByAttachmentId, signing),
11421
11695
  };
@@ -11481,8 +11755,11 @@ class BaseMindooDB {
11481
11755
  this.registerAutomergeHashMapping(docId, automerge_adapter_1.Automerge.decodeChange(changeBytes).hash, entry.id);
11482
11756
  internalDoc.doc = newDoc;
11483
11757
  internalDoc.lastModified = now;
11484
- internalDoc.awaitingWitness = (0, storeEntryTime_1.isProvisional)(entry) || (internalDoc.awaitingWitness ?? false);
11485
- const versioned = (0, storeEntryTime_1.isVersioned)(entry) || internalDoc.awaitingWitness || (internalDoc.witnessed ?? false);
11758
+ internalDoc.awaitingWitness =
11759
+ (0, storeEntryTime_1.isProvisional)(entry) || (internalDoc.awaitingWitness ?? false);
11760
+ const versioned = (0, storeEntryTime_1.isVersioned)(entry) ||
11761
+ internalDoc.awaitingWitness ||
11762
+ (internalDoc.witnessed ?? false);
11486
11763
  internalDoc.witnessed = versioned && !internalDoc.awaitingWitness;
11487
11764
  await this.storeCachedDocument(internalDoc);
11488
11765
  this.updateIndex(docId, internalDoc.lastModified, internalDoc.isDeleted, internalDoc.decryptionKeyId, "visible", internalDoc.awaitingWitness, internalDoc.witnessed, true);
@@ -11567,7 +11844,8 @@ class BaseMindooDB {
11567
11844
  const storeKind = options?.storeKind ?? types_2.StoreKind.docs;
11568
11845
  const localStore = this.getStoreForKind(storeKind);
11569
11846
  const remoteStore = this.resolveStore(remote, storeKind);
11570
- if (localStore.getId() !== remoteStore.getId() || localStore.getStoreKind() !== remoteStore.getStoreKind()) {
11847
+ if (localStore.getId() !== remoteStore.getId() ||
11848
+ localStore.getStoreKind() !== remoteStore.getStoreKind()) {
11571
11849
  throw new Error(`[BaseMindooDB] Cannot pull entries from the incompatible store ${localStore.getId()}/${localStore.getStoreKind()}`);
11572
11850
  }
11573
11851
  this.logger.info(`Pulling entries from remote store ${remoteStore.getId()}/${remoteStore.getStoreKind()}`);
@@ -11590,10 +11868,15 @@ class BaseMindooDB {
11590
11868
  if (storeKind === types_2.StoreKind.docs) {
11591
11869
  await this.reconcileAfterDocsPull();
11592
11870
  }
11593
- return { transferredEntries: 0, transferredBytes, scannedEntries: syncResult.scanned, cancelled: false };
11871
+ return {
11872
+ transferredEntries: 0,
11873
+ transferredBytes,
11874
+ scannedEntries: syncResult.scanned,
11875
+ cancelled: false,
11876
+ };
11594
11877
  }
11595
11878
  options?.onProgress?.({
11596
- phase: 'processing',
11879
+ phase: "processing",
11597
11880
  message: `Processing ${syncResult.transferred} new entries...`,
11598
11881
  transferredEntries: syncResult.transferred,
11599
11882
  transferredBytes,
@@ -11625,7 +11908,7 @@ class BaseMindooDB {
11625
11908
  }
11626
11909
  this.logger.info(`Pull complete, synced ${syncResult.transferred} entries`);
11627
11910
  options?.onProgress?.({
11628
- phase: 'complete',
11911
+ phase: "complete",
11629
11912
  message: `Pull complete: ${syncResult.transferred} ${storeKind} entries synced`,
11630
11913
  transferredEntries: syncResult.transferred,
11631
11914
  transferredBytes,
@@ -11682,7 +11965,8 @@ class BaseMindooDB {
11682
11965
  const storeKind = options?.storeKind ?? types_2.StoreKind.docs;
11683
11966
  const localStore = this.getStoreForKind(storeKind);
11684
11967
  const remoteStore = this.resolveStore(remote, storeKind);
11685
- if (localStore.getId() !== remoteStore.getId() || localStore.getStoreKind() !== remoteStore.getStoreKind()) {
11968
+ if (localStore.getId() !== remoteStore.getId() ||
11969
+ localStore.getStoreKind() !== remoteStore.getStoreKind()) {
11686
11970
  throw new Error(`[BaseMindooDB] Cannot push entries to the incompatible store ${localStore.getId()}/${localStore.getStoreKind()}`);
11687
11971
  }
11688
11972
  this.logger.info(`Pushing entries to remote store ${remoteStore.getId()}/${remoteStore.getStoreKind()}`);
@@ -11713,7 +11997,7 @@ class BaseMindooDB {
11713
11997
  this.logger.info(`Pushed ${syncResult.transferred} entries to remote store`);
11714
11998
  }
11715
11999
  options?.onProgress?.({
11716
- phase: 'complete',
12000
+ phase: "complete",
11717
12001
  message: `Push complete: ${syncResult.transferred} entries transferred`,
11718
12002
  transferredEntries: syncResult.transferred,
11719
12003
  transferredBytes,