@peerbit/document 15.0.32 → 15.1.0
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 +49 -0
- package/dist/src/batch-error.d.ts +23 -0
- package/dist/src/batch-error.d.ts.map +1 -0
- package/dist/src/batch-error.js +26 -0
- package/dist/src/batch-error.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/program.d.ts +5 -1
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +99 -39
- package/dist/src/program.js.map +1 -1
- package/package.json +14 -14
- package/src/batch-error.ts +45 -0
- package/src/index.ts +1 -0
- package/src/program.ts +150 -44
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/document",
|
|
3
|
-
"version": "15.0
|
|
3
|
+
"version": "15.1.0",
|
|
4
4
|
"description": "Document store implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -61,20 +61,20 @@
|
|
|
61
61
|
"p-defer": "^4.0.0",
|
|
62
62
|
"uint8arrays": "^5.1.0",
|
|
63
63
|
"@peerbit/cache": "3.1.1",
|
|
64
|
-
"@peerbit/
|
|
65
|
-
"@peerbit/indexer-interface": "3.0.13",
|
|
64
|
+
"@peerbit/document-interface": "3.2.77",
|
|
66
65
|
"@peerbit/indexer-cache": "0.2.16",
|
|
67
|
-
"@peerbit/document-interface": "3.2.76",
|
|
68
66
|
"@peerbit/indexer-simple": "1.2.17",
|
|
67
|
+
"@peerbit/indexer-interface": "3.0.13",
|
|
69
68
|
"@peerbit/indexer-sqlite3": "3.0.20",
|
|
70
|
-
"@peerbit/log": "6.2.
|
|
69
|
+
"@peerbit/log": "6.2.33",
|
|
70
|
+
"@peerbit/crypto": "3.1.6",
|
|
71
71
|
"@peerbit/logger": "2.0.2",
|
|
72
|
-
"@peerbit/program": "6.0.
|
|
73
|
-
"@peerbit/
|
|
74
|
-
"@peerbit/
|
|
75
|
-
"@peerbit/
|
|
76
|
-
"@peerbit/
|
|
77
|
-
"@peerbit/
|
|
72
|
+
"@peerbit/program": "6.0.60",
|
|
73
|
+
"@peerbit/shared-log": "16.0.30",
|
|
74
|
+
"@peerbit/pubsub": "5.4.6",
|
|
75
|
+
"@peerbit/rpc": "6.1.28",
|
|
76
|
+
"@peerbit/stream-interface": "6.0.16",
|
|
77
|
+
"@peerbit/time": "3.0.1"
|
|
78
78
|
},
|
|
79
79
|
"optionalDependencies": {
|
|
80
80
|
"@peerbit/document-rust": "0.1.1"
|
|
@@ -86,9 +86,9 @@
|
|
|
86
86
|
"pidusage": "^4.0.1",
|
|
87
87
|
"uuid": "^11.1.1",
|
|
88
88
|
"@peerbit/log-rust": "1.1.4",
|
|
89
|
-
"@peerbit/
|
|
90
|
-
"
|
|
91
|
-
"peerbit": "
|
|
89
|
+
"@peerbit/native-backbone": "0.2.15",
|
|
90
|
+
"peerbit": "5.4.2",
|
|
91
|
+
"@peerbit/test-utils": "3.1.41"
|
|
92
92
|
},
|
|
93
93
|
"repository": {
|
|
94
94
|
"type": "git",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type DocumentBatchCommittedItem = Readonly<{
|
|
2
|
+
/** Position in the input array captured when putMany was invoked. */
|
|
3
|
+
index: number;
|
|
4
|
+
hash: string;
|
|
5
|
+
}>;
|
|
6
|
+
|
|
7
|
+
export type DocumentBatchLocalCommit =
|
|
8
|
+
| "not-started"
|
|
9
|
+
| "committed"
|
|
10
|
+
| "indeterminate";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Failure of a putMany invocation with batching: "required". Local append
|
|
14
|
+
* evidence does not prove remote receipt, document projection completion, or
|
|
15
|
+
* an atomic storage transaction. An indeterminate outcome requires recovery
|
|
16
|
+
* and must never be treated as an empty committed set that is safe to retry.
|
|
17
|
+
*/
|
|
18
|
+
export class DocumentBatchCommitError extends Error {
|
|
19
|
+
readonly cause: unknown;
|
|
20
|
+
readonly localCommit: DocumentBatchLocalCommit;
|
|
21
|
+
readonly committedItems: readonly DocumentBatchCommittedItem[];
|
|
22
|
+
/** Safety of replaying this local append only; not application side effects. */
|
|
23
|
+
readonly retrySafe: boolean;
|
|
24
|
+
/** Unresolved local append outcome; false does not rule out projection repair. */
|
|
25
|
+
readonly recoveryRequired: boolean;
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
cause: unknown,
|
|
29
|
+
localCommit: DocumentBatchLocalCommit,
|
|
30
|
+
committedItems: readonly DocumentBatchCommittedItem[],
|
|
31
|
+
) {
|
|
32
|
+
super(
|
|
33
|
+
`Required document batch failed (${localCommit}): ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
34
|
+
);
|
|
35
|
+
this.name = "DocumentBatchCommitError";
|
|
36
|
+
this.cause = cause;
|
|
37
|
+
this.localCommit = localCommit;
|
|
38
|
+
this.committedItems = Object.freeze(
|
|
39
|
+
committedItems.map(({ index, hash }) => Object.freeze({ index, hash })),
|
|
40
|
+
);
|
|
41
|
+
this.retrySafe = localCommit === "not-started";
|
|
42
|
+
this.recoveryRequired = localCommit === "indeterminate";
|
|
43
|
+
Object.freeze(this);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.ts
CHANGED
package/src/program.ts
CHANGED
|
@@ -30,12 +30,14 @@ import { logger as loggerFn } from "@peerbit/logger";
|
|
|
30
30
|
import { Program, type ProgramEvents } from "@peerbit/program";
|
|
31
31
|
import {
|
|
32
32
|
type EntryReplicated,
|
|
33
|
+
NativeDurableCommitError,
|
|
33
34
|
PersistedDeliveryError,
|
|
34
35
|
type ReplicationDomain,
|
|
35
36
|
type SharedAppendOptions,
|
|
36
37
|
SharedLog,
|
|
37
38
|
type SharedLogOptions,
|
|
38
39
|
} from "@peerbit/shared-log";
|
|
40
|
+
import { DocumentBatchCommitError } from "./batch-error.js";
|
|
39
41
|
import {
|
|
40
42
|
detachCanPerformCallbackProperties,
|
|
41
43
|
detachEntryForCallback,
|
|
@@ -240,6 +242,16 @@ type DocumentPutOptions = SharedAppendOptions<Operation> & {
|
|
|
240
242
|
checkRemote?: boolean;
|
|
241
243
|
};
|
|
242
244
|
|
|
245
|
+
export type DocumentPutManyOptions = DocumentPutOptions & {
|
|
246
|
+
/** Require a supported independent batch; never fall back to sequential puts. */
|
|
247
|
+
batching?: "required";
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
type RequiredDocumentBatch<T> = TrustedLocalCommitEvidence & {
|
|
251
|
+
prepared: PreparedPlainPut<T>[];
|
|
252
|
+
appendStarted: boolean;
|
|
253
|
+
};
|
|
254
|
+
|
|
243
255
|
type TrustedLocalCommitEvidence = {
|
|
244
256
|
committedHashes: Set<string>;
|
|
245
257
|
};
|
|
@@ -363,6 +375,7 @@ interface DocumentBackend<T> {
|
|
|
363
375
|
putMany(
|
|
364
376
|
docs: T[],
|
|
365
377
|
options?: DocumentPutOptions,
|
|
378
|
+
batch?: RequiredDocumentBatch<T>,
|
|
366
379
|
): MaybePromise<DocumentPutManyResult>;
|
|
367
380
|
del(
|
|
368
381
|
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
@@ -439,6 +452,7 @@ type DocumentBackendPut<T> = (
|
|
|
439
452
|
type DocumentBackendPutMany<T> = (
|
|
440
453
|
docs: T[],
|
|
441
454
|
options?: DocumentPutOptions,
|
|
455
|
+
batch?: RequiredDocumentBatch<T>,
|
|
442
456
|
) => MaybePromise<DocumentPutManyResult>;
|
|
443
457
|
type DocumentBackendDelete = (
|
|
444
458
|
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
@@ -459,8 +473,9 @@ class CompatDocumentBackend<T> implements DocumentBackend<T> {
|
|
|
459
473
|
putMany(
|
|
460
474
|
docs: T[],
|
|
461
475
|
options?: DocumentPutOptions,
|
|
476
|
+
batch?: RequiredDocumentBatch<T>,
|
|
462
477
|
): MaybePromise<DocumentPutManyResult> {
|
|
463
|
-
return this.putManyImpl(docs, options);
|
|
478
|
+
return this.putManyImpl(docs, options, batch);
|
|
464
479
|
}
|
|
465
480
|
|
|
466
481
|
del(
|
|
@@ -589,6 +604,7 @@ class NativeDocumentBackend<T, I extends Record<string, any>>
|
|
|
589
604
|
async putMany(
|
|
590
605
|
docs: T[],
|
|
591
606
|
options?: DocumentPutOptions,
|
|
607
|
+
batch?: RequiredDocumentBatch<T>,
|
|
592
608
|
): Promise<DocumentPutManyResult> {
|
|
593
609
|
if (docs.length === 0) {
|
|
594
610
|
return { entries: [], removed: [] };
|
|
@@ -597,8 +613,13 @@ class NativeDocumentBackend<T, I extends Record<string, any>>
|
|
|
597
613
|
for (const doc of docs) {
|
|
598
614
|
this.context.assertPlainPutSupported(doc, putOptions);
|
|
599
615
|
}
|
|
600
|
-
const prepared =
|
|
616
|
+
const prepared =
|
|
617
|
+
batch?.prepared ?? docs.map((doc) => this.context.preparePlainPut(doc));
|
|
601
618
|
if (this.context.hasDuplicatePreparedPutKeys(prepared)) {
|
|
619
|
+
if (batch)
|
|
620
|
+
throw new Error(
|
|
621
|
+
"Required putMany batching requires distinct document keys",
|
|
622
|
+
);
|
|
602
623
|
if (hasPersistedDelivery(options)) {
|
|
603
624
|
throw this.context.nativeModeError(
|
|
604
625
|
"requires distinct document keys for persisted putMany",
|
|
@@ -700,6 +721,7 @@ class NativeDocumentBackend<T, I extends Record<string, any>>
|
|
|
700
721
|
resolveTrimmedEntries: this.context.shouldResolveTrimmedEntries(),
|
|
701
722
|
options: putOptions,
|
|
702
723
|
useNativeExistingDocumentContext,
|
|
724
|
+
batch,
|
|
703
725
|
}),
|
|
704
726
|
(documentAppendCommit) => {
|
|
705
727
|
if (!documentAppendCommit) {
|
|
@@ -1113,6 +1135,7 @@ type NativeDocumentAppendManyCommitInput<T, I extends Record<string, any>> = {
|
|
|
1113
1135
|
resolveTrimmedEntries: boolean;
|
|
1114
1136
|
options?: DocumentPutOptions;
|
|
1115
1137
|
useNativeExistingDocumentContext?: boolean;
|
|
1138
|
+
batch?: RequiredDocumentBatch<T>;
|
|
1116
1139
|
};
|
|
1117
1140
|
|
|
1118
1141
|
type DocumentAppendManyCommitFacts<T, I extends Record<string, any>> = {
|
|
@@ -3373,8 +3396,18 @@ export class Documents<
|
|
|
3373
3396
|
};
|
|
3374
3397
|
}
|
|
3375
3398
|
|
|
3376
|
-
private preparePlainPut(doc: T): PreparedPlainPut<T> {
|
|
3377
|
-
const
|
|
3399
|
+
private preparePlainPut(doc: T, capture = false): PreparedPlainPut<T> {
|
|
3400
|
+
const resolvedKey = this.idResolver(doc);
|
|
3401
|
+
const keyValue =
|
|
3402
|
+
capture && ArrayBuffer.isView(resolvedKey)
|
|
3403
|
+
? new Uint8Array(
|
|
3404
|
+
new Uint8Array(
|
|
3405
|
+
resolvedKey.buffer,
|
|
3406
|
+
resolvedKey.byteOffset,
|
|
3407
|
+
resolvedKey.byteLength,
|
|
3408
|
+
),
|
|
3409
|
+
)
|
|
3410
|
+
: resolvedKey;
|
|
3378
3411
|
indexerTypes.checkId(keyValue);
|
|
3379
3412
|
const documentBytes = serialize(doc);
|
|
3380
3413
|
if (documentBytes.length > MAX_BATCH_SIZE) {
|
|
@@ -3386,7 +3419,9 @@ export class Documents<
|
|
|
3386
3419
|
}
|
|
3387
3420
|
const operationPayloadBytes = encodePutOperationPayload(documentBytes);
|
|
3388
3421
|
return {
|
|
3389
|
-
document:
|
|
3422
|
+
document: capture
|
|
3423
|
+
? this._index.valueEncoding.decoder(documentBytes)
|
|
3424
|
+
: doc,
|
|
3390
3425
|
encodedDocument: operationPayloadBytes.subarray(
|
|
3391
3426
|
PUT_OPERATION_PREFIX_LENGTH,
|
|
3392
3427
|
),
|
|
@@ -3542,56 +3577,106 @@ export class Documents<
|
|
|
3542
3577
|
|
|
3543
3578
|
public async putMany(
|
|
3544
3579
|
docs: T[],
|
|
3545
|
-
options?:
|
|
3580
|
+
options?: DocumentPutManyOptions,
|
|
3546
3581
|
): Promise<DocumentPutManyResult> {
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
options,
|
|
3551
|
-
this.isNativeMode() && docs.length > 0
|
|
3552
|
-
? (capturedOptions) => {
|
|
3553
|
-
if (capturedOptions.encryption) {
|
|
3554
|
-
this.assertNativeModePlainPutSupported(docs[0]!, capturedOptions);
|
|
3555
|
-
}
|
|
3556
|
-
}
|
|
3557
|
-
: undefined,
|
|
3558
|
-
);
|
|
3559
|
-
const persistedRequested = hasPersistedDelivery(options);
|
|
3560
|
-
const result = await this._documentBackend.putMany(docs, options);
|
|
3561
|
-
if (!persistedRequested) {
|
|
3562
|
-
return result;
|
|
3582
|
+
const batching = options?.batching;
|
|
3583
|
+
if (batching !== undefined && batching !== "required") {
|
|
3584
|
+
throw new Error('Unsupported putMany batching mode; expected "required"');
|
|
3563
3585
|
}
|
|
3564
|
-
const
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3586
|
+
const batch: RequiredDocumentBatch<T> | undefined =
|
|
3587
|
+
batching === "required"
|
|
3588
|
+
? { prepared: [], committedHashes: new Set(), appendStarted: false }
|
|
3589
|
+
: undefined;
|
|
3590
|
+
try {
|
|
3591
|
+
if (batch) docs = docs.slice();
|
|
3592
|
+
options = asTrustedDocumentSharedLog(
|
|
3593
|
+
this.log,
|
|
3594
|
+
).snapshotDocumentAppendOptions(
|
|
3595
|
+
options,
|
|
3596
|
+
this.isNativeMode() && docs.length > 0
|
|
3597
|
+
? (capturedOptions) => {
|
|
3598
|
+
if (capturedOptions.encryption) {
|
|
3599
|
+
this.assertNativeModePlainPutSupported(
|
|
3600
|
+
docs[0]!,
|
|
3601
|
+
capturedOptions,
|
|
3602
|
+
);
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
: undefined,
|
|
3606
|
+
);
|
|
3607
|
+
if (batch) {
|
|
3608
|
+
if (Program.isPrototypeOf(this._clazz)) {
|
|
3609
|
+
throw new Error(
|
|
3610
|
+
"Required putMany batching does not support program-valued documents",
|
|
3611
|
+
);
|
|
3612
|
+
}
|
|
3613
|
+
// Capture every encoded value and key before the first asynchronous
|
|
3614
|
+
// operation, then reuse these bytes in the ordinary native batch path.
|
|
3615
|
+
batch.prepared = docs.map((doc) => this.preparePlainPut(doc, true));
|
|
3616
|
+
docs = batch.prepared.map(({ document }) => document);
|
|
3617
|
+
}
|
|
3618
|
+
const persistedRequested = hasPersistedDelivery(options);
|
|
3619
|
+
const result = await this._documentBackend.putMany(docs, options, batch);
|
|
3620
|
+
if (!persistedRequested) {
|
|
3621
|
+
return result;
|
|
3622
|
+
}
|
|
3623
|
+
const appendDelivery = persistedDocumentAppendDelivery.get(result);
|
|
3624
|
+
if (appendDelivery) {
|
|
3625
|
+
persistedDocumentAppendDelivery.delete(result);
|
|
3626
|
+
await this.deliverPersistedDocumentAppendCommits(
|
|
3627
|
+
appendDelivery,
|
|
3628
|
+
options!,
|
|
3629
|
+
);
|
|
3630
|
+
let entries: Entry<Operation>[] | undefined;
|
|
3631
|
+
return {
|
|
3632
|
+
get entries() {
|
|
3633
|
+
return (entries ??= result.entries);
|
|
3634
|
+
},
|
|
3635
|
+
removed: result.removed,
|
|
3636
|
+
};
|
|
3637
|
+
}
|
|
3638
|
+
const entries = result.entries;
|
|
3639
|
+
if (entries.length === 0) {
|
|
3640
|
+
return result;
|
|
3641
|
+
}
|
|
3642
|
+
await this.deliverPersistedDocumentEntries(entries, options!);
|
|
3643
|
+
return { entries, removed: result.removed };
|
|
3644
|
+
} catch (error) {
|
|
3645
|
+
if (!batch) throw error;
|
|
3646
|
+
const hashes = [...batch.committedHashes];
|
|
3647
|
+
// The trusted independent-batch seam emits all hashes in input order.
|
|
3648
|
+
// Never invent indexes from incomplete or contradictory batch evidence.
|
|
3649
|
+
const complete =
|
|
3650
|
+
hashes.length === batch.prepared.length && hashes.length > 0;
|
|
3651
|
+
const cause =
|
|
3652
|
+
error instanceof PersistedDeliveryError ? error.cause : error;
|
|
3653
|
+
const localCommit =
|
|
3654
|
+
complete && !(cause instanceof NativeDurableCommitError)
|
|
3655
|
+
? "committed"
|
|
3656
|
+
: batch.appendStarted || hashes.length > 0
|
|
3657
|
+
? "indeterminate"
|
|
3658
|
+
: "not-started";
|
|
3659
|
+
throw new DocumentBatchCommitError(
|
|
3660
|
+
error,
|
|
3661
|
+
localCommit,
|
|
3662
|
+
complete ? hashes.map((hash, index) => ({ index, hash })) : [],
|
|
3570
3663
|
);
|
|
3571
|
-
let entries: Entry<Operation>[] | undefined;
|
|
3572
|
-
return {
|
|
3573
|
-
get entries() {
|
|
3574
|
-
return (entries ??= result.entries);
|
|
3575
|
-
},
|
|
3576
|
-
removed: result.removed,
|
|
3577
|
-
};
|
|
3578
|
-
}
|
|
3579
|
-
const entries = result.entries;
|
|
3580
|
-
if (entries.length === 0) {
|
|
3581
|
-
return result;
|
|
3582
3664
|
}
|
|
3583
|
-
await this.deliverPersistedDocumentEntries(entries, options!);
|
|
3584
|
-
return { entries, removed: result.removed };
|
|
3585
3665
|
}
|
|
3586
3666
|
|
|
3587
3667
|
private async putManyCompatDocumentBackend(
|
|
3588
3668
|
docs: T[],
|
|
3589
3669
|
options?: DocumentPutOptions,
|
|
3670
|
+
batch?: RequiredDocumentBatch<T>,
|
|
3590
3671
|
): Promise<DocumentPutManyResult> {
|
|
3591
3672
|
if (docs.length === 0) {
|
|
3592
3673
|
return { entries: [], removed: [] };
|
|
3593
3674
|
}
|
|
3594
3675
|
if (!this.canUsePlainPutManyFastPath(docs, options)) {
|
|
3676
|
+
if (batch)
|
|
3677
|
+
throw new Error(
|
|
3678
|
+
"Required putMany batching requires the independent batched document path",
|
|
3679
|
+
);
|
|
3595
3680
|
if (hasPersistedDelivery(options)) {
|
|
3596
3681
|
throw new Error(
|
|
3597
3682
|
"persisted putMany requires the independent batched document path",
|
|
@@ -3600,8 +3685,13 @@ export class Documents<
|
|
|
3600
3685
|
return this.putManySequential(docs, options);
|
|
3601
3686
|
}
|
|
3602
3687
|
|
|
3603
|
-
const prepared =
|
|
3688
|
+
const prepared =
|
|
3689
|
+
batch?.prepared ?? docs.map((doc) => this.preparePlainPut(doc));
|
|
3604
3690
|
if (this.hasDuplicatePreparedPutKeys(prepared)) {
|
|
3691
|
+
if (batch)
|
|
3692
|
+
throw new Error(
|
|
3693
|
+
"Required putMany batching requires distinct document keys",
|
|
3694
|
+
);
|
|
3605
3695
|
if (hasPersistedDelivery(options)) {
|
|
3606
3696
|
throw new Error("persisted putMany requires distinct document keys");
|
|
3607
3697
|
}
|
|
@@ -3619,8 +3709,13 @@ export class Documents<
|
|
|
3619
3709
|
})),
|
|
3620
3710
|
resolveTrimmedEntries: !this._index.canGetIdentityIndexedByHead(),
|
|
3621
3711
|
options,
|
|
3712
|
+
batch,
|
|
3622
3713
|
});
|
|
3623
3714
|
if (!documentAppendCommit) {
|
|
3715
|
+
if (batch)
|
|
3716
|
+
throw new Error(
|
|
3717
|
+
"Required putMany batching requires native batched payload append support",
|
|
3718
|
+
);
|
|
3624
3719
|
if (hasPersistedDelivery(options)) {
|
|
3625
3720
|
throw new Error(
|
|
3626
3721
|
"persisted putMany requires native batched payload append support",
|
|
@@ -4132,6 +4227,12 @@ export class Documents<
|
|
|
4132
4227
|
private async commitNativeDocumentAppendMany(
|
|
4133
4228
|
input: NativeDocumentAppendManyCommitInput<T, I>,
|
|
4134
4229
|
): Promise<DocumentAppendManyCommitFacts<T, I> | undefined> {
|
|
4230
|
+
if (input.batch) {
|
|
4231
|
+
return this.commitNativeDocumentAppendManyWithEvidence(
|
|
4232
|
+
input,
|
|
4233
|
+
input.batch,
|
|
4234
|
+
);
|
|
4235
|
+
}
|
|
4135
4236
|
if (!hasPersistedDelivery(input.options)) {
|
|
4136
4237
|
return this.commitNativeDocumentAppendManyWithEvidence(input, undefined);
|
|
4137
4238
|
}
|
|
@@ -4180,10 +4281,13 @@ export class Documents<
|
|
|
4180
4281
|
}
|
|
4181
4282
|
return [next];
|
|
4182
4283
|
});
|
|
4284
|
+
const payloads = input.puts.map((put) => put.operationPayloadBytes);
|
|
4285
|
+
const appendOptions = withoutPersistedDelivery(input.options);
|
|
4286
|
+
if (input.batch) input.batch.appendStarted = true;
|
|
4183
4287
|
const appended =
|
|
4184
4288
|
await trustedLog.appendLocallyPreparedPayloadsManyIndependent(
|
|
4185
|
-
|
|
4186
|
-
|
|
4289
|
+
payloads,
|
|
4290
|
+
appendOptions,
|
|
4187
4291
|
{
|
|
4188
4292
|
resolveTrimmedEntries: input.resolveTrimmedEntries,
|
|
4189
4293
|
nexts,
|
|
@@ -4193,6 +4297,8 @@ export class Documents<
|
|
|
4193
4297
|
},
|
|
4194
4298
|
);
|
|
4195
4299
|
if (!appended) {
|
|
4300
|
+
// An unsupported lower append can already have prepared native state.
|
|
4301
|
+
// Absence of success evidence cannot prove that replay is safe.
|
|
4196
4302
|
if (this.isNativeMode()) {
|
|
4197
4303
|
throw this.nativeModeError(
|
|
4198
4304
|
"requires native batched payload append support",
|