mindoodb 0.0.85 → 0.0.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-server.md +1 -0
- package/README.md +6 -4
- package/dist/cloudflare/DurableObjectSql.d.ts +56 -0
- package/dist/cloudflare/DurableObjectSql.d.ts.map +1 -0
- package/dist/cloudflare/DurableObjectSql.js +180 -0
- package/dist/cloudflare/DurableObjectSql.js.map +1 -0
- package/dist/cloudflare/MindooDatabaseObject.d.ts +86 -0
- package/dist/cloudflare/MindooDatabaseObject.d.ts.map +1 -0
- package/dist/cloudflare/MindooDatabaseObject.js +614 -0
- package/dist/cloudflare/MindooDatabaseObject.js.map +1 -0
- package/dist/cloudflare/MindooServerObject.d.ts +63 -0
- package/dist/cloudflare/MindooServerObject.d.ts.map +1 -0
- package/dist/cloudflare/MindooServerObject.js +521 -0
- package/dist/cloudflare/MindooServerObject.js.map +1 -0
- package/dist/cloudflare/WorkersCryptoAdapter.d.ts +7 -0
- package/dist/cloudflare/WorkersCryptoAdapter.d.ts.map +1 -0
- package/dist/cloudflare/WorkersCryptoAdapter.js +14 -0
- package/dist/cloudflare/WorkersCryptoAdapter.js.map +1 -0
- package/dist/cloudflare/host.d.ts +49 -0
- package/dist/cloudflare/host.d.ts.map +1 -0
- package/dist/cloudflare/host.js +104 -0
- package/dist/cloudflare/host.js.map +1 -0
- package/dist/cloudflare/http.d.ts +91 -0
- package/dist/cloudflare/http.d.ts.map +1 -0
- package/dist/cloudflare/http.js +266 -0
- package/dist/cloudflare/http.js.map +1 -0
- package/dist/cloudflare/index.d.ts +12 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +20 -0
- package/dist/cloudflare/index.js.map +1 -0
- package/dist/cloudflare/storeRpc.d.ts +22 -0
- package/dist/cloudflare/storeRpc.d.ts.map +1 -0
- package/dist/cloudflare/storeRpc.js +85 -0
- package/dist/cloudflare/storeRpc.js.map +1 -0
- package/dist/cloudflare/types.d.ts +101 -0
- package/dist/cloudflare/types.d.ts.map +1 -0
- package/dist/cloudflare/types.js +10 -0
- package/dist/cloudflare/types.js.map +1 -0
- package/dist/cloudflare/worker.d.ts +25 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +170 -0
- package/dist/cloudflare/worker.js.map +1 -0
- package/dist/core/BaseMindooDB.d.ts +28 -1
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +180 -86
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +14 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +46 -0
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts +10 -0
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +79 -8
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
- package/dist/core/ChangeDocDraft.d.ts +133 -0
- package/dist/core/ChangeDocDraft.d.ts.map +1 -0
- package/dist/core/ChangeDocDraft.js +492 -0
- package/dist/core/ChangeDocDraft.js.map +1 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts +8 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.js +19 -0
- package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
- package/dist/core/appendonlystores/network/IrohStreamIO.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/IrohStreamIO.js +3 -23
- package/dist/core/appendonlystores/network/IrohStreamIO.js.map +1 -1
- package/dist/core/appendonlystores/rpc/storeRpcCodec.d.ts.map +1 -1
- package/dist/core/appendonlystores/rpc/storeRpcCodec.js +3 -23
- package/dist/core/appendonlystores/rpc/storeRpcCodec.js.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js +21 -30
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts +37 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.js +99 -40
- package/dist/core/appendonlystores/sqlite/SqliteDriver.js.map +1 -1
- package/dist/core/expressions/evaluateExpression.d.ts +8 -0
- package/dist/core/expressions/evaluateExpression.d.ts.map +1 -1
- package/dist/core/expressions/evaluateExpression.js +29 -4
- package/dist/core/expressions/evaluateExpression.js.map +1 -1
- package/dist/core/expressions/metadata.js +4 -4
- package/dist/core/expressions/metadata.js.map +1 -1
- package/dist/core/types.d.ts +61 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/uri/MindooURI.d.ts.map +1 -1
- package/dist/core/uri/MindooURI.js +3 -24
- package/dist/core/uri/MindooURI.js.map +1 -1
- package/dist/core/utils/base64.d.ts +17 -0
- package/dist/core/utils/base64.d.ts.map +1 -0
- package/dist/core/utils/base64.js +54 -0
- package/dist/core/utils/base64.js.map +1 -0
- package/dist/core/utils/idGeneration.d.ts.map +1 -1
- package/dist/core/utils/idGeneration.js +14 -3
- package/dist/core/utils/idGeneration.js.map +1 -1
- package/dist/node/server/FsServerDataStore.d.ts +23 -0
- package/dist/node/server/FsServerDataStore.d.ts.map +1 -0
- package/dist/node/server/FsServerDataStore.js +59 -0
- package/dist/node/server/FsServerDataStore.js.map +1 -0
- package/dist/node/server/IrohServerEndpoint.d.ts +1 -1
- package/dist/node/server/IrohServerEndpoint.d.ts.map +1 -1
- package/dist/node/server/IrohServerRpc.d.ts +5 -5
- package/dist/node/server/IrohServerRpc.d.ts.map +1 -1
- package/dist/node/server/IrohServerRpc.js +1 -1
- package/dist/node/server/IrohServerRpc.js.map +1 -1
- package/dist/node/server/MindooDBServer.d.ts +29 -150
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +160 -1573
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/PurgedDocRegistry.d.ts +4 -27
- package/dist/node/server/PurgedDocRegistry.d.ts.map +1 -1
- package/dist/node/server/PurgedDocRegistry.js +6 -83
- package/dist/node/server/PurgedDocRegistry.js.map +1 -1
- package/dist/node/server/StoreFactory.d.ts +1 -1
- package/dist/node/server/StoreFactory.d.ts.map +1 -1
- package/dist/node/server/TenantManager.d.ts +16 -284
- package/dist/node/server/TenantManager.d.ts.map +1 -1
- package/dist/node/server/TenantManager.js +35 -1168
- package/dist/node/server/TenantManager.js.map +1 -1
- package/dist/node/server/add-to-network.js +1 -1
- package/dist/node/server/add-to-network.js.map +1 -1
- package/dist/node/server/config.d.ts +11 -15
- package/dist/node/server/config.d.ts.map +1 -1
- package/dist/node/server/config.js +30 -245
- package/dist/node/server/config.js.map +1 -1
- package/dist/node/server/expressAdapter.d.ts +23 -0
- package/dist/node/server/expressAdapter.d.ts.map +1 -0
- package/dist/node/server/expressAdapter.js +108 -0
- package/dist/node/server/expressAdapter.js.map +1 -0
- package/dist/node/server/nativeIrohStreamIO.d.ts +1 -1
- package/dist/node/server/nativeIrohStreamIO.d.ts.map +1 -1
- package/dist/node/server/peer/FileClusterAuditStorage.d.ts +16 -0
- package/dist/node/server/peer/FileClusterAuditStorage.d.ts.map +1 -0
- package/dist/node/server/peer/FileClusterAuditStorage.js +39 -0
- package/dist/node/server/peer/FileClusterAuditStorage.js.map +1 -0
- package/dist/node/server/peer/IrohPeerLink.d.ts +1 -1
- package/dist/node/server/peer/IrohPeerLink.d.ts.map +1 -1
- package/dist/node/server/peer/routes.d.ts +10 -44
- package/dist/node/server/peer/routes.d.ts.map +1 -1
- package/dist/node/server/peer/routes.js +33 -275
- package/dist/node/server/peer/routes.js.map +1 -1
- package/dist/node/server/resolveServerPassword.js +1 -1
- package/dist/node/server/resolveServerPassword.js.map +1 -1
- package/dist/node/server/server.js +1 -1
- package/dist/node/server/server.js.map +1 -1
- package/dist/node/server/serverinit.js +1 -1
- package/dist/node/server/serverinit.js.map +1 -1
- package/dist/server/CapabilityMatcher.d.ts +60 -0
- package/dist/server/CapabilityMatcher.d.ts.map +1 -0
- package/dist/server/CapabilityMatcher.js +138 -0
- package/dist/server/CapabilityMatcher.js.map +1 -0
- package/dist/server/DeviceDiscoveryService.d.ts +36 -0
- package/dist/server/DeviceDiscoveryService.d.ts.map +1 -0
- package/dist/server/DeviceDiscoveryService.js +165 -0
- package/dist/server/DeviceDiscoveryService.js.map +1 -0
- package/dist/server/PurgedDocRegistry.d.ts +35 -0
- package/dist/server/PurgedDocRegistry.d.ts.map +1 -0
- package/dist/server/PurgedDocRegistry.js +90 -0
- package/dist/server/PurgedDocRegistry.js.map +1 -0
- package/dist/server/ServerDataStore.d.ts +67 -0
- package/dist/server/ServerDataStore.d.ts.map +1 -0
- package/dist/server/ServerDataStore.js +88 -0
- package/dist/server/ServerDataStore.js.map +1 -0
- package/dist/server/SyncEventBus.d.ts +39 -0
- package/dist/server/SyncEventBus.d.ts.map +1 -0
- package/dist/server/SyncEventBus.js +41 -0
- package/dist/server/SyncEventBus.js.map +1 -0
- package/dist/server/SystemAdminAuth.d.ts +82 -0
- package/dist/server/SystemAdminAuth.d.ts.map +1 -0
- package/dist/server/SystemAdminAuth.js +228 -0
- package/dist/server/SystemAdminAuth.js.map +1 -0
- package/dist/server/TenantManager.d.ts +330 -0
- package/dist/server/TenantManager.d.ts.map +1 -0
- package/dist/server/TenantManager.js +1186 -0
- package/dist/server/TenantManager.js.map +1 -0
- package/dist/server/http/MindooDBServerCore.d.ts +313 -0
- package/dist/server/http/MindooDBServerCore.d.ts.map +1 -0
- package/dist/server/http/MindooDBServerCore.js +1403 -0
- package/dist/server/http/MindooDBServerCore.js.map +1 -0
- package/dist/server/http/types.d.ts +89 -0
- package/dist/server/http/types.d.ts.map +1 -0
- package/dist/server/http/types.js +29 -0
- package/dist/server/http/types.js.map +1 -0
- package/dist/server/index.d.ts +32 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +76 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/peer/ClusterAuditLog.d.ts +71 -0
- package/dist/server/peer/ClusterAuditLog.d.ts.map +1 -0
- package/dist/server/peer/ClusterAuditLog.js +81 -0
- package/dist/server/peer/ClusterAuditLog.js.map +1 -0
- package/dist/server/peer/ClusterJobRunner.d.ts +43 -0
- package/dist/server/peer/ClusterJobRunner.d.ts.map +1 -0
- package/dist/server/peer/ClusterJobRunner.js +119 -0
- package/dist/server/peer/ClusterJobRunner.js.map +1 -0
- package/dist/server/peer/ClusterManager.d.ts +149 -0
- package/dist/server/peer/ClusterManager.d.ts.map +1 -0
- package/dist/server/peer/ClusterManager.js +292 -0
- package/dist/server/peer/ClusterManager.js.map +1 -0
- package/dist/server/peer/PeerAuthService.d.ts +69 -0
- package/dist/server/peer/PeerAuthService.d.ts.map +1 -0
- package/dist/server/peer/PeerAuthService.js +208 -0
- package/dist/server/peer/PeerAuthService.js.map +1 -0
- package/dist/server/peer/PeerReplicator.d.ts +303 -0
- package/dist/server/peer/PeerReplicator.d.ts.map +1 -0
- package/dist/server/peer/PeerReplicator.js +1071 -0
- package/dist/server/peer/PeerReplicator.js.map +1 -0
- package/dist/server/peer/clusterHttp.d.ts +113 -0
- package/dist/server/peer/clusterHttp.d.ts.map +1 -0
- package/dist/server/peer/clusterHttp.js +290 -0
- package/dist/server/peer/clusterHttp.js.map +1 -0
- package/dist/server/peer/types.d.ts +244 -0
- package/dist/server/peer/types.d.ts.map +1 -0
- package/dist/server/peer/types.js +189 -0
- package/dist/server/peer/types.js.map +1 -0
- package/dist/server/rateLimits.d.ts +119 -0
- package/dist/server/rateLimits.d.ts.map +1 -0
- package/dist/server/rateLimits.js +159 -0
- package/dist/server/rateLimits.js.map +1 -0
- package/dist/server/serverConfig.d.ts +37 -0
- package/dist/server/serverConfig.d.ts.map +1 -0
- package/dist/server/serverConfig.js +251 -0
- package/dist/server/serverConfig.js.map +1 -0
- package/dist/server/timestampProxy.d.ts +129 -0
- package/dist/server/timestampProxy.d.ts.map +1 -0
- package/dist/server/timestampProxy.js +361 -0
- package/dist/server/timestampProxy.js.map +1 -0
- package/dist/server/types.d.ts +267 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +56 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/validation.d.ts +43 -0
- package/dist/server/validation.d.ts.map +1 -0
- package/dist/server/validation.js +104 -0
- package/dist/server/validation.js.map +1 -0
- package/package.json +9 -1
|
@@ -5,6 +5,7 @@ exports.BaseMindooDB = exports.CUSTOM_DOC_ID_INITIAL_CHANGE_BYTES = void 0;
|
|
|
5
5
|
// React Native: native Rust (react-native-automerge-generated)
|
|
6
6
|
// Browser/Node.js: WASM (@automerge/automerge/slim)
|
|
7
7
|
const automerge_adapter_1 = require("./automerge-adapter");
|
|
8
|
+
const ChangeDocDraft_1 = require("./ChangeDocDraft");
|
|
8
9
|
const values_1 = require("./values");
|
|
9
10
|
const storeEntryTime_1 = require("./storeEntryTime");
|
|
10
11
|
const changeAttribution_1 = require("./changeAttribution");
|
|
@@ -364,6 +365,25 @@ class BaseMindooDB {
|
|
|
364
365
|
*/
|
|
365
366
|
this.revisionFeedDocCache = new Map();
|
|
366
367
|
this.revisionFeedCacheLimit = 256;
|
|
368
|
+
/**
|
|
369
|
+
* Revisions of documents whose fold suffix holds un-witnessed entries, keyed
|
|
370
|
+
* by the exact fold (entry order, witness state and prefix). The feed
|
|
371
|
+
* re-discovers such entries on every resume, since their trusted time is the
|
|
372
|
+
* provisional `now`; while nothing about the document changed, only that
|
|
373
|
+
* trusted time differs, so the revisions are re-emitted from here instead
|
|
374
|
+
* of being loaded, verified, decrypted and folded again. Without it, every
|
|
375
|
+
* pass re-folded every un-witnessed document: registering N users offline
|
|
376
|
+
* cost O(N) per registration. An entry is replaced on any change and
|
|
377
|
+
* dropped once the document has no un-witnessed entries left.
|
|
378
|
+
*
|
|
379
|
+
* Each revision holds its own document state, so the cache is bounded: a
|
|
380
|
+
* document with a longer suffix, or one arriving when the cache is full, is
|
|
381
|
+
* folded every pass as before.
|
|
382
|
+
*/
|
|
383
|
+
this.provisionalRevisionCache = new Map();
|
|
384
|
+
this.provisionalRevisionCacheSize = 0;
|
|
385
|
+
this.provisionalRevisionCacheLimit = 4096;
|
|
386
|
+
this.provisionalRevisionCacheDocLimit = 32;
|
|
367
387
|
/**
|
|
368
388
|
* Window size for batching encrypted-payload loads while folding a document's
|
|
369
389
|
* revision suffix ({@link foldDocRevisions}): one {@link ContentAddressedStore.getEntries}
|
|
@@ -5176,6 +5196,27 @@ class BaseMindooDB {
|
|
|
5176
5196
|
if (firstChangedIdx < 0) {
|
|
5177
5197
|
return;
|
|
5178
5198
|
}
|
|
5199
|
+
// Unchanged document whose suffix is still provisional: re-emit the
|
|
5200
|
+
// previous fold with the current trusted times (see provisionalRevisionCache).
|
|
5201
|
+
const suffix = ttSorted.slice(firstChangedIdx);
|
|
5202
|
+
const hasProvisional = suffix.some((r) => !r.witnessed);
|
|
5203
|
+
const foldKey = [
|
|
5204
|
+
ttSorted.slice(0, firstChangedIdx).map((r) => r.meta.id).join(","),
|
|
5205
|
+
suffix.map((r) => `${r.meta.id}:${r.meta.receivedAt ?? "-"}`).join(","),
|
|
5206
|
+
].join("|");
|
|
5207
|
+
const cachedFold = this.provisionalRevisionCache.get(docId);
|
|
5208
|
+
if (cachedFold && cachedFold.key === foldKey) {
|
|
5209
|
+
for (let i = 0; i < cachedFold.revisions.length; i++) {
|
|
5210
|
+
yield { ...cachedFold.revisions[i], trustedTime: suffix[i].tt, cursor: resumeCursor };
|
|
5211
|
+
}
|
|
5212
|
+
return;
|
|
5213
|
+
}
|
|
5214
|
+
if (cachedFold) {
|
|
5215
|
+
this.provisionalRevisionCache.delete(docId);
|
|
5216
|
+
this.provisionalRevisionCacheSize -= cachedFold.revisions.length;
|
|
5217
|
+
}
|
|
5218
|
+
const foldedRevisions = [];
|
|
5219
|
+
let foldComplete = true;
|
|
5179
5220
|
// Origin time and key id come from the document's create entry, independent
|
|
5180
5221
|
// of fold order (under the trusted-time rule un-witnessed entries can sort
|
|
5181
5222
|
// before the create, so we must not rely on seeing the create first).
|
|
@@ -5225,6 +5266,7 @@ class BaseMindooDB {
|
|
|
5225
5266
|
// Absent from the loaded window means missing in the store or it failed
|
|
5226
5267
|
// signature verification (already logged during the parallel prepare).
|
|
5227
5268
|
this.logger.warn(`Revision entry ${meta.id} unavailable (missing or invalid), skipping`);
|
|
5269
|
+
foldComplete = false;
|
|
5228
5270
|
continue;
|
|
5229
5271
|
}
|
|
5230
5272
|
const entryData = ready.entry;
|
|
@@ -5249,16 +5291,24 @@ class BaseMindooDB {
|
|
|
5249
5291
|
// this document's replay entries seen up to and including this one.
|
|
5250
5292
|
isDeleted: this.computeIsDeletedFromMetadata([...seenMeta]),
|
|
5251
5293
|
};
|
|
5252
|
-
|
|
5294
|
+
const revision = {
|
|
5253
5295
|
docId,
|
|
5254
5296
|
entryId: meta.id,
|
|
5255
5297
|
doc: this.wrapDocument(internalDoc),
|
|
5256
5298
|
entryType: meta.entryType,
|
|
5257
|
-
trustedTime: rev.tt,
|
|
5258
5299
|
witnessed: rev.witnessed,
|
|
5259
5300
|
createdByPublicKey: meta.createdByPublicKey,
|
|
5260
|
-
cursor: resumeCursor,
|
|
5261
5301
|
};
|
|
5302
|
+
foldedRevisions.push(revision);
|
|
5303
|
+
yield { ...revision, trustedTime: rev.tt, cursor: resumeCursor };
|
|
5304
|
+
}
|
|
5305
|
+
// Reached only when the consumer took every revision of this document.
|
|
5306
|
+
if (hasProvisional &&
|
|
5307
|
+
foldComplete &&
|
|
5308
|
+
foldedRevisions.length <= this.provisionalRevisionCacheDocLimit &&
|
|
5309
|
+
this.provisionalRevisionCacheSize + foldedRevisions.length <= this.provisionalRevisionCacheLimit) {
|
|
5310
|
+
this.provisionalRevisionCache.set(docId, { key: foldKey, revisions: foldedRevisions });
|
|
5311
|
+
this.provisionalRevisionCacheSize += foldedRevisions.length;
|
|
5262
5312
|
}
|
|
5263
5313
|
// Cache the doc's full merged state for the next incremental advance.
|
|
5264
5314
|
this.putRevisionFeedCache(docId, {
|
|
@@ -8137,8 +8187,6 @@ class BaseMindooDB {
|
|
|
8137
8187
|
//
|
|
8138
8188
|
// We use a two-phase approach: the callback can do async work and collect
|
|
8139
8189
|
// what needs to be changed, then we apply those changes in Automerge.change()
|
|
8140
|
-
const pendingChanges = new Map();
|
|
8141
|
-
const pendingDeletions = new Set();
|
|
8142
8190
|
// Track pending attachment operations
|
|
8143
8191
|
const pendingAttachmentAdditions = [];
|
|
8144
8192
|
const pendingAttachmentRemovals = new Set();
|
|
@@ -8146,19 +8194,6 @@ class BaseMindooDB {
|
|
|
8146
8194
|
const pendingAttachmentAppends = new Map();
|
|
8147
8195
|
// Map of attachmentId -> extraction result for setAttachmentExtractedText
|
|
8148
8196
|
const pendingAttachmentTextUpdates = new Map();
|
|
8149
|
-
// incrementCounter() calls, applied in call order after the field
|
|
8150
|
-
// assignments so they can target counters assigned in the same callback.
|
|
8151
|
-
const pendingCounterIncrements = [];
|
|
8152
|
-
// Assignments and deletions are applied before the increments, so an
|
|
8153
|
-
// assignment or deletion of a field supersedes the increments queued on it
|
|
8154
|
-
// (or below it) earlier in the callback; later increments still apply.
|
|
8155
|
-
const dropPendingCounterIncrements = (field) => {
|
|
8156
|
-
for (let i = pendingCounterIncrements.length - 1; i >= 0; i--) {
|
|
8157
|
-
if (pendingCounterIncrements[i].path[0] === field) {
|
|
8158
|
-
pendingCounterIncrements.splice(i, 1);
|
|
8159
|
-
}
|
|
8160
|
-
}
|
|
8161
|
-
};
|
|
8162
8197
|
// Reference to db for closures
|
|
8163
8198
|
const db = this;
|
|
8164
8199
|
// Guard flag to prevent operations after callback completes
|
|
@@ -8169,6 +8204,15 @@ class BaseMindooDB {
|
|
|
8169
8204
|
throw new Error(`${methodName}() cannot be called after changeDoc() callback has completed. Document changes can only be made within the callback.`);
|
|
8170
8205
|
}
|
|
8171
8206
|
};
|
|
8207
|
+
// getData() edits a lazily built shadow copy and logs every edit, at any
|
|
8208
|
+
// depth, for replay inside Automerge.change() below.
|
|
8209
|
+
const draft = new ChangeDocDraft_1.ChangeDocDraft(internalDoc.doc, {
|
|
8210
|
+
scalarKind: (value) => db.automergeScalarKind(value),
|
|
8211
|
+
readScalar: (value) => db.readAutomergeScalar(value),
|
|
8212
|
+
makeCounter: (value) => new automerge_adapter_1.Automerge.Counter(value),
|
|
8213
|
+
isRichTextInBase: (path) => db.isRichTextAt(internalDoc.doc, path),
|
|
8214
|
+
assertActive: throwIfCallbackInactive,
|
|
8215
|
+
});
|
|
8172
8216
|
// Create a document wrapper that collects changes
|
|
8173
8217
|
const collectingDoc = {
|
|
8174
8218
|
getDatabase: () => this,
|
|
@@ -8186,62 +8230,7 @@ class BaseMindooDB {
|
|
|
8186
8230
|
isEncryptedFor: (users) => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId) &&
|
|
8187
8231
|
(0, recipients_1.isPayloadEncryptedFor)(internalDoc.doc, internalDoc.sealedRecipients, Array.isArray(users) ? users : [users]),
|
|
8188
8232
|
getHeads: () => automerge_adapter_1.Automerge.getHeads(internalDoc.doc),
|
|
8189
|
-
getData: () =>
|
|
8190
|
-
// Return a proxy that collects property assignments and deletions
|
|
8191
|
-
const currentData = internalDoc.doc;
|
|
8192
|
-
return new Proxy(currentData, {
|
|
8193
|
-
set: (target, prop, value) => {
|
|
8194
|
-
throwIfCallbackInactive("set property");
|
|
8195
|
-
if (typeof prop === "string") {
|
|
8196
|
-
dropPendingCounterIncrements(prop);
|
|
8197
|
-
// If this property was marked for deletion, remove it from deletions
|
|
8198
|
-
pendingDeletions.delete(prop);
|
|
8199
|
-
// Track the change
|
|
8200
|
-
pendingChanges.set(prop, value);
|
|
8201
|
-
// NOTE: Don't set on target immediately - Automerge requires changes
|
|
8202
|
-
// to be made inside Automerge.change(). Pending changes are applied later.
|
|
8203
|
-
}
|
|
8204
|
-
return true;
|
|
8205
|
-
},
|
|
8206
|
-
deleteProperty: (target, prop) => {
|
|
8207
|
-
throwIfCallbackInactive("delete property");
|
|
8208
|
-
if (typeof prop === "string") {
|
|
8209
|
-
dropPendingCounterIncrements(prop);
|
|
8210
|
-
// Mark for deletion
|
|
8211
|
-
pendingDeletions.add(prop);
|
|
8212
|
-
// Remove from pending changes if it was there
|
|
8213
|
-
pendingChanges.delete(prop);
|
|
8214
|
-
// NOTE: Don't delete from target immediately - Automerge requires changes
|
|
8215
|
-
// to be made inside Automerge.change(). Pending deletions are applied later.
|
|
8216
|
-
}
|
|
8217
|
-
return true;
|
|
8218
|
-
},
|
|
8219
|
-
get: (target, prop) => {
|
|
8220
|
-
// If marked for deletion, return undefined
|
|
8221
|
-
if (typeof prop === "string" && pendingDeletions.has(prop)) {
|
|
8222
|
-
return undefined;
|
|
8223
|
-
}
|
|
8224
|
-
// Check pending changes first, then target
|
|
8225
|
-
if (typeof prop === "string" && pendingChanges.has(prop)) {
|
|
8226
|
-
return pendingChanges.get(prop);
|
|
8227
|
-
}
|
|
8228
|
-
// Counters read as numbers and immutable strings as strings here
|
|
8229
|
-
// too; change counters with incrementCounter().
|
|
8230
|
-
return db.readAutomergeScalar(target[prop]);
|
|
8231
|
-
},
|
|
8232
|
-
has: (target, prop) => {
|
|
8233
|
-
// If marked for deletion, it doesn't exist
|
|
8234
|
-
if (typeof prop === "string" && pendingDeletions.has(prop)) {
|
|
8235
|
-
return false;
|
|
8236
|
-
}
|
|
8237
|
-
// Check pending changes first, then target
|
|
8238
|
-
if (typeof prop === "string" && pendingChanges.has(prop)) {
|
|
8239
|
-
return true;
|
|
8240
|
-
}
|
|
8241
|
-
return prop in target;
|
|
8242
|
-
},
|
|
8243
|
-
});
|
|
8244
|
-
},
|
|
8233
|
+
getData: () => draft.getRoot(),
|
|
8245
8234
|
// ========== Attachment Write Methods (work in changeDoc context) ==========
|
|
8246
8235
|
addAttachment: async (fileData, fileName, mimeType, keyId) => {
|
|
8247
8236
|
throwIfCallbackInactive("addAttachment");
|
|
@@ -8356,12 +8345,25 @@ class BaseMindooDB {
|
|
|
8356
8345
|
}
|
|
8357
8346
|
},
|
|
8358
8347
|
// ========== Counter Write Methods ==========
|
|
8348
|
+
updateText: (path, value) => {
|
|
8349
|
+
const segments = typeof path === "string" ? [path] : [...path];
|
|
8350
|
+
db.validateJsonPath(segments, "updateText");
|
|
8351
|
+
if (draft.getFieldType(segments) === "richText") {
|
|
8352
|
+
throw new Error(`updateText: '${segments.map(String).join(".")}' is rich text (marks or blocks); use applyRichTextPatch() or applyRichTextStepsPatch()`);
|
|
8353
|
+
}
|
|
8354
|
+
draft.updateText(segments, value);
|
|
8355
|
+
},
|
|
8356
|
+
getFieldType: (path) => {
|
|
8357
|
+
const segments = typeof path === "string" ? [path] : [...path];
|
|
8358
|
+
db.validateJsonPath(segments, "getFieldType");
|
|
8359
|
+
return draft.getFieldType(segments);
|
|
8360
|
+
},
|
|
8359
8361
|
incrementCounter: (path, delta) => {
|
|
8360
8362
|
throwIfCallbackInactive("incrementCounter");
|
|
8361
8363
|
const segments = typeof path === "string" ? [path] : [...path];
|
|
8362
8364
|
db.validateJsonPath(segments, "incrementCounter");
|
|
8363
8365
|
(0, values_1.assertCounterAmount)(delta, "incrementCounter delta");
|
|
8364
|
-
|
|
8366
|
+
draft.incrementCounter(segments, delta);
|
|
8365
8367
|
},
|
|
8366
8368
|
// ========== Attachment Read Methods (also work in changeDoc context) ==========
|
|
8367
8369
|
getAttachments: () => {
|
|
@@ -8396,20 +8398,14 @@ class BaseMindooDB {
|
|
|
8396
8398
|
let newDoc;
|
|
8397
8399
|
try {
|
|
8398
8400
|
newDoc = this.runChangeWithOutdatedDocRecovery(internalDoc, (doc) => automerge_adapter_1.Automerge.change(doc, { message: changeMessage }, (automergeDoc) => {
|
|
8399
|
-
//
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
for (const key of pendingDeletions) {
|
|
8405
|
-
delete automergeDoc[key];
|
|
8406
|
-
}
|
|
8401
|
+
// Replay the callback's field edits and counter increments in the
|
|
8402
|
+
// order they were made: an assignment after an increment replaces
|
|
8403
|
+
// it, an increment after an assignment adds to the new counter, and
|
|
8404
|
+
// a list index means the element it meant at that moment.
|
|
8405
|
+
this.applyChangeDocDraftOps(automergeDoc, draft.ops);
|
|
8407
8406
|
// Engine-internal edits that need the raw Automerge document, e.g.
|
|
8408
8407
|
// restoreDocumentToEntry's rich-text spans.
|
|
8409
8408
|
internalMutation?.(automergeDoc);
|
|
8410
|
-
for (const { path, delta } of pendingCounterIncrements) {
|
|
8411
|
-
this.incrementCounterAtPath(automergeDoc, path, delta);
|
|
8412
|
-
}
|
|
8413
8409
|
// Apply pending attachment changes
|
|
8414
8410
|
if (pendingAttachmentAdditions.length > 0 ||
|
|
8415
8411
|
pendingAttachmentRemovals.size > 0 ||
|
|
@@ -8514,6 +8510,96 @@ class BaseMindooDB {
|
|
|
8514
8510
|
}
|
|
8515
8511
|
await Promise.all(pendingAttachmentAdditions.map((ref) => this.clearPendingAttachmentUploadLedger(ref.attachmentId)));
|
|
8516
8512
|
}
|
|
8513
|
+
/** "counter" / "atomic" for the CRDT scalars that read as plain values, otherwise null. */
|
|
8514
|
+
automergeScalarKind(value) {
|
|
8515
|
+
if (this.isAutomergeCounter(value))
|
|
8516
|
+
return "counter";
|
|
8517
|
+
if (this.isAutomergeImmutableString(value))
|
|
8518
|
+
return "atomic";
|
|
8519
|
+
return null;
|
|
8520
|
+
}
|
|
8521
|
+
/** Whether the text at `path` carries marks or block markers (rich text). */
|
|
8522
|
+
isRichTextAt(automergeDoc, path) {
|
|
8523
|
+
if (typeof this.readValueAtPath(automergeDoc, path) !== "string")
|
|
8524
|
+
return false;
|
|
8525
|
+
const spans = automerge_adapter_1.Automerge.spans(automergeDoc, path);
|
|
8526
|
+
return spans.some((span) => span.type === "block" || (span.marks !== undefined && Object.keys(span.marks).length > 0));
|
|
8527
|
+
}
|
|
8528
|
+
fieldTypeAt(automergeDoc, path) {
|
|
8529
|
+
if (path.length === 0)
|
|
8530
|
+
return "map";
|
|
8531
|
+
let parent = automergeDoc;
|
|
8532
|
+
for (const segment of path.slice(0, -1)) {
|
|
8533
|
+
parent = parent?.[segment];
|
|
8534
|
+
if (parent === null || typeof parent !== "object" || this.automergeScalarKind(parent) !== null)
|
|
8535
|
+
return undefined;
|
|
8536
|
+
}
|
|
8537
|
+
const key = path[path.length - 1];
|
|
8538
|
+
if (!Object.prototype.hasOwnProperty.call(parent, key))
|
|
8539
|
+
return undefined;
|
|
8540
|
+
const value = parent[key];
|
|
8541
|
+
if (typeof value === "string")
|
|
8542
|
+
return this.isRichTextAt(automergeDoc, path) ? "richText" : "text";
|
|
8543
|
+
return (0, ChangeDocDraft_1.fieldTypeOf)(value, { scalarKind: (v) => this.automergeScalarKind(v) });
|
|
8544
|
+
}
|
|
8545
|
+
async getFieldType(doc, path) {
|
|
8546
|
+
const segments = typeof path === "string" ? [path] : [...path];
|
|
8547
|
+
this.validateJsonPath(segments, "getFieldType");
|
|
8548
|
+
const docId = doc.getId();
|
|
8549
|
+
let internalDoc = this.wrappedInternalDocs.get(doc) ?? this.getCachedDocument(docId);
|
|
8550
|
+
if (!internalDoc) {
|
|
8551
|
+
const loadedDoc = await this.loadDocumentInternal(docId);
|
|
8552
|
+
if (!loadedDoc) {
|
|
8553
|
+
throw new errors_1.DocumentNotFoundError(docId);
|
|
8554
|
+
}
|
|
8555
|
+
internalDoc = loadedDoc;
|
|
8556
|
+
}
|
|
8557
|
+
return this.fieldTypeAt(internalDoc.doc, segments);
|
|
8558
|
+
}
|
|
8559
|
+
/** Replays the edits a changeDoc() callback made through getData(), see ChangeDocDraft. */
|
|
8560
|
+
applyChangeDocDraftOps(automergeDoc, ops) {
|
|
8561
|
+
const containerAt = (path) => {
|
|
8562
|
+
let current = automergeDoc;
|
|
8563
|
+
for (const segment of path)
|
|
8564
|
+
current = current[segment];
|
|
8565
|
+
return current;
|
|
8566
|
+
};
|
|
8567
|
+
for (const op of ops) {
|
|
8568
|
+
if (op.kind === "counter") {
|
|
8569
|
+
this.incrementCounterAtPath(automergeDoc, op.path, op.delta);
|
|
8570
|
+
continue;
|
|
8571
|
+
}
|
|
8572
|
+
if (op.kind === "splice") {
|
|
8573
|
+
const list = containerAt(op.path);
|
|
8574
|
+
const values = this.hydrateTypedValues(op.items);
|
|
8575
|
+
list.splice(op.index, op.deleteCount, ...this.withoutNestedFloats(values));
|
|
8576
|
+
values.forEach((value, offset) => {
|
|
8577
|
+
if (value instanceof automerge_adapter_1.Automerge.Float64)
|
|
8578
|
+
list[op.index + offset] = new automerge_adapter_1.Automerge.Float64(value.value);
|
|
8579
|
+
else
|
|
8580
|
+
this.restoreNestedFloats(list[op.index + offset], value);
|
|
8581
|
+
});
|
|
8582
|
+
continue;
|
|
8583
|
+
}
|
|
8584
|
+
const parent = containerAt(op.path.slice(0, -1));
|
|
8585
|
+
const key = op.path[op.path.length - 1];
|
|
8586
|
+
if (op.kind === "delete") {
|
|
8587
|
+
delete parent[key];
|
|
8588
|
+
continue;
|
|
8589
|
+
}
|
|
8590
|
+
const current = parent[key];
|
|
8591
|
+
if (op.kind === "text" && typeof current === "string") {
|
|
8592
|
+
// Splice only the changed middle, so the edit merges with concurrent
|
|
8593
|
+
// typing instead of replacing the whole text.
|
|
8594
|
+
const splice = (0, ChangeDocDraft_1.diffTextSplice)(current, op.value);
|
|
8595
|
+
if (splice) {
|
|
8596
|
+
automerge_adapter_1.Automerge.splice(automergeDoc, op.path, splice.index, splice.deleteCount, splice.insert);
|
|
8597
|
+
}
|
|
8598
|
+
continue;
|
|
8599
|
+
}
|
|
8600
|
+
this.assignHydrated(parent, key, this.hydrateTypedValues(op.value));
|
|
8601
|
+
}
|
|
8602
|
+
}
|
|
8517
8603
|
validateTextPatch(patch) {
|
|
8518
8604
|
if (!Array.isArray(patch.path) || patch.path.length === 0) {
|
|
8519
8605
|
throw new Error("Text patch path must contain at least one segment");
|
|
@@ -12367,6 +12453,14 @@ class BaseMindooDB {
|
|
|
12367
12453
|
setAttachmentExtractedText: () => {
|
|
12368
12454
|
throw new Error("setAttachmentExtractedText() can only be called within changeDoc() callback");
|
|
12369
12455
|
},
|
|
12456
|
+
getFieldType: (path) => {
|
|
12457
|
+
const segments = typeof path === "string" ? [path] : [...path];
|
|
12458
|
+
this.validateJsonPath(segments, "getFieldType");
|
|
12459
|
+
return this.fieldTypeAt(internalDoc.doc, segments);
|
|
12460
|
+
},
|
|
12461
|
+
updateText: () => {
|
|
12462
|
+
throw new Error("updateText() can only be called within changeDoc() callback; use applyJsonPatch() with textSplice outside of it");
|
|
12463
|
+
},
|
|
12370
12464
|
incrementCounter: () => {
|
|
12371
12465
|
throw new Error("incrementCounter() can only be called within changeDoc() callback; use applyJsonPatch() with counterIncrement outside of it");
|
|
12372
12466
|
},
|