effect-dynamodb 0.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/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/Aggregate.d.ts +210 -0
- package/dist/Aggregate.d.ts.map +1 -0
- package/dist/Aggregate.js +1169 -0
- package/dist/Aggregate.js.map +1 -0
- package/dist/Batch.d.ts +62 -0
- package/dist/Batch.d.ts.map +1 -0
- package/dist/Batch.js +218 -0
- package/dist/Batch.js.map +1 -0
- package/dist/Collection.d.ts +58 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Collection.js +195 -0
- package/dist/Collection.js.map +1 -0
- package/dist/Collections.d.ts +121 -0
- package/dist/Collections.d.ts.map +1 -0
- package/dist/Collections.js +121 -0
- package/dist/Collections.js.map +1 -0
- package/dist/DynamoClient.d.ts +317 -0
- package/dist/DynamoClient.d.ts.map +1 -0
- package/dist/DynamoClient.js +653 -0
- package/dist/DynamoClient.js.map +1 -0
- package/dist/DynamoModel.d.ts +278 -0
- package/dist/DynamoModel.d.ts.map +1 -0
- package/dist/DynamoModel.js +453 -0
- package/dist/DynamoModel.js.map +1 -0
- package/dist/DynamoSchema.d.ts +137 -0
- package/dist/DynamoSchema.d.ts.map +1 -0
- package/dist/DynamoSchema.js +188 -0
- package/dist/DynamoSchema.js.map +1 -0
- package/dist/Entity.d.ts +628 -0
- package/dist/Entity.d.ts.map +1 -0
- package/dist/Entity.js +2371 -0
- package/dist/Entity.js.map +1 -0
- package/dist/Errors.d.ts +227 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Errors.js +93 -0
- package/dist/Errors.js.map +1 -0
- package/dist/EventStore.d.ts +208 -0
- package/dist/EventStore.d.ts.map +1 -0
- package/dist/EventStore.js +333 -0
- package/dist/EventStore.js.map +1 -0
- package/dist/Expression.d.ts +50 -0
- package/dist/Expression.d.ts.map +1 -0
- package/dist/Expression.js +170 -0
- package/dist/Expression.js.map +1 -0
- package/dist/KeyComposer.d.ts +125 -0
- package/dist/KeyComposer.d.ts.map +1 -0
- package/dist/KeyComposer.js +257 -0
- package/dist/KeyComposer.js.map +1 -0
- package/dist/Marshaller.d.ts +30 -0
- package/dist/Marshaller.d.ts.map +1 -0
- package/dist/Marshaller.js +115 -0
- package/dist/Marshaller.js.map +1 -0
- package/dist/Projection.d.ts +28 -0
- package/dist/Projection.d.ts.map +1 -0
- package/dist/Projection.js +39 -0
- package/dist/Projection.js.map +1 -0
- package/dist/Query.d.ts +214 -0
- package/dist/Query.d.ts.map +1 -0
- package/dist/Query.js +397 -0
- package/dist/Query.js.map +1 -0
- package/dist/Table.d.ts +178 -0
- package/dist/Table.d.ts.map +1 -0
- package/dist/Table.js +211 -0
- package/dist/Table.js.map +1 -0
- package/dist/Transaction.d.ts +79 -0
- package/dist/Transaction.d.ts.map +1 -0
- package/dist/Transaction.js +215 -0
- package/dist/Transaction.js.map +1 -0
- package/dist/_AggregateCursor.d.ts +44 -0
- package/dist/_AggregateCursor.d.ts.map +1 -0
- package/dist/_AggregateCursor.js +18 -0
- package/dist/_AggregateCursor.js.map +1 -0
- package/dist/_AggregateEdges.d.ts +77 -0
- package/dist/_AggregateEdges.d.ts.map +1 -0
- package/dist/_AggregateEdges.js +41 -0
- package/dist/_AggregateEdges.js.map +1 -0
- package/dist/_AggregateSchemas.d.ts +69 -0
- package/dist/_AggregateSchemas.d.ts.map +1 -0
- package/dist/_AggregateSchemas.js +194 -0
- package/dist/_AggregateSchemas.js.map +1 -0
- package/dist/_AggregateTypes.d.ts +94 -0
- package/dist/_AggregateTypes.d.ts.map +1 -0
- package/dist/_AggregateTypes.js +7 -0
- package/dist/_AggregateTypes.js.map +1 -0
- package/dist/_EntityCombinators.d.ts +155 -0
- package/dist/_EntityCombinators.d.ts.map +1 -0
- package/dist/_EntityCombinators.js +158 -0
- package/dist/_EntityCombinators.js.map +1 -0
- package/dist/_EntityConfig.d.ts +100 -0
- package/dist/_EntityConfig.d.ts.map +1 -0
- package/dist/_EntityConfig.js +7 -0
- package/dist/_EntityConfig.js.map +1 -0
- package/dist/_EntityOps.d.ts +205 -0
- package/dist/_EntityOps.d.ts.map +1 -0
- package/dist/_EntityOps.js +137 -0
- package/dist/_EntityOps.js.map +1 -0
- package/dist/_EntitySchemas.d.ts +57 -0
- package/dist/_EntitySchemas.d.ts.map +1 -0
- package/dist/_EntitySchemas.js +298 -0
- package/dist/_EntitySchemas.js.map +1 -0
- package/dist/_EntityTypes.d.ts +81 -0
- package/dist/_EntityTypes.d.ts.map +1 -0
- package/dist/_EntityTypes.js +7 -0
- package/dist/_EntityTypes.js.map +1 -0
- package/dist/_sparse_check.d.ts +2 -0
- package/dist/_sparse_check.d.ts.map +1 -0
- package/dist/_sparse_check.js +193 -0
- package/dist/_sparse_check.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/AggregateCursor.d.ts +44 -0
- package/dist/internal/AggregateCursor.d.ts.map +1 -0
- package/dist/internal/AggregateCursor.js +18 -0
- package/dist/internal/AggregateCursor.js.map +1 -0
- package/dist/internal/AggregateEdges.d.ts +77 -0
- package/dist/internal/AggregateEdges.d.ts.map +1 -0
- package/dist/internal/AggregateEdges.js +41 -0
- package/dist/internal/AggregateEdges.js.map +1 -0
- package/dist/internal/AggregateSchemas.d.ts +69 -0
- package/dist/internal/AggregateSchemas.d.ts.map +1 -0
- package/dist/internal/AggregateSchemas.js +193 -0
- package/dist/internal/AggregateSchemas.js.map +1 -0
- package/dist/internal/AggregateTypes.d.ts +94 -0
- package/dist/internal/AggregateTypes.d.ts.map +1 -0
- package/dist/internal/AggregateTypes.js +7 -0
- package/dist/internal/AggregateTypes.js.map +1 -0
- package/dist/internal/BoundQuery.d.ts +107 -0
- package/dist/internal/BoundQuery.d.ts.map +1 -0
- package/dist/internal/BoundQuery.js +111 -0
- package/dist/internal/BoundQuery.js.map +1 -0
- package/dist/internal/EntityCombinators.d.ts +173 -0
- package/dist/internal/EntityCombinators.d.ts.map +1 -0
- package/dist/internal/EntityCombinators.js +183 -0
- package/dist/internal/EntityCombinators.js.map +1 -0
- package/dist/internal/EntityConfig.d.ts +100 -0
- package/dist/internal/EntityConfig.d.ts.map +1 -0
- package/dist/internal/EntityConfig.js +7 -0
- package/dist/internal/EntityConfig.js.map +1 -0
- package/dist/internal/EntityOps.d.ts +268 -0
- package/dist/internal/EntityOps.d.ts.map +1 -0
- package/dist/internal/EntityOps.js +153 -0
- package/dist/internal/EntityOps.js.map +1 -0
- package/dist/internal/EntitySchemas.d.ts +57 -0
- package/dist/internal/EntitySchemas.d.ts.map +1 -0
- package/dist/internal/EntitySchemas.js +299 -0
- package/dist/internal/EntitySchemas.js.map +1 -0
- package/dist/internal/EntityTypes.d.ts +128 -0
- package/dist/internal/EntityTypes.d.ts.map +1 -0
- package/dist/internal/EntityTypes.js +7 -0
- package/dist/internal/EntityTypes.js.map +1 -0
- package/dist/internal/Expr.d.ts +141 -0
- package/dist/internal/Expr.d.ts.map +1 -0
- package/dist/internal/Expr.js +332 -0
- package/dist/internal/Expr.js.map +1 -0
- package/dist/internal/PathBuilder.d.ts +88 -0
- package/dist/internal/PathBuilder.d.ts.map +1 -0
- package/dist/internal/PathBuilder.js +100 -0
- package/dist/internal/PathBuilder.js.map +1 -0
- package/dist/internal/TransactableOps.d.ts +25 -0
- package/dist/internal/TransactableOps.d.ts.map +1 -0
- package/dist/internal/TransactableOps.js +58 -0
- package/dist/internal/TransactableOps.js.map +1 -0
- package/dist/internal/sparse_check.d.ts +2 -0
- package/dist/internal/sparse_check.d.ts.map +1 -0
- package/dist/internal/sparse_check.js +196 -0
- package/dist/internal/sparse_check.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventStore — Typed, Effect-native event sourcing on DynamoDB.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `Decider` type for command-event-state modeling
|
|
6
|
+
* - `makeStream` factory for creating event streams bound to a Table
|
|
7
|
+
* - Core operations: `append`, `read`, `readFrom`, `currentVersion`
|
|
8
|
+
* - `commandHandler` combinator for read-decide-append cycle
|
|
9
|
+
* - `fold` / `foldFrom` helpers for state reconstruction
|
|
10
|
+
*
|
|
11
|
+
* Built on the existing library primitives (DynamoSchema, KeyComposer, Query,
|
|
12
|
+
* DynamoClient, Marshaller).
|
|
13
|
+
*/
|
|
14
|
+
import { Effect, Schema } from "effect";
|
|
15
|
+
import { DynamoClient, type DynamoClientError } from "./DynamoClient.js";
|
|
16
|
+
import { TransactionCancelled, ValidationError, VersionConflict } from "./Errors.js";
|
|
17
|
+
import * as Query from "./Query.js";
|
|
18
|
+
import type { Table, TableConfig } from "./Table.js";
|
|
19
|
+
/**
|
|
20
|
+
* A Decider encodes the command-event-state triad for an aggregate.
|
|
21
|
+
*
|
|
22
|
+
* - `decide` — given a command and current state, produce events (or fail with E)
|
|
23
|
+
* - `evolve` — pure left fold: apply one event to a state
|
|
24
|
+
* - `initialState` — starting state for a new aggregate
|
|
25
|
+
*/
|
|
26
|
+
export interface Decider<State, Command, Event, E = never> {
|
|
27
|
+
readonly decide: (command: Command, state: State) => Effect.Effect<ReadonlyArray<Event>, E>;
|
|
28
|
+
readonly evolve: (state: State, event: Event) => State;
|
|
29
|
+
readonly initialState: State;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A persisted event read from a stream, enriched with stream metadata.
|
|
33
|
+
*/
|
|
34
|
+
export interface StreamEvent<A> {
|
|
35
|
+
readonly streamId: string;
|
|
36
|
+
readonly version: number;
|
|
37
|
+
readonly eventType: string;
|
|
38
|
+
readonly data: A;
|
|
39
|
+
readonly metadata: Record<string, unknown> | undefined;
|
|
40
|
+
readonly timestamp: string;
|
|
41
|
+
}
|
|
42
|
+
/** Result of appending events to a stream. */
|
|
43
|
+
export interface AppendResult<A> {
|
|
44
|
+
readonly version: number;
|
|
45
|
+
readonly events: ReadonlyArray<A>;
|
|
46
|
+
}
|
|
47
|
+
/** Result of a command handler execution. */
|
|
48
|
+
export interface CommandHandlerResult<State, Event> extends AppendResult<Event> {
|
|
49
|
+
readonly state: State;
|
|
50
|
+
}
|
|
51
|
+
type StreamIdInput<T extends ReadonlyArray<string>> = {
|
|
52
|
+
readonly [K in T[number]]: string;
|
|
53
|
+
};
|
|
54
|
+
declare const EventStreamTypeId: unique symbol;
|
|
55
|
+
export type EventStreamTypeId = typeof EventStreamTypeId;
|
|
56
|
+
/**
|
|
57
|
+
* An EventStream is the repository for a named event stream.
|
|
58
|
+
*
|
|
59
|
+
* Created via {@link makeStream}. Operations are called directly on the stream:
|
|
60
|
+
* `MatchEvents.append(...)`, `MatchEvents.read(...)`, `MatchEvents.query.events(...)`.
|
|
61
|
+
*/
|
|
62
|
+
export interface EventStream<TEvent, TStreamIdFields extends ReadonlyArray<string>, TMetadata> {
|
|
63
|
+
readonly [EventStreamTypeId]: EventStreamTypeId;
|
|
64
|
+
readonly streamName: string;
|
|
65
|
+
readonly eventSchema: Schema.Top;
|
|
66
|
+
readonly append: (streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: {
|
|
67
|
+
readonly metadata?: TMetadata;
|
|
68
|
+
} | undefined) => Effect.Effect<AppendResult<TEvent>, VersionConflict | DynamoClientError | ValidationError | TransactionCancelled, DynamoClient | TableConfig>;
|
|
69
|
+
readonly read: (streamId: StreamIdInput<TStreamIdFields>) => Effect.Effect<ReadonlyArray<StreamEvent<TEvent>>, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
70
|
+
readonly readFrom: (streamId: StreamIdInput<TStreamIdFields>, afterVersion: number) => Effect.Effect<ReadonlyArray<StreamEvent<TEvent>>, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
71
|
+
readonly currentVersion: (streamId: StreamIdInput<TStreamIdFields>) => Effect.Effect<number, DynamoClientError | ValidationError, DynamoClient | TableConfig>;
|
|
72
|
+
readonly query: {
|
|
73
|
+
readonly events: (streamId: StreamIdInput<TStreamIdFields>) => Query.Query<StreamEvent<TEvent>>;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create an EventStream bound to a Table.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* class MatchStarted extends Schema.Class<MatchStarted>("MatchStarted")({
|
|
82
|
+
* venue: Schema.String,
|
|
83
|
+
* }) {}
|
|
84
|
+
*
|
|
85
|
+
* class InningsCompleted extends Schema.Class<InningsCompleted>("InningsCompleted")({
|
|
86
|
+
* innings: Schema.Number,
|
|
87
|
+
* runs: Schema.Number,
|
|
88
|
+
* }) {}
|
|
89
|
+
*
|
|
90
|
+
* const MatchEvents = EventStore.makeStream({
|
|
91
|
+
* table: EventsTable,
|
|
92
|
+
* streamName: "Match",
|
|
93
|
+
* events: [MatchStarted, InningsCompleted],
|
|
94
|
+
* streamId: { composite: ["matchId"] },
|
|
95
|
+
* })
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare const makeStream: <const TEvents extends ReadonlyArray<Schema.Top>, TTable extends Table, const TStreamName extends string, const TStreamId extends {
|
|
99
|
+
readonly composite: ReadonlyArray<string>;
|
|
100
|
+
}, TMetadata extends Schema.Top | undefined = undefined>(config: {
|
|
101
|
+
readonly table: TTable;
|
|
102
|
+
readonly streamName: TStreamName;
|
|
103
|
+
readonly events: TEvents;
|
|
104
|
+
readonly streamId: TStreamId;
|
|
105
|
+
readonly metadata?: TMetadata;
|
|
106
|
+
}) => EventStream<Schema.Schema.Type<TEvents[number]>, TStreamId["composite"], TMetadata extends Schema.Top ? Schema.Schema.Type<TMetadata> : undefined>;
|
|
107
|
+
/**
|
|
108
|
+
* An EventStream whose operations have `DynamoClient` and `TableConfig` already
|
|
109
|
+
* resolved, so all methods return `Effect<A, E, never>`.
|
|
110
|
+
*
|
|
111
|
+
* Created via {@link bind}. Use in service layers to avoid leaking infrastructure
|
|
112
|
+
* requirements through service method signatures.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* export class MatchEventService extends Context.Service<MatchEventService>()("MatchEventService", {
|
|
117
|
+
* make: Effect.gen(function* () {
|
|
118
|
+
* const stream = yield* EventStore.bind(MatchEvents)
|
|
119
|
+
* return {
|
|
120
|
+
* append: (matchId, events, version) => stream.append({ matchId }, events, version),
|
|
121
|
+
* read: (matchId) => stream.read({ matchId }),
|
|
122
|
+
* }
|
|
123
|
+
* }),
|
|
124
|
+
* }) {}
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export interface BoundEventStream<TEvent, TStreamIdFields extends ReadonlyArray<string>, TMetadata> {
|
|
128
|
+
readonly [EventStreamTypeId]: EventStreamTypeId;
|
|
129
|
+
readonly streamName: string;
|
|
130
|
+
readonly eventSchema: Schema.Top;
|
|
131
|
+
readonly append: (streamId: StreamIdInput<TStreamIdFields>, events: ReadonlyArray<TEvent>, expectedVersion: number, options?: {
|
|
132
|
+
readonly metadata?: TMetadata;
|
|
133
|
+
} | undefined) => Effect.Effect<AppendResult<TEvent>, VersionConflict | DynamoClientError | ValidationError | TransactionCancelled, never>;
|
|
134
|
+
readonly read: (streamId: StreamIdInput<TStreamIdFields>) => Effect.Effect<ReadonlyArray<StreamEvent<TEvent>>, DynamoClientError | ValidationError, never>;
|
|
135
|
+
readonly readFrom: (streamId: StreamIdInput<TStreamIdFields>, afterVersion: number) => Effect.Effect<ReadonlyArray<StreamEvent<TEvent>>, DynamoClientError | ValidationError, never>;
|
|
136
|
+
readonly currentVersion: (streamId: StreamIdInput<TStreamIdFields>) => Effect.Effect<number, DynamoClientError | ValidationError, never>;
|
|
137
|
+
readonly query: {
|
|
138
|
+
readonly events: (streamId: StreamIdInput<TStreamIdFields>) => Query.Query<StreamEvent<TEvent>>;
|
|
139
|
+
};
|
|
140
|
+
/** Escape hatch: provide DynamoClient | TableConfig to an arbitrary effect. */
|
|
141
|
+
readonly provide: <A, E>(effect: Effect.Effect<A, E, DynamoClient | TableConfig>) => Effect.Effect<A, E, never>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Bind an EventStream to resolved `DynamoClient` and `TableConfig` services.
|
|
145
|
+
* Returns a {@link BoundEventStream} where all operations have `R = never`.
|
|
146
|
+
*
|
|
147
|
+
* Use inside `Context.Service` make effects to prevent service methods
|
|
148
|
+
* from leaking infrastructure requirements.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const stream = yield* EventStore.bind(MatchEvents)
|
|
153
|
+
* const events = yield* stream.read({ matchId: "m-1" }) // R = never
|
|
154
|
+
* yield* stream.append({ matchId: "m-1" }, [event], 0) // R = never
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export declare const bind: <TEvent, TStreamIdFields extends ReadonlyArray<string>, TMetadata>(stream: EventStream<TEvent, TStreamIdFields, TMetadata>) => Effect.Effect<BoundEventStream<TEvent, TStreamIdFields, TMetadata>, never, DynamoClient | TableConfig>;
|
|
158
|
+
type CommandHandler<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata> = (streamId: StreamIdInput<TStreamIdFields>, command: Command, options?: {
|
|
159
|
+
readonly metadata?: TMetadata;
|
|
160
|
+
} | undefined) => Effect.Effect<CommandHandlerResult<State, TEvent>, E | VersionConflict | DynamoClientError | ValidationError | TransactionCancelled, DynamoClient | TableConfig>;
|
|
161
|
+
type BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata> = (streamId: StreamIdInput<TStreamIdFields>, command: Command, options?: {
|
|
162
|
+
readonly metadata?: TMetadata;
|
|
163
|
+
} | undefined) => Effect.Effect<CommandHandlerResult<State, TEvent>, E | VersionConflict | DynamoClientError | ValidationError | TransactionCancelled, never>;
|
|
164
|
+
/**
|
|
165
|
+
* Create a command handler that reads, decides, and appends atomically.
|
|
166
|
+
*
|
|
167
|
+
* Supports both data-first and data-last (pipeable) usage, and works with
|
|
168
|
+
* both `EventStream` (R = DynamoClient | TableConfig) and `BoundEventStream` (R = never).
|
|
169
|
+
*
|
|
170
|
+
* ```typescript
|
|
171
|
+
* // Data-first with EventStream
|
|
172
|
+
* const handle = EventStore.commandHandler(decider, stream)
|
|
173
|
+
*
|
|
174
|
+
* // Data-first with BoundEventStream
|
|
175
|
+
* const handle = EventStore.commandHandler(decider, boundStream)
|
|
176
|
+
*
|
|
177
|
+
* // Data-last (pipe)
|
|
178
|
+
* const handle = stream.pipe(EventStore.commandHandler(decider))
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare const commandHandler: {
|
|
182
|
+
<State, Command, TEvent, E>(decider: Decider<State, Command, TEvent, E>): {
|
|
183
|
+
<TStreamIdFields extends ReadonlyArray<string>, TMetadata>(stream: BoundEventStream<TEvent, TStreamIdFields, TMetadata>): BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata>;
|
|
184
|
+
<TStreamIdFields extends ReadonlyArray<string>, TMetadata>(stream: EventStream<TEvent, TStreamIdFields, TMetadata>): CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata>;
|
|
185
|
+
};
|
|
186
|
+
<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata>(decider: Decider<State, Command, TEvent, E>, stream: BoundEventStream<TEvent, TStreamIdFields, TMetadata>): BoundCommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata>;
|
|
187
|
+
<State, Command, TEvent, E, TStreamIdFields extends ReadonlyArray<string>, TMetadata>(decider: Decider<State, Command, TEvent, E>, stream: EventStream<TEvent, TStreamIdFields, TMetadata>): CommandHandler<State, Command, TEvent, E, TStreamIdFields, TMetadata>;
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Reconstruct state from events by folding through a decider's `evolve` function.
|
|
191
|
+
*
|
|
192
|
+
* Pure synchronous — no DynamoDB access.
|
|
193
|
+
*/
|
|
194
|
+
export declare const fold: {
|
|
195
|
+
<A>(events: ReadonlyArray<StreamEvent<A>>): <S, C, E>(decider: Decider<S, C, A, E>) => S;
|
|
196
|
+
<S, C, A, E>(decider: Decider<S, C, A, E>, events: ReadonlyArray<StreamEvent<A>>): S;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Fold from a starting state (e.g., snapshot + delta events).
|
|
200
|
+
*
|
|
201
|
+
* Pure synchronous — no DynamoDB access.
|
|
202
|
+
*/
|
|
203
|
+
export declare const foldFrom: {
|
|
204
|
+
<A>(startState: unknown, events: ReadonlyArray<StreamEvent<A>>): <S, C, E>(decider: Decider<S, C, A, E>) => S;
|
|
205
|
+
<S, C, A, E>(decider: Decider<S, C, A, E>, startState: S, events: ReadonlyArray<StreamEvent<A>>): S;
|
|
206
|
+
};
|
|
207
|
+
export {};
|
|
208
|
+
//# sourceMappingURL=EventStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventStore.d.ts","sourceRoot":"","sources":["../src/EventStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventStore — Typed, Effect-native event sourcing on DynamoDB.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `Decider` type for command-event-state modeling
|
|
6
|
+
* - `makeStream` factory for creating event streams bound to a Table
|
|
7
|
+
* - Core operations: `append`, `read`, `readFrom`, `currentVersion`
|
|
8
|
+
* - `commandHandler` combinator for read-decide-append cycle
|
|
9
|
+
* - `fold` / `foldFrom` helpers for state reconstruction
|
|
10
|
+
*
|
|
11
|
+
* Built on the existing library primitives (DynamoSchema, KeyComposer, Query,
|
|
12
|
+
* DynamoClient, Marshaller).
|
|
13
|
+
*/
|
|
14
|
+
import { Effect, Function, Schema } from "effect";
|
|
15
|
+
import { DynamoClient } from "./DynamoClient.js";
|
|
16
|
+
import * as DynamoSchema from "./DynamoSchema.js";
|
|
17
|
+
import { isAwsTransactionCancelled, TransactionCancelled, ValidationError, VersionConflict, } from "./Errors.js";
|
|
18
|
+
import * as KeyComposer from "./KeyComposer.js";
|
|
19
|
+
import { toAttributeMap } from "./Marshaller.js";
|
|
20
|
+
import * as Query from "./Query.js";
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// EventStreamTypeId
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const EventStreamTypeId = Symbol.for("effect-dynamodb/EventStream");
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// makeStream factory
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Create an EventStream bound to a Table.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* class MatchStarted extends Schema.Class<MatchStarted>("MatchStarted")({
|
|
34
|
+
* venue: Schema.String,
|
|
35
|
+
* }) {}
|
|
36
|
+
*
|
|
37
|
+
* class InningsCompleted extends Schema.Class<InningsCompleted>("InningsCompleted")({
|
|
38
|
+
* innings: Schema.Number,
|
|
39
|
+
* runs: Schema.Number,
|
|
40
|
+
* }) {}
|
|
41
|
+
*
|
|
42
|
+
* const MatchEvents = EventStore.makeStream({
|
|
43
|
+
* table: EventsTable,
|
|
44
|
+
* streamName: "Match",
|
|
45
|
+
* events: [MatchStarted, InningsCompleted],
|
|
46
|
+
* streamId: { composite: ["matchId"] },
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export const makeStream = (config) => {
|
|
51
|
+
const schema = config.table.schema;
|
|
52
|
+
const entityType = `${config.streamName.toLowerCase()}.event`;
|
|
53
|
+
const compositeFields = config.streamId.composite;
|
|
54
|
+
// Build union schema from event schemas for decoding
|
|
55
|
+
const eventUnion = config.events.length === 1
|
|
56
|
+
? config.events[0]
|
|
57
|
+
: Schema.Union(config.events);
|
|
58
|
+
// Metadata schema (optional)
|
|
59
|
+
const metadataSchema = config.metadata;
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Key helpers
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
const composeStreamPk = (streamId) => {
|
|
64
|
+
const composites = KeyComposer.extractComposites(compositeFields, streamId);
|
|
65
|
+
return DynamoSchema.composeKey(schema, config.streamName.toLowerCase(), composites);
|
|
66
|
+
};
|
|
67
|
+
const composeEventSk = (version) => DynamoSchema.composeEventVersionKey(schema, entityType, version);
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Decode a raw DynamoDB item → StreamEvent<TEvent>
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
const decodeStreamEvent = (raw) => Effect.gen(function* () {
|
|
72
|
+
const decoder = Schema.decodeUnknownEffect(eventUnion);
|
|
73
|
+
const data = yield* decoder(raw.data).pipe(Effect.mapError((cause) => new ValidationError({
|
|
74
|
+
entityType,
|
|
75
|
+
operation: "EventStore.decode",
|
|
76
|
+
cause,
|
|
77
|
+
})));
|
|
78
|
+
return {
|
|
79
|
+
streamId: raw.streamId,
|
|
80
|
+
version: raw.version,
|
|
81
|
+
eventType: raw.eventType,
|
|
82
|
+
data,
|
|
83
|
+
metadata: raw.metadata,
|
|
84
|
+
timestamp: raw.timestamp,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// append
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
const append = (streamId, events, expectedVersion, options) => Effect.gen(function* () {
|
|
91
|
+
if (events.length === 0) {
|
|
92
|
+
return { version: expectedVersion, events: [] };
|
|
93
|
+
}
|
|
94
|
+
const client = yield* DynamoClient;
|
|
95
|
+
const { name: tableName } = yield* config.table.Tag;
|
|
96
|
+
const pk = composeStreamPk(streamId);
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
// Resolve stream ID string for storage (join composites)
|
|
99
|
+
const streamIdStr = compositeFields
|
|
100
|
+
.map((f) => streamId[f])
|
|
101
|
+
.join("#");
|
|
102
|
+
// Validate and encode metadata if schema provided
|
|
103
|
+
let encodedMetadata;
|
|
104
|
+
if (options?.metadata !== undefined && metadataSchema) {
|
|
105
|
+
const validated = yield* Schema.decodeUnknownEffect(metadataSchema)(options.metadata).pipe(Effect.mapError((cause) => new ValidationError({
|
|
106
|
+
entityType,
|
|
107
|
+
operation: "EventStore.append.metadata",
|
|
108
|
+
cause,
|
|
109
|
+
})));
|
|
110
|
+
encodedMetadata = validated;
|
|
111
|
+
}
|
|
112
|
+
else if (options?.metadata !== undefined) {
|
|
113
|
+
encodedMetadata = options.metadata;
|
|
114
|
+
}
|
|
115
|
+
// Build transact items — one Put per event, each with attribute_not_exists(pk)
|
|
116
|
+
const transactItems = events.map((event, i) => {
|
|
117
|
+
const version = expectedVersion + i + 1;
|
|
118
|
+
// In Effect v4, Schema.Class instances don't have _tag as an own property.
|
|
119
|
+
// The identifier is on the constructor (class) itself.
|
|
120
|
+
const evtType = event._tag ??
|
|
121
|
+
event.constructor.identifier ??
|
|
122
|
+
event.constructor.name;
|
|
123
|
+
const eventData = { _tag: evtType, ...event };
|
|
124
|
+
const item = {
|
|
125
|
+
pk,
|
|
126
|
+
sk: composeEventSk(version),
|
|
127
|
+
__edd_e__: entityType,
|
|
128
|
+
streamId: streamIdStr,
|
|
129
|
+
version,
|
|
130
|
+
eventType: evtType,
|
|
131
|
+
data: eventData,
|
|
132
|
+
timestamp: now,
|
|
133
|
+
};
|
|
134
|
+
if (encodedMetadata !== undefined) {
|
|
135
|
+
item.metadata = encodedMetadata;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
Put: {
|
|
139
|
+
TableName: tableName,
|
|
140
|
+
Item: toAttributeMap(item),
|
|
141
|
+
ConditionExpression: "attribute_not_exists(pk)",
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
yield* client.transactWriteItems({ TransactItems: transactItems }).pipe(Effect.mapError((error) => {
|
|
146
|
+
if (isAwsTransactionCancelled(error.cause)) {
|
|
147
|
+
const reasons = (error.cause.CancellationReasons ?? []).map((r) => ({
|
|
148
|
+
code: r?.Code,
|
|
149
|
+
message: r?.Message,
|
|
150
|
+
}));
|
|
151
|
+
const hasConflict = reasons.some((r) => r.code === "ConditionalCheckFailed");
|
|
152
|
+
if (hasConflict) {
|
|
153
|
+
return new VersionConflict({
|
|
154
|
+
streamName: config.streamName,
|
|
155
|
+
streamId: streamIdStr,
|
|
156
|
+
expectedVersion,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return new TransactionCancelled({
|
|
160
|
+
operation: "TransactWriteItems",
|
|
161
|
+
reasons,
|
|
162
|
+
cause: error.cause,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return error;
|
|
166
|
+
}));
|
|
167
|
+
return {
|
|
168
|
+
version: expectedVersion + events.length,
|
|
169
|
+
events,
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// read
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
const read = (streamId) => Effect.gen(function* () {
|
|
176
|
+
const query = buildEventsQuery(streamId);
|
|
177
|
+
return yield* Query.collect(query);
|
|
178
|
+
});
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// readFrom
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
const readFrom = (streamId, afterVersion) => Effect.gen(function* () {
|
|
183
|
+
const query = buildEventsQuery(streamId).pipe(Query.where({ gt: composeEventSk(afterVersion) }));
|
|
184
|
+
return yield* Query.collect(query);
|
|
185
|
+
});
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// currentVersion
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
const currentVersion = (streamId) => Effect.gen(function* () {
|
|
190
|
+
const query = buildEventsQuery(streamId).pipe(Query.reverse, Query.limit(1));
|
|
191
|
+
const results = yield* Query.collect(query);
|
|
192
|
+
if (results.length === 0)
|
|
193
|
+
return 0;
|
|
194
|
+
return results[0].version;
|
|
195
|
+
});
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
// query.events helper
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
const buildEventsQuery = (streamId) => {
|
|
200
|
+
const pk = composeStreamPk(streamId);
|
|
201
|
+
return Query.make({
|
|
202
|
+
tableName: "",
|
|
203
|
+
indexName: undefined,
|
|
204
|
+
pkField: "pk",
|
|
205
|
+
pkValue: pk,
|
|
206
|
+
skField: "sk",
|
|
207
|
+
entityTypes: [entityType],
|
|
208
|
+
decoder: (raw) => decodeStreamEvent(raw),
|
|
209
|
+
resolveTableName: config.table.Tag.useSync((tc) => tc.name),
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
const queryNamespace = {
|
|
213
|
+
events: (streamId) => buildEventsQuery(streamId),
|
|
214
|
+
};
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
// Return EventStream
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// Cast rationale: makeStream builds the stream object from closures that capture
|
|
219
|
+
// the generic config. The Table.Tag service has a dynamically-created tag whose R
|
|
220
|
+
// type parameter is opaque, causing Effect.gen to infer `unknown` for R. The cast
|
|
221
|
+
// is safe because all operations correctly require DynamoClient | TableConfig at
|
|
222
|
+
// runtime — the user must provide these layers.
|
|
223
|
+
return {
|
|
224
|
+
[EventStreamTypeId]: EventStreamTypeId,
|
|
225
|
+
streamName: config.streamName,
|
|
226
|
+
eventSchema: eventUnion,
|
|
227
|
+
append,
|
|
228
|
+
read,
|
|
229
|
+
readFrom,
|
|
230
|
+
currentVersion,
|
|
231
|
+
query: queryNamespace,
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// EventStore.bind — resolve services, return BoundEventStream with R = never
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
/**
|
|
238
|
+
* Bind an EventStream to resolved `DynamoClient` and `TableConfig` services.
|
|
239
|
+
* Returns a {@link BoundEventStream} where all operations have `R = never`.
|
|
240
|
+
*
|
|
241
|
+
* Use inside `Context.Service` make effects to prevent service methods
|
|
242
|
+
* from leaking infrastructure requirements.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const stream = yield* EventStore.bind(MatchEvents)
|
|
247
|
+
* const events = yield* stream.read({ matchId: "m-1" }) // R = never
|
|
248
|
+
* yield* stream.append({ matchId: "m-1" }, [event], 0) // R = never
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export const bind = (stream) => Effect.gen(function* () {
|
|
252
|
+
const ctx = yield* Effect.context();
|
|
253
|
+
const provide = (effect) => Effect.provide(effect, ctx);
|
|
254
|
+
return {
|
|
255
|
+
[EventStreamTypeId]: EventStreamTypeId,
|
|
256
|
+
streamName: stream.streamName,
|
|
257
|
+
eventSchema: stream.eventSchema,
|
|
258
|
+
append: (streamId, events, expectedVersion, options) => provide(stream.append(streamId, events, expectedVersion, options)),
|
|
259
|
+
read: (streamId) => provide(stream.read(streamId)),
|
|
260
|
+
readFrom: (streamId, afterVersion) => provide(stream.readFrom(streamId, afterVersion)),
|
|
261
|
+
currentVersion: (streamId) => provide(stream.currentVersion(streamId)),
|
|
262
|
+
query: stream.query,
|
|
263
|
+
provide,
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
/**
|
|
267
|
+
* Create a command handler that reads, decides, and appends atomically.
|
|
268
|
+
*
|
|
269
|
+
* Supports both data-first and data-last (pipeable) usage, and works with
|
|
270
|
+
* both `EventStream` (R = DynamoClient | TableConfig) and `BoundEventStream` (R = never).
|
|
271
|
+
*
|
|
272
|
+
* ```typescript
|
|
273
|
+
* // Data-first with EventStream
|
|
274
|
+
* const handle = EventStore.commandHandler(decider, stream)
|
|
275
|
+
*
|
|
276
|
+
* // Data-first with BoundEventStream
|
|
277
|
+
* const handle = EventStore.commandHandler(decider, boundStream)
|
|
278
|
+
*
|
|
279
|
+
* // Data-last (pipe)
|
|
280
|
+
* const handle = stream.pipe(EventStore.commandHandler(decider))
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
export const commandHandler = Function.dual(2, (decider, stream) => (streamId, command, options) => Effect.gen(function* () {
|
|
284
|
+
// 1. Read all events
|
|
285
|
+
const events = yield* stream.read(streamId);
|
|
286
|
+
// 2. Fold to current state
|
|
287
|
+
const curVersion = events.length > 0 ? events[events.length - 1].version : 0;
|
|
288
|
+
let state = decider.initialState;
|
|
289
|
+
for (const event of events) {
|
|
290
|
+
state = decider.evolve(state, event.data);
|
|
291
|
+
}
|
|
292
|
+
// 3. Decide
|
|
293
|
+
const newEvents = yield* decider.decide(command, state);
|
|
294
|
+
// 4. No-op command — return current state
|
|
295
|
+
if (newEvents.length === 0) {
|
|
296
|
+
return { state, version: curVersion, events: [] };
|
|
297
|
+
}
|
|
298
|
+
// 5. Append with optimistic concurrency
|
|
299
|
+
const result = yield* stream.append(streamId, newEvents, curVersion, options);
|
|
300
|
+
// 6. Evolve state through new events
|
|
301
|
+
for (const event of newEvents) {
|
|
302
|
+
state = decider.evolve(state, event);
|
|
303
|
+
}
|
|
304
|
+
return { state, version: result.version, events: newEvents };
|
|
305
|
+
}));
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
// fold helpers
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
/**
|
|
310
|
+
* Reconstruct state from events by folding through a decider's `evolve` function.
|
|
311
|
+
*
|
|
312
|
+
* Pure synchronous — no DynamoDB access.
|
|
313
|
+
*/
|
|
314
|
+
export const fold = Function.dual(2, (decider, events) => {
|
|
315
|
+
let state = decider.initialState;
|
|
316
|
+
for (const event of events) {
|
|
317
|
+
state = decider.evolve(state, event.data);
|
|
318
|
+
}
|
|
319
|
+
return state;
|
|
320
|
+
});
|
|
321
|
+
/**
|
|
322
|
+
* Fold from a starting state (e.g., snapshot + delta events).
|
|
323
|
+
*
|
|
324
|
+
* Pure synchronous — no DynamoDB access.
|
|
325
|
+
*/
|
|
326
|
+
export const foldFrom = Function.dual(3, (decider, startState, events) => {
|
|
327
|
+
let state = startState;
|
|
328
|
+
for (const event of events) {
|
|
329
|
+
state = decider.evolve(state, event.data);
|
|
330
|
+
}
|
|
331
|
+
return state;
|
|
332
|
+
});
|
|
333
|
+
//# sourceMappingURL=EventStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventStore.js","sourceRoot":"","sources":["../src/EventStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression — Type-safe builders for DynamoDB expressions.
|
|
3
|
+
*
|
|
4
|
+
* Produces expression strings with attribute name/value placeholders,
|
|
5
|
+
* matching the shape used by DynamoDB query/put/update/delete operations.
|
|
6
|
+
*
|
|
7
|
+
* Three builder types:
|
|
8
|
+
* - condition: For conditional puts/deletes (ConditionExpression)
|
|
9
|
+
* - filter: For query result filtering (FilterExpression)
|
|
10
|
+
* - update: For update operations (UpdateExpression)
|
|
11
|
+
*/
|
|
12
|
+
import type { AttributeValue } from "@aws-sdk/client-dynamodb";
|
|
13
|
+
export interface ExpressionResult {
|
|
14
|
+
readonly expression: string;
|
|
15
|
+
readonly names: Record<string, string>;
|
|
16
|
+
readonly values: Record<string, AttributeValue>;
|
|
17
|
+
}
|
|
18
|
+
export interface ConditionInput {
|
|
19
|
+
readonly eq?: Record<string, unknown> | undefined;
|
|
20
|
+
readonly ne?: Record<string, unknown> | undefined;
|
|
21
|
+
readonly lt?: Record<string, unknown> | undefined;
|
|
22
|
+
readonly le?: Record<string, unknown> | undefined;
|
|
23
|
+
readonly gt?: Record<string, unknown> | undefined;
|
|
24
|
+
readonly ge?: Record<string, unknown> | undefined;
|
|
25
|
+
readonly between?: Record<string, readonly [unknown, unknown]> | undefined;
|
|
26
|
+
readonly beginsWith?: Record<string, string> | undefined;
|
|
27
|
+
readonly attributeExists?: string | ReadonlyArray<string> | undefined;
|
|
28
|
+
readonly attributeNotExists?: string | ReadonlyArray<string> | undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build a ConditionExpression for conditional puts/deletes.
|
|
32
|
+
* All clauses are ANDed together.
|
|
33
|
+
*/
|
|
34
|
+
export declare const condition: (input: ConditionInput) => ExpressionResult;
|
|
35
|
+
/**
|
|
36
|
+
* Build a FilterExpression for query result filtering.
|
|
37
|
+
* Same syntax as condition expressions.
|
|
38
|
+
*/
|
|
39
|
+
export declare const filter: (input: ConditionInput) => ExpressionResult;
|
|
40
|
+
export interface UpdateInput {
|
|
41
|
+
readonly set?: Record<string, unknown> | undefined;
|
|
42
|
+
readonly remove?: ReadonlyArray<string> | undefined;
|
|
43
|
+
readonly add?: Record<string, number> | undefined;
|
|
44
|
+
readonly delete?: Record<string, unknown> | undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build an UpdateExpression with SET, REMOVE, ADD, DELETE clauses.
|
|
48
|
+
*/
|
|
49
|
+
export declare const update: (input: UpdateInput) => ExpressionResult;
|
|
50
|
+
//# sourceMappingURL=Expression.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Expression.d.ts","sourceRoot":"","sources":["../src/Expression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAK9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CAChD;AAID,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAA;IAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IACxD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;IACrE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;CACzE;AAsGD;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,cAAc,KAAG,gBAAyC,CAAA;AAE3F;;;GAGG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,cAAc,KAAG,gBAAyC,CAAA;AAIxF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;IACnD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;CACtD;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,WAAW,KAAG,gBA8D3C,CAAA"}
|