create-auto-app 0.1.4 → 0.1.6

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 (72) hide show
  1. package/dist/index.js +125 -111
  2. package/dist/index.js.map +1 -1
  3. package/package.json +2 -2
  4. package/templates/shopping-app/.context/auto-ia-scheme.json +8 -29
  5. package/templates/shopping-app/.context/design-system.md +59 -35
  6. package/templates/shopping-app/.context/figma-variables.json +335 -1024
  7. package/templates/shopping-app/.context/schema.json +3 -7
  8. package/templates/shopping-app/.context/shadcn-filter.ts +2 -4
  9. package/templates/shopping-app/auto.config.ts +2 -2
  10. package/templates/shopping-app/client/src/gql/fragment-masking.ts +22 -22
  11. package/templates/shopping-app/client/src/gql/gql.ts +12 -5
  12. package/templates/shopping-app/client/src/gql/graphql.ts +125 -11
  13. package/templates/shopping-app/client/src/gql/index.ts +2 -2
  14. package/templates/shopping-app/client/src/graphql/mutations.ts +9 -9
  15. package/templates/shopping-app/client/src/graphql/queries.ts +10 -10
  16. package/templates/shopping-app/flows/shopping-assistant.flow.ts +2 -2
  17. package/templates/shopping-app/package.json +1 -1
  18. package/templates/shopping-app/pnpm-workspace.yaml +2 -2
  19. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/commands.ts +2 -2
  20. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.specs.ts +20 -20
  21. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.ts +8 -11
  22. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/events.ts +2 -2
  23. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/evolve.ts +3 -3
  24. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/handle.ts +8 -15
  25. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/mutation.resolver.ts +5 -9
  26. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/register.ts +4 -7
  27. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/react.specs.ts +19 -31
  28. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/react.ts +6 -12
  29. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/register.ts +4 -11
  30. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/commands.ts +2 -2
  31. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.specs.ts +14 -14
  32. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.ts +8 -11
  33. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/events.ts +2 -2
  34. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/evolve.ts +3 -3
  35. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/handle.ts +8 -15
  36. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/mutation.resolver.ts +5 -9
  37. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/register.ts +4 -7
  38. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/commands.ts +2 -2
  39. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/decide.specs.ts +23 -23
  40. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/decide.ts +9 -13
  41. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/events.ts +2 -2
  42. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/evolve.ts +3 -3
  43. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/handle.ts +11 -18
  44. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/mutation.resolver.ts +5 -9
  45. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/register.ts +4 -7
  46. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/projection.specs.ts +35 -35
  47. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/projection.ts +8 -11
  48. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/query.resolver.ts +4 -7
  49. package/templates/shopping-app/server/src/domain/shared/ReadModel.d.ts +7 -7
  50. package/templates/shopping-app/server/src/domain/shared/ReadModel.js +17 -17
  51. package/templates/shopping-app/server/src/domain/shared/index.d.ts +1 -1
  52. package/templates/shopping-app/server/src/domain/shared/index.js +1 -1
  53. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.d.ts +42 -21
  54. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.js +148 -140
  55. package/templates/shopping-app/server/src/domain/shared/sendCommand.d.ts +5 -2
  56. package/templates/shopping-app/server/src/domain/shared/sendCommand.js +14 -15
  57. package/templates/shopping-app/server/src/domain/shared/types.d.ts +10 -10
  58. package/templates/shopping-app/server/src/domain/shared/types.js +37 -36
  59. package/templates/shopping-app/server/src/integrations/ai-integration.ts +1 -1
  60. package/templates/shopping-app/server/src/integrations/cart-integration.ts +1 -1
  61. package/templates/shopping-app/server/src/integrations/index.ts +1 -1
  62. package/templates/shopping-app/server/src/integrations/product-catalogue-integration.ts +1 -1
  63. package/templates/shopping-app/server/src/utils/index.d.ts +1 -1
  64. package/templates/shopping-app/server/src/utils/index.js +1 -1
  65. package/templates/shopping-app/server/src/utils/loadProjections.d.ts +1 -1
  66. package/templates/shopping-app/server/src/utils/loadProjections.js +18 -16
  67. package/templates/shopping-app/server/src/utils/loadRegisterFiles.d.ts +2 -2
  68. package/templates/shopping-app/server/src/utils/loadRegisterFiles.js +19 -21
  69. package/templates/shopping-app/server/src/utils/loadResolvers.d.ts +2 -2
  70. package/templates/shopping-app/server/src/utils/loadResolvers.js +22 -22
  71. package/templates/shopping-app/server/tsconfig.json +2 -8
  72. package/templates/shopping-app/tsconfig.json +2 -8
@@ -1,53 +1,53 @@
1
- import { describe, it, beforeEach, expect } from "vitest";
2
- import { InMemoryProjectionSpec } from "@event-driven-io/emmett";
3
- import { projection } from "./projection";
4
- import type { ShoppingItemsSuggested } from "../selects-items-relevant-to-the-shopping-criteria-/events";
5
- import { SuggestedItems } from "./state";
1
+ import { describe, it, beforeEach, expect } from 'vitest';
2
+ import { InMemoryProjectionSpec } from '@event-driven-io/emmett';
3
+ import { projection } from './projection';
4
+ import type { ShoppingItemsSuggested } from '../selects-items-relevant-to-the-shopping-criteria-/events';
5
+ import { SuggestedItems } from './state';
6
6
 
7
7
  type ProjectionEvent = ShoppingItemsSuggested;
8
8
 
9
- describe("SuggestedItemsProjection Projection", () => {
9
+ describe('SuggestedItemsProjection Projection', () => {
10
10
  let given: InMemoryProjectionSpec<ProjectionEvent>;
11
11
 
12
12
  beforeEach(() => {
13
13
  given = InMemoryProjectionSpec.for({ projection });
14
14
  });
15
15
 
16
- it("creates or updates SuggestedItems document - case 1", () =>
16
+ it('creates or updates SuggestedItems document - case 1', () =>
17
17
  given([
18
18
  {
19
- type: "ShoppingItemsSuggested",
19
+ type: 'ShoppingItemsSuggested',
20
20
  data: {
21
- sessionId: "session-abc",
21
+ sessionId: 'session-abc',
22
22
  suggestedItems: [
23
23
  {
24
- productId: "prod-soccer-ball",
25
- name: "Super Soccer Ball",
24
+ productId: 'prod-soccer-ball',
25
+ name: 'Super Soccer Ball',
26
26
  quantity: 1,
27
- reason: "Perfect for your daughter who loves soccer",
27
+ reason: 'Perfect for your daughter who loves soccer',
28
28
  },
29
29
  {
30
- productId: "prod-craft-kit",
31
- name: "Deluxe Craft Kit",
30
+ productId: 'prod-craft-kit',
31
+ name: 'Deluxe Craft Kit',
32
32
  quantity: 1,
33
- reason: "Great for creative activities and crafts",
33
+ reason: 'Great for creative activities and crafts',
34
34
  },
35
35
  {
36
- productId: "prod-laptop-bag",
37
- name: "Tech Laptop Backpack",
36
+ productId: 'prod-laptop-bag',
37
+ name: 'Tech Laptop Backpack',
38
38
  quantity: 1,
39
39
  reason: "Essential for your son's school computer needs",
40
40
  },
41
41
  {
42
- productId: "prod-mtg-starter",
43
- name: "Magic the Gathering Starter Set",
42
+ productId: 'prod-mtg-starter',
43
+ name: 'Magic the Gathering Starter Set',
44
44
  quantity: 1,
45
- reason: "Ideal starter set for Magic the Gathering enthusiasts",
45
+ reason: 'Ideal starter set for Magic the Gathering enthusiasts',
46
46
  },
47
47
  ],
48
48
  },
49
49
  metadata: {
50
- streamName: "ignored-stream",
50
+ streamName: 'ignored-stream',
51
51
  streamPosition: 1n,
52
52
  globalPosition: 1n,
53
53
  },
@@ -56,35 +56,35 @@ describe("SuggestedItemsProjection Projection", () => {
56
56
  .when([])
57
57
  .then(async (state) => {
58
58
  const document = await state.database
59
- .collection<SuggestedItems>("SuggestedItemsProjection")
60
- .findOne((doc) => doc.sessionId === "session-abc");
59
+ .collection<SuggestedItems>('SuggestedItemsProjection')
60
+ .findOne((doc) => doc.sessionId === 'session-abc');
61
61
 
62
62
  const expected: SuggestedItems = {
63
- sessionId: "session-abc",
63
+ sessionId: 'session-abc',
64
64
  items: [
65
65
  {
66
- productId: "prod-soccer-ball",
67
- name: "Super Soccer Ball",
66
+ productId: 'prod-soccer-ball',
67
+ name: 'Super Soccer Ball',
68
68
  quantity: 1,
69
- reason: "Perfect for your daughter who loves soccer",
69
+ reason: 'Perfect for your daughter who loves soccer',
70
70
  },
71
71
  {
72
- productId: "prod-craft-kit",
73
- name: "Deluxe Craft Kit",
72
+ productId: 'prod-craft-kit',
73
+ name: 'Deluxe Craft Kit',
74
74
  quantity: 1,
75
- reason: "Great for creative activities and crafts",
75
+ reason: 'Great for creative activities and crafts',
76
76
  },
77
77
  {
78
- productId: "prod-laptop-bag",
79
- name: "Tech Laptop Backpack",
78
+ productId: 'prod-laptop-bag',
79
+ name: 'Tech Laptop Backpack',
80
80
  quantity: 1,
81
81
  reason: "Essential for your son's school computer needs",
82
82
  },
83
83
  {
84
- productId: "prod-mtg-starter",
85
- name: "Magic the Gathering Starter Set",
84
+ productId: 'prod-mtg-starter',
85
+ name: 'Magic the Gathering Starter Set',
86
86
  quantity: 1,
87
- reason: "Ideal starter set for Magic the Gathering enthusiasts",
87
+ reason: 'Ideal starter set for Magic the Gathering enthusiasts',
88
88
  },
89
89
  ],
90
90
  };
@@ -2,32 +2,29 @@ import {
2
2
  inMemorySingleStreamProjection,
3
3
  type ReadEvent,
4
4
  type InMemoryReadEventMetadata,
5
- } from "@event-driven-io/emmett";
6
- import type { SuggestedItems } from "./state";
7
- import type { ShoppingItemsSuggested } from "../selects-items-relevant-to-the-shopping-criteria-/events";
5
+ } from '@event-driven-io/emmett';
6
+ import type { SuggestedItems } from './state';
7
+ import type { ShoppingItemsSuggested } from '../selects-items-relevant-to-the-shopping-criteria-/events';
8
8
 
9
9
  type AllEvents = ShoppingItemsSuggested;
10
10
 
11
- export const projection = inMemorySingleStreamProjection<
12
- SuggestedItems,
13
- AllEvents
14
- >({
15
- collectionName: "SuggestedItemsProjection",
16
- canHandle: ["ShoppingItemsSuggested"],
11
+ export const projection = inMemorySingleStreamProjection<SuggestedItems, AllEvents>({
12
+ collectionName: 'SuggestedItemsProjection',
13
+ canHandle: ['ShoppingItemsSuggested'],
17
14
  getDocumentId: (event) => event.data.sessionId,
18
15
  evolve: (
19
16
  document: SuggestedItems | null,
20
17
  event: ReadEvent<AllEvents, InMemoryReadEventMetadata>,
21
18
  ): SuggestedItems | null => {
22
19
  switch (event.type) {
23
- case "ShoppingItemsSuggested": {
20
+ case 'ShoppingItemsSuggested': {
24
21
  /**
25
22
  * ## IMPLEMENTATION INSTRUCTIONS ##
26
23
  * This event adds or updates the document.
27
24
  * Implement the correct fields as needed for your read model.
28
25
  */
29
26
  return {
30
- sessionId: /* TODO: map from event.data */ "",
27
+ sessionId: /* TODO: map from event.data */ '',
31
28
  items: /* TODO: map from event.data */ [],
32
29
  };
33
30
  }
@@ -1,5 +1,5 @@
1
- import { Query, Resolver, Arg, Ctx, ObjectType, Field, ID } from "type-graphql";
2
- import { type GraphQLContext, ReadModel } from "../../../shared";
1
+ import { Query, Resolver, Arg, Ctx, ObjectType, Field, ID } from 'type-graphql';
2
+ import { type GraphQLContext, ReadModel } from '../../../shared';
3
3
 
4
4
  @ObjectType()
5
5
  export class SuggestedItems {
@@ -32,12 +32,9 @@ export class ViewsSuggestedItemsQueryResolver {
32
32
  @Query(() => [SuggestedItems])
33
33
  async suggestedItems(
34
34
  @Ctx() ctx: GraphQLContext,
35
- @Arg("sessionId", () => ID, { nullable: true }) sessionId?: string,
35
+ @Arg('sessionId', () => ID, { nullable: true }) sessionId?: string,
36
36
  ): Promise<SuggestedItems[]> {
37
- const model = new ReadModel<SuggestedItems>(
38
- ctx.eventStore,
39
- "SuggestedItemsProjection",
40
- );
37
+ const model = new ReadModel<SuggestedItems>(ctx.eventStore, 'SuggestedItemsProjection');
41
38
 
42
39
  // ## IMPLEMENTATION INSTRUCTIONS ##
43
40
  // You can query the projection using the ReadModel API:
@@ -1,10 +1,10 @@
1
1
  import type { InMemoryEventStore } from '@event-driven-io/emmett';
2
2
  export declare class ReadModel<T extends Record<string, unknown>> {
3
- private collection;
4
- constructor(eventStore: InMemoryEventStore, collectionName: string);
5
- getAll(): Promise<T[]>;
6
- getById(id: string, idField?: keyof T): Promise<T | null>;
7
- find(filterFn: (item: T) => boolean): Promise<T[]>;
8
- first(filterFn: (item: T) => boolean): Promise<T | null>;
3
+ private collection;
4
+ constructor(eventStore: InMemoryEventStore, collectionName: string);
5
+ getAll(): Promise<T[]>;
6
+ getById(id: string, idField?: keyof T): Promise<T | null>;
7
+ find(filterFn: (item: T) => boolean): Promise<T[]>;
8
+ first(filterFn: (item: T) => boolean): Promise<T | null>;
9
9
  }
10
- //# sourceMappingURL=ReadModel.d.ts.map
10
+ //# sourceMappingURL=ReadModel.d.ts.map
@@ -1,19 +1,19 @@
1
1
  export class ReadModel {
2
- constructor(eventStore, collectionName) {
3
- this.collection = eventStore.database.collection(collectionName);
4
- }
5
- async getAll() {
6
- return this.collection.find();
7
- }
8
- async getById(id, idField = 'id') {
9
- return this.collection.findOne((doc) => doc[idField] === id);
10
- }
11
- async find(filterFn) {
12
- return this.collection.find(filterFn);
13
- }
14
- async first(filterFn) {
15
- const all = await this.collection.find(filterFn);
16
- return all[0] ?? null;
17
- }
2
+ constructor(eventStore, collectionName) {
3
+ this.collection = eventStore.database.collection(collectionName);
4
+ }
5
+ async getAll() {
6
+ return this.collection.find();
7
+ }
8
+ async getById(id, idField = 'id') {
9
+ return this.collection.findOne((doc) => doc[idField] === id);
10
+ }
11
+ async find(filterFn) {
12
+ return this.collection.find(filterFn);
13
+ }
14
+ async first(filterFn) {
15
+ const all = await this.collection.find(filterFn);
16
+ return all[0] ?? null;
17
+ }
18
18
  }
19
- //# sourceMappingURL=ReadModel.js.map
19
+ //# sourceMappingURL=ReadModel.js.map
@@ -2,4 +2,4 @@ export * from './types';
2
2
  export * from './ReadModel';
3
3
  export * from './reactorSpecification';
4
4
  export * from './sendCommand';
5
- //# sourceMappingURL=index.d.ts.map
5
+ //# sourceMappingURL=index.d.ts.map
@@ -2,4 +2,4 @@ export * from './types.js';
2
2
  export * from './ReadModel.js';
3
3
  export * from './reactorSpecification.js';
4
4
  export * from './sendCommand.js';
5
- //# sourceMappingURL=index.js.map
5
+ //# sourceMappingURL=index.js.map
@@ -1,35 +1,56 @@
1
1
  import { CommandSender, type ErrorConstructor, type MessageProcessor } from '@event-driven-io/emmett';
2
2
  interface CommandCheck<CommandType> {
3
- (command: CommandType): boolean;
3
+ (command: CommandType): boolean;
4
4
  }
5
5
  interface ErrorCheck<ErrorType> {
6
- (error: ErrorType): boolean;
6
+ (error: ErrorType): boolean;
7
7
  }
8
- export type ThenThrows<ErrorType extends Error> = (() => void) | ((errorConstructor: ErrorConstructor<ErrorType>) => void) | ((errorCheck: ErrorCheck<ErrorType>) => void) | ((errorConstructor: ErrorConstructor<ErrorType>, errorCheck?: ErrorCheck<ErrorType>) => void);
8
+ export type ThenThrows<ErrorType extends Error> =
9
+ | (() => void)
10
+ | ((errorConstructor: ErrorConstructor<ErrorType>) => void)
11
+ | ((errorCheck: ErrorCheck<ErrorType>) => void)
12
+ | ((errorConstructor: ErrorConstructor<ErrorType>, errorCheck?: ErrorCheck<ErrorType>) => void);
9
13
  interface ReactorSpecificationReturn<Event, Command, Context> {
10
- when: (event: Event | Event[], context?: Context) => {
11
- then: (expectedCommand: Command | Command[] | CommandCheck<Command> | CommandCheck<Command[]>) => Promise<void>;
12
- thenNothingHappened: () => Promise<void>;
13
- thenThrows: <ErrorType extends Error = Error>(...args: Parameters<ThenThrows<ErrorType>>) => Promise<void>;
14
- };
14
+ when: (
15
+ event: Event | Event[],
16
+ context?: Context,
17
+ ) => {
18
+ then: (expectedCommand: Command | Command[] | CommandCheck<Command> | CommandCheck<Command[]>) => Promise<void>;
19
+ thenNothingHappened: () => Promise<void>;
20
+ thenThrows: <ErrorType extends Error = Error>(...args: Parameters<ThenThrows<ErrorType>>) => Promise<void>;
21
+ };
15
22
  }
16
- export interface ReactorSpecification<Event, Command, Context extends {
23
+ export interface ReactorSpecification<
24
+ Event,
25
+ Command,
26
+ Context extends {
17
27
  commandSender: CommandSender;
18
- } = {
28
+ } = {
19
29
  commandSender: CommandSender;
20
- }> {
21
- (givenEvents: Event | Event[]): ReactorSpecificationReturn<Event, Command, Context>;
30
+ },
31
+ > {
32
+ (givenEvents: Event | Event[]): ReactorSpecificationReturn<Event, Command, Context>;
22
33
  }
23
34
  export declare const ReactorSpecification: {
24
- for: typeof reactorSpecificationFor;
35
+ for: typeof reactorSpecificationFor;
25
36
  };
26
- type ReactorLike<Event, Context> = {
27
- handle: (events: Event[], context: Context) => Promise<any>;
28
- } | {
29
- eachMessage: (event: Event, context: Context) => Promise<any>;
30
- } | MessageProcessor<any, any, any>;
31
- declare function reactorSpecificationFor<Event, Command, Context extends {
37
+ type ReactorLike<Event, Context> =
38
+ | {
39
+ handle: (events: Event[], context: Context) => Promise<any>;
40
+ }
41
+ | {
42
+ eachMessage: (event: Event, context: Context) => Promise<any>;
43
+ }
44
+ | MessageProcessor<any, any, any>;
45
+ declare function reactorSpecificationFor<
46
+ Event,
47
+ Command,
48
+ Context extends {
32
49
  commandSender: CommandSender;
33
- }>(processorOrReactor: ReactorLike<Event, Context> | (() => ReactorLike<Event, Context>), createContext: (commandSender: CommandSender) => Context): ReactorSpecification<Event, Command, Context>;
50
+ },
51
+ >(
52
+ processorOrReactor: ReactorLike<Event, Context> | (() => ReactorLike<Event, Context>),
53
+ createContext: (commandSender: CommandSender) => Context,
54
+ ): ReactorSpecification<Event, Command, Context>;
34
55
  export {};
35
- //# sourceMappingURL=reactorSpecification.d.ts.map
56
+ //# sourceMappingURL=reactorSpecification.d.ts.map
@@ -1,155 +1,163 @@
1
- import { isErrorConstructor, AssertionError, assertTrue, } from '@event-driven-io/emmett';
1
+ import { isErrorConstructor, AssertionError, assertTrue } from '@event-driven-io/emmett';
2
2
  export const ReactorSpecification = {
3
- for: reactorSpecificationFor,
3
+ for: reactorSpecificationFor,
4
4
  };
5
5
  function createMockCommandSender() {
6
- const sentCommands = [];
7
- const send = async (command) => {
8
- sentCommands.push(command);
9
- };
10
- return {
11
- send,
12
- sentCommands,
13
- reset: () => {
14
- sentCommands.length = 0;
15
- },
16
- };
6
+ const sentCommands = [];
7
+ const send = async (command) => {
8
+ sentCommands.push(command);
9
+ };
10
+ return {
11
+ send,
12
+ sentCommands,
13
+ reset: () => {
14
+ sentCommands.length = 0;
15
+ },
16
+ };
17
17
  }
18
18
  function reactorSpecificationFor(processorOrReactor, createContext) {
19
- return (givenEvents) => {
20
- return {
21
- when: (whenEvent, contextOverride) => {
22
- const mockCommandSender = createMockCommandSender();
23
- const defaultContext = createContext(mockCommandSender);
24
- const context = contextOverride || defaultContext;
25
- const handle = async () => {
26
- const givenArray = Array.isArray(givenEvents) ? givenEvents : givenEvents != null ? [givenEvents] : [];
27
- const whenArray = Array.isArray(whenEvent) ? whenEvent : [whenEvent];
28
- const allEvents = [...givenArray, ...whenArray];
29
- // Transform events to have metadata
30
- const eventsWithMetadata = allEvents.map((event, index) => ({
31
- ...event,
32
- kind: 'Event',
33
- metadata: {
34
- streamName: 'test-stream',
35
- messageId: `test-${index}`,
36
- streamPosition: BigInt(index + 1),
37
- globalPosition: BigInt(index + 1),
38
- },
39
- }));
40
- const contextWithMock = { ...context, commandSender: mockCommandSender };
41
- // Get the actual reactor instance
42
- const reactor = typeof processorOrReactor === 'function' ? processorOrReactor() : processorOrReactor;
43
- // Handle different reactor types
44
- if ('handle' in reactor && typeof reactor.handle === 'function') {
45
- // It's a MessageProcessor or has a handle method
46
- await reactor.handle(eventsWithMetadata, contextWithMock);
47
- }
48
- else if ('eachMessage' in reactor && typeof reactor.eachMessage === 'function') {
49
- // It has eachMessage
50
- for (const event of eventsWithMetadata) {
51
- await reactor.eachMessage(event, contextWithMock);
52
- }
53
- }
54
- else {
55
- throw new Error('Reactor must have either a handle or eachMessage method');
56
- }
57
- return mockCommandSender.sentCommands;
58
- };
59
- return {
60
- then: async (expectedCommand) => {
61
- try {
62
- const sentCommands = await handle();
63
- if (typeof expectedCommand === 'function') {
64
- const checkFn = expectedCommand;
65
- if (sentCommands.length === 1) {
66
- assertTrue(checkFn(sentCommands[0]), `Sent command did not match the expected condition: ${JSON.stringify(sentCommands[0])}`);
67
- }
68
- else {
69
- assertTrue(checkFn(sentCommands), `Sent commands did not match the expected condition: ${JSON.stringify(sentCommands)}`);
70
- }
71
- return;
72
- }
73
- if (Array.isArray(expectedCommand)) {
74
- assertTrue(sentCommands.length === expectedCommand.length, `Expected ${expectedCommand.length} command(s) to be sent, but ${sentCommands.length} were sent`);
75
- expectedCommand.forEach((expected, index) => {
76
- const sent = sentCommands[index];
77
- assertCommandsMatch(sent, expected, index);
78
- });
79
- return;
80
- }
81
- if (sentCommands.length === 0) {
82
- throw new AssertionError('No commands were sent');
83
- }
84
- if (sentCommands.length > 1) {
85
- throw new AssertionError(`Expected 1 command to be sent, but ${sentCommands.length} were sent`);
86
- }
87
- assertCommandsMatch(sentCommands[0], expectedCommand);
88
- }
89
- finally {
90
- mockCommandSender.reset();
91
- }
92
- },
93
- thenNothingHappened: async () => {
94
- try {
95
- const sentCommands = await handle();
96
- if (sentCommands.length > 0) {
97
- throw new AssertionError(`Expected no commands to be sent, but ${sentCommands.length} command(s) were sent: ${JSON.stringify(sentCommands)}`);
98
- }
99
- }
100
- finally {
101
- mockCommandSender.reset();
102
- }
103
- },
104
- thenThrows: async (...args) => {
105
- try {
106
- await handle();
107
- throw new AssertionError('Reactor did not fail as expected');
108
- }
109
- catch (error) {
110
- thenThrowsErrorHandler(error, args);
111
- }
112
- finally {
113
- mockCommandSender.reset();
114
- }
115
- },
116
- };
19
+ return (givenEvents) => {
20
+ return {
21
+ when: (whenEvent, contextOverride) => {
22
+ const mockCommandSender = createMockCommandSender();
23
+ const defaultContext = createContext(mockCommandSender);
24
+ const context = contextOverride || defaultContext;
25
+ const handle = async () => {
26
+ const givenArray = Array.isArray(givenEvents) ? givenEvents : givenEvents != null ? [givenEvents] : [];
27
+ const whenArray = Array.isArray(whenEvent) ? whenEvent : [whenEvent];
28
+ const allEvents = [...givenArray, ...whenArray];
29
+ // Transform events to have metadata
30
+ const eventsWithMetadata = allEvents.map((event, index) => ({
31
+ ...event,
32
+ kind: 'Event',
33
+ metadata: {
34
+ streamName: 'test-stream',
35
+ messageId: `test-${index}`,
36
+ streamPosition: BigInt(index + 1),
37
+ globalPosition: BigInt(index + 1),
117
38
  },
39
+ }));
40
+ const contextWithMock = { ...context, commandSender: mockCommandSender };
41
+ // Get the actual reactor instance
42
+ const reactor = typeof processorOrReactor === 'function' ? processorOrReactor() : processorOrReactor;
43
+ // Handle different reactor types
44
+ if ('handle' in reactor && typeof reactor.handle === 'function') {
45
+ // It's a MessageProcessor or has a handle method
46
+ await reactor.handle(eventsWithMetadata, contextWithMock);
47
+ } else if ('eachMessage' in reactor && typeof reactor.eachMessage === 'function') {
48
+ // It has eachMessage
49
+ for (const event of eventsWithMetadata) {
50
+ await reactor.eachMessage(event, contextWithMock);
51
+ }
52
+ } else {
53
+ throw new Error('Reactor must have either a handle or eachMessage method');
54
+ }
55
+ return mockCommandSender.sentCommands;
118
56
  };
57
+ return {
58
+ then: async (expectedCommand) => {
59
+ try {
60
+ const sentCommands = await handle();
61
+ if (typeof expectedCommand === 'function') {
62
+ const checkFn = expectedCommand;
63
+ if (sentCommands.length === 1) {
64
+ assertTrue(
65
+ checkFn(sentCommands[0]),
66
+ `Sent command did not match the expected condition: ${JSON.stringify(sentCommands[0])}`,
67
+ );
68
+ } else {
69
+ assertTrue(
70
+ checkFn(sentCommands),
71
+ `Sent commands did not match the expected condition: ${JSON.stringify(sentCommands)}`,
72
+ );
73
+ }
74
+ return;
75
+ }
76
+ if (Array.isArray(expectedCommand)) {
77
+ assertTrue(
78
+ sentCommands.length === expectedCommand.length,
79
+ `Expected ${expectedCommand.length} command(s) to be sent, but ${sentCommands.length} were sent`,
80
+ );
81
+ expectedCommand.forEach((expected, index) => {
82
+ const sent = sentCommands[index];
83
+ assertCommandsMatch(sent, expected, index);
84
+ });
85
+ return;
86
+ }
87
+ if (sentCommands.length === 0) {
88
+ throw new AssertionError('No commands were sent');
89
+ }
90
+ if (sentCommands.length > 1) {
91
+ throw new AssertionError(`Expected 1 command to be sent, but ${sentCommands.length} were sent`);
92
+ }
93
+ assertCommandsMatch(sentCommands[0], expectedCommand);
94
+ } finally {
95
+ mockCommandSender.reset();
96
+ }
97
+ },
98
+ thenNothingHappened: async () => {
99
+ try {
100
+ const sentCommands = await handle();
101
+ if (sentCommands.length > 0) {
102
+ throw new AssertionError(
103
+ `Expected no commands to be sent, but ${sentCommands.length} command(s) were sent: ${JSON.stringify(sentCommands)}`,
104
+ );
105
+ }
106
+ } finally {
107
+ mockCommandSender.reset();
108
+ }
109
+ },
110
+ thenThrows: async (...args) => {
111
+ try {
112
+ await handle();
113
+ throw new AssertionError('Reactor did not fail as expected');
114
+ } catch (error) {
115
+ thenThrowsErrorHandler(error, args);
116
+ } finally {
117
+ mockCommandSender.reset();
118
+ }
119
+ },
120
+ };
121
+ },
119
122
  };
123
+ };
120
124
  }
121
125
  // eslint-disable-next-line complexity
122
126
  function assertCommandsMatch(actual, expected, index) {
123
- const actualCopy = { ...actual };
124
- const expectedCopy = { ...expected };
125
- if (actualCopy.metadata !== undefined && expectedCopy.metadata !== undefined) {
126
- for (const key in expectedCopy.metadata) {
127
- const expectedValue = expectedCopy.metadata[key];
128
- const actualValue = actualCopy.metadata[key];
129
- const expectedStr = expectedValue === undefined ? 'undefined' : expectedValue === null ? 'null' : String(expectedValue);
130
- const actualStr = actualValue === undefined ? 'undefined' : actualValue === null ? 'null' : String(actualValue);
131
- assertTrue(actualValue === expectedValue, `Command${index !== undefined ? ` at index ${index}` : ''} metadata.${key} does not match.\nExpected: ${expectedStr}\nActual: ${actualStr}`);
132
- }
133
- delete actualCopy.metadata;
134
- delete expectedCopy.metadata;
135
- }
136
- else if (actualCopy.metadata !== undefined && expectedCopy.metadata === undefined) {
137
- delete actualCopy.metadata;
127
+ const actualCopy = { ...actual };
128
+ const expectedCopy = { ...expected };
129
+ if (actualCopy.metadata !== undefined && expectedCopy.metadata !== undefined) {
130
+ for (const key in expectedCopy.metadata) {
131
+ const expectedValue = expectedCopy.metadata[key];
132
+ const actualValue = actualCopy.metadata[key];
133
+ const expectedStr =
134
+ expectedValue === undefined ? 'undefined' : expectedValue === null ? 'null' : String(expectedValue);
135
+ const actualStr = actualValue === undefined ? 'undefined' : actualValue === null ? 'null' : String(actualValue);
136
+ assertTrue(
137
+ actualValue === expectedValue,
138
+ `Command${index !== undefined ? ` at index ${index}` : ''} metadata.${key} does not match.\nExpected: ${expectedStr}\nActual: ${actualStr}`,
139
+ );
138
140
  }
139
- assertTrue(JSON.stringify(actualCopy) === JSON.stringify(expectedCopy), `Command${index !== undefined ? ` at index ${index}` : ''} does not match.\nExpected: ${JSON.stringify(expected)}\nActual: ${JSON.stringify(actual)}`);
141
+ delete actualCopy.metadata;
142
+ delete expectedCopy.metadata;
143
+ } else if (actualCopy.metadata !== undefined && expectedCopy.metadata === undefined) {
144
+ delete actualCopy.metadata;
145
+ }
146
+ assertTrue(
147
+ JSON.stringify(actualCopy) === JSON.stringify(expectedCopy),
148
+ `Command${index !== undefined ? ` at index ${index}` : ''} does not match.\nExpected: ${JSON.stringify(expected)}\nActual: ${JSON.stringify(actual)}`,
149
+ );
140
150
  }
141
151
  function thenThrowsErrorHandler(error, args) {
142
- if (error instanceof AssertionError)
143
- throw error;
144
- if (args.length === 0)
145
- return;
146
- if (!isErrorConstructor(args[0])) {
147
- assertTrue(args[0](error), `Error didn't match the error condition: ${error?.toString()}`);
148
- return;
149
- }
150
- assertTrue(error instanceof args[0], `Caught error is not an instance of the expected type: ${error?.toString()}`);
151
- if (args[1]) {
152
- assertTrue(args[1](error), `Error didn't match the error condition: ${error?.toString()}`);
153
- }
152
+ if (error instanceof AssertionError) throw error;
153
+ if (args.length === 0) return;
154
+ if (!isErrorConstructor(args[0])) {
155
+ assertTrue(args[0](error), `Error didn't match the error condition: ${error?.toString()}`);
156
+ return;
157
+ }
158
+ assertTrue(error instanceof args[0], `Caught error is not an instance of the expected type: ${error?.toString()}`);
159
+ if (args[1]) {
160
+ assertTrue(args[1](error), `Error didn't match the error condition: ${error?.toString()}`);
161
+ }
154
162
  }
155
- //# sourceMappingURL=reactorSpecification.js.map
163
+ //# sourceMappingURL=reactorSpecification.js.map