effect-dynamodb 1.31.0 → 1.33.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/dist/EventStore.d.ts +397 -20
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +602 -59
- package/dist/EventStore.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/TransactWriteOps.d.ts +102 -4
- package/dist/internal/TransactWriteOps.d.ts.map +1 -1
- package/dist/internal/TransactWriteOps.js +104 -4
- package/dist/internal/TransactWriteOps.js.map +1 -1
- package/package.json +2 -2
package/dist/EventStore.d.ts
CHANGED
|
@@ -11,7 +11,15 @@
|
|
|
11
11
|
* - `commandHandler` combinator for the load-decide-fold-append cycle
|
|
12
12
|
* (snapshot-aware single-request loads, consistent loads, an optional
|
|
13
13
|
* `VersionConflict` retry policy, caller-supplied `expectedVersion`,
|
|
14
|
-
* decision-derived `additionalItems`, inline snapshots
|
|
14
|
+
* decision-derived `additionalItems`, inline snapshots, a caller's own
|
|
15
|
+
* state record as the load via `loadState`)
|
|
16
|
+
* - Head proofs (`append({ headProof })`, #164): an additional item or the
|
|
17
|
+
* inline snapshot proves the stream head in place of the version-contiguity
|
|
18
|
+
* `ConditionCheck`
|
|
19
|
+
* - Sealing (#166): `append(..., { seal: true })` makes its last event the
|
|
20
|
+
* stream's final one (`StreamSealed` for any later append), and
|
|
21
|
+
* `stream.appendOp(...)` carries one stream's append — sealing or not — in
|
|
22
|
+
* another append's transaction
|
|
15
23
|
* - Stream indexes (`makeStream({ indexes })`): sub-streams ordered by a key
|
|
16
24
|
* derived from each event, on an LSI or GSI, each projecting all of the
|
|
17
25
|
* event, all but its metadata, or only its keys — `readIndex`,
|
|
@@ -36,13 +44,13 @@
|
|
|
36
44
|
import type { AttributeDefinition, GlobalSecondaryIndex, LocalSecondaryIndex } from "@aws-sdk/client-dynamodb";
|
|
37
45
|
import { type PackedConfig } from "@effect-dynamodb/schema/DynamoModel.js";
|
|
38
46
|
import * as DynamoSchema from "@effect-dynamodb/schema/DynamoSchema.js";
|
|
39
|
-
import { AdditionalItemConditionFailed, AppendTooLarge, type ConcurrentModification, DuplicateCommand, type OptimisticLockError, TransactionCancelled, type UniqueConstraintViolation, ValidationError, VersionConflict } from "@effect-dynamodb/schema/Errors.js";
|
|
47
|
+
import { AdditionalItemConditionFailed, AppendTooLarge, type ConcurrentModification, DuplicateCommand, type OptimisticLockError, StreamSealed, TransactionCancelled, type UniqueConstraintViolation, ValidationError, VersionConflict } from "@effect-dynamodb/schema/Errors.js";
|
|
40
48
|
import { DateTime, type Duration, Effect, Option, Pipeable, Schedule, Schema } from "effect";
|
|
41
49
|
import { DynamoClient, type DynamoClientError } from "./DynamoClient.js";
|
|
42
50
|
import { type EventProjection } from "./internal/EventProjection.js";
|
|
43
51
|
import { type MultiProjection, type MultiSource } from "./internal/MultiProjection.js";
|
|
44
52
|
import { type StreamImage } from "./internal/Packed.js";
|
|
45
|
-
import { type
|
|
53
|
+
import { type AppendWriteOp, type StreamAppendOp } from "./internal/TransactWriteOps.js";
|
|
46
54
|
import * as Query from "./Query.js";
|
|
47
55
|
import { type Table, type TableConfig } from "./Table.js";
|
|
48
56
|
/**
|
|
@@ -81,6 +89,18 @@ export interface StreamEvent<A, M = Record<string, unknown> | undefined> {
|
|
|
81
89
|
* ({@link AppendOptionsBase.eventTimestamps}).
|
|
82
90
|
*/
|
|
83
91
|
readonly timestamp: string;
|
|
92
|
+
/**
|
|
93
|
+
* Present, and `true`, only on a sealing event: the stream's final event
|
|
94
|
+
* (see {@link AppendOptionsBase.seal}). Absent on every other event.
|
|
95
|
+
*
|
|
96
|
+
* Read from the item's `__edd_sealed__` marker, so it is reported by every
|
|
97
|
+
* read of the item itself — `read`, `readFrom`, `query.events`,
|
|
98
|
+
* `readLatest`, `decodeStreamImage`, and a stream index of projection
|
|
99
|
+
* `"all"` or `"keys"` — but not through a `"withoutMetadata"` index (whose
|
|
100
|
+
* projection does not include the marker), nor on a raw row whose
|
|
101
|
+
* `Query.select` projection omits it.
|
|
102
|
+
*/
|
|
103
|
+
readonly sealed?: true;
|
|
84
104
|
}
|
|
85
105
|
/**
|
|
86
106
|
* A {@link StreamEvent} together with the event's stored `data` in its wire
|
|
@@ -219,7 +239,8 @@ export interface AppendMeasurement {
|
|
|
219
239
|
* What the stream's own actions (the contiguity check, the event puts, the
|
|
220
240
|
* sentinel and the inline snapshot) add to the `TransactWriteItems` request
|
|
221
241
|
* — its 4 MB (4,194,304-byte) limit counts items, keys and expressions.
|
|
222
|
-
* Caller `additionalItems` are not included: add their size yourself.
|
|
242
|
+
* Caller `additionalItems` are not included: add their size yourself. With
|
|
243
|
+
* a `headProof` there is no contiguity check to count.
|
|
223
244
|
*/
|
|
224
245
|
readonly transactionBytes: number;
|
|
225
246
|
}
|
|
@@ -316,6 +337,20 @@ export type AppendMetadataOptions<TMetadata> = {
|
|
|
316
337
|
*/
|
|
317
338
|
readonly eventMetadata?: ReadonlyArray<TMetadata | undefined>;
|
|
318
339
|
};
|
|
340
|
+
/**
|
|
341
|
+
* The item of an {@link EventStream.append} that proves the stream head is at
|
|
342
|
+
* `expectedVersion`, in place of the version-contiguity `ConditionCheck` (see
|
|
343
|
+
* {@link AppendOptionsBase.headProof}).
|
|
344
|
+
*
|
|
345
|
+
* - `{ additionalItem: n }` — `additionalItems[n]`, whose own condition holds
|
|
346
|
+
* only when the stream is at `expectedVersion` (the caller's state record,
|
|
347
|
+
* conditioned on the version it was loaded at, or on its absence at 0).
|
|
348
|
+
* - `"snapshot"` — the append's inline snapshot, conditioned on
|
|
349
|
+
* `asOfVersion = expectedVersion`.
|
|
350
|
+
*/
|
|
351
|
+
export type HeadProof = {
|
|
352
|
+
readonly additionalItem: number;
|
|
353
|
+
} | "snapshot";
|
|
319
354
|
/**
|
|
320
355
|
* The options of {@link EventStream.append} other than its metadata (see
|
|
321
356
|
* {@link AppendMetadataOptions}).
|
|
@@ -341,8 +376,21 @@ export interface AppendOptionsBase<TState = never> {
|
|
|
341
376
|
* the entity's put would: `UniqueConstraintViolation`, a history
|
|
342
377
|
* `ValidationError`, or — a race lost on every attempt —
|
|
343
378
|
* `OptimisticLockError` / `ConcurrentModification`.
|
|
379
|
+
*
|
|
380
|
+
* **Another stream's append** (#166): `otherStream.appendOp(...)` (see
|
|
381
|
+
* {@link EventStream.appendOp}) rides here too, so several streams' events
|
|
382
|
+
* commit together or not at all — and a stream can be sealed in the same
|
|
383
|
+
* transaction that opens its successor. Its failures name the inner stream
|
|
384
|
+
* (`StreamSealed`, `VersionConflict`), judged after this stream's own and
|
|
385
|
+
* ahead of the other items' errors.
|
|
386
|
+
*
|
|
387
|
+
* The element type is {@link AppendWriteOp}, wider than the
|
|
388
|
+
* `TransactWriteOp` that `Transaction.transactWrite` takes. Passing a
|
|
389
|
+
* `TransactWriteOp[]` here is unaffected; code that reads this property's
|
|
390
|
+
* type and forwards the value to `transactWrite` must annotate it
|
|
391
|
+
* `ReadonlyArray<TransactWriteOp>`.
|
|
344
392
|
*/
|
|
345
|
-
readonly additionalItems?: ReadonlyArray<
|
|
393
|
+
readonly additionalItems?: ReadonlyArray<AppendWriteOp>;
|
|
346
394
|
/** Opt in to exactly-once command processing — see {@link AppendIdempotency}. */
|
|
347
395
|
readonly idempotency?: AppendIdempotency;
|
|
348
396
|
/**
|
|
@@ -380,6 +428,107 @@ export interface AppendOptionsBase<TState = never> {
|
|
|
380
428
|
* repeat, run backwards or lie in the future, as imported history can.
|
|
381
429
|
*/
|
|
382
430
|
readonly eventTimestamps?: ReadonlyArray<DateTime.DateTime | undefined>;
|
|
431
|
+
/**
|
|
432
|
+
* The item that proves the stream head is at `expectedVersion`, in place of
|
|
433
|
+
* the version-contiguity `ConditionCheck`. Omitted: the check is written.
|
|
434
|
+
*
|
|
435
|
+
* The check reads the event at `expectedVersion`, and DynamoDB bills a
|
|
436
|
+
* `ConditionCheck` inside a transaction at 2 WCU per KB of the checked
|
|
437
|
+
* item, so with large events it is a sizeable part of every append. The
|
|
438
|
+
* event puts already reject a stale `expectedVersion`; the check rejects
|
|
439
|
+
* one that is ahead of the head, which would leave a gap. An item whose own
|
|
440
|
+
* condition holds only at `expectedVersion` proves that just as well.
|
|
441
|
+
*
|
|
442
|
+
* - `{ additionalItem: n }` — `additionalItems[n]` is the proof. It must
|
|
443
|
+
* carry a condition of its own (`.condition()`, `create()`,
|
|
444
|
+
* `Transaction.check`); one without, or an `n` that is not an index into
|
|
445
|
+
* `additionalItems`, fails with `ValidationError` before anything is
|
|
446
|
+
* written. When that condition fails, the append fails with
|
|
447
|
+
* `VersionConflict` — never `AdditionalItemConditionFailed` — judged
|
|
448
|
+
* after `DuplicateCommand` and the event puts, ahead of the other items.
|
|
449
|
+
*
|
|
450
|
+
* **The caller owns the invariant**: every writer of the stream (a
|
|
451
|
+
* handler, an import, a migration, a raw `append`) must write the item in
|
|
452
|
+
* the same transaction as its events, conditioned the same way. An append
|
|
453
|
+
* without it leaves the item behind the head, and every later append
|
|
454
|
+
* fails with `VersionConflict` until it is repaired. Writing the item's
|
|
455
|
+
* version without the events it counts moves it ahead of the head — the
|
|
456
|
+
* one way to open a gap — so write that version only in their append.
|
|
457
|
+
* - `"snapshot"` — the inline snapshot is the proof: its `Put` is
|
|
458
|
+
* conditioned on `asOfVersion = expectedVersion` (`attribute_not_exists`
|
|
459
|
+
* at version 0), and a failure is a `VersionConflict`. Requires
|
|
460
|
+
* `snapshot` (else `ValidationError`) and a stream whose snapshot config
|
|
461
|
+
* is `mode: "inline"` without `every` (else a defect, `[EDD-9085]`). A
|
|
462
|
+
* snapshot can lag the head (a raw `append`, data written before inline
|
|
463
|
+
* mode), and then fails the condition: use it only when the snapshot is
|
|
464
|
+
* known to be at the head, as {@link CommandHandlerOptions.headProof}
|
|
465
|
+
* does.
|
|
466
|
+
*
|
|
467
|
+
* **On a sealed stream** ({@link AppendOptionsBase.seal}): a head proof
|
|
468
|
+
* replaces the contiguity check, which is where the seal is enforced.
|
|
469
|
+
*
|
|
470
|
+
* - `"snapshot"`: the sealing append's inline snapshot carries the seal
|
|
471
|
+
* marker, and the proof's condition also requires the snapshot to be
|
|
472
|
+
* unmarked (`StreamSealed` otherwise). A seal written through a
|
|
473
|
+
* definition **without** this snapshot config leaves the snapshot
|
|
474
|
+
* unmarked below the seal; a later `writeSnapshot` at the seal version
|
|
475
|
+
* then writes an unmarked snapshot there, and a snapshot-proof append can
|
|
476
|
+
* land past the seal (see {@link EventStream.writeSnapshot}). Seal through
|
|
477
|
+
* a definition that shares the writers' snapshot config.
|
|
478
|
+
* - `{ additionalItem: n }`: the library does not enforce the seal (it
|
|
479
|
+
* cannot know the stream is sealed without a read). Seal such a stream
|
|
480
|
+
* with **exactly one event**, and keep the record at the seal's
|
|
481
|
+
* `expectedVersion` (one below the seal, with a sealed flag and the
|
|
482
|
+
* seal's version for {@link LoadedState.sealedVersion}): every
|
|
483
|
+
* record-proof writer then appends at that version, and its first event
|
|
484
|
+
* put lands on the sealing event and fails with `StreamSealed`.
|
|
485
|
+
* Advancing the record to the seal's version lets a record-proof writer
|
|
486
|
+
* append past the seal, unless every writer's record condition also tests
|
|
487
|
+
* the sealed flag. A seal of several events leaves a record-proof writer
|
|
488
|
+
* on `VersionConflict` instead.
|
|
489
|
+
*/
|
|
490
|
+
readonly headProof?: HeadProof | undefined;
|
|
491
|
+
/**
|
|
492
|
+
* Seal the stream with this append (#166): its **last** event becomes the
|
|
493
|
+
* stream's final event, and no append can land after it — one that tries
|
|
494
|
+
* fails with `StreamSealed`. `false` and `undefined` do nothing.
|
|
495
|
+
*
|
|
496
|
+
* The append writes events `expectedVersion + 1 … expectedVersion + n`, so
|
|
497
|
+
* the seal version is `expectedVersion + n`. The library writes a marker
|
|
498
|
+
* attribute (`__edd_sealed__`) on that event's item, and on the inline
|
|
499
|
+
* snapshot when the append writes one; reads report it
|
|
500
|
+
* ({@link StreamEvent.sealed}, {@link LatestState.seal}). A seal is
|
|
501
|
+
* permanent.
|
|
502
|
+
*
|
|
503
|
+
* - A value that is not a boolean, or `true` with no events, fails with
|
|
504
|
+
* `ValidationError` (`operation: "EventStore.append.seal"`) before
|
|
505
|
+
* anything is written.
|
|
506
|
+
* - On a stream whose snapshot config is `mode: "inline"` without `every`,
|
|
507
|
+
* `true` also requires `snapshot`, so the snapshot at the seal version is
|
|
508
|
+
* the marked one and an unverified load sees the seal.
|
|
509
|
+
* - Combines with every other option. Through another stream's
|
|
510
|
+
* `additionalItems` use {@link EventStream.appendOp}.
|
|
511
|
+
*
|
|
512
|
+
* **Enforcement.** Every append after version 0 already checks the event
|
|
513
|
+
* at its `expectedVersion`; that check also requires the event to be
|
|
514
|
+
* unmarked. A writer that loaded after the seal fails it; one that loaded
|
|
515
|
+
* just before fails on its first event put, which lands on the sealing
|
|
516
|
+
* event; both get `StreamSealed`. A writer further behind gets
|
|
517
|
+
* `VersionConflict` and learns of the seal when it reloads.
|
|
518
|
+
*
|
|
519
|
+
* **Upgrade every writer first.** A writer on a library version that does
|
|
520
|
+
* not enforce the seal, a record-proof writer whose record was advanced to
|
|
521
|
+
* the seal, or a snapshot-proof writer on an unmarked snapshot at the seal
|
|
522
|
+
* version can land one event past the seal — and that event, unmarked,
|
|
523
|
+
* reopens the stream for every writer. Reads still report the seal while
|
|
524
|
+
* the sealing event is among the items they fetch
|
|
525
|
+
* (`seal.version < version` on {@link LatestState}).
|
|
526
|
+
*
|
|
527
|
+
* Zero-event appends (only `additionalItems` and/or `idempotency`) write no
|
|
528
|
+
* event, and still land on a sealed stream: a seal stops events, not side
|
|
529
|
+
* writes.
|
|
530
|
+
*/
|
|
531
|
+
readonly seal?: boolean | undefined;
|
|
383
532
|
}
|
|
384
533
|
/**
|
|
385
534
|
* Options accepted by {@link EventStream.append}: {@link AppendOptionsBase}
|
|
@@ -390,8 +539,22 @@ export interface AppendOptionsBase<TState = never> {
|
|
|
390
539
|
* union: an interface cannot extend it.
|
|
391
540
|
*/
|
|
392
541
|
export type AppendOptions<TMetadata, TState = never> = AppendOptionsBase<TState> & AppendMetadataOptions<TMetadata>;
|
|
393
|
-
/**
|
|
394
|
-
|
|
542
|
+
/**
|
|
543
|
+
* The options of {@link EventStream.appendOp}: those of
|
|
544
|
+
* {@link EventStream.append} except `additionalItems`, `idempotency` and
|
|
545
|
+
* `headProof`, which a nested append may not carry (they are refused with
|
|
546
|
+
* `ValidationError` at runtime too, `operation: "EventStore.appendOp"`).
|
|
547
|
+
* The appending stream carries them: a record the nested stream's writers
|
|
548
|
+
* load goes in the OUTER append's `additionalItems`.
|
|
549
|
+
*/
|
|
550
|
+
export type NestedAppendOptions<TMetadata, TState = never> = Omit<AppendOptionsBase<TState>, "additionalItems" | "idempotency" | "headProof"> & AppendMetadataOptions<TMetadata>;
|
|
551
|
+
export type { AppendWriteOp, StreamAppendOp };
|
|
552
|
+
/**
|
|
553
|
+
* Error channel of {@link EventStream.append}. A nested
|
|
554
|
+
* {@link EventStream.appendOp}'s failures are reported through it too, naming
|
|
555
|
+
* the inner stream.
|
|
556
|
+
*/
|
|
557
|
+
export type AppendError = VersionConflict | StreamSealed | DuplicateCommand | AdditionalItemConditionFailed | AppendTooLarge | DynamoClientError | ValidationError | TransactionCancelled | UniqueConstraintViolation | OptimisticLockError | ConcurrentModification;
|
|
395
558
|
/**
|
|
396
559
|
* Options accepted by {@link EventStream.read}, {@link EventStream.readFrom} and
|
|
397
560
|
* {@link EventStream.currentVersion}.
|
|
@@ -455,11 +618,30 @@ export interface ReadLatestOptions extends ReadOptions {
|
|
|
455
618
|
* present, it is the snapshot's `asOfVersion` and `events` is empty —
|
|
456
619
|
* **unverified**: events appended without a snapshot (a raw `append`, data
|
|
457
620
|
* written before `mode: "inline"`) may follow it.
|
|
621
|
+
* - `seal` — the sealing event, when the read found one (see
|
|
622
|
+
* {@link AppendOptionsBase.seal}).
|
|
458
623
|
*/
|
|
459
624
|
export interface LatestState<TState, TEvent, M = Record<string, unknown> | undefined> {
|
|
460
625
|
readonly snapshot: Option.Option<Snapshot<TState>>;
|
|
461
626
|
readonly events: ReadonlyArray<StreamEvent<TEvent, M>>;
|
|
462
627
|
readonly version: number;
|
|
628
|
+
/**
|
|
629
|
+
* The sealing event when the read found one, absent otherwise. It is
|
|
630
|
+
* separate from `events` because `events` holds only what follows the
|
|
631
|
+
* snapshot, and a snapshot written by the sealing append already folds it
|
|
632
|
+
* in (it is in `events` too when it follows the snapshot).
|
|
633
|
+
*
|
|
634
|
+
* Found from **any** sealed event among the items the read fetches, not
|
|
635
|
+
* only the newest, with no extra request — except with
|
|
636
|
+
* `verifySnapshot: false`, where a sealed snapshot costs one `GetItem` of
|
|
637
|
+
* the sealing event. An unverified read of a snapshot left unmarked (a seal
|
|
638
|
+
* written through a definition without this snapshot config) does not
|
|
639
|
+
* report it.
|
|
640
|
+
*
|
|
641
|
+
* `seal.version < version` means events were written past the seal by a
|
|
642
|
+
* writer that does not enforce it: they are on a closed stream.
|
|
643
|
+
*/
|
|
644
|
+
readonly seal?: StreamEvent<TEvent, M>;
|
|
463
645
|
}
|
|
464
646
|
/**
|
|
465
647
|
* The stream id as a stream's index functions receive it: the value of each
|
|
@@ -883,6 +1065,23 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
883
1065
|
* infers the `pipe` subject. Method syntax makes the parameter bivariant, so
|
|
884
1066
|
* `EventStream<E, F, M, never>` unifies with `EventStream<E, F, M, TState>`
|
|
885
1067
|
* again. Callers are unaffected: supplying a `state` still requires `TState`.
|
|
1068
|
+
*
|
|
1069
|
+
* **Sealed streams** ({@link AppendOptionsBase.seal}): `writeSnapshot` is
|
|
1070
|
+
* one plain conditional `PutItem`. It does not know whether the stream is
|
|
1071
|
+
* sealed and never writes the seal marker, so it **must not target a sealed
|
|
1072
|
+
* head with an unmarked snapshot**. Skip sealed streams in a job that
|
|
1073
|
+
* snapshots streams (`readLatest(...).seal` is present), or seal through a
|
|
1074
|
+
* definition that shares the writers' snapshot config: the sealing append
|
|
1075
|
+
* then writes a marked snapshot at the seal version, which this monotonic
|
|
1076
|
+
* write never replaces.
|
|
1077
|
+
*
|
|
1078
|
+
* The residual when it does: a stream sealed at `S` through a definition
|
|
1079
|
+
* without the writers' `mode: "inline"`-without-`every` snapshot config
|
|
1080
|
+
* keeps an unmarked snapshot below `S`; a `writeSnapshot` at `S` then puts
|
|
1081
|
+
* an unmarked snapshot at the seal version, and an append with
|
|
1082
|
+
* `headProof: "snapshot"` at `S` passes its proof and lands event `S + 1`
|
|
1083
|
+
* past the seal — which reopens the stream for every writer. A verified
|
|
1084
|
+
* `readLatest` still reports the seal (`seal.version < version`).
|
|
886
1085
|
*/
|
|
887
1086
|
writeSnapshot(streamId: StreamIdInput<TStreamIdFields>, state: TState, asOfVersion: number): Effect.Effect<void, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
888
1087
|
/**
|
|
@@ -900,6 +1099,55 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
900
1099
|
* `options.snapshot` is `never`) stays assignable to other streams.
|
|
901
1100
|
*/
|
|
902
1101
|
append(streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: AppendOptions<TMetadata, TState> | undefined): Effect.Effect<AppendResult<TEvent>, AppendError, DynamoClient | TableConfig>;
|
|
1102
|
+
/**
|
|
1103
|
+
* An append of this stream as a transact item of ANOTHER stream's append
|
|
1104
|
+
* (its `additionalItems`, or a `commandHandler`'s): it commits if and only
|
|
1105
|
+
* if that append does (#166). Nothing is built or written until the outer
|
|
1106
|
+
* append runs.
|
|
1107
|
+
*
|
|
1108
|
+
* - **With or without `seal`.** Without it, several streams' events commit
|
|
1109
|
+
* together or not at all (an atomic multi-stream append). With it, a
|
|
1110
|
+
* stream is sealed in the same transaction that opens its successor:
|
|
1111
|
+
*
|
|
1112
|
+
* ```ts
|
|
1113
|
+
* const latest = yield* Ledgers.readLatest(genA, { consistentRead: true })
|
|
1114
|
+
* yield* Ledgers.append(genB, [new LedgerOpened({ continuesFrom: latest.version })], 0, {
|
|
1115
|
+
* additionalItems: [
|
|
1116
|
+
* Ledgers.appendOp(genA, [new LedgerClosed({ continuedIn: "4" })], latest.version, {
|
|
1117
|
+
* seal: true,
|
|
1118
|
+
* }),
|
|
1119
|
+
* ],
|
|
1120
|
+
* })
|
|
1121
|
+
* ```
|
|
1122
|
+
* - **The seal's `expectedVersion` is the version the carried-over state
|
|
1123
|
+
* was read at** — the same `readLatest` result, or the version carried in
|
|
1124
|
+
* the decided opening event — never a separate read of the stream's head.
|
|
1125
|
+
* Re-reading the head between the carry-over read and the commit seals
|
|
1126
|
+
* over an append the opening event never carried, and that append is
|
|
1127
|
+
* lost. With the carry-over version, a stale append in between fails the
|
|
1128
|
+
* seal's check instead (`VersionConflict` naming this stream): re-read and
|
|
1129
|
+
* build both again.
|
|
1130
|
+
* - It is a full append of this stream — its contiguity check, event puts,
|
|
1131
|
+
* seal marker and optional inline snapshot (`seal`, `snapshot`,
|
|
1132
|
+
* `metadata` / `eventMetadata`, `eventTimestamps`) — enforced
|
|
1133
|
+
* independently of the outer append. It may not carry `additionalItems`,
|
|
1134
|
+
* `idempotency` or `headProof` (see {@link NestedAppendOptions}); a record
|
|
1135
|
+
* this stream's writers load (a `loadState` record, a record head proof)
|
|
1136
|
+
* is written by the outer append's `additionalItems`, beside this op —
|
|
1137
|
+
* on a sealing op with `sealedVersion` (see {@link LoadedState}). Zero
|
|
1138
|
+
* events fail with `ValidationError` (`operation: "EventStore.appendOp"`).
|
|
1139
|
+
* - Its failures name this stream: `StreamSealed` (terminal) or
|
|
1140
|
+
* `VersionConflict`, judged after the outer stream's own and ahead of
|
|
1141
|
+
* the other additional items. It cannot be a `headProof` target.
|
|
1142
|
+
* - **One client per append.** Its items are sent in the outer append's
|
|
1143
|
+
* single `TransactWriteItems`, through the outer append's `DynamoClient`.
|
|
1144
|
+
* This unbound op resolves this stream's `TableConfig` from the outer
|
|
1145
|
+
* append's context, which must provide it; a bound stream's op resolves
|
|
1146
|
+
* it from its own captured context — but never uses its captured client.
|
|
1147
|
+
* Every table must be reachable through the outer client.
|
|
1148
|
+
* - `Transaction.transactWrite` does not accept it.
|
|
1149
|
+
*/
|
|
1150
|
+
appendOp(streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: NestedAppendOptions<TMetadata, TState> | undefined): StreamAppendOp;
|
|
903
1151
|
/**
|
|
904
1152
|
* Read every event of the stream, ascending by version. Pass
|
|
905
1153
|
* `{ consistentRead: true }` for read-your-writes — see {@link ReadOptions}.
|
|
@@ -943,6 +1191,10 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
943
1191
|
* verified read. Accepted only on a `mode: "inline"` stream without `every`
|
|
944
1192
|
* (otherwise a defect, `[EDD-9068]`), ignored on a stream without a
|
|
945
1193
|
* `snapshot` config — see {@link ReadLatestOptions}.
|
|
1194
|
+
*
|
|
1195
|
+
* On a sealed stream the result carries the sealing event as `seal` when
|
|
1196
|
+
* the read fetches the sealing event, in any mode (see
|
|
1197
|
+
* {@link LatestState.seal} for the cases it does not).
|
|
946
1198
|
*/
|
|
947
1199
|
readLatest(streamId: StreamIdInput<TStreamIdFields>, options?: ReadLatestOptions | undefined): Effect.Effect<LatestState<TState, TEvent, StreamMetadata<TMetadata>>, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
948
1200
|
/**
|
|
@@ -1191,8 +1443,8 @@ export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<strin
|
|
|
1191
1443
|
* declare (such as a misspelled `projection`, also a type error).
|
|
1192
1444
|
* @throws `[EDD-9064]` when an index attribute is one the stream writes itself
|
|
1193
1445
|
* (`pk`, `sk`, `__edd_e__`, `streamId`, `version`, `eventType`, `data`,
|
|
1194
|
-
* `metadata`, `timestamp`, `asOfVersion`, `state`, `commandId`,
|
|
1195
|
-
* default TTL attribute `_ttl`). A custom `TableConfig.ttlAttributeName`
|
|
1446
|
+
* `metadata`, `timestamp`, `asOfVersion`, `state`, `commandId`, the seal
|
|
1447
|
+
* marker `__edd_sealed__`, or the default TTL attribute `_ttl`). A custom `TableConfig.ttlAttributeName`
|
|
1196
1448
|
* is only known at runtime: an index attribute equal to it fails each append
|
|
1197
1449
|
* with `ValidationError`.
|
|
1198
1450
|
* @throws `[EDD-9065]` when two indexes share a physical index name or an
|
|
@@ -1272,6 +1524,15 @@ export interface BoundEventStream<TEvent, TStreamIdFields extends ReadonlyArray<
|
|
|
1272
1524
|
readSnapshot(streamId: StreamIdInput<TStreamIdFields>): Effect.Effect<Option.Option<Snapshot<TState>>, DynamoClientError | ValidationError, never>;
|
|
1273
1525
|
/** See {@link EventStream.append}. */
|
|
1274
1526
|
append(streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: AppendOptions<TMetadata, TState> | undefined): Effect.Effect<AppendResult<TEvent>, AppendError, never>;
|
|
1527
|
+
/**
|
|
1528
|
+
* See {@link EventStream.appendOp}. The op builds in this bound stream's
|
|
1529
|
+
* captured context, so it resolves this stream's `TableConfig` (and
|
|
1530
|
+
* `Compression` registry) itself: a stream on another table needs no extra
|
|
1531
|
+
* layer in the outer append. Its items are still sent through the OUTER
|
|
1532
|
+
* append's `DynamoClient` — one transaction cannot span clients — so the
|
|
1533
|
+
* table must be reachable through it.
|
|
1534
|
+
*/
|
|
1535
|
+
appendOp(streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: NestedAppendOptions<TMetadata, TState> | undefined): StreamAppendOp;
|
|
1275
1536
|
/** See {@link EventStream.read}. */
|
|
1276
1537
|
read(streamId: StreamIdInput<TStreamIdFields>, options?: ReadOptions | undefined): Effect.Effect<ReadonlyArray<StreamEvent<TEvent, StreamMetadata<TMetadata>>>, DynamoClientError | ValidationError, never>;
|
|
1277
1538
|
/** See {@link EventStream.readFrom}. */
|
|
@@ -1406,14 +1667,43 @@ export declare const indexDefinitions: (...streams: ReadonlyArray<{
|
|
|
1406
1667
|
};
|
|
1407
1668
|
};
|
|
1408
1669
|
}>) => StreamIndexDefinitions;
|
|
1670
|
+
/**
|
|
1671
|
+
* The state and stream version a {@link CommandHandlerOptions.loadState}
|
|
1672
|
+
* loads from the caller's own record: `version` is the stream version the
|
|
1673
|
+
* state is as of, which the handler appends after.
|
|
1674
|
+
*/
|
|
1675
|
+
export interface LoadedState<State> {
|
|
1676
|
+
readonly state: State;
|
|
1677
|
+
readonly version: number;
|
|
1678
|
+
/**
|
|
1679
|
+
* The caller's record says the stream is sealed at this version (#166):
|
|
1680
|
+
* the handler then fails with `StreamSealed` before `decide`, without
|
|
1681
|
+
* spending a transaction (after `DuplicateCommand` for a committed
|
|
1682
|
+
* redelivery). It may be `version + 1`: a record-proof stream keeps its
|
|
1683
|
+
* record one below the seal (see {@link AppendOptionsBase.headProof}).
|
|
1684
|
+
*
|
|
1685
|
+
* Must be a non-negative integer, not below `version` — otherwise the call
|
|
1686
|
+
* fails with `ValidationError`
|
|
1687
|
+
* (`operation: "EventStore.commandHandler.loadState"`). The sealing
|
|
1688
|
+
* transaction writes it: in a changeover, the outer append's
|
|
1689
|
+
* `additionalItems` carries the record beside the sealing `appendOp`.
|
|
1690
|
+
* Without it, a record more than one version below the seal leaves the
|
|
1691
|
+
* handler on `VersionConflict` until its retry schedule ends.
|
|
1692
|
+
*/
|
|
1693
|
+
readonly sealedVersion?: number | undefined;
|
|
1694
|
+
}
|
|
1409
1695
|
/**
|
|
1410
1696
|
* Handler-level configuration for {@link commandHandler}.
|
|
1411
1697
|
*
|
|
1412
1698
|
* `idempotency` carries the policy that is fixed for the handler; the
|
|
1413
1699
|
* `commandId` that identifies one delivery can only be per-call and lives in the
|
|
1414
1700
|
* handler's own options.
|
|
1701
|
+
*
|
|
1702
|
+
* `State` and `TStreamId` type {@link loadState}: the decider's state, and the
|
|
1703
|
+
* stream id the handler is called with (`any` for a data-last handler, whose
|
|
1704
|
+
* stream is not yet known).
|
|
1415
1705
|
*/
|
|
1416
|
-
export interface CommandHandlerOptions {
|
|
1706
|
+
export interface CommandHandlerOptions<State = any, TStreamId = any> {
|
|
1417
1707
|
/**
|
|
1418
1708
|
* Retry policy applied to `VersionConflict` **only**.
|
|
1419
1709
|
*
|
|
@@ -1427,9 +1717,16 @@ export interface CommandHandlerOptions {
|
|
|
1427
1717
|
* A number `n` is shorthand for `Schedule.recurs(n)` (n retries *after* the
|
|
1428
1718
|
* initial attempt). Omit for the default: no retry.
|
|
1429
1719
|
*
|
|
1430
|
-
* `DuplicateCommand` is deliberately NOT retried — it is terminal
|
|
1431
|
-
*
|
|
1432
|
-
*
|
|
1720
|
+
* `DuplicateCommand` is deliberately NOT retried — it is terminal, as is
|
|
1721
|
+
* `StreamSealed` (#166). Nor is a `VersionConflict` of this stream on a
|
|
1722
|
+
* call that supplies {@link CommandOptionsBase.expectedVersion}: the caller
|
|
1723
|
+
* asked for a conditional write, so it is always surfaced.
|
|
1724
|
+
*
|
|
1725
|
+
* A `VersionConflict` naming **another** stream — a stream's `appendOp`
|
|
1726
|
+
* carried in `additionalItems` (#166) — is retried, with or without an
|
|
1727
|
+
* `expectedVersion`: this stream's If-Match was not wrong, and the retried
|
|
1728
|
+
* attempt reloads this stream and checks the If-Match again before
|
|
1729
|
+
* `decide`. Without a schedule it is returned as-is, naming that stream.
|
|
1433
1730
|
*/
|
|
1434
1731
|
readonly retry?: number | Schedule.Schedule<unknown, VersionConflict> | undefined;
|
|
1435
1732
|
/** Opt in to exactly-once command processing — see {@link AppendIdempotency}. */
|
|
@@ -1512,7 +1809,72 @@ export interface CommandHandlerOptions {
|
|
|
1512
1809
|
* not extra item reads.
|
|
1513
1810
|
*/
|
|
1514
1811
|
readonly verifySnapshot?: boolean | undefined;
|
|
1812
|
+
/**
|
|
1813
|
+
* Load the state and head from the caller's own record instead of the
|
|
1814
|
+
* stream (#164). `None` is a new stream: the decider's initial state at
|
|
1815
|
+
* version 0.
|
|
1816
|
+
*
|
|
1817
|
+
* The rest of the cycle is unchanged: the If-Match check against the loaded
|
|
1818
|
+
* `version`, `decide`, `evolve`, the derived items, then the append after
|
|
1819
|
+
* `version` — where the caller writes the record, through `additionalItems`.
|
|
1820
|
+
* A `VersionConflict` re-runs `loadState` under the {@link retry} policy, as
|
|
1821
|
+
* a stream load is re-run. A no-op decision or a `decide` failure is
|
|
1822
|
+
* answered from the record: the stream head is not read.
|
|
1823
|
+
*
|
|
1824
|
+
* - **Read strongly consistent.** An eventually consistent read can return
|
|
1825
|
+
* a record behind the head; the append then fails with `VersionConflict`
|
|
1826
|
+
* and burns a retry (nothing is corrupted).
|
|
1827
|
+
* - Without {@link headProof} the append still writes the
|
|
1828
|
+
* version-contiguity check, so a record that is stale or ahead of the
|
|
1829
|
+
* head conflicts rather than opening a gap. With
|
|
1830
|
+
* `headProof: { additionalItem: n }`, the record is the proof, and its
|
|
1831
|
+
* contract (see {@link AppendOptionsBase.headProof}) covers **every**
|
|
1832
|
+
* writer of the stream.
|
|
1833
|
+
* - A `version` that is not a non-negative integer, or a result that is not
|
|
1834
|
+
* an `Option`, fails with `ValidationError`
|
|
1835
|
+
* (`operation: "EventStore.commandHandler.loadState"`), never retried. A
|
|
1836
|
+
* failure of the `Effect` surfaces as is. Its error and requirements join
|
|
1837
|
+
* the handler's (a `BoundEventStream` handler's only requirements).
|
|
1838
|
+
* - On a snapshot-configured stream the snapshot is not read, so its
|
|
1839
|
+
* version is unknown: a `mode: "inline"` stream without `every` still
|
|
1840
|
+
* writes it in every append; with `every` (inline or after-append), one
|
|
1841
|
+
* is written when an append crosses a multiple of `every`.
|
|
1842
|
+
* - Refused with {@link verifySnapshot}`: false` (there is no stream load
|
|
1843
|
+
* to skip) and with `headProof: "snapshot"` (the handler never sees the
|
|
1844
|
+
* snapshot, so cannot know it is at the head): `[EDD-9085]` when the
|
|
1845
|
+
* handler is created.
|
|
1846
|
+
*/
|
|
1847
|
+
readonly loadState?: ((streamId: TStreamId) => Effect.Effect<Option.Option<LoadedState<State>>, any, any>) | undefined;
|
|
1848
|
+
/**
|
|
1849
|
+
* The item that proves the stream head, in place of the version-contiguity
|
|
1850
|
+
* `ConditionCheck`, on every append the handler makes (see
|
|
1851
|
+
* {@link AppendOptionsBase.headProof}). Omitted: the check is written.
|
|
1852
|
+
*
|
|
1853
|
+
* - `{ additionalItem: n }` — the caller's record at `additionalItems[n]`,
|
|
1854
|
+
* conditioned on the loaded version (or its absence at version 0). Every
|
|
1855
|
+
* call whose decision appends must then return that item, carrying its
|
|
1856
|
+
* own condition; otherwise the call fails with `ValidationError` and
|
|
1857
|
+
* nothing is written. A failure of its condition is a `VersionConflict`,
|
|
1858
|
+
* and follows the {@link retry} policy. Usually paired with
|
|
1859
|
+
* {@link loadState}.
|
|
1860
|
+
* - `"snapshot"` — the inline snapshot, on a `mode: "inline"` stream
|
|
1861
|
+
* without `every` (any other throws `[EDD-9085]` when the handler is
|
|
1862
|
+
* created). Applied on an attempt only when its load found the snapshot
|
|
1863
|
+
* at the head — a verified load with no event after the snapshot, or an
|
|
1864
|
+
* unverified one ({@link verifySnapshot}`: false`); otherwise that
|
|
1865
|
+
* append writes the check. A conflict goes through the same stale-snapshot
|
|
1866
|
+
* handling and retry policy as without it.
|
|
1867
|
+
*/
|
|
1868
|
+
readonly headProof?: HeadProof | undefined;
|
|
1515
1869
|
}
|
|
1870
|
+
/** @internal The error of a handler config's {@link CommandHandlerOptions.loadState}. */
|
|
1871
|
+
type LoadStateError<TConfig> = TConfig extends {
|
|
1872
|
+
readonly loadState: (...args: any) => Effect.Effect<any, infer EL, any>;
|
|
1873
|
+
} ? EL : never;
|
|
1874
|
+
/** @internal The requirements of a handler config's {@link CommandHandlerOptions.loadState}. */
|
|
1875
|
+
type LoadStateContext<TConfig> = TConfig extends {
|
|
1876
|
+
readonly loadState: (...args: any) => Effect.Effect<any, any, infer RL>;
|
|
1877
|
+
} ? RL : never;
|
|
1516
1878
|
/**
|
|
1517
1879
|
* The outcome of one `decide` call, handed to a function-form
|
|
1518
1880
|
* {@link CommandOptionsBase.additionalItems}, to `eventMetadata`
|
|
@@ -1543,8 +1905,23 @@ export interface Decision<State, Event> {
|
|
|
1543
1905
|
* directly (pure projection) or as an `Effect` (a projection that needs a read).
|
|
1544
1906
|
* The effect's `E2` joins the handler's error channel and its `R2` the handler's
|
|
1545
1907
|
* requirements.
|
|
1908
|
+
*
|
|
1909
|
+
* The ops are {@link AppendWriteOp}s: another stream's `appendOp` (#166) rides
|
|
1910
|
+
* here too, so a handler on stream B can carry stream A's sealing append. Its
|
|
1911
|
+
* `expectedVersion` must come from the **decision** — the version carried in
|
|
1912
|
+
* the decided opening event (`decision.events[0].continuesFrom.version`, say),
|
|
1913
|
+
* from A's state as `decide` read it — never from a separate read of A's head,
|
|
1914
|
+
* which would seal over an append the opening event never carried.
|
|
1915
|
+
*
|
|
1916
|
+
* A `VersionConflict` naming A (not this handler's stream) is never taken
|
|
1917
|
+
* for this stream's lagging snapshot, and is retried by the
|
|
1918
|
+
* {@link CommandHandlerOptions.retry} schedule even under an If-Match. A
|
|
1919
|
+
* `StreamSealed` naming A is terminal: another closer sealed it.
|
|
1920
|
+
*
|
|
1921
|
+
* Code that reads this type and forwards a static array to
|
|
1922
|
+
* `Transaction.transactWrite` must annotate it `ReadonlyArray<TransactWriteOp>`.
|
|
1546
1923
|
*/
|
|
1547
|
-
export type AdditionalItemsInput<State, Event, E2 = never, R2 = never> = ReadonlyArray<
|
|
1924
|
+
export type AdditionalItemsInput<State, Event, E2 = never, R2 = never> = ReadonlyArray<AppendWriteOp> | ((decision: Decision<State, Event>) => ReadonlyArray<AppendWriteOp> | Effect.Effect<ReadonlyArray<AppendWriteOp>, E2, R2>);
|
|
1548
1925
|
/**
|
|
1549
1926
|
* The form `eventMetadata` ({@link CommandMetadataOptions}) accepts: a
|
|
1550
1927
|
* function of the {@link Decision} returning one metadata entry per event
|
|
@@ -1743,20 +2120,20 @@ export type IdempotentCommandOptions<TMetadata, State = unknown, Event = unknown
|
|
|
1743
2120
|
type CommandOptionsArgs<TMetadata, TConfig extends CommandHandlerOptions | undefined, State, TEvent, E2, R2, E3, R3, E4, R4> = TConfig extends {
|
|
1744
2121
|
readonly idempotency: object;
|
|
1745
2122
|
} ? [options: IdempotentCommandOptions<TMetadata, State, TEvent, E2, R2, E3, R3, E4, R4>] : [options?: CommandOptions<TMetadata, State, TEvent, E2, R2, E3, R3, E4, R4> | undefined];
|
|
1746
|
-
type CommandHandlerErrors<E> = E | VersionConflict | DuplicateCommand | AdditionalItemConditionFailed | AppendTooLarge | DynamoClientError | ValidationError | TransactionCancelled | UniqueConstraintViolation | OptimisticLockError | ConcurrentModification;
|
|
2123
|
+
type CommandHandlerErrors<E> = E | VersionConflict | StreamSealed | DuplicateCommand | AdditionalItemConditionFailed | AppendTooLarge | DynamoClientError | ValidationError | TransactionCancelled | UniqueConstraintViolation | OptimisticLockError | ConcurrentModification;
|
|
1747
2124
|
/**
|
|
1748
2125
|
* A handler over an {@link EventStream}. Generic per call over the error (`E2`)
|
|
1749
2126
|
* and requirements (`R2`) of a function-form `additionalItems` that returns an
|
|
1750
2127
|
* `Effect`, those (`E3` / `R3`) of an `eventMetadata` that does, and those
|
|
1751
2128
|
* (`E4` / `R4`) of an `eventTimestamps` that does; all are `never` otherwise.
|
|
1752
2129
|
*/
|
|
1753
|
-
type CommandHandler<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TConfig extends CommandHandlerOptions | undefined = undefined> = <E2 = never, R2 = never, E3 = never, R3 = never, E4 = never, R4 = never>(streamId: StreamIdInput<TStreamIdFields>, command: Command, ...options: CommandOptionsArgs<TMetadata, TConfig, State, TEvent, E2, R2, E3, R3, E4, R4>) => Effect.Effect<CommandHandlerResult<State, TEvent>, CommandHandlerErrors<E> | E2 | E3 | E4
|
|
2130
|
+
type CommandHandler<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TConfig extends CommandHandlerOptions | undefined = undefined> = <E2 = never, R2 = never, E3 = never, R3 = never, E4 = never, R4 = never>(streamId: StreamIdInput<TStreamIdFields>, command: Command, ...options: CommandOptionsArgs<TMetadata, TConfig, State, TEvent, E2, R2, E3, R3, E4, R4>) => Effect.Effect<CommandHandlerResult<State, TEvent>, CommandHandlerErrors<E> | E2 | E3 | E4 | LoadStateError<TConfig>, DynamoClient | TableConfig | R2 | R3 | R4 | LoadStateContext<TConfig>>;
|
|
1754
2131
|
/**
|
|
1755
2132
|
* A handler over a {@link BoundEventStream}: the stream's services are already
|
|
1756
2133
|
* provided, so the `R2` / `R3` / `R4` of a function-form `additionalItems` /
|
|
1757
2134
|
* `eventMetadata` / `eventTimestamps` are its only requirements.
|
|
1758
2135
|
*/
|
|
1759
|
-
type BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TConfig extends CommandHandlerOptions | undefined = undefined> = <E2 = never, R2 = never, E3 = never, R3 = never, E4 = never, R4 = never>(streamId: StreamIdInput<TStreamIdFields>, command: Command, ...options: CommandOptionsArgs<TMetadata, TConfig, State, TEvent, E2, R2, E3, R3, E4, R4>) => Effect.Effect<CommandHandlerResult<State, TEvent>, CommandHandlerErrors<E> | E2 | E3 | E4
|
|
2136
|
+
type BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TConfig extends CommandHandlerOptions | undefined = undefined> = <E2 = never, R2 = never, E3 = never, R3 = never, E4 = never, R4 = never>(streamId: StreamIdInput<TStreamIdFields>, command: Command, ...options: CommandOptionsArgs<TMetadata, TConfig, State, TEvent, E2, R2, E3, R3, E4, R4>) => Effect.Effect<CommandHandlerResult<State, TEvent>, CommandHandlerErrors<E> | E2 | E3 | E4 | LoadStateError<TConfig>, R2 | R3 | R4 | LoadStateContext<TConfig>>;
|
|
1760
2137
|
/**
|
|
1761
2138
|
* The handler the data-last {@link commandHandler} returns for stream `S`: a
|
|
1762
2139
|
* {@link BoundCommandHandler} for a `BoundEventStream` (checked first — a bound
|
|
@@ -1863,13 +2240,13 @@ type CommandHandlerFor<S, State, Command, TEvent, E, TConfig extends CommandHand
|
|
|
1863
2240
|
* `EventStreamTypeId` brand of the second argument.
|
|
1864
2241
|
*/
|
|
1865
2242
|
export declare const commandHandler: {
|
|
1866
|
-
<State, Command, TEvent, E, const TConfig extends CommandHandlerOptions | undefined
|
|
2243
|
+
<State, Command, TEvent, E, const TConfig extends CommandHandlerOptions<State> | undefined>(decider: Decider<State, Command, TEvent, E>, options?: TConfig): <S extends BoundEventStream<TEvent, any, any, State, any, any, any> | EventStream<TEvent, ReadonlyArray<string>, any, State, any, any, any>>(stream: S) => CommandHandlerFor<S, State, Command, TEvent, E, TConfig>;
|
|
1867
2244
|
<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState extends State, TIndexName extends string, TIndexProjections extends {
|
|
1868
2245
|
readonly [K in TIndexName]: StreamIndexProjection;
|
|
1869
|
-
}, TPartitionedIndexName extends string, const TConfig extends CommandHandlerOptions | undefined
|
|
2246
|
+
}, TPartitionedIndexName extends string, const TConfig extends CommandHandlerOptions<State, StreamIdInput<TStreamIdFields>> | undefined>(decider: Decider<State, Command, TEvent, E>, stream: BoundEventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections, TPartitionedIndexName>, options?: TConfig): BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig>;
|
|
1870
2247
|
<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata, TState extends State, TIndexName extends string, TIndexProjections extends {
|
|
1871
2248
|
readonly [K in TIndexName]: StreamIndexProjection;
|
|
1872
|
-
}, TPartitionedIndexName extends string, const TConfig extends CommandHandlerOptions | undefined
|
|
2249
|
+
}, TPartitionedIndexName extends string, const TConfig extends CommandHandlerOptions<State, StreamIdInput<TStreamIdFields>> | undefined>(decider: Decider<State, Command, TEvent, E>, stream: EventStream<TEvent, TStreamIdFields, TMetadata, TState, TIndexName, TIndexProjections, TPartitionedIndexName>, options?: TConfig): CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata, TConfig>;
|
|
1873
2250
|
};
|
|
1874
2251
|
/**
|
|
1875
2252
|
* Reconstruct state from events by folding through a decider's `evolve` function.
|