mindoodb 0.0.45 → 0.0.47
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.md +9 -0
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +4 -0
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- package/dist/browser/index.mjs +31 -0
- package/dist/core/BaseMindooDB.d.ts +75 -0
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +204 -0
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +22 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +38 -0
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/DocumentDagAnalysis.d.ts +32 -0
- package/dist/core/DocumentDagAnalysis.d.ts.map +1 -1
- package/dist/core/DocumentDagAnalysis.js +46 -6
- package/dist/core/DocumentDagAnalysis.js.map +1 -1
- package/dist/core/copy/attachments.d.ts +53 -0
- package/dist/core/copy/attachments.d.ts.map +1 -0
- package/dist/core/copy/attachments.js +186 -0
- package/dist/core/copy/attachments.js.map +1 -0
- package/dist/core/copy/copyDocument.d.ts +86 -0
- package/dist/core/copy/copyDocument.d.ts.map +1 -0
- package/dist/core/copy/copyDocument.js +369 -0
- package/dist/core/copy/copyDocument.js.map +1 -0
- package/dist/core/copy/copyDocuments.d.ts +57 -0
- package/dist/core/copy/copyDocuments.d.ts.map +1 -0
- package/dist/core/copy/copyDocuments.js +167 -0
- package/dist/core/copy/copyDocuments.js.map +1 -0
- package/dist/core/copy/entryRewrite.d.ts +49 -0
- package/dist/core/copy/entryRewrite.d.ts.map +1 -0
- package/dist/core/copy/entryRewrite.js +74 -0
- package/dist/core/copy/entryRewrite.js.map +1 -0
- package/dist/core/copy/feasibility.d.ts +73 -0
- package/dist/core/copy/feasibility.d.ts.map +1 -0
- package/dist/core/copy/feasibility.js +169 -0
- package/dist/core/copy/feasibility.js.map +1 -0
- package/dist/core/copy/flatten.d.ts +55 -0
- package/dist/core/copy/flatten.d.ts.map +1 -0
- package/dist/core/copy/flatten.js +155 -0
- package/dist/core/copy/flatten.js.map +1 -0
- package/dist/core/copy/host.d.ts +92 -0
- package/dist/core/copy/host.d.ts.map +1 -0
- package/dist/core/copy/host.js +16 -0
- package/dist/core/copy/host.js.map +1 -0
- package/dist/core/copy/preflight.d.ts +62 -0
- package/dist/core/copy/preflight.d.ts.map +1 -0
- package/dist/core/copy/preflight.js +98 -0
- package/dist/core/copy/preflight.js.map +1 -0
- package/dist/core/copy/provenance.d.ts +74 -0
- package/dist/core/copy/provenance.d.ts.map +1 -0
- package/dist/core/copy/provenance.js +91 -0
- package/dist/core/copy/provenance.js.map +1 -0
- package/dist/core/copy/types.d.ts +418 -0
- package/dist/core/copy/types.d.ts.map +1 -0
- package/dist/core/copy/types.js +21 -0
- package/dist/core/copy/types.js.map +1 -0
- package/dist/core/crypto/DomainStatement.d.ts +44 -0
- package/dist/core/crypto/DomainStatement.d.ts.map +1 -0
- package/dist/core/crypto/DomainStatement.js +71 -0
- package/dist/core/crypto/DomainStatement.js.map +1 -0
- package/dist/core/crypto/EntrySignature.d.ts +109 -15
- package/dist/core/crypto/EntrySignature.d.ts.map +1 -1
- package/dist/core/crypto/EntrySignature.js +83 -22
- package/dist/core/crypto/EntrySignature.js.map +1 -1
- package/dist/core/index.d.ts +21 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +54 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/timestamps/timestampClient.d.ts +88 -0
- package/dist/core/timestamps/timestampClient.d.ts.map +1 -0
- package/dist/core/timestamps/timestampClient.js +157 -0
- package/dist/core/timestamps/timestampClient.js.map +1 -0
- package/dist/core/types.d.ts +118 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/node/server/MindooDBServer.d.ts +37 -0
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +157 -0
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/config.d.ts.map +1 -1
- package/dist/node/server/config.js +16 -0
- package/dist/node/server/config.js.map +1 -1
- package/dist/node/server/timestampProxy.d.ts +129 -0
- package/dist/node/server/timestampProxy.d.ts.map +1 -0
- package/dist/node/server/timestampProxy.js +361 -0
- package/dist/node/server/timestampProxy.js.map +1 -0
- package/dist/node/server/types.d.ts +20 -0
- package/dist/node/server/types.d.ts.map +1 -1
- package/dist/node/server/types.js +12 -0
- package/dist/node/server/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,6 +18,8 @@ const idGeneration_1 = require("./utils/idGeneration");
|
|
|
18
18
|
const timeSource_1 = require("./utils/timeSource");
|
|
19
19
|
const errors_1 = require("./errors");
|
|
20
20
|
const EntrySignature_1 = require("./crypto/EntrySignature");
|
|
21
|
+
const copyDocument_1 = require("./copy/copyDocument");
|
|
22
|
+
const copyDocuments_1 = require("./copy/copyDocuments");
|
|
21
23
|
const materializationGuard_1 = require("./accesscontrol/materializationGuard");
|
|
22
24
|
const Ed25519WitnessProvider_1 = require("./accesscontrol/timestamp/Ed25519WitnessProvider");
|
|
23
25
|
const AccessDeniedError_1 = require("./accesscontrol/AccessDeniedError");
|
|
@@ -4278,6 +4280,7 @@ class BaseMindooDB {
|
|
|
4278
4280
|
doc: wrappedDoc,
|
|
4279
4281
|
changeCreatedAt: entryMetadata.createdAt,
|
|
4280
4282
|
changeCreatedByPublicKey: entryMetadata.createdByPublicKey,
|
|
4283
|
+
changeDependencyIds: [...entryMetadata.dependencyIds],
|
|
4281
4284
|
};
|
|
4282
4285
|
}
|
|
4283
4286
|
}
|
|
@@ -4881,6 +4884,49 @@ class BaseMindooDB {
|
|
|
4881
4884
|
doc: this.wrapDocument(internalDoc),
|
|
4882
4885
|
};
|
|
4883
4886
|
}
|
|
4887
|
+
async materializeDocumentAtHeads(docId, headEntryIds) {
|
|
4888
|
+
const startedAt = Date.now();
|
|
4889
|
+
const allEntryMetadata = await this.scanAllMetadata(this.store, { docId });
|
|
4890
|
+
const plan = (0, DocumentDagAnalysis_1.computeHeadsMaterializationPlan)(docId, allEntryMetadata, headEntryIds);
|
|
4891
|
+
if (!plan) {
|
|
4892
|
+
this.performanceCallback?.onHistoryOperation?.({
|
|
4893
|
+
operation: "materializeDocumentAtHeads",
|
|
4894
|
+
docId,
|
|
4895
|
+
time: Date.now() - startedAt,
|
|
4896
|
+
scannedEntries: allEntryMetadata.length,
|
|
4897
|
+
returnedEntries: 0,
|
|
4898
|
+
bounded: true,
|
|
4899
|
+
});
|
|
4900
|
+
return null;
|
|
4901
|
+
}
|
|
4902
|
+
const metadataById = new Map(allEntryMetadata.map((entry) => [entry.id, entry]));
|
|
4903
|
+
const branchEntries = plan.branchEntryIds
|
|
4904
|
+
.map((entryId) => metadataById.get(entryId))
|
|
4905
|
+
.filter((entry) => entry !== undefined);
|
|
4906
|
+
const internalDoc = await this.materializeDocumentFromPlan(docId, allEntryMetadata, branchEntries, plan.snapshotEntryId, plan.entryIdsToApply, plan.headCreatedAt);
|
|
4907
|
+
this.performanceCallback?.onHistoryOperation?.({
|
|
4908
|
+
operation: "materializeDocumentAtHeads",
|
|
4909
|
+
docId,
|
|
4910
|
+
time: Date.now() - startedAt,
|
|
4911
|
+
scannedEntries: allEntryMetadata.length,
|
|
4912
|
+
returnedEntries: internalDoc ? 1 : 0,
|
|
4913
|
+
bounded: true,
|
|
4914
|
+
});
|
|
4915
|
+
if (!internalDoc) {
|
|
4916
|
+
return null;
|
|
4917
|
+
}
|
|
4918
|
+
return {
|
|
4919
|
+
docId,
|
|
4920
|
+
headEntryId: plan.headEntryIds[plan.headEntryIds.length - 1],
|
|
4921
|
+
headEntryIds: [...plan.headEntryIds],
|
|
4922
|
+
headCreatedAt: plan.headCreatedAt,
|
|
4923
|
+
headCreatedByPublicKey: plan.headCreatedByPublicKey,
|
|
4924
|
+
snapshotEntryId: plan.snapshotEntryId,
|
|
4925
|
+
entryIdsApplied: [...plan.entryIdsToApply],
|
|
4926
|
+
branchEntryIds: [...plan.branchEntryIds],
|
|
4927
|
+
doc: this.wrapDocument(internalDoc),
|
|
4928
|
+
};
|
|
4929
|
+
}
|
|
4884
4930
|
async materializeDocumentBranchAtTimestamp(docId, timestamp, headEntryId) {
|
|
4885
4931
|
const startedAt = Date.now();
|
|
4886
4932
|
const resolvedTimestamp = this.resolveDagTimestamp(timestamp);
|
|
@@ -10545,6 +10591,164 @@ class BaseMindooDB {
|
|
|
10545
10591
|
}
|
|
10546
10592
|
};
|
|
10547
10593
|
}
|
|
10594
|
+
// ==========================================================================
|
|
10595
|
+
// Document copy across databases (src/core/copy/, docs/document-copy.md)
|
|
10596
|
+
// ==========================================================================
|
|
10597
|
+
/**
|
|
10598
|
+
* The seam the copy engine reaches this database through.
|
|
10599
|
+
*
|
|
10600
|
+
* The engine lives in `src/core/copy/` rather than as more methods on this
|
|
10601
|
+
* already-large class, and needs a few things that are private here (entry
|
|
10602
|
+
* signing, the attachment-ref snapshot, the attachment crypto envelope). This
|
|
10603
|
+
* hands them over as one narrow object instead of widening their visibility.
|
|
10604
|
+
*
|
|
10605
|
+
* @internal Not part of the supported API; may change without notice.
|
|
10606
|
+
*/
|
|
10607
|
+
getCopyEngineHost() {
|
|
10608
|
+
return {
|
|
10609
|
+
db: this,
|
|
10610
|
+
tenant: this.tenant,
|
|
10611
|
+
store: this.store,
|
|
10612
|
+
attachmentStore: this.getEffectiveAttachmentStore(),
|
|
10613
|
+
computeEntryMetadataSignature: (meta, signing) => this.computeEntryMetadataSignature(meta, signing),
|
|
10614
|
+
collectAttachmentRefs: (doc) => this.collectAttachmentRefs(doc),
|
|
10615
|
+
decryptAttachmentPayload: (payload, keyId) => this.tenant.decryptAttachmentPayload(payload, keyId),
|
|
10616
|
+
encryptAttachmentPayload: (payload, keyId) => this.tenant.encryptAttachmentPayload(payload, keyId),
|
|
10617
|
+
syncStoreChanges: () => this.syncStoreChanges(),
|
|
10618
|
+
evaluateWriteAccess: (op, signerKey, isAuthor) => this.evaluateClientWriteAccess({ op, signerKey, isAuthor }),
|
|
10619
|
+
hasWriteContentRules: async (op) => {
|
|
10620
|
+
const directory = await this.tenant.openDirectory();
|
|
10621
|
+
return (await directory.hasWriteContentRules?.(op, this.store.getId())) ?? false;
|
|
10622
|
+
},
|
|
10623
|
+
remapAttachmentPointers: (docId, lastChunkIdByAttachmentId, signing) => this.remapAttachmentPointers(docId, lastChunkIdByAttachmentId, signing),
|
|
10624
|
+
};
|
|
10625
|
+
}
|
|
10626
|
+
/** Obtain the copy seam from another database, with a clear error if absent. */
|
|
10627
|
+
resolveCopyHost(db, role) {
|
|
10628
|
+
const host = db.getCopyEngineHost?.();
|
|
10629
|
+
if (!host) {
|
|
10630
|
+
throw new Error(`The ${role} database does not support document copying (expected a BaseMindooDB instance).`);
|
|
10631
|
+
}
|
|
10632
|
+
return host;
|
|
10633
|
+
}
|
|
10634
|
+
/**
|
|
10635
|
+
* Re-point `_attachments[].lastChunkId` at a different set of chunks, as one
|
|
10636
|
+
* `doc_change`.
|
|
10637
|
+
*
|
|
10638
|
+
* Only used when a document is duplicated inside its own database: the copied
|
|
10639
|
+
* chunks had to be renamed to avoid colliding with the source's (see
|
|
10640
|
+
* `copy/attachments.ts`), so the copy's current revision has to be told where
|
|
10641
|
+
* its own chunks are. `changeDoc` deliberately offers no way to write
|
|
10642
|
+
* `_attachments` directly, hence this internal path.
|
|
10643
|
+
*/
|
|
10644
|
+
async remapAttachmentPointers(docId, lastChunkIdByAttachmentId, signing) {
|
|
10645
|
+
if (lastChunkIdByAttachmentId.size === 0) {
|
|
10646
|
+
return;
|
|
10647
|
+
}
|
|
10648
|
+
const internalDoc = this.getCachedDocument(docId) ?? (await this.loadDocumentInternal(docId));
|
|
10649
|
+
if (!internalDoc) {
|
|
10650
|
+
throw new Error(`Cannot remap attachment pointers: document ${docId} was not found.`);
|
|
10651
|
+
}
|
|
10652
|
+
const now = (0, timeSource_1.semanticNow)();
|
|
10653
|
+
let changed = false;
|
|
10654
|
+
const newDoc = this.runChangeWithOutdatedDocRecovery(internalDoc, (doc) => automerge_adapter_1.Automerge.change(doc, { time: now }, (mutableDoc) => {
|
|
10655
|
+
const attachments = mutableDoc._attachments ?? [];
|
|
10656
|
+
for (const attachment of attachments) {
|
|
10657
|
+
const nextChunkId = lastChunkIdByAttachmentId.get(attachment.attachmentId);
|
|
10658
|
+
if (nextChunkId && attachment.lastChunkId !== nextChunkId) {
|
|
10659
|
+
attachment.lastChunkId = nextChunkId;
|
|
10660
|
+
changed = true;
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
if (changed) {
|
|
10664
|
+
mutableDoc._lastModified = now;
|
|
10665
|
+
}
|
|
10666
|
+
}));
|
|
10667
|
+
if (!changed) {
|
|
10668
|
+
return;
|
|
10669
|
+
}
|
|
10670
|
+
const changeBytes = automerge_adapter_1.Automerge.getLastLocalChange(newDoc);
|
|
10671
|
+
if (!changeBytes) {
|
|
10672
|
+
throw new Error("Failed to get change bytes while remapping attachment pointers");
|
|
10673
|
+
}
|
|
10674
|
+
const entry = await this.buildDocChangeStoreEntry({
|
|
10675
|
+
internalDoc,
|
|
10676
|
+
changeBytes,
|
|
10677
|
+
now,
|
|
10678
|
+
useCustomKey: signing !== undefined,
|
|
10679
|
+
signingKeyPair: signing?.signingKeyPair,
|
|
10680
|
+
signingKeyPassword: signing?.signingKeyPassword,
|
|
10681
|
+
attachmentRefs: this.collectAttachmentRefs(newDoc),
|
|
10682
|
+
});
|
|
10683
|
+
await this.store.putEntries([entry]);
|
|
10684
|
+
this.registerAutomergeHashMapping(docId, automerge_adapter_1.Automerge.decodeChange(changeBytes).hash, entry.id);
|
|
10685
|
+
internalDoc.doc = newDoc;
|
|
10686
|
+
internalDoc.lastModified = now;
|
|
10687
|
+
internalDoc.awaitingWitness = (0, storeEntryTime_1.isProvisional)(entry) || (internalDoc.awaitingWitness ?? false);
|
|
10688
|
+
const versioned = (0, storeEntryTime_1.isVersioned)(entry) || internalDoc.awaitingWitness || (internalDoc.witnessed ?? false);
|
|
10689
|
+
internalDoc.witnessed = versioned && !internalDoc.awaitingWitness;
|
|
10690
|
+
await this.storeCachedDocument(internalDoc);
|
|
10691
|
+
this.updateIndex(docId, internalDoc.lastModified, internalDoc.isDeleted, internalDoc.decryptionKeyId, "visible", internalDoc.awaitingWitness, internalDoc.witnessed, true);
|
|
10692
|
+
this.markDocDirty(docId);
|
|
10693
|
+
}
|
|
10694
|
+
/**
|
|
10695
|
+
* Report what {@link copyDocumentTo} would do with these options — the chosen
|
|
10696
|
+
* strategy, whether the original authors' signatures would survive, whether
|
|
10697
|
+
* the copy would merge into an existing document — without writing anything.
|
|
10698
|
+
*
|
|
10699
|
+
* The returned `reasons` explain a refusal, and also explain why a permitted
|
|
10700
|
+
* copy has to re-author, so a caller can distinguish an unavoidable
|
|
10701
|
+
* re-authoring from an accidental one.
|
|
10702
|
+
*
|
|
10703
|
+
* @param docId The document to copy.
|
|
10704
|
+
* @param target The database the copy would be written to.
|
|
10705
|
+
* @param options The same options that would be passed to {@link copyDocumentTo}.
|
|
10706
|
+
*/
|
|
10707
|
+
async canCopyDocumentTo(docId, target, options) {
|
|
10708
|
+
return (0, copyDocument_1.canCopyDocument)(this.getCopyEngineHost(), this.resolveCopyHost(target, "target"), docId, options);
|
|
10709
|
+
}
|
|
10710
|
+
/**
|
|
10711
|
+
* Copy one document into another database, either flattened to a single
|
|
10712
|
+
* revision or with its full history.
|
|
10713
|
+
*
|
|
10714
|
+
* See `docs/document-copy.md` for the strategy matrix. In short: the default
|
|
10715
|
+
* writes a flattened copy under a fresh id; `mode: "history"` carries the
|
|
10716
|
+
* whole revision graph; and adding `targetDocId: "same"` with
|
|
10717
|
+
* `authorship: "preserve"` (same tenant, same key, different database) keeps
|
|
10718
|
+
* the original signers, which is what makes sharding possible.
|
|
10719
|
+
*
|
|
10720
|
+
* @param docId The document to copy.
|
|
10721
|
+
* @param target The database to copy into.
|
|
10722
|
+
* @param options See {@link CopyDocumentOptions}; every default is documented there.
|
|
10723
|
+
* @return What was copied, including the target document id — returned even on
|
|
10724
|
+
* cancellation, so a resumed run can target the same id.
|
|
10725
|
+
*/
|
|
10726
|
+
async copyDocumentTo(docId, target, options) {
|
|
10727
|
+
const targetHost = this.resolveCopyHost(target, "target");
|
|
10728
|
+
this.assertWritable("copyDocumentTo");
|
|
10729
|
+
return (0, copyDocument_1.copyDocument)(this.getCopyEngineHost(), targetHost, docId, options);
|
|
10730
|
+
}
|
|
10731
|
+
/**
|
|
10732
|
+
* Copy many documents into another database in one pass.
|
|
10733
|
+
*
|
|
10734
|
+
* With `mode: "history"`, `targetDocId: "same"` and `authorship: "preserve"`
|
|
10735
|
+
* this is the database sharding primitive: document ids, full history and the
|
|
10736
|
+
* original signers all survive the split, and nothing is decrypted or
|
|
10737
|
+
* re-signed along the way. Repeated runs are safe and transfer only the delta,
|
|
10738
|
+
* so a shard can proceed against a live database.
|
|
10739
|
+
*
|
|
10740
|
+
* Per-document failures do not abort the run; they are collected in
|
|
10741
|
+
* {@link CopyDocumentsResult.failed}.
|
|
10742
|
+
*
|
|
10743
|
+
* @param selector Which documents to copy — explicit ids, id prefixes, or both.
|
|
10744
|
+
* @param target The database to copy into.
|
|
10745
|
+
* @param options See {@link CopyDocumentsOptions}.
|
|
10746
|
+
*/
|
|
10747
|
+
async copyDocumentsTo(selector, target, options) {
|
|
10748
|
+
const targetHost = this.resolveCopyHost(target, "target");
|
|
10749
|
+
this.assertWritable("copyDocumentsTo");
|
|
10750
|
+
return (0, copyDocuments_1.copyDocuments)(this.getCopyEngineHost(), targetHost, selector, options);
|
|
10751
|
+
}
|
|
10548
10752
|
/**
|
|
10549
10753
|
* Pull changes from a remote content-addressed store or another MindooDB instance.
|
|
10550
10754
|
*
|