@arts-n-crafts/ts 3.13.1

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.
@@ -0,0 +1,420 @@
1
+ type WithIdentifier<T = object> = {
2
+ id: string;
3
+ } & T;
4
+
5
+ interface CommandMetadata {
6
+ correlationId?: string;
7
+ causationId?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ interface Command<TType = string, TPayload = unknown> extends WithIdentifier {
11
+ type: TType;
12
+ aggregateId: string;
13
+ payload: TPayload;
14
+ kind: 'command';
15
+ timestamp: string;
16
+ metadata: Partial<CommandMetadata>;
17
+ }
18
+
19
+ interface CommandHandler<CommandType extends Command, TReturnType = Promise<void>> {
20
+ execute(aCommand: CommandType): TReturnType;
21
+ }
22
+
23
+ interface IntegrationEventMetadata {
24
+ correlationId?: string;
25
+ causationId?: string;
26
+ [key: string]: unknown;
27
+ }
28
+ interface IntegrationEvent<TPayload = unknown> {
29
+ id: string;
30
+ type: string;
31
+ source: 'external';
32
+ payload: TPayload;
33
+ timestamp: string;
34
+ metadata: {} & Partial<IntegrationEventMetadata>;
35
+ }
36
+
37
+ interface DomainEventMetadata {
38
+ correlationId?: string;
39
+ causationId?: string;
40
+ [key: string]: unknown;
41
+ }
42
+ interface DomainEvent<TPayload = unknown> {
43
+ id: string;
44
+ type: string;
45
+ aggregateId: string;
46
+ source: 'internal';
47
+ payload: TPayload;
48
+ timestamp: string;
49
+ metadata: Partial<DomainEventMetadata>;
50
+ }
51
+
52
+ type BaseEvent<TPayload = unknown> = DomainEvent<TPayload> | IntegrationEvent<TPayload>;
53
+
54
+ interface Handling<TEvent extends BaseEvent, TReturnType> {
55
+ handle(anEvent: TEvent): TReturnType;
56
+ }
57
+ interface EventHandler<TEvent extends BaseEvent, TReturnType = Promise<void>> extends Handling<TEvent, TReturnType> {
58
+ }
59
+
60
+ type Module = Record<symbol, unknown>;
61
+
62
+ interface QueryMetadata {
63
+ [key: string]: unknown;
64
+ }
65
+ interface Query<TType = string, TPayload = unknown> extends WithIdentifier {
66
+ type: TType;
67
+ payload: TPayload;
68
+ kind: 'query';
69
+ timestamp: string;
70
+ metadata: Partial<QueryMetadata>;
71
+ }
72
+
73
+ interface QueryHandler<TQuery extends Query, TProjection = Promise<unknown>> {
74
+ execute(aQuery: TQuery): TProjection;
75
+ }
76
+
77
+ type FilledArray = [Record<string, unknown>, ...Record<string, unknown>[]];
78
+
79
+ type Maybe<T> = T | null | undefined;
80
+
81
+ type Nullable<T> = {
82
+ [P in keyof T]: T[P] | null;
83
+ };
84
+
85
+ type Primitive = string | number | boolean | bigint | symbol | null | undefined;
86
+
87
+ declare function createCommand<TType extends string, TPayload>(type: TType, aggregateId: string, payload: TPayload, metadata?: Partial<CommandMetadata>): Command<TType, TPayload>;
88
+
89
+ declare function createQuery<TType extends string, TPayload>(type: TType, payload: TPayload, metadata?: QueryMetadata): Query<TType, TPayload>;
90
+
91
+ declare function isCommand(candidate: unknown): candidate is Command<string, unknown>;
92
+
93
+ declare function isQuery(candidate: unknown): candidate is Query<unknown>;
94
+
95
+ interface Identifiable<TId> {
96
+ id: TId;
97
+ }
98
+ interface HasProperties<TProps extends object> {
99
+ props: TProps;
100
+ }
101
+ interface hasOutbox<TEvent extends DomainEvent> {
102
+ uncommittedEvents: TEvent[];
103
+ }
104
+ interface EventBased<TEvent extends DomainEvent> {
105
+ fromEvents(events: TEvent[]): void;
106
+ }
107
+ interface AggregateRoot<TId, TProps extends object, TEvent extends DomainEvent> extends Identifiable<TId>, HasProperties<TProps>, hasOutbox<TEvent> {
108
+ get id(): TId;
109
+ get props(): TProps;
110
+ get uncommittedEvents(): TEvent[];
111
+ }
112
+ interface EventBasedAggregateRoot<TId, TProps extends object, TEvent extends DomainEvent> extends AggregateRoot<TId, TProps, TEvent>, EventBased<TEvent> {
113
+ }
114
+
115
+ interface Decider<TState, TCommand, TEvent extends DomainEvent> {
116
+ decide(this: void, command: TCommand, currentState: TState): TEvent[];
117
+ evolve(this: void, currentState: TState, event: TEvent): TState;
118
+ initialState(this: void, id: string): TState;
119
+ }
120
+
121
+ interface Loadable$1<TReturnType> {
122
+ load(aggregateId: string): TReturnType;
123
+ }
124
+ interface Storable<TEvent, TReturnType = Promise<void>> {
125
+ store(events: TEvent[]): TReturnType;
126
+ }
127
+ interface Repository<TEvent, TLoadReturnType, TStoreReturnType = Promise<void>> extends Loadable$1<TLoadReturnType>, Storable<TEvent, TStoreReturnType> {
128
+ readonly streamName: string;
129
+ }
130
+
131
+ type QueryNode = {
132
+ type: 'eq' | 'gt' | 'lt';
133
+ field: string | number | symbol;
134
+ value: Primitive;
135
+ } | {
136
+ type: 'and' | 'or';
137
+ nodes: QueryNode[];
138
+ } | {
139
+ type: 'not';
140
+ node: QueryNode;
141
+ };
142
+
143
+ declare abstract class Specification<T> {
144
+ abstract isSatisfiedBy(entity: T): boolean;
145
+ abstract toQuery(): QueryNode;
146
+ and(other: Specification<T>): Specification<T>;
147
+ or(other: Specification<T>): Specification<T>;
148
+ not(): Specification<T>;
149
+ }
150
+ declare class AndSpecification<T> extends Specification<T> {
151
+ private left;
152
+ private right;
153
+ constructor(left: Specification<T>, right: Specification<T>);
154
+ isSatisfiedBy(entity: T): boolean;
155
+ toQuery(): QueryNode;
156
+ }
157
+ declare class OrSpecification<T> extends Specification<T> {
158
+ private left;
159
+ private right;
160
+ constructor(left: Specification<T>, right: Specification<T>);
161
+ isSatisfiedBy(entity: T): boolean;
162
+ toQuery(): QueryNode;
163
+ }
164
+ declare class NotSpecification<T> extends Specification<T> {
165
+ private spec;
166
+ constructor(spec: Specification<T>);
167
+ isSatisfiedBy(entity: T): boolean;
168
+ toQuery(): QueryNode;
169
+ }
170
+
171
+ declare class FieldEquals<T> extends Specification<T> {
172
+ private field;
173
+ private value;
174
+ constructor(field: keyof T, value: Primitive);
175
+ isSatisfiedBy(entity: T): boolean;
176
+ toQuery(): QueryNode;
177
+ }
178
+
179
+ declare class FieldGreaterThan<T> extends Specification<T> {
180
+ private field;
181
+ private value;
182
+ constructor(field: keyof T, value: number);
183
+ private isNumber;
184
+ isSatisfiedBy(entity: T): boolean;
185
+ toQuery(): QueryNode;
186
+ }
187
+
188
+ declare function createQueryNode(type: 'eq' | 'gt' | 'lt', field: string | number | symbol, value: Primitive): QueryNode;
189
+ declare function createQueryNode(type: 'and' | 'or', field: undefined, value: QueryNode[]): QueryNode;
190
+ declare function createQueryNode(type: 'not', field: undefined, value: QueryNode): QueryNode;
191
+
192
+ declare function createDomainEvent<TPayload = unknown>(type: string, aggregateId: string, payload: TPayload, metadata?: Partial<DomainEventMetadata>): DomainEvent<TPayload>;
193
+
194
+ declare function isDomainEvent(event: unknown): event is DomainEvent;
195
+
196
+ declare function isEvent(event: unknown): event is BaseEvent;
197
+
198
+ interface Registerable$1<TCommand extends Command, TResult = void> {
199
+ register(aTypeOfCommand: TCommand['type'], anHandler: CommandHandler<TCommand>): TResult;
200
+ }
201
+ interface Executable$2<TCommand extends Command, TResult = Promise<void>> {
202
+ execute(aCommand: TCommand): TResult;
203
+ }
204
+ interface CommandBus<TCommand extends Command, TExecutionResult = Promise<void>, TRegisterResult = void> extends Executable$2<TCommand, TExecutionResult>, Registerable$1<TCommand, TRegisterResult> {
205
+ }
206
+
207
+ declare class SimpleCommandBus<TCommand extends Command> implements CommandBus<TCommand> {
208
+ private handlers;
209
+ register(aTypeOfCommand: TCommand['type'], anHandler: CommandHandler<TCommand>): void;
210
+ execute(aCommand: TCommand): Promise<void>;
211
+ }
212
+
213
+ declare enum Operation {
214
+ CREATE = "CREATE",
215
+ PUT = "PUT",
216
+ PATCH = "PATCH",
217
+ DELETE = "DELETE"
218
+ }
219
+ interface Statement<TModel> {
220
+ operation: Operation;
221
+ payload: TModel;
222
+ }
223
+ interface CreateStatement<TModel> extends Statement<TModel> {
224
+ operation: Operation.CREATE;
225
+ payload: TModel;
226
+ }
227
+ interface PutStatement<TModel> extends Statement<TModel> {
228
+ operation: Operation.PUT;
229
+ payload: TModel;
230
+ }
231
+ interface PatchStatement<TModel> extends Statement<Partial<TModel>> {
232
+ operation: Operation.PATCH;
233
+ payload: WithIdentifier<Partial<TModel>>;
234
+ }
235
+ interface DeleteStatement extends Statement<WithIdentifier> {
236
+ operation: Operation.DELETE;
237
+ payload: WithIdentifier;
238
+ }
239
+ interface Executable$1<TModel, TReturnType = Promise<void>> {
240
+ execute(tableName: string, statement: CreateStatement<TModel>): TReturnType;
241
+ execute(tableName: string, statement: PutStatement<TModel>): TReturnType;
242
+ execute(tableName: string, statement: PatchStatement<TModel>): TReturnType;
243
+ execute(tableName: string, statement: DeleteStatement): TReturnType;
244
+ }
245
+ interface QueryAble<TModel, TReturnType = Promise<TModel[]>> {
246
+ query(collectionName: string, specification: Specification<TModel>): TReturnType;
247
+ }
248
+ interface Database<TModel, TExecuteReturnType = void, TQueryReturnType = Promise<TModel[]>> extends QueryAble<TModel, TQueryReturnType>, Executable$1<TModel, TExecuteReturnType> {
249
+ }
250
+
251
+ declare class SimpleDatabase<TModel extends WithIdentifier> implements Database<TModel, Promise<void>, Promise<TModel[]>> {
252
+ private readonly datasource;
253
+ private simulateOffline;
254
+ query(tableName: string, specification: Specification<TModel>): Promise<TModel[]>;
255
+ execute(tableName: string, statement: CreateStatement<TModel> | PutStatement<TModel> | PatchStatement<TModel> | DeleteStatement): Promise<void>;
256
+ goOffline(): void;
257
+ }
258
+
259
+ interface EventProducer<TEvent extends BaseEvent, TReturnType = Promise<void>> {
260
+ publish(stream: string, anEvent: TEvent): TReturnType;
261
+ }
262
+ interface EventConsumer<TEvent extends BaseEvent, TEventHandler = EventHandler<TEvent>, TConsumeReturnType = Promise<void>, TSubscribeReturnType = void> {
263
+ subscribe(stream: string, handler: TEventHandler): TSubscribeReturnType;
264
+ consume(stream: string, anEvent: TEvent): TConsumeReturnType;
265
+ }
266
+
267
+ declare class SimpleEventBus<TEvent extends BaseEvent> implements EventConsumer<TEvent>, EventProducer<TEvent> {
268
+ private handlers;
269
+ subscribe(stream: string, aHandler: EventHandler<TEvent>): void;
270
+ consume(stream: string, anEvent: TEvent): Promise<void>;
271
+ publish(stream: string, anEvent: TEvent): Promise<void>;
272
+ }
273
+
274
+ declare function createIntegrationEvent<TPayload = unknown>(type: string, payload: TPayload, metadata?: Partial<IntegrationEventMetadata>): IntegrationEvent<TPayload>;
275
+
276
+ declare function isIntegrationEvent<TPayload>(event: unknown): event is IntegrationEvent<TPayload>;
277
+
278
+ declare function fail(anExpression: Error): () => never;
279
+
280
+ declare function invariant(condition: boolean, onInvalid: () => never): asserts condition;
281
+
282
+ declare function isEqual<T>(a: T, b: T): boolean;
283
+
284
+ declare function parseAsError(value: unknown): Error;
285
+
286
+ type StreamKey = `${string}#${string}`;
287
+
288
+ declare function makeStreamKey(streamName: string, aggregateId: string): StreamKey;
289
+
290
+ interface StoredEvent<TEvent> {
291
+ id: string;
292
+ streamKey: StreamKey;
293
+ version: number;
294
+ createdAt: string;
295
+ event: TEvent;
296
+ }
297
+
298
+ interface Loadable<TEvent, TReturnType = Promise<StoredEvent<TEvent>>> {
299
+ load(streamName: string, aggregateId: string): TReturnType;
300
+ }
301
+ interface Appendable<TEvent, TReturnType = Promise<void>> {
302
+ append(streamName: string, events: TEvent[]): TReturnType;
303
+ }
304
+ interface EventStore<TEvent, TAppendReturnType = Promise<void>, TLoadReturnType = Promise<TEvent[]>> extends Loadable<TEvent, TLoadReturnType>, Appendable<TEvent, TAppendReturnType> {
305
+ }
306
+
307
+ interface OutboxEntry {
308
+ id: string;
309
+ event: DomainEvent;
310
+ published: boolean;
311
+ retryCount: number;
312
+ lastAttemptAt?: string;
313
+ }
314
+
315
+ interface Queueable<TReturnType = Promise<void>> {
316
+ enqueue(event: OutboxEntry['event']): TReturnType;
317
+ }
318
+ interface Outbox<TEnqueueReturnType = Promise<void>, TGetPendingReturnType = Promise<OutboxEntry[]>, TMarkAsPublishedReturnType = Promise<void>, TMarkAsFailedReturnType = Promise<void>> extends Queueable<TEnqueueReturnType> {
319
+ getPending(limit?: number): TGetPendingReturnType;
320
+ markAsPublished(id: string): TMarkAsPublishedReturnType;
321
+ markAsFailed(id: string): TMarkAsFailedReturnType;
322
+ }
323
+
324
+ declare class SimpleEventStore<TEvent extends DomainEvent> implements EventStore<TEvent, Promise<void>, Promise<TEvent[]>> {
325
+ private readonly database;
326
+ private readonly outbox?;
327
+ private readonly tableName;
328
+ constructor(database: Database<StoredEvent<TEvent>, Promise<void>, Promise<StoredEvent<TEvent>[]>>, outbox?: Outbox | undefined);
329
+ load(streamName: string, aggregateId: string): Promise<TEvent[]>;
330
+ append(streamName: string, events: TEvent[]): Promise<void>;
331
+ }
332
+
333
+ declare function createStoredEvent<TEvent extends DomainEvent>(streamName: string, version: number, event: TEvent): StoredEvent<TEvent>;
334
+
335
+ interface Runnable<TReturnType = Promise<void>> {
336
+ runOnce(): TReturnType;
337
+ }
338
+ interface Tickable<TReturnType = Promise<void>> {
339
+ tick(): TReturnType;
340
+ }
341
+ interface Startable<TReturnType = void> {
342
+ start(intervalMs: number): TReturnType;
343
+ }
344
+ interface OutboxWorker extends Runnable, Tickable, Startable {
345
+ }
346
+
347
+ declare class GenericOutboxWorker implements OutboxWorker {
348
+ protected outbox: Outbox;
349
+ protected eventBus: EventProducer<BaseEvent>;
350
+ protected stream: string;
351
+ constructor(outbox: Outbox, eventBus: EventProducer<BaseEvent>, stream: string);
352
+ runOnce(): Promise<void>;
353
+ tick(): Promise<void>;
354
+ start(intervalMs: number): void;
355
+ }
356
+
357
+ declare class InMemoryOutbox implements Outbox {
358
+ protected entries: OutboxEntry[];
359
+ protected idCounter: number;
360
+ enqueue(event: DomainEvent<unknown>): Promise<void>;
361
+ getPending(limit?: number): Promise<OutboxEntry[]>;
362
+ markAsPublished(id: string): Promise<void>;
363
+ markAsFailed(id: string): Promise<void>;
364
+ }
365
+
366
+ declare function createOutboxEntry(event: DomainEvent<unknown>): OutboxEntry;
367
+
368
+ interface Registerable<TQuery extends Query, TResult = void> {
369
+ register(aTypeOfQuery: TQuery['type'], anHandler: QueryHandler<TQuery>): TResult;
370
+ }
371
+ interface Executable<TQuery extends Query, TResult = Promise<unknown>> {
372
+ execute(aQuery: TQuery): TResult;
373
+ }
374
+ interface QueryBus<TQuery extends Query, TExecutionResult, TRegisterResult = void> extends Executable<TQuery, TExecutionResult>, Registerable<TQuery, TRegisterResult> {
375
+ }
376
+
377
+ declare class SimpleQueryBus<TQuery extends Query, TProjection> implements QueryBus<TQuery, Promise<TProjection>> {
378
+ private handlers;
379
+ register(aTypeOfQuery: TQuery['type'], anHandler: QueryHandler<TQuery, Promise<TProjection>>): void;
380
+ execute(aQuery: TQuery): Promise<TProjection>;
381
+ }
382
+
383
+ declare class SimpleRepository<TState, TCommand, TEvent extends DomainEvent> implements Repository<TEvent, Promise<TState>, Promise<void>> {
384
+ private readonly eventStore;
385
+ readonly streamName: string;
386
+ private readonly evolveFn;
387
+ private readonly initialState;
388
+ constructor(eventStore: EventStore<TEvent, Promise<void>, Promise<TEvent[]>>, streamName: string, evolveFn: Decider<TState, TCommand, TEvent>['evolve'], initialState: Decider<TState, TCommand, TEvent>['initialState']);
389
+ load(aggregateId: string): Promise<TState>;
390
+ store(events: TEvent[]): Promise<void>;
391
+ }
392
+
393
+ type GivenInput = (DomainEvent | IntegrationEvent)[];
394
+ type WhenInput = Command | Query | DomainEvent | IntegrationEvent;
395
+ type ThenInput = DomainEvent | Array<Record<string, unknown>>;
396
+ declare class ScenarioTest<TState, TEvent extends DomainEvent> {
397
+ private readonly streamName;
398
+ private readonly eventBus;
399
+ private readonly eventStore;
400
+ private readonly commandBus;
401
+ private readonly queryBus;
402
+ private readonly repository;
403
+ private readonly outboxWorker;
404
+ private givenInput;
405
+ private whenInput;
406
+ constructor(streamName: string, eventBus: EventProducer<BaseEvent> & EventConsumer<BaseEvent>, eventStore: EventStore<TEvent, Promise<void>, Promise<TEvent[]>>, commandBus: CommandBus<Command>, queryBus: QueryBus<Query, Promise<Record<string, unknown>[]>>, repository: Repository<DomainEvent, Promise<TState>>, outboxWorker: OutboxWorker);
407
+ given(...events: GivenInput): {
408
+ when(action: WhenInput): ReturnType<ScenarioTest<TState, TEvent>['when']>;
409
+ then(outcome: ThenInput): Promise<void>;
410
+ };
411
+ when(action: WhenInput): {
412
+ then(outcome: ThenInput): Promise<void>;
413
+ };
414
+ then(thenInput: ThenInput): Promise<void>;
415
+ private handleCommand;
416
+ private handleQuery;
417
+ private handleEvent;
418
+ }
419
+
420
+ export { type AggregateRoot, AndSpecification, type BaseEvent, type Command, type CommandBus, type CommandHandler, type CommandMetadata, type CreateStatement, type Database, type Decider, type DeleteStatement, type DomainEvent, type DomainEventMetadata, type EventBasedAggregateRoot, type EventConsumer, type EventHandler, type EventProducer, type EventStore, FieldEquals, FieldGreaterThan, type FilledArray, GenericOutboxWorker, InMemoryOutbox, type IntegrationEvent, type IntegrationEventMetadata, type Maybe, type Module, NotSpecification, type Nullable, Operation, OrSpecification, type Outbox, type OutboxEntry, type OutboxWorker, type PatchStatement, type Primitive, type PutStatement, type Query, type QueryBus, type QueryHandler, type QueryMetadata, type QueryNode, type Repository, ScenarioTest, SimpleCommandBus, SimpleDatabase, SimpleEventBus, SimpleEventStore, SimpleQueryBus, SimpleRepository, Specification, type StoredEvent, type StreamKey, type WithIdentifier, createCommand, createDomainEvent, createIntegrationEvent, createOutboxEntry, createQuery, createQueryNode, createStoredEvent, fail, invariant, isCommand, isDomainEvent, isEqual, isEvent, isIntegrationEvent, isQuery, makeStreamKey, parseAsError };