@peerbit/document 15.0.15 → 15.0.16
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 +25 -0
- package/dist/src/program.d.ts +6 -0
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +292 -133
- package/dist/src/program.js.map +1 -1
- package/package.json +15 -15
- package/src/program.ts +659 -347
package/dist/src/program.js
CHANGED
|
@@ -35,16 +35,16 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
35
35
|
import { BorshError, deserialize, field, serialize, variant, } from "@dao-xyz/borsh";
|
|
36
36
|
import { AccessError } from "@peerbit/crypto";
|
|
37
37
|
import { Context, NotFoundError, } from "@peerbit/document-interface";
|
|
38
|
-
import { extractDocumentFieldSimple, initializeDocumentRust, planDocumentContext, planDocumentContextBatch, tryPlanDocumentContext, tryPlanDocumentContextBatch, } from "./native-rust.js";
|
|
39
38
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
40
39
|
import { Entry, EntryType, LamportClock, ShallowEntry, ShallowMeta, Timestamp, entryV0PlainPayloadDataFromStorage, } from "@peerbit/log";
|
|
41
40
|
import { logger as loggerFn } from "@peerbit/logger";
|
|
42
41
|
import { Program } from "@peerbit/program";
|
|
43
|
-
import { SharedLog, } from "@peerbit/shared-log";
|
|
42
|
+
import { PersistedDeliveryError, SharedLog, } from "@peerbit/shared-log";
|
|
44
43
|
import { detachCanPerformCallbackProperties, detachEntryForCallback, detachEntryPayloadForCallback, } from "./callback-detachment.js";
|
|
45
44
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
45
|
+
import { extractDocumentFieldSimple, initializeDocumentRust, planDocumentContext, planDocumentContextBatch, tryPlanDocumentContext, tryPlanDocumentContextBatch, } from "./native-rust.js";
|
|
46
46
|
import { BORSH_ENCODING_OPERATION, DeleteOperation, PutOperation, PutWithKeyOperation, coerceDeleteOperation, isDeleteOperation, isPutOperation, } from "./operation.js";
|
|
47
|
-
import {
|
|
47
|
+
import { canPerformPolicyDeleteFieldPaths, canPerformPolicyNeedsDeleteValue, canPerformPolicyNeedsPreviousEntries, canPerformPolicyPutNeedsEntryPublicKeys, canPerformPolicySignedByFieldPaths, createCanPerformDeletePolicyEvaluator, createCanPerformPolicyEvaluator, getCanPerformPolicyDescriptor, } from "./policy.js";
|
|
48
48
|
import { isResultIndexedValue } from "./result-shape.js";
|
|
49
49
|
import { DocumentIndex, INDEX_CONTEXT_SHAPE, coerceWithContext, coerceWithIndexed, coerceWithLazyIndexed, encodeContextSuffix as encodeDocumentContextSuffix, } from "./search.js";
|
|
50
50
|
import { getDocumentTransformDescriptor, } from "./transform.js";
|
|
@@ -111,6 +111,54 @@ const encodePutOperationPayload = (data) => {
|
|
|
111
111
|
return encoded;
|
|
112
112
|
};
|
|
113
113
|
const toContextBigInt = (value) => typeof value === "bigint" ? value : BigInt(value);
|
|
114
|
+
const hasPersistedDelivery = (options) => typeof options?.delivery === "object" &&
|
|
115
|
+
options.delivery.reliability === "persisted";
|
|
116
|
+
const withoutPersistedDelivery = (options) => {
|
|
117
|
+
if (!hasPersistedDelivery(options)) {
|
|
118
|
+
return options;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
...options,
|
|
122
|
+
target: "none",
|
|
123
|
+
delivery: false,
|
|
124
|
+
replicate: false,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
const runAfterDocumentCommit = (options, committedHashes, fn) => {
|
|
128
|
+
if (!hasPersistedDelivery(options))
|
|
129
|
+
return fn();
|
|
130
|
+
const resolvedHashes = typeof committedHashes === "function" ? committedHashes() : committedHashes;
|
|
131
|
+
const hashes = typeof resolvedHashes === "string" ? [resolvedHashes] : resolvedHashes;
|
|
132
|
+
try {
|
|
133
|
+
const result = fn();
|
|
134
|
+
if (isPromiseLike(result)) {
|
|
135
|
+
return result.catch((error) => {
|
|
136
|
+
throw new PersistedDeliveryError(error, hashes);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
throw new PersistedDeliveryError(error, hashes);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const runWithTrustedLocalCommitEvidence = (options, evidence, fn) => {
|
|
146
|
+
if (!evidence || !hasPersistedDelivery(options))
|
|
147
|
+
return fn();
|
|
148
|
+
const classify = (error) => {
|
|
149
|
+
if (evidence.committedHashes.size > 0) {
|
|
150
|
+
throw new PersistedDeliveryError(error, evidence.committedHashes);
|
|
151
|
+
}
|
|
152
|
+
throw error;
|
|
153
|
+
};
|
|
154
|
+
try {
|
|
155
|
+
const result = fn();
|
|
156
|
+
return isPromiseLike(result) ? result.catch(classify) : result;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
return classify(error);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
114
162
|
const NATIVE_LOCAL_PUT_OPTIONS = Object.freeze({
|
|
115
163
|
replicate: false,
|
|
116
164
|
target: "none",
|
|
@@ -136,6 +184,7 @@ const cachedNativeLocalPutOptions = (options) => {
|
|
|
136
184
|
}
|
|
137
185
|
return options.unique === true ? NATIVE_LOCAL_UNIQUE_PUT_OPTIONS : undefined;
|
|
138
186
|
};
|
|
187
|
+
const persistedDeliveryAlreadySettled = new WeakSet();
|
|
139
188
|
class CompatDocumentBackend {
|
|
140
189
|
putImpl;
|
|
141
190
|
putManyImpl;
|
|
@@ -186,15 +235,7 @@ class NativeDocumentBackend {
|
|
|
186
235
|
useNativeExistingDocumentContext,
|
|
187
236
|
requiredPreviousSignerPublicKey,
|
|
188
237
|
existing,
|
|
189
|
-
}), (documentAppendCommit) =>
|
|
190
|
-
this.context.keepEntry(documentAppendCommit.append.hash);
|
|
191
|
-
return {
|
|
192
|
-
get entry() {
|
|
193
|
-
return documentAppendCommit.entry;
|
|
194
|
-
},
|
|
195
|
-
removed: documentAppendCommit.removed,
|
|
196
|
-
};
|
|
197
|
-
}));
|
|
238
|
+
}), (documentAppendCommit) => this.context.finishPreparedPlainPutCommit(documentAppendCommit, options));
|
|
198
239
|
};
|
|
199
240
|
const assertPolicyAndCommit = (existingContext, previousSignerPublicKey) => {
|
|
200
241
|
const existingHead = this.context.getIndexedContextHead(existingContext);
|
|
@@ -239,6 +280,9 @@ class NativeDocumentBackend {
|
|
|
239
280
|
}
|
|
240
281
|
const prepared = docs.map((doc) => this.context.preparePlainPut(doc));
|
|
241
282
|
if (this.context.hasDuplicatePreparedPutKeys(prepared)) {
|
|
283
|
+
if (hasPersistedDelivery(options)) {
|
|
284
|
+
throw this.context.nativeModeError("requires distinct document keys for persisted putMany");
|
|
285
|
+
}
|
|
242
286
|
const results = [];
|
|
243
287
|
for (const doc of docs) {
|
|
244
288
|
results.push(await this.put(doc, putOptions));
|
|
@@ -318,17 +362,7 @@ class NativeDocumentBackend {
|
|
|
318
362
|
if (!documentAppendCommit) {
|
|
319
363
|
throw this.context.nativeModeError("requires native batched payload append support");
|
|
320
364
|
}
|
|
321
|
-
return
|
|
322
|
-
for (const commit of documentAppendCommit.commits) {
|
|
323
|
-
this.context.keepEntry(commit.append.hash);
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
get entries() {
|
|
327
|
-
return documentAppendCommit.entries;
|
|
328
|
-
},
|
|
329
|
-
removed: documentAppendCommit.removed,
|
|
330
|
-
};
|
|
331
|
-
});
|
|
365
|
+
return this.context.finishPreparedPlainPutManyCommit(documentAppendCommit, options);
|
|
332
366
|
});
|
|
333
367
|
}
|
|
334
368
|
del(id, options) {
|
|
@@ -337,6 +371,10 @@ class NativeDocumentBackend {
|
|
|
337
371
|
}
|
|
338
372
|
}
|
|
339
373
|
const nativeDocumentContextFactsAsContext = (facts) => facts;
|
|
374
|
+
// Keep the public putMany result shape unchanged while carrying the native
|
|
375
|
+
// commit/coordinate facts to the internal persisted-delivery seam. The result
|
|
376
|
+
// remains the lifetime owner of the lazy full-entry materializer.
|
|
377
|
+
const persistedDocumentAppendDelivery = new WeakMap();
|
|
340
378
|
const asTrustedDocumentSharedLog = (log) => log;
|
|
341
379
|
const documentIndexStoreKey = (id) => {
|
|
342
380
|
const key = indexerTypes.toIdeable(id);
|
|
@@ -531,12 +569,9 @@ let Documents = (() => {
|
|
|
531
569
|
},
|
|
532
570
|
commitNativeDocumentAppend: (input) => this.commitNativeDocumentAppend(input),
|
|
533
571
|
commitNativeDocumentAppendMany: (input) => this.commitNativeDocumentAppendMany(input),
|
|
534
|
-
|
|
535
|
-
|
|
572
|
+
finishPreparedPlainPutCommit: (commit, options) => this.finishPreparedPlainPutCommit(commit, options),
|
|
573
|
+
finishPreparedPlainPutManyCommit: (commit, options) => this.finishPreparedPlainPutManyCommit(commit, options),
|
|
536
574
|
deleteDocument: (id, options) => this.delNativeDocumentBackend(id, options),
|
|
537
|
-
keepEntry: (hash) => {
|
|
538
|
-
this.keepCache?.add(hash);
|
|
539
|
-
},
|
|
540
575
|
nativeModeError: (message) => this.nativeModeError(message),
|
|
541
576
|
};
|
|
542
577
|
}
|
|
@@ -727,10 +762,14 @@ let Documents = (() => {
|
|
|
727
762
|
if (options?.replicate === true) {
|
|
728
763
|
unsupported.push("replicated put");
|
|
729
764
|
}
|
|
730
|
-
if (options?.target &&
|
|
765
|
+
if (options?.target &&
|
|
766
|
+
options.target !== "none" &&
|
|
767
|
+
!(hasPersistedDelivery(options) && options.target === "replicators")) {
|
|
731
768
|
unsupported.push("non-local target");
|
|
732
769
|
}
|
|
733
|
-
if (options?.delivery !== undefined &&
|
|
770
|
+
if (options?.delivery !== undefined &&
|
|
771
|
+
options.delivery !== false &&
|
|
772
|
+
!hasPersistedDelivery(options)) {
|
|
734
773
|
unsupported.push("delivery");
|
|
735
774
|
}
|
|
736
775
|
if (options?.checkRemote) {
|
|
@@ -805,7 +844,8 @@ let Documents = (() => {
|
|
|
805
844
|
return this.nativeFieldValueMatchesPublicKey(value, localPublicKey);
|
|
806
845
|
}
|
|
807
846
|
nativeFieldValueMatchesPublicKey(value, publicKey) {
|
|
808
|
-
const localRawPublicKey = publicKey
|
|
847
|
+
const localRawPublicKey = publicKey
|
|
848
|
+
.publicKey;
|
|
809
849
|
return (value instanceof Uint8Array &&
|
|
810
850
|
(bytesEqual(value, publicKey.bytes) ||
|
|
811
851
|
(localRawPublicKey ? bytesEqual(value, localRawPublicKey) : false)));
|
|
@@ -961,6 +1001,9 @@ let Documents = (() => {
|
|
|
961
1001
|
return;
|
|
962
1002
|
}
|
|
963
1003
|
const unsupported = this.unsupportedNativePutOptions(options);
|
|
1004
|
+
if (options && hasPersistedDelivery(options)) {
|
|
1005
|
+
unsupported.push("delivery");
|
|
1006
|
+
}
|
|
964
1007
|
if (options?.unique !== undefined) {
|
|
965
1008
|
unsupported.push("unique delete");
|
|
966
1009
|
}
|
|
@@ -1004,6 +1047,9 @@ let Documents = (() => {
|
|
|
1004
1047
|
if (!this.isNativeMode()) {
|
|
1005
1048
|
return options;
|
|
1006
1049
|
}
|
|
1050
|
+
if (hasPersistedDelivery(options)) {
|
|
1051
|
+
return options;
|
|
1052
|
+
}
|
|
1007
1053
|
if (options?.replicate === false && options.target === "none") {
|
|
1008
1054
|
return options;
|
|
1009
1055
|
}
|
|
@@ -1332,8 +1378,7 @@ let Documents = (() => {
|
|
|
1332
1378
|
this._documentInternalChangeListenerCount = Math.max(0, this._documentChangeListenerCount - changeListenersBeforeIndexOpen);
|
|
1333
1379
|
this._nativeDocumentFieldExtractionPlans ??= new Map();
|
|
1334
1380
|
this._nativeDocumentFieldExtractionPlans.clear();
|
|
1335
|
-
this._nativeDocumentIdExtractionPlan =
|
|
1336
|
-
asTrustedDocumentIndex(this._index).getNativeDocumentFieldExtractionPlan(idProperty);
|
|
1381
|
+
this._nativeDocumentIdExtractionPlan = asTrustedDocumentIndex(this._index).getNativeDocumentFieldExtractionPlan(idProperty);
|
|
1337
1382
|
// B12: the historical document->log compatibility mapping (6 -> log v8,
|
|
1338
1383
|
// 7 -> log v9) is retired; the rejection at the top of open() fires for
|
|
1339
1384
|
// any defined value before this point.
|
|
@@ -1658,7 +1703,8 @@ let Documents = (() => {
|
|
|
1658
1703
|
: reference.document);
|
|
1659
1704
|
}
|
|
1660
1705
|
else {
|
|
1661
|
-
keyValue =
|
|
1706
|
+
keyValue =
|
|
1707
|
+
await this.getNativeDocumentIdFromPutOperation(putOperation);
|
|
1662
1708
|
if (keyValue == null) {
|
|
1663
1709
|
if (this.isNativeMode()) {
|
|
1664
1710
|
return false;
|
|
@@ -1949,7 +1995,28 @@ let Documents = (() => {
|
|
|
1949
1995
|
};
|
|
1950
1996
|
}
|
|
1951
1997
|
async put(doc, options) {
|
|
1952
|
-
|
|
1998
|
+
if (hasPersistedDelivery(options)) {
|
|
1999
|
+
asTrustedDocumentSharedLog(this.log).assertPersistedDeliveryOptions(options);
|
|
2000
|
+
}
|
|
2001
|
+
const result = await this._documentBackend.put(doc, options);
|
|
2002
|
+
if (!hasPersistedDelivery(options) ||
|
|
2003
|
+
persistedDeliveryAlreadySettled.has(result)) {
|
|
2004
|
+
return result;
|
|
2005
|
+
}
|
|
2006
|
+
const entry = result.entry;
|
|
2007
|
+
await this.deliverPersistedDocumentEntries([entry], options);
|
|
2008
|
+
return {
|
|
2009
|
+
get entry() {
|
|
2010
|
+
return entry;
|
|
2011
|
+
},
|
|
2012
|
+
removed: result.removed,
|
|
2013
|
+
};
|
|
2014
|
+
}
|
|
2015
|
+
deliverPersistedDocumentEntries(entries, options) {
|
|
2016
|
+
return asTrustedDocumentSharedLog(this.log).deliverPersistedEntries(entries, options);
|
|
2017
|
+
}
|
|
2018
|
+
deliverPersistedDocumentAppendCommits(delivery, options) {
|
|
2019
|
+
return asTrustedDocumentSharedLog(this.log).deliverPersistedAppendCommits(delivery.appendCommits, delivery.materializeEntries, options);
|
|
1953
2020
|
}
|
|
1954
2021
|
async putCompatDocumentBackend(doc, options) {
|
|
1955
2022
|
const putOptions = this.normalizeNativeModePutOptions(options);
|
|
@@ -1979,6 +2046,7 @@ let Documents = (() => {
|
|
|
1979
2046
|
const operation = "operation" in prepared
|
|
1980
2047
|
? prepared.operation
|
|
1981
2048
|
: new PutOperation({ data: prepared.encodedDocument });
|
|
2049
|
+
const persistedDelivery = hasPersistedDelivery(putOptions);
|
|
1982
2050
|
const appended = await this.log.append(operation, {
|
|
1983
2051
|
...putOptions,
|
|
1984
2052
|
meta: {
|
|
@@ -1991,32 +2059,73 @@ let Documents = (() => {
|
|
|
1991
2059
|
operation,
|
|
1992
2060
|
});
|
|
1993
2061
|
},
|
|
1994
|
-
onChange:
|
|
1995
|
-
|
|
2062
|
+
onChange: persistedDelivery
|
|
2063
|
+
? (change) => runAfterDocumentCommit(putOptions, () => change.added.map(({ entry }) => entry.hash), () => mapMaybePromise(this.handleChanges(change, {
|
|
1996
2064
|
document: prepared.document,
|
|
1997
2065
|
operation,
|
|
1998
2066
|
key: prepared.key,
|
|
1999
2067
|
unique: putOptions?.unique,
|
|
2000
2068
|
existing: existingLocalContext,
|
|
2001
|
-
})
|
|
2002
|
-
|
|
2069
|
+
}), () => {
|
|
2070
|
+
this.keepCache?.add(change.added[0].entry.hash);
|
|
2071
|
+
}))
|
|
2072
|
+
: (change) => this.handleChanges(change, {
|
|
2073
|
+
document: prepared.document,
|
|
2074
|
+
operation,
|
|
2075
|
+
key: prepared.key,
|
|
2076
|
+
unique: putOptions?.unique,
|
|
2077
|
+
existing: existingLocalContext,
|
|
2078
|
+
}),
|
|
2003
2079
|
replicate: putOptions?.replicate,
|
|
2004
2080
|
});
|
|
2005
2081
|
this.keepCache?.add(appended.entry.hash);
|
|
2082
|
+
if (persistedDelivery) {
|
|
2083
|
+
persistedDeliveryAlreadySettled.add(appended);
|
|
2084
|
+
}
|
|
2006
2085
|
return appended;
|
|
2007
2086
|
}
|
|
2008
2087
|
async putMany(docs, options) {
|
|
2009
|
-
|
|
2088
|
+
if (hasPersistedDelivery(options)) {
|
|
2089
|
+
asTrustedDocumentSharedLog(this.log).assertPersistedDeliveryOptions(options);
|
|
2090
|
+
}
|
|
2091
|
+
const result = await this._documentBackend.putMany(docs, options);
|
|
2092
|
+
if (!hasPersistedDelivery(options)) {
|
|
2093
|
+
return result;
|
|
2094
|
+
}
|
|
2095
|
+
const appendDelivery = persistedDocumentAppendDelivery.get(result);
|
|
2096
|
+
if (appendDelivery) {
|
|
2097
|
+
persistedDocumentAppendDelivery.delete(result);
|
|
2098
|
+
await this.deliverPersistedDocumentAppendCommits(appendDelivery, options);
|
|
2099
|
+
let entries;
|
|
2100
|
+
return {
|
|
2101
|
+
get entries() {
|
|
2102
|
+
return (entries ??= result.entries);
|
|
2103
|
+
},
|
|
2104
|
+
removed: result.removed,
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
const entries = result.entries;
|
|
2108
|
+
if (entries.length === 0) {
|
|
2109
|
+
return result;
|
|
2110
|
+
}
|
|
2111
|
+
await this.deliverPersistedDocumentEntries(entries, options);
|
|
2112
|
+
return { entries, removed: result.removed };
|
|
2010
2113
|
}
|
|
2011
2114
|
async putManyCompatDocumentBackend(docs, options) {
|
|
2012
2115
|
if (docs.length === 0) {
|
|
2013
2116
|
return { entries: [], removed: [] };
|
|
2014
2117
|
}
|
|
2015
2118
|
if (!this.canUsePlainPutManyFastPath(docs, options)) {
|
|
2119
|
+
if (hasPersistedDelivery(options)) {
|
|
2120
|
+
throw new Error("persisted putMany requires the independent batched document path");
|
|
2121
|
+
}
|
|
2016
2122
|
return this.putManySequential(docs, options);
|
|
2017
2123
|
}
|
|
2018
2124
|
const prepared = docs.map((doc) => this.preparePlainPut(doc));
|
|
2019
2125
|
if (this.hasDuplicatePreparedPutKeys(prepared)) {
|
|
2126
|
+
if (hasPersistedDelivery(options)) {
|
|
2127
|
+
throw new Error("persisted putMany requires distinct document keys");
|
|
2128
|
+
}
|
|
2020
2129
|
return this.putManySequential(docs, options);
|
|
2021
2130
|
}
|
|
2022
2131
|
const documentAppendCommit = await this.commitNativeDocumentAppendMany({
|
|
@@ -2032,18 +2141,12 @@ let Documents = (() => {
|
|
|
2032
2141
|
options,
|
|
2033
2142
|
});
|
|
2034
2143
|
if (!documentAppendCommit) {
|
|
2144
|
+
if (hasPersistedDelivery(options)) {
|
|
2145
|
+
throw new Error("persisted putMany requires native batched payload append support");
|
|
2146
|
+
}
|
|
2035
2147
|
return this.putManySequential(docs, options);
|
|
2036
2148
|
}
|
|
2037
|
-
await this.
|
|
2038
|
-
for (const commit of documentAppendCommit.commits) {
|
|
2039
|
-
this.keepCache?.add(commit.append.hash);
|
|
2040
|
-
}
|
|
2041
|
-
return {
|
|
2042
|
-
get entries() {
|
|
2043
|
-
return documentAppendCommit.entries;
|
|
2044
|
-
},
|
|
2045
|
-
removed: documentAppendCommit.removed,
|
|
2046
|
-
};
|
|
2149
|
+
return await this.finishPreparedPlainPutManyCommit(documentAppendCommit, options);
|
|
2047
2150
|
}
|
|
2048
2151
|
async putManySequential(docs, options) {
|
|
2049
2152
|
const entries = [];
|
|
@@ -2066,6 +2169,7 @@ let Documents = (() => {
|
|
|
2066
2169
|
return false;
|
|
2067
2170
|
}
|
|
2068
2171
|
canUsePlainPutFastPath(doc, options) {
|
|
2172
|
+
const persistedDelivery = hasPersistedDelivery(options);
|
|
2069
2173
|
return (this._mode !== "compat" &&
|
|
2070
2174
|
this.canPerformAllowsPlainPutFastPath(doc) &&
|
|
2071
2175
|
!this.immutable &&
|
|
@@ -2085,16 +2189,26 @@ let Documents = (() => {
|
|
|
2085
2189
|
!options?.meta?.timestamp &&
|
|
2086
2190
|
!options?.meta?.gidSeed &&
|
|
2087
2191
|
options?.replicate !== true &&
|
|
2088
|
-
(!options?.target ||
|
|
2089
|
-
|
|
2192
|
+
(!options?.target ||
|
|
2193
|
+
options.target === "none" ||
|
|
2194
|
+
(persistedDelivery && options.target === "replicators")) &&
|
|
2195
|
+
(options?.delivery === undefined ||
|
|
2196
|
+
options.delivery === false ||
|
|
2197
|
+
persistedDelivery) &&
|
|
2090
2198
|
!options?.checkRemote &&
|
|
2091
2199
|
options?.replicas === undefined);
|
|
2092
2200
|
}
|
|
2093
2201
|
canUsePlainPutManyFastPath(docs, options) {
|
|
2202
|
+
const persistedDelivery = hasPersistedDelivery(options);
|
|
2094
2203
|
return (options?.unique === true &&
|
|
2095
2204
|
options?.replicate !== true &&
|
|
2096
|
-
options?.target === "none"
|
|
2097
|
-
|
|
2205
|
+
(options?.target === "none" ||
|
|
2206
|
+
(persistedDelivery &&
|
|
2207
|
+
(options.target === undefined ||
|
|
2208
|
+
options.target === "replicators"))) &&
|
|
2209
|
+
(options?.delivery === undefined ||
|
|
2210
|
+
options.delivery === false ||
|
|
2211
|
+
persistedDelivery) &&
|
|
2098
2212
|
docs.every((doc) => this.canUsePlainPutFastPath(doc, options)));
|
|
2099
2213
|
}
|
|
2100
2214
|
async createPlainPutCommitPlan(prepared, existingHead, existingLocalContext, options, assumePlainPutFastPath = false) {
|
|
@@ -2143,41 +2257,43 @@ let Documents = (() => {
|
|
|
2143
2257
|
options,
|
|
2144
2258
|
unique: plan.unique,
|
|
2145
2259
|
existing: plan.existing,
|
|
2146
|
-
}), (documentAppendCommit) =>
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
document: plan.document,
|
|
2153
|
-
operation: documentAppendCommit.operation ??
|
|
2154
|
-
plan.operation ??
|
|
2155
|
-
new PutOperation({ data: plan.encodedDocument }),
|
|
2156
|
-
key: plan.key,
|
|
2157
|
-
unique: plan.unique,
|
|
2158
|
-
existing: plan.existing,
|
|
2159
|
-
})
|
|
2160
|
-
: this.handlePreparedPlainPutCommit(documentAppendCommit);
|
|
2161
|
-
return mapMaybePromise(handled, () => {
|
|
2162
|
-
this.keepCache?.add(documentAppendCommit.append.hash);
|
|
2163
|
-
return {
|
|
2164
|
-
get entry() {
|
|
2165
|
-
return documentAppendCommit.entry;
|
|
2260
|
+
}), (documentAppendCommit) => this.finishPreparedPlainPutCommit(documentAppendCommit, options, () => plan.useGenericChangeHandler
|
|
2261
|
+
? this.handleChanges({
|
|
2262
|
+
added: [
|
|
2263
|
+
{
|
|
2264
|
+
head: true,
|
|
2265
|
+
entry: documentAppendCommit.entry,
|
|
2166
2266
|
},
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2267
|
+
],
|
|
2268
|
+
removed: documentAppendCommit.removed,
|
|
2269
|
+
}, {
|
|
2270
|
+
document: plan.document,
|
|
2271
|
+
operation: documentAppendCommit.operation ??
|
|
2272
|
+
plan.operation ??
|
|
2273
|
+
new PutOperation({ data: plan.encodedDocument }),
|
|
2274
|
+
key: plan.key,
|
|
2275
|
+
unique: plan.unique,
|
|
2276
|
+
existing: plan.existing,
|
|
2277
|
+
})
|
|
2278
|
+
: this.handlePreparedPlainPutCommit(documentAppendCommit)));
|
|
2171
2279
|
}
|
|
2172
2280
|
commitNativeDocumentAppend(input) {
|
|
2281
|
+
if (!hasPersistedDelivery(input.options)) {
|
|
2282
|
+
return this.commitNativeDocumentAppendWithEvidence(input, undefined);
|
|
2283
|
+
}
|
|
2284
|
+
const localCommitEvidence = { committedHashes: new Set() };
|
|
2285
|
+
return runWithTrustedLocalCommitEvidence(input.options, localCommitEvidence, () => this.commitNativeDocumentAppendWithEvidence(input, localCommitEvidence));
|
|
2286
|
+
}
|
|
2287
|
+
commitNativeDocumentAppendWithEvidence(input, localCommitEvidence) {
|
|
2173
2288
|
const trustedLog = asTrustedDocumentSharedLog(this.log);
|
|
2289
|
+
const localAppendOptions = withoutPersistedDelivery(input.options);
|
|
2174
2290
|
const appendOptions = {
|
|
2175
|
-
...
|
|
2291
|
+
...localAppendOptions,
|
|
2176
2292
|
meta: {
|
|
2177
2293
|
next: input.next,
|
|
2178
|
-
...
|
|
2294
|
+
...localAppendOptions?.meta,
|
|
2179
2295
|
},
|
|
2180
|
-
replicate:
|
|
2296
|
+
replicate: localAppendOptions?.replicate,
|
|
2181
2297
|
};
|
|
2182
2298
|
const prepareNativeDocumentIndexWithAppendFacts = this.createNativeBackboneDocumentIndexAppendFactsPreparer(input);
|
|
2183
2299
|
const preferAppendFactsDocumentIndex = this.isNativeMode() && !!prepareNativeDocumentIndexWithAppendFacts;
|
|
@@ -2198,6 +2314,7 @@ let Documents = (() => {
|
|
|
2198
2314
|
resolveTrimmedEntries: input.resolveTrimmedEntries,
|
|
2199
2315
|
payloadData: input.operationPayloadBytes,
|
|
2200
2316
|
useNativeExistingDocumentContext: input.useNativeExistingDocumentContext,
|
|
2317
|
+
...(localCommitEvidence ? { localCommitEvidence } : undefined),
|
|
2201
2318
|
...(nativeDocumentIndexCommit
|
|
2202
2319
|
? {
|
|
2203
2320
|
nativeBackboneDocumentIndex: this.toNativeBackboneDocumentIndexCommitInput(input, nativeDocumentIndexCommit),
|
|
@@ -2219,14 +2336,14 @@ let Documents = (() => {
|
|
|
2219
2336
|
if (this.isNativeMode()) {
|
|
2220
2337
|
throw this.nativeModeError("requires payload-backed put operations");
|
|
2221
2338
|
}
|
|
2222
|
-
return mapMaybePromise(trustedLog.appendLocallyPrepared(input.operation, appendOptions, appendProperties), (appended) => this.createNativeCheckedDocumentAppendCommitFacts(input, appended, committedNativeDocumentIndex));
|
|
2339
|
+
return mapMaybePromise(trustedLog.appendLocallyPrepared(input.operation, appendOptions, appendProperties), (appended) => runAfterDocumentCommit(input.options, appended.appendCommit.hash, () => this.createNativeCheckedDocumentAppendCommitFacts(input, appended, committedNativeDocumentIndex)));
|
|
2223
2340
|
}
|
|
2224
2341
|
const commitOnlyAppend = this.isNativeMode()
|
|
2225
2342
|
? trustedLog.appendStrictNativeDocumentPayloadCommitOnly(input.operationPayloadBytes, appendOptions, appendProperties)
|
|
2226
2343
|
: trustedLog.appendLocallyPreparedPayloadCommitOnly(input.operationPayloadBytes, appendOptions, appendProperties);
|
|
2227
2344
|
return mapMaybePromise(commitOnlyAppend, (commitOnly) => {
|
|
2228
2345
|
if (commitOnly) {
|
|
2229
|
-
return this.createNativeCheckedDocumentAppendCommitFacts(input, commitOnly, committedNativeDocumentIndex);
|
|
2346
|
+
return runAfterDocumentCommit(input.options, commitOnly.appendCommit.hash, () => this.createNativeCheckedDocumentAppendCommitFacts(input, commitOnly, committedNativeDocumentIndex));
|
|
2230
2347
|
}
|
|
2231
2348
|
if (this.isNativeMode()) {
|
|
2232
2349
|
throw this.nativeModeError("requires native payload commit-only append");
|
|
@@ -2304,16 +2421,24 @@ let Documents = (() => {
|
|
|
2304
2421
|
appended = await trustedLog.appendLocallyPreparedPayload(input.operationPayloadBytes, appendOptions, appendProperties);
|
|
2305
2422
|
}
|
|
2306
2423
|
catch (error) {
|
|
2307
|
-
if (
|
|
2424
|
+
if (appendProperties.localCommitEvidence?.committedHashes.size ||
|
|
2425
|
+
!(error instanceof Error) ||
|
|
2308
2426
|
error.message !==
|
|
2309
2427
|
"appendLocallyPrepared payload-only path requires native append support") {
|
|
2310
2428
|
throw error;
|
|
2311
2429
|
}
|
|
2312
2430
|
appended = await trustedLog.appendLocallyPrepared(new PutOperation({ data: input.documentBytes }), appendOptions, appendProperties);
|
|
2313
2431
|
}
|
|
2314
|
-
return this.createDocumentAppendCommitFacts(input, appended, nativeBackboneDocumentIndex);
|
|
2432
|
+
return await runAfterDocumentCommit(input.options, appended.appendCommit.hash, () => this.createDocumentAppendCommitFacts(input, appended, nativeBackboneDocumentIndex));
|
|
2315
2433
|
}
|
|
2316
2434
|
async commitNativeDocumentAppendMany(input) {
|
|
2435
|
+
if (!hasPersistedDelivery(input.options)) {
|
|
2436
|
+
return this.commitNativeDocumentAppendManyWithEvidence(input, undefined);
|
|
2437
|
+
}
|
|
2438
|
+
const localCommitEvidence = { committedHashes: new Set() };
|
|
2439
|
+
return await runWithTrustedLocalCommitEvidence(input.options, localCommitEvidence, () => this.commitNativeDocumentAppendManyWithEvidence(input, localCommitEvidence));
|
|
2440
|
+
}
|
|
2441
|
+
async commitNativeDocumentAppendManyWithEvidence(input, localCommitEvidence) {
|
|
2317
2442
|
const trustedLog = asTrustedDocumentSharedLog(this.log);
|
|
2318
2443
|
const nativeBackboneDocumentIndexes = await this.prepareNativeBackboneDocumentIndexCommitBatch(input.puts);
|
|
2319
2444
|
const nativeBackboneDocumentIndexInputs = nativeBackboneDocumentIndexes?.map((commit, index) => this.toNativeBackboneDocumentIndexCommitInput(input.puts[index], commit, input.useNativeExistingDocumentContext === true));
|
|
@@ -2332,14 +2457,12 @@ let Documents = (() => {
|
|
|
2332
2457
|
}
|
|
2333
2458
|
return [next];
|
|
2334
2459
|
});
|
|
2335
|
-
const appended = await trustedLog.appendLocallyPreparedPayloadsManyIndependent(input.puts.map((put) => put.operationPayloadBytes), {
|
|
2336
|
-
...input.options,
|
|
2337
|
-
replicate: input.options?.replicate,
|
|
2338
|
-
}, {
|
|
2460
|
+
const appended = await trustedLog.appendLocallyPreparedPayloadsManyIndependent(input.puts.map((put) => put.operationPayloadBytes), withoutPersistedDelivery(input.options), {
|
|
2339
2461
|
resolveTrimmedEntries: input.resolveTrimmedEntries,
|
|
2340
2462
|
nexts,
|
|
2341
2463
|
nativeBackboneDocumentIndexes: nativeBackboneDocumentIndexInputs,
|
|
2342
2464
|
retainMaterializationBytes: this._hasLogTrim,
|
|
2465
|
+
...(localCommitEvidence ? { localCommitEvidence } : undefined),
|
|
2343
2466
|
});
|
|
2344
2467
|
if (!appended) {
|
|
2345
2468
|
if (this.isNativeMode()) {
|
|
@@ -2347,36 +2470,38 @@ let Documents = (() => {
|
|
|
2347
2470
|
}
|
|
2348
2471
|
return undefined;
|
|
2349
2472
|
}
|
|
2350
|
-
|
|
2351
|
-
input
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2473
|
+
return await runAfterDocumentCommit(input.options, () => appended.appendCommits.map((commit) => commit.hash), async () => {
|
|
2474
|
+
const appendInputs = input.puts.map((put, index) => ({
|
|
2475
|
+
input: nativeBackboneDocumentIndexes?.[index]
|
|
2476
|
+
? {
|
|
2477
|
+
...put,
|
|
2478
|
+
nativeBackboneDocumentIndex: nativeBackboneDocumentIndexes[index],
|
|
2479
|
+
}
|
|
2480
|
+
: put,
|
|
2481
|
+
appended: (() => {
|
|
2482
|
+
const materializeEntry = appended.materializeEntries?.[index];
|
|
2483
|
+
let entry;
|
|
2484
|
+
return {
|
|
2485
|
+
get entry() {
|
|
2486
|
+
return (entry ??= materializeEntry
|
|
2487
|
+
? materializeEntry()
|
|
2488
|
+
: appended.entries[index]);
|
|
2489
|
+
},
|
|
2490
|
+
removed: [],
|
|
2491
|
+
appendCommit: appended.appendCommits[index],
|
|
2492
|
+
};
|
|
2493
|
+
})(),
|
|
2494
|
+
}));
|
|
2495
|
+
const commits = await this.createDocumentAppendCommitFactsBatch(appendInputs);
|
|
2496
|
+
let entries;
|
|
2497
|
+
return {
|
|
2498
|
+
get entries() {
|
|
2499
|
+
return (entries ??= commits.map((commit) => commit.entry));
|
|
2500
|
+
},
|
|
2501
|
+
removed: appended.removed,
|
|
2502
|
+
commits,
|
|
2503
|
+
};
|
|
2504
|
+
});
|
|
2380
2505
|
}
|
|
2381
2506
|
prepareNativeBackboneDocumentIndexCommitBatch(inputs) {
|
|
2382
2507
|
if (!this._nativeBackboneDocumentIndexEnabled || inputs.length === 0) {
|
|
@@ -2667,6 +2792,40 @@ let Documents = (() => {
|
|
|
2667
2792
|
}),
|
|
2668
2793
|
});
|
|
2669
2794
|
}
|
|
2795
|
+
finishPreparedPlainPutCommit(commit, options, handle = () => this.handlePreparedPlainPutCommit(commit)) {
|
|
2796
|
+
return runAfterDocumentCommit(options, commit.append.hash, () => mapMaybePromise(handle(), () => {
|
|
2797
|
+
this.keepCache?.add(commit.append.hash);
|
|
2798
|
+
const persistedEntry = hasPersistedDelivery(options)
|
|
2799
|
+
? commit.entry
|
|
2800
|
+
: undefined;
|
|
2801
|
+
return {
|
|
2802
|
+
get entry() {
|
|
2803
|
+
return persistedEntry ?? commit.entry;
|
|
2804
|
+
},
|
|
2805
|
+
removed: commit.removed,
|
|
2806
|
+
};
|
|
2807
|
+
}));
|
|
2808
|
+
}
|
|
2809
|
+
finishPreparedPlainPutManyCommit(commit, options) {
|
|
2810
|
+
return runAfterDocumentCommit(options, () => commit.commits.map((item) => item.append.hash), () => mapMaybePromise(this.handlePreparedPlainPutManyCommit(commit), () => {
|
|
2811
|
+
for (const item of commit.commits) {
|
|
2812
|
+
this.keepCache?.add(item.append.hash);
|
|
2813
|
+
}
|
|
2814
|
+
const result = {
|
|
2815
|
+
get entries() {
|
|
2816
|
+
return commit.entries;
|
|
2817
|
+
},
|
|
2818
|
+
removed: commit.removed,
|
|
2819
|
+
};
|
|
2820
|
+
if (hasPersistedDelivery(options)) {
|
|
2821
|
+
persistedDocumentAppendDelivery.set(result, {
|
|
2822
|
+
appendCommits: commit.commits.map((item) => item.append),
|
|
2823
|
+
materializeEntries: () => commit.entries,
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
return result;
|
|
2827
|
+
}));
|
|
2828
|
+
}
|
|
2670
2829
|
handlePreparedPlainPutCommit(commit) {
|
|
2671
2830
|
const shouldPrepareChange = this.hasDocumentChangeConsumers();
|
|
2672
2831
|
const removedAlreadyHandled = commit.nativeBackboneDocumentIndexTrimmedHeadsProcessed === true;
|
|
@@ -2943,8 +3102,7 @@ let Documents = (() => {
|
|
|
2943
3102
|
}
|
|
2944
3103
|
}
|
|
2945
3104
|
async handlePreparedPlainPutManyCommit(commit) {
|
|
2946
|
-
if (!this.hasDocumentChangeConsumers() &&
|
|
2947
|
-
commit.removed.length === 0) {
|
|
3105
|
+
if (!this.hasDocumentChangeConsumers() && commit.removed.length === 0) {
|
|
2948
3106
|
const stored = await asTrustedDocumentIndex(this._index)._putManyPreparedNativeBackboneDocumentIndexStored(commit.commits.map((put) => {
|
|
2949
3107
|
const existing = put.unique || put.existing === null ? null : put.existing;
|
|
2950
3108
|
return {
|
|
@@ -2993,16 +3151,15 @@ let Documents = (() => {
|
|
|
2993
3151
|
encodedValueParts: put.contextualEncodedValueParts,
|
|
2994
3152
|
},
|
|
2995
3153
|
})));
|
|
2996
|
-
indexedDocuments ??=
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
})));
|
|
3154
|
+
indexedDocuments ??= await asTrustedDocumentIndex(this._index)._putManyPreparedNativeBackboneDocumentIndexWithContext(putsToIndex.map((put) => ({
|
|
3155
|
+
value: put.document,
|
|
3156
|
+
id: put.key,
|
|
3157
|
+
context: put.context,
|
|
3158
|
+
nativeDocumentIndex: put.nativeBackboneDocumentIndex,
|
|
3159
|
+
options: {
|
|
3160
|
+
replace: put.replace,
|
|
3161
|
+
},
|
|
3162
|
+
})));
|
|
3006
3163
|
if (indexedDocuments) {
|
|
3007
3164
|
documentsChanged.added.push(...indexedDocuments);
|
|
3008
3165
|
}
|
|
@@ -3305,6 +3462,9 @@ let Documents = (() => {
|
|
|
3305
3462
|
return resolved ? resolved : undefined;
|
|
3306
3463
|
}
|
|
3307
3464
|
async del(id, options) {
|
|
3465
|
+
if (hasPersistedDelivery(options)) {
|
|
3466
|
+
throw new Error("persisted delivery is not supported for document deletes");
|
|
3467
|
+
}
|
|
3308
3468
|
return this._documentBackend.del(id, options);
|
|
3309
3469
|
}
|
|
3310
3470
|
async delCompatDocumentBackend(id, options) {
|
|
@@ -3489,8 +3649,7 @@ let Documents = (() => {
|
|
|
3489
3649
|
}
|
|
3490
3650
|
const existing = reference?.unique || reference?.existing === null
|
|
3491
3651
|
? null
|
|
3492
|
-
: isReferencedAppendEntry &&
|
|
3493
|
-
reference?.existing !== undefined
|
|
3652
|
+
: isReferencedAppendEntry && reference?.existing !== undefined
|
|
3494
3653
|
? reference.existing
|
|
3495
3654
|
: this.getNativeModeIndexedContext(key) || null;
|
|
3496
3655
|
if (!this.strictHistory && existing) {
|