mindoodb 0.0.84 → 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/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +15 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +75 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts +9 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +38 -10
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- 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 +43 -1
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +209 -87
- 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/InMemoryContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +1 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -1
- 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/network/NetworkTransport.d.ts +7 -1
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.d.ts +23 -0
- package/dist/core/appendonlystores/network/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.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/appendonlystores/syncStores.d.ts.map +1 -1
- package/dist/core/appendonlystores/syncStores.js +253 -168
- package/dist/core/appendonlystores/syncStores.js.map +1 -1
- package/dist/core/appendonlystores/types.d.ts +8 -0
- package/dist/core/appendonlystores/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/types.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/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -1
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js +1 -0
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.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 -1568
- 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/compressionMiddleware.d.ts +14 -0
- package/dist/node/server/compressionMiddleware.d.ts.map +1 -1
- package/dist/node/server/compressionMiddleware.js +46 -3
- package/dist/node/server/compressionMiddleware.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");
|
|
@@ -293,6 +294,8 @@ class BaseMindooDB {
|
|
|
293
294
|
this.nextChangeSeq = 1;
|
|
294
295
|
// Cache of loaded documents: Map<docId, InternalDoc>
|
|
295
296
|
this.docCache = new Map();
|
|
297
|
+
/** Document loads in progress; see {@link loadDocumentInternal}. */
|
|
298
|
+
this.documentLoadsInFlight = new Map();
|
|
296
299
|
this.wrappedInternalDocs = new WeakMap();
|
|
297
300
|
/**
|
|
298
301
|
* Per-document count of local writes since the last snapshot eligibility
|
|
@@ -362,6 +365,25 @@ class BaseMindooDB {
|
|
|
362
365
|
*/
|
|
363
366
|
this.revisionFeedDocCache = new Map();
|
|
364
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;
|
|
365
387
|
/**
|
|
366
388
|
* Window size for batching encrypted-payload loads while folding a document's
|
|
367
389
|
* revision suffix ({@link foldDocRevisions}): one {@link ContentAddressedStore.getEntries}
|
|
@@ -5174,6 +5196,27 @@ class BaseMindooDB {
|
|
|
5174
5196
|
if (firstChangedIdx < 0) {
|
|
5175
5197
|
return;
|
|
5176
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;
|
|
5177
5220
|
// Origin time and key id come from the document's create entry, independent
|
|
5178
5221
|
// of fold order (under the trusted-time rule un-witnessed entries can sort
|
|
5179
5222
|
// before the create, so we must not rely on seeing the create first).
|
|
@@ -5223,6 +5266,7 @@ class BaseMindooDB {
|
|
|
5223
5266
|
// Absent from the loaded window means missing in the store or it failed
|
|
5224
5267
|
// signature verification (already logged during the parallel prepare).
|
|
5225
5268
|
this.logger.warn(`Revision entry ${meta.id} unavailable (missing or invalid), skipping`);
|
|
5269
|
+
foldComplete = false;
|
|
5226
5270
|
continue;
|
|
5227
5271
|
}
|
|
5228
5272
|
const entryData = ready.entry;
|
|
@@ -5247,16 +5291,24 @@ class BaseMindooDB {
|
|
|
5247
5291
|
// this document's replay entries seen up to and including this one.
|
|
5248
5292
|
isDeleted: this.computeIsDeletedFromMetadata([...seenMeta]),
|
|
5249
5293
|
};
|
|
5250
|
-
|
|
5294
|
+
const revision = {
|
|
5251
5295
|
docId,
|
|
5252
5296
|
entryId: meta.id,
|
|
5253
5297
|
doc: this.wrapDocument(internalDoc),
|
|
5254
5298
|
entryType: meta.entryType,
|
|
5255
|
-
trustedTime: rev.tt,
|
|
5256
5299
|
witnessed: rev.witnessed,
|
|
5257
5300
|
createdByPublicKey: meta.createdByPublicKey,
|
|
5258
|
-
cursor: resumeCursor,
|
|
5259
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;
|
|
5260
5312
|
}
|
|
5261
5313
|
// Cache the doc's full merged state for the next incremental advance.
|
|
5262
5314
|
this.putRevisionFeedCache(docId, {
|
|
@@ -8135,8 +8187,6 @@ class BaseMindooDB {
|
|
|
8135
8187
|
//
|
|
8136
8188
|
// We use a two-phase approach: the callback can do async work and collect
|
|
8137
8189
|
// what needs to be changed, then we apply those changes in Automerge.change()
|
|
8138
|
-
const pendingChanges = new Map();
|
|
8139
|
-
const pendingDeletions = new Set();
|
|
8140
8190
|
// Track pending attachment operations
|
|
8141
8191
|
const pendingAttachmentAdditions = [];
|
|
8142
8192
|
const pendingAttachmentRemovals = new Set();
|
|
@@ -8144,19 +8194,6 @@ class BaseMindooDB {
|
|
|
8144
8194
|
const pendingAttachmentAppends = new Map();
|
|
8145
8195
|
// Map of attachmentId -> extraction result for setAttachmentExtractedText
|
|
8146
8196
|
const pendingAttachmentTextUpdates = new Map();
|
|
8147
|
-
// incrementCounter() calls, applied in call order after the field
|
|
8148
|
-
// assignments so they can target counters assigned in the same callback.
|
|
8149
|
-
const pendingCounterIncrements = [];
|
|
8150
|
-
// Assignments and deletions are applied before the increments, so an
|
|
8151
|
-
// assignment or deletion of a field supersedes the increments queued on it
|
|
8152
|
-
// (or below it) earlier in the callback; later increments still apply.
|
|
8153
|
-
const dropPendingCounterIncrements = (field) => {
|
|
8154
|
-
for (let i = pendingCounterIncrements.length - 1; i >= 0; i--) {
|
|
8155
|
-
if (pendingCounterIncrements[i].path[0] === field) {
|
|
8156
|
-
pendingCounterIncrements.splice(i, 1);
|
|
8157
|
-
}
|
|
8158
|
-
}
|
|
8159
|
-
};
|
|
8160
8197
|
// Reference to db for closures
|
|
8161
8198
|
const db = this;
|
|
8162
8199
|
// Guard flag to prevent operations after callback completes
|
|
@@ -8167,6 +8204,15 @@ class BaseMindooDB {
|
|
|
8167
8204
|
throw new Error(`${methodName}() cannot be called after changeDoc() callback has completed. Document changes can only be made within the callback.`);
|
|
8168
8205
|
}
|
|
8169
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
|
+
});
|
|
8170
8216
|
// Create a document wrapper that collects changes
|
|
8171
8217
|
const collectingDoc = {
|
|
8172
8218
|
getDatabase: () => this,
|
|
@@ -8184,62 +8230,7 @@ class BaseMindooDB {
|
|
|
8184
8230
|
isEncryptedFor: (users) => (0, sealedTypes_1.isSealedKeyId)(internalDoc.decryptionKeyId) &&
|
|
8185
8231
|
(0, recipients_1.isPayloadEncryptedFor)(internalDoc.doc, internalDoc.sealedRecipients, Array.isArray(users) ? users : [users]),
|
|
8186
8232
|
getHeads: () => automerge_adapter_1.Automerge.getHeads(internalDoc.doc),
|
|
8187
|
-
getData: () =>
|
|
8188
|
-
// Return a proxy that collects property assignments and deletions
|
|
8189
|
-
const currentData = internalDoc.doc;
|
|
8190
|
-
return new Proxy(currentData, {
|
|
8191
|
-
set: (target, prop, value) => {
|
|
8192
|
-
throwIfCallbackInactive("set property");
|
|
8193
|
-
if (typeof prop === "string") {
|
|
8194
|
-
dropPendingCounterIncrements(prop);
|
|
8195
|
-
// If this property was marked for deletion, remove it from deletions
|
|
8196
|
-
pendingDeletions.delete(prop);
|
|
8197
|
-
// Track the change
|
|
8198
|
-
pendingChanges.set(prop, value);
|
|
8199
|
-
// NOTE: Don't set on target immediately - Automerge requires changes
|
|
8200
|
-
// to be made inside Automerge.change(). Pending changes are applied later.
|
|
8201
|
-
}
|
|
8202
|
-
return true;
|
|
8203
|
-
},
|
|
8204
|
-
deleteProperty: (target, prop) => {
|
|
8205
|
-
throwIfCallbackInactive("delete property");
|
|
8206
|
-
if (typeof prop === "string") {
|
|
8207
|
-
dropPendingCounterIncrements(prop);
|
|
8208
|
-
// Mark for deletion
|
|
8209
|
-
pendingDeletions.add(prop);
|
|
8210
|
-
// Remove from pending changes if it was there
|
|
8211
|
-
pendingChanges.delete(prop);
|
|
8212
|
-
// NOTE: Don't delete from target immediately - Automerge requires changes
|
|
8213
|
-
// to be made inside Automerge.change(). Pending deletions are applied later.
|
|
8214
|
-
}
|
|
8215
|
-
return true;
|
|
8216
|
-
},
|
|
8217
|
-
get: (target, prop) => {
|
|
8218
|
-
// If marked for deletion, return undefined
|
|
8219
|
-
if (typeof prop === "string" && pendingDeletions.has(prop)) {
|
|
8220
|
-
return undefined;
|
|
8221
|
-
}
|
|
8222
|
-
// Check pending changes first, then target
|
|
8223
|
-
if (typeof prop === "string" && pendingChanges.has(prop)) {
|
|
8224
|
-
return pendingChanges.get(prop);
|
|
8225
|
-
}
|
|
8226
|
-
// Counters read as numbers and immutable strings as strings here
|
|
8227
|
-
// too; change counters with incrementCounter().
|
|
8228
|
-
return db.readAutomergeScalar(target[prop]);
|
|
8229
|
-
},
|
|
8230
|
-
has: (target, prop) => {
|
|
8231
|
-
// If marked for deletion, it doesn't exist
|
|
8232
|
-
if (typeof prop === "string" && pendingDeletions.has(prop)) {
|
|
8233
|
-
return false;
|
|
8234
|
-
}
|
|
8235
|
-
// Check pending changes first, then target
|
|
8236
|
-
if (typeof prop === "string" && pendingChanges.has(prop)) {
|
|
8237
|
-
return true;
|
|
8238
|
-
}
|
|
8239
|
-
return prop in target;
|
|
8240
|
-
},
|
|
8241
|
-
});
|
|
8242
|
-
},
|
|
8233
|
+
getData: () => draft.getRoot(),
|
|
8243
8234
|
// ========== Attachment Write Methods (work in changeDoc context) ==========
|
|
8244
8235
|
addAttachment: async (fileData, fileName, mimeType, keyId) => {
|
|
8245
8236
|
throwIfCallbackInactive("addAttachment");
|
|
@@ -8354,12 +8345,25 @@ class BaseMindooDB {
|
|
|
8354
8345
|
}
|
|
8355
8346
|
},
|
|
8356
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
|
+
},
|
|
8357
8361
|
incrementCounter: (path, delta) => {
|
|
8358
8362
|
throwIfCallbackInactive("incrementCounter");
|
|
8359
8363
|
const segments = typeof path === "string" ? [path] : [...path];
|
|
8360
8364
|
db.validateJsonPath(segments, "incrementCounter");
|
|
8361
8365
|
(0, values_1.assertCounterAmount)(delta, "incrementCounter delta");
|
|
8362
|
-
|
|
8366
|
+
draft.incrementCounter(segments, delta);
|
|
8363
8367
|
},
|
|
8364
8368
|
// ========== Attachment Read Methods (also work in changeDoc context) ==========
|
|
8365
8369
|
getAttachments: () => {
|
|
@@ -8394,20 +8398,14 @@ class BaseMindooDB {
|
|
|
8394
8398
|
let newDoc;
|
|
8395
8399
|
try {
|
|
8396
8400
|
newDoc = this.runChangeWithOutdatedDocRecovery(internalDoc, (doc) => automerge_adapter_1.Automerge.change(doc, { message: changeMessage }, (automergeDoc) => {
|
|
8397
|
-
//
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
for (const key of pendingDeletions) {
|
|
8403
|
-
delete automergeDoc[key];
|
|
8404
|
-
}
|
|
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);
|
|
8405
8406
|
// Engine-internal edits that need the raw Automerge document, e.g.
|
|
8406
8407
|
// restoreDocumentToEntry's rich-text spans.
|
|
8407
8408
|
internalMutation?.(automergeDoc);
|
|
8408
|
-
for (const { path, delta } of pendingCounterIncrements) {
|
|
8409
|
-
this.incrementCounterAtPath(automergeDoc, path, delta);
|
|
8410
|
-
}
|
|
8411
8409
|
// Apply pending attachment changes
|
|
8412
8410
|
if (pendingAttachmentAdditions.length > 0 ||
|
|
8413
8411
|
pendingAttachmentRemovals.size > 0 ||
|
|
@@ -8512,6 +8510,96 @@ class BaseMindooDB {
|
|
|
8512
8510
|
}
|
|
8513
8511
|
await Promise.all(pendingAttachmentAdditions.map((ref) => this.clearPendingAttachmentUploadLedger(ref.attachmentId)));
|
|
8514
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
|
+
}
|
|
8515
8603
|
validateTextPatch(patch) {
|
|
8516
8604
|
if (!Array.isArray(patch.path) || patch.path.length === 0) {
|
|
8517
8605
|
throw new Error("Text patch path must contain at least one segment");
|
|
@@ -11751,7 +11839,33 @@ class BaseMindooDB {
|
|
|
11751
11839
|
this.docCache.delete(docId);
|
|
11752
11840
|
this.dirtyDocIds.delete(docId);
|
|
11753
11841
|
}
|
|
11754
|
-
|
|
11842
|
+
/**
|
|
11843
|
+
* Materialize a document, sharing a load that is already running for it.
|
|
11844
|
+
*
|
|
11845
|
+
* Several readers often want the same document at the same moment: the
|
|
11846
|
+
* summary buffer and the full-text index follow the same changefeed after
|
|
11847
|
+
* every sync page, each with its own prefetch window. Without sharing, both
|
|
11848
|
+
* windows miss the L1 cache for documents the other is still loading and
|
|
11849
|
+
* each materializes them, so a first sync with both indexes paid every
|
|
11850
|
+
* document twice. A load is only shared while no newer entries for the
|
|
11851
|
+
* document were indexed since it started, so no caller gets a state older
|
|
11852
|
+
* than its call.
|
|
11853
|
+
*/
|
|
11854
|
+
loadDocumentInternal(docId) {
|
|
11855
|
+
const generation = this.docEntryGeneration.get(docId) ?? 0;
|
|
11856
|
+
const inFlight = this.documentLoadsInFlight.get(docId);
|
|
11857
|
+
if (inFlight && inFlight.generation === generation) {
|
|
11858
|
+
return inFlight.promise;
|
|
11859
|
+
}
|
|
11860
|
+
const promise = this.loadDocumentUncoalesced(docId).finally(() => {
|
|
11861
|
+
if (this.documentLoadsInFlight.get(docId)?.promise === promise) {
|
|
11862
|
+
this.documentLoadsInFlight.delete(docId);
|
|
11863
|
+
}
|
|
11864
|
+
});
|
|
11865
|
+
this.documentLoadsInFlight.set(docId, { generation, promise });
|
|
11866
|
+
return promise;
|
|
11867
|
+
}
|
|
11868
|
+
async loadDocumentUncoalesced(docId) {
|
|
11755
11869
|
const startedAt = Date.now();
|
|
11756
11870
|
const cacheCheckStartedAt = Date.now();
|
|
11757
11871
|
// Short-circuit on the visibility layer: a doc marked
|
|
@@ -12339,6 +12453,14 @@ class BaseMindooDB {
|
|
|
12339
12453
|
setAttachmentExtractedText: () => {
|
|
12340
12454
|
throw new Error("setAttachmentExtractedText() can only be called within changeDoc() callback");
|
|
12341
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
|
+
},
|
|
12342
12464
|
incrementCounter: () => {
|
|
12343
12465
|
throw new Error("incrementCounter() can only be called within changeDoc() callback; use applyJsonPatch() with counterIncrement outside of it");
|
|
12344
12466
|
},
|