effect-dynamodb 1.27.0 → 1.29.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.
Files changed (61) hide show
  1. package/dist/Batch.d.ts.map +1 -1
  2. package/dist/Batch.js +3 -2
  3. package/dist/Batch.js.map +1 -1
  4. package/dist/Entity.d.ts +24 -1
  5. package/dist/Entity.d.ts.map +1 -1
  6. package/dist/Entity.js +33 -17
  7. package/dist/Entity.js.map +1 -1
  8. package/dist/EventStore.d.ts +66 -5
  9. package/dist/EventStore.d.ts.map +1 -1
  10. package/dist/EventStore.js +100 -2
  11. package/dist/EventStore.js.map +1 -1
  12. package/dist/Transaction.d.ts.map +1 -1
  13. package/dist/Transaction.js +5 -2
  14. package/dist/Transaction.js.map +1 -1
  15. package/dist/change-feed/ChangeFeed.d.ts +203 -0
  16. package/dist/change-feed/ChangeFeed.d.ts.map +1 -0
  17. package/dist/change-feed/ChangeFeed.js +498 -0
  18. package/dist/change-feed/ChangeFeed.js.map +1 -0
  19. package/dist/change-feed/CheckpointStore.d.ts +113 -0
  20. package/dist/change-feed/CheckpointStore.d.ts.map +1 -0
  21. package/dist/change-feed/CheckpointStore.js +247 -0
  22. package/dist/change-feed/CheckpointStore.js.map +1 -0
  23. package/dist/change-feed/DynamoStreamsClient.d.ts +71 -0
  24. package/dist/change-feed/DynamoStreamsClient.d.ts.map +1 -0
  25. package/dist/change-feed/DynamoStreamsClient.js +92 -0
  26. package/dist/change-feed/DynamoStreamsClient.js.map +1 -0
  27. package/dist/change-feed/Errors.d.ts +84 -0
  28. package/dist/change-feed/Errors.d.ts.map +1 -0
  29. package/dist/change-feed/Errors.js +40 -0
  30. package/dist/change-feed/Errors.js.map +1 -0
  31. package/dist/change-feed/index.d.ts +36 -0
  32. package/dist/change-feed/index.d.ts.map +1 -0
  33. package/dist/change-feed/index.js +36 -0
  34. package/dist/change-feed/index.js.map +1 -0
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/internal/EntityOps.d.ts +7 -2
  40. package/dist/internal/EntityOps.d.ts.map +1 -1
  41. package/dist/internal/EntityOps.js.map +1 -1
  42. package/dist/internal/EventProjection.d.ts +782 -0
  43. package/dist/internal/EventProjection.d.ts.map +1 -0
  44. package/dist/internal/EventProjection.js +608 -0
  45. package/dist/internal/EventProjection.js.map +1 -0
  46. package/dist/internal/MultiProjection.d.ts +255 -0
  47. package/dist/internal/MultiProjection.d.ts.map +1 -0
  48. package/dist/internal/MultiProjection.js +377 -0
  49. package/dist/internal/MultiProjection.js.map +1 -0
  50. package/dist/internal/ProjectionEngine.d.ts +253 -0
  51. package/dist/internal/ProjectionEngine.d.ts.map +1 -0
  52. package/dist/internal/ProjectionEngine.js +837 -0
  53. package/dist/internal/ProjectionEngine.js.map +1 -0
  54. package/dist/internal/TransactWriteOps.d.ts.map +1 -1
  55. package/dist/internal/TransactWriteOps.js +12 -3
  56. package/dist/internal/TransactWriteOps.js.map +1 -1
  57. package/dist/internal/TransactableOps.d.ts +44 -1
  58. package/dist/internal/TransactableOps.d.ts.map +1 -1
  59. package/dist/internal/TransactableOps.js +52 -2
  60. package/dist/internal/TransactableOps.js.map +1 -1
  61. package/package.json +14 -3
@@ -0,0 +1,203 @@
1
+ /**
2
+ * A polled change feed: an Effect `Stream` over a DynamoDB stream's records,
3
+ * for consumers outside Lambda and EventBridge Pipes (#156). See
4
+ * `docs/designs/change-feed.md`.
5
+ *
6
+ * @module
7
+ */
8
+ import type { _Record } from "@aws-sdk/client-dynamodb-streams";
9
+ import type { StreamRecordIdentifierMissing } from "@effect-dynamodb/schema/Errors.js";
10
+ import { Duration, Effect, Stream } from "effect";
11
+ import { type AnyEventProjection, type BatchItemFailuresResponse, type DecodableStream, type ProcessBatchesResult, type ProcessBatchOptions, type ProjectionRequirementsOf } from "../internal/EventProjection.js";
12
+ import { CheckpointStore } from "./CheckpointStore.js";
13
+ import { DynamoStreamsClient, type DynamoStreamsClientError } from "./DynamoStreamsClient.js";
14
+ import { type ChangeFeedLeaseHeld, ChangeFeedLeaseLost, ChangeFeedTrimmed, type CheckpointStoreError, type ShardIteratorExpired, type StreamDataTrimmed } from "./Errors.js";
15
+ /**
16
+ * A change-feed record: the SDK's `GetRecords` record, shaped like the record a
17
+ * Lambda event source mapping delivers (`eventID`, `eventName`,
18
+ * `dynamodb.SequenceNumber`, `dynamodb.NewImage` as DynamoDB JSON with `B` as
19
+ * bytes) — so `EventStore.processBatch` and the stream decoders take it as is.
20
+ */
21
+ export type ChangeFeedRecord = _Record;
22
+ /**
23
+ * One shard's records, in sequence order, read by one `GetRecords`. The shard
24
+ * is not read again until the batch is acknowledged with {@link
25
+ * ChangeFeedBatch.commit} or {@link ChangeFeedBatch.complete} — so a shard's
26
+ * batches are processed in order, and a consumer that never acknowledges a
27
+ * batch stalls its shard.
28
+ */
29
+ export interface ChangeFeedBatch {
30
+ readonly streamArn: string;
31
+ readonly shardId: string;
32
+ /** Non-empty, in sequence order. */
33
+ readonly records: ReadonlyArray<ChangeFeedRecord>;
34
+ readonly firstSequenceNumber: string;
35
+ readonly lastSequenceNumber: string;
36
+ /**
37
+ * Acknowledge every record: commit the shard's checkpoint at
38
+ * `lastSequenceNumber`, and let the shard read on. Only the first
39
+ * acknowledgement that commits counts; one whose write failed can be
40
+ * retried (the shard waits meanwhile). Fails with `ChangeFeedLeaseLost`,
41
+ * writing nothing, once the feed has lost its lease.
42
+ */
43
+ readonly commit: () => Effect.Effect<void, CheckpointStoreError | ChangeFeedLeaseLost>;
44
+ /**
45
+ * Acknowledge per a partial batch response whose identifiers are
46
+ * `SequenceNumber`s (`source: "lambda"`): with no failures, {@link commit};
47
+ * otherwise commit the checkpoint at the record before the earliest failed
48
+ * one (none when that is the first record), and read the shard again from
49
+ * the failed record after a backoff. An identifier that names no record of
50
+ * the batch fails the whole batch, as Lambda does.
51
+ */
52
+ readonly complete: (response: BatchItemFailuresResponse) => Effect.Effect<void, CheckpointStoreError | ChangeFeedLeaseLost>;
53
+ }
54
+ /** Where a shard without a checkpoint starts, at a consumer's first start. */
55
+ export type StartingPosition = "TRIM_HORIZON" | "LATEST";
56
+ /** The feed's lease — see {@link ChangeFeedOptions.lease}. */
57
+ export interface ChangeFeedLeaseOptions {
58
+ /** How long a lease lasts unless renewed. Default 30 s. */
59
+ readonly duration?: Duration.Input | undefined;
60
+ /**
61
+ * How often the holder renews it. Default a third of `duration`. Must be
62
+ * less than half of `duration` (`[EDD-9083]` otherwise): a renewal the store
63
+ * fails to write is retried until `renewEvery` before the lease would lapse,
64
+ * which leaves `duration − 2 × renewEvery` to retry in.
65
+ */
66
+ readonly renewEvery?: Duration.Input | undefined;
67
+ /**
68
+ * A lease held by another process: `"fail"` with `ChangeFeedLeaseHeld`
69
+ * (default), or `"wait"` — try again every `renewEvery` until it is
70
+ * released or expires.
71
+ */
72
+ readonly onHeld?: "fail" | "wait" | undefined;
73
+ /** This process's owner id. Default: a random UUID. */
74
+ readonly owner?: string | undefined;
75
+ }
76
+ /** Options of {@link changeFeed}. */
77
+ export interface ChangeFeedOptions {
78
+ /** The stream to read (`TableDescription.LatestStreamArn`). */
79
+ readonly streamArn: string;
80
+ /**
81
+ * The application consuming the stream: checkpoints and the lease are kept
82
+ * per consumer, so several applications can read one stream with one
83
+ * checkpoint store. Default `"default"`.
84
+ */
85
+ readonly consumer?: string | undefined;
86
+ /**
87
+ * Where shards without a checkpoint start when the consumer has no
88
+ * checkpoints at all for the stream. `"TRIM_HORIZON"` (default): every
89
+ * record still retained. `"LATEST"`: the shards open now start after their
90
+ * latest record, and closed shards are checkpointed as finished unread.
91
+ * Every other shard without a checkpoint — a child found later, or any shard
92
+ * after a restart — starts at its trim horizon.
93
+ */
94
+ readonly startingPosition?: StartingPosition | undefined;
95
+ /** How long an idle shard waits between empty reads. Default 1 s. */
96
+ readonly pollInterval?: Duration.Input | undefined;
97
+ /** Records per batch (`GetRecords.Limit`, 1–1000). Default 100. */
98
+ readonly batchSize?: number | undefined;
99
+ /** How often the whole stream is described again for new shards. Default 30 s. */
100
+ readonly describeInterval?: Duration.Input | undefined;
101
+ /**
102
+ * How many shard reads (`GetShardIterator` / `GetRecords` calls) may be in
103
+ * flight at once, across all shards. Every shard keeps its own reader and
104
+ * takes turns, so a bound below the number of open shards slows reading
105
+ * rather than starving any shard. Default 16.
106
+ */
107
+ readonly maxConcurrentReads?: number | undefined;
108
+ /**
109
+ * Backoff for throttling and transient errors (retried without limit) and
110
+ * for re-reading a batch with failed records: jittered, exponential from
111
+ * `initial` (default 100 ms) up to `max` (default 10 s).
112
+ */
113
+ readonly backoff?: {
114
+ readonly initial?: Duration.Input | undefined;
115
+ readonly max?: Duration.Input | undefined;
116
+ } | undefined;
117
+ /**
118
+ * One lease per consumer and stream, held while the feed runs, so a second
119
+ * process can't consume the same feed by accident. `false` disables it.
120
+ * Default: enabled, with the defaults of {@link ChangeFeedLeaseOptions}.
121
+ */
122
+ readonly lease?: ChangeFeedLeaseOptions | false | undefined;
123
+ }
124
+ /** What a change feed fails with. */
125
+ export type ChangeFeedError = Exclude<DynamoStreamsClientError, ShardIteratorExpired | StreamDataTrimmed> | ChangeFeedTrimmed | ChangeFeedLeaseHeld | ChangeFeedLeaseLost | CheckpointStoreError;
126
+ /**
127
+ * A change feed over `options.streamArn`: a `Stream` of {@link ChangeFeedBatch}es.
128
+ *
129
+ * - **Shards** are found with `DescribeStream` (paginated), at start and every
130
+ * `describeInterval`; a drained shard's children are looked up with
131
+ * `ShardFilter` (`CHILD_SHARDS`), falling back to a full describe where the
132
+ * filter is unsupported (DynamoDB Local) or finds nothing yet.
133
+ * - **A parent shard is read to its end before its children**, so one item's
134
+ * records stay in order across a split. A closed shard is drained, its last
135
+ * batch acknowledged, checkpointed as finished, and dropped.
136
+ * - **Shards are read concurrently**, each in order with one batch in flight:
137
+ * a shard reads again only once its batch is acknowledged, so a slow
138
+ * consumer slows polling.
139
+ * `maxConcurrentReads` bounds the reads in flight across shards.
140
+ * - **Checkpoints** move only when a batch is acknowledged — at least once.
141
+ * A shard resumes after its checkpoint (`AFTER_SEQUENCE_NUMBER`). An expired
142
+ * iterator is re-acquired from the shard's position; a position past the
143
+ * stream's retention fails with `ChangeFeedTrimmed`.
144
+ * - **Throttling and transient errors** retry with jittered backoff. An idle
145
+ * shard polls every `pollInterval`.
146
+ * - **The lease** keeps a second process from consuming the same feed.
147
+ *
148
+ * The stream ends when the stream is disabled and every shard is drained;
149
+ * otherwise it runs until interrupted.
150
+ *
151
+ * Throws `[EDD-9083]` for options it can't honour: `lease.renewEvery` of half
152
+ * `lease.duration` or more, a `batchSize` outside 1–1000, a
153
+ * `maxConcurrentReads` that is not a positive integer.
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * const feed = changeFeed({ streamArn, startingPosition: "TRIM_HORIZON" })
158
+ * yield* feed.pipe(
159
+ * Stream.mapEffect((batch) => handle(batch.records).pipe(Effect.andThen(batch.commit()))),
160
+ * Stream.runDrain,
161
+ * )
162
+ * ```
163
+ */
164
+ export declare const changeFeed: (options: ChangeFeedOptions) => Stream.Stream<ChangeFeedBatch, ChangeFeedError, DynamoStreamsClient | CheckpointStore>;
165
+ /** Options of {@link runChangeFeed}. */
166
+ export type RunChangeFeedOptions<Projections extends {
167
+ readonly [name: string]: AnyEventProjection;
168
+ }, Streams extends {
169
+ readonly [name: string]: DecodableStream;
170
+ }, E2, R2> = ProcessBatchOptions<ChangeFeedRecord> & {
171
+ /** The projections to apply, as `EventStore.processBatch` takes them. */
172
+ readonly projections: Projections;
173
+ /** Streams to decode without a projection — their events come back as `unrouted`. */
174
+ readonly streams?: Streams | undefined;
175
+ /**
176
+ * Called with each batch and its result before the batch is acknowledged —
177
+ * to act on `applied` events or `unrouted` ones. Its failure ends the run
178
+ * before the acknowledgement, so the batch is read again on restart.
179
+ */
180
+ readonly onBatch?: ((batch: ChangeFeedBatch, result: ProcessBatchesResult<Projections, ChangeFeedRecord, Streams>) => Effect.Effect<void, E2, R2>) | undefined;
181
+ };
182
+ /**
183
+ * Run a change feed into projections: each batch goes through
184
+ * `EventStore.processBatch(batch.records, { projections, source: "lambda" })`,
185
+ * then `batch.complete(result.response)` — the checkpoint moves past the
186
+ * batch, or to the record before its earliest failed record, which the shard
187
+ * reads again. Batches of different shards are processed concurrently.
188
+ *
189
+ * Runs until the feed ends (its stream disabled and drained) or fails.
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * yield* runChangeFeed(changeFeed({ streamArn }), {
194
+ * projections: { summaries: OrderSummaryProjection },
195
+ * })
196
+ * ```
197
+ */
198
+ export declare const runChangeFeed: <const Projections extends {
199
+ readonly [name: string]: AnyEventProjection;
200
+ }, E, R, const Streams extends {
201
+ readonly [name: string]: DecodableStream;
202
+ } = {}, E2 = never, R2 = never>(feed: Stream.Stream<ChangeFeedBatch, E, R>, options: RunChangeFeedOptions<Projections, Streams, E2, R2>) => Effect.Effect<void, E | E2 | CheckpointStoreError | ChangeFeedLeaseLost | StreamRecordIdentifierMissing, R | R2 | ProjectionRequirementsOf<Projections[keyof Projections]>>;
203
+ //# sourceMappingURL=ChangeFeed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChangeFeed.d.ts","sourceRoot":"","sources":["../../src/change-feed/ChangeFeed.ts"],"names":[],"mappings":"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"}