@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.
@@ -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 { createCanPerformPolicyEvaluator, createCanPerformDeletePolicyEvaluator, getCanPerformPolicyDescriptor, canPerformPolicyDeleteFieldPaths, canPerformPolicyNeedsDeleteValue, canPerformPolicyNeedsPreviousEntries, canPerformPolicyPutNeedsEntryPublicKeys, canPerformPolicySignedByFieldPaths, } from "./policy.js";
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) => mapMaybePromise(this.context.handlePreparedPlainPutCommit(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 mapMaybePromise(this.context.handlePreparedPlainPutManyCommit(documentAppendCommit), () => {
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
- handlePreparedPlainPutCommit: (commit) => this.handlePreparedPlainPutCommit(commit),
535
- handlePreparedPlainPutManyCommit: (commit) => this.handlePreparedPlainPutManyCommit(commit),
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 && options.target !== "none") {
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 && options.delivery !== false) {
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.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 = await this.getNativeDocumentIdFromPutOperation(putOperation);
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
- return this._documentBackend.put(doc, options);
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: (change) => {
1995
- return this.handleChanges(change, {
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
- return this._documentBackend.putMany(docs, options);
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.handlePreparedPlainPutManyCommit(documentAppendCommit);
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 || options.target === "none") &&
2089
- (options?.delivery === undefined || options.delivery === false) &&
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
- (options?.delivery === undefined || options.delivery === false) &&
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
- const handled = plan.useGenericChangeHandler
2148
- ? this.handleChanges({
2149
- added: [{ head: true, entry: documentAppendCommit.entry }],
2150
- removed: documentAppendCommit.removed,
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
- removed: documentAppendCommit.removed,
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
- ...input.options,
2291
+ ...localAppendOptions,
2176
2292
  meta: {
2177
2293
  next: input.next,
2178
- ...input.options?.meta,
2294
+ ...localAppendOptions?.meta,
2179
2295
  },
2180
- replicate: input.options?.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 (!(error instanceof Error) ||
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
- const appendInputs = input.puts.map((put, index) => ({
2351
- input: nativeBackboneDocumentIndexes?.[index]
2352
- ? {
2353
- ...put,
2354
- nativeBackboneDocumentIndex: nativeBackboneDocumentIndexes[index],
2355
- }
2356
- : put,
2357
- appended: (() => {
2358
- const materializeEntry = appended.materializeEntries?.[index];
2359
- let entry;
2360
- return {
2361
- get entry() {
2362
- return (entry ??= materializeEntry
2363
- ? materializeEntry()
2364
- : appended.entries[index]);
2365
- },
2366
- removed: [],
2367
- appendCommit: appended.appendCommits[index],
2368
- };
2369
- })(),
2370
- }));
2371
- const commits = await this.createDocumentAppendCommitFactsBatch(appendInputs);
2372
- let entries;
2373
- return {
2374
- get entries() {
2375
- return (entries ??= commits.map((commit) => commit.entry));
2376
- },
2377
- removed: appended.removed,
2378
- commits,
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
- await asTrustedDocumentIndex(this._index)._putManyPreparedNativeBackboneDocumentIndexWithContext(putsToIndex.map((put) => ({
2998
- value: put.document,
2999
- id: put.key,
3000
- context: put.context,
3001
- nativeDocumentIndex: put.nativeBackboneDocumentIndex,
3002
- options: {
3003
- replace: put.replace,
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) {