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.
- package/dist/index.js +125 -111
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/shopping-app/.context/auto-ia-scheme.json +8 -29
- package/templates/shopping-app/.context/design-system.md +59 -35
- package/templates/shopping-app/.context/figma-variables.json +335 -1024
- package/templates/shopping-app/.context/schema.json +3 -7
- package/templates/shopping-app/.context/shadcn-filter.ts +2 -4
- package/templates/shopping-app/auto.config.ts +2 -2
- package/templates/shopping-app/client/src/gql/fragment-masking.ts +22 -22
- package/templates/shopping-app/client/src/gql/gql.ts +12 -5
- package/templates/shopping-app/client/src/gql/graphql.ts +125 -11
- package/templates/shopping-app/client/src/gql/index.ts +2 -2
- package/templates/shopping-app/client/src/graphql/mutations.ts +9 -9
- package/templates/shopping-app/client/src/graphql/queries.ts +10 -10
- package/templates/shopping-app/flows/shopping-assistant.flow.ts +2 -2
- package/templates/shopping-app/package.json +1 -1
- package/templates/shopping-app/pnpm-workspace.yaml +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/commands.ts +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.specs.ts +20 -20
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.ts +8 -11
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/events.ts +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/evolve.ts +3 -3
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/handle.ts +8 -15
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/mutation.resolver.ts +5 -9
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/register.ts +4 -7
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/react.specs.ts +19 -31
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/react.ts +6 -12
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/register.ts +4 -11
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/commands.ts +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.specs.ts +14 -14
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.ts +8 -11
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/events.ts +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/evolve.ts +3 -3
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/handle.ts +8 -15
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/mutation.resolver.ts +5 -9
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/register.ts +4 -7
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/commands.ts +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/decide.specs.ts +23 -23
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/decide.ts +9 -13
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/events.ts +2 -2
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/evolve.ts +3 -3
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/handle.ts +11 -18
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/mutation.resolver.ts +5 -9
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/register.ts +4 -7
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/projection.specs.ts +35 -35
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/projection.ts +8 -11
- package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/query.resolver.ts +4 -7
- package/templates/shopping-app/server/src/domain/shared/ReadModel.d.ts +7 -7
- package/templates/shopping-app/server/src/domain/shared/ReadModel.js +17 -17
- package/templates/shopping-app/server/src/domain/shared/index.d.ts +1 -1
- package/templates/shopping-app/server/src/domain/shared/index.js +1 -1
- package/templates/shopping-app/server/src/domain/shared/reactorSpecification.d.ts +42 -21
- package/templates/shopping-app/server/src/domain/shared/reactorSpecification.js +148 -140
- package/templates/shopping-app/server/src/domain/shared/sendCommand.d.ts +5 -2
- package/templates/shopping-app/server/src/domain/shared/sendCommand.js +14 -15
- package/templates/shopping-app/server/src/domain/shared/types.d.ts +10 -10
- package/templates/shopping-app/server/src/domain/shared/types.js +37 -36
- package/templates/shopping-app/server/src/integrations/ai-integration.ts +1 -1
- package/templates/shopping-app/server/src/integrations/cart-integration.ts +1 -1
- package/templates/shopping-app/server/src/integrations/index.ts +1 -1
- package/templates/shopping-app/server/src/integrations/product-catalogue-integration.ts +1 -1
- package/templates/shopping-app/server/src/utils/index.d.ts +1 -1
- package/templates/shopping-app/server/src/utils/index.js +1 -1
- package/templates/shopping-app/server/src/utils/loadProjections.d.ts +1 -1
- package/templates/shopping-app/server/src/utils/loadProjections.js +18 -16
- package/templates/shopping-app/server/src/utils/loadRegisterFiles.d.ts +2 -2
- package/templates/shopping-app/server/src/utils/loadRegisterFiles.js +19 -21
- package/templates/shopping-app/server/src/utils/loadResolvers.d.ts +2 -2
- package/templates/shopping-app/server/src/utils/loadResolvers.js +22 -22
- package/templates/shopping-app/server/tsconfig.json +2 -8
- package/templates/shopping-app/tsconfig.json +2 -8
|
@@ -1,31 +1,19 @@
|
|
|
1
|
-
import { describe, it, beforeEach } from
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from
|
|
8
|
-
import { type ReactorContext, ReactorSpecification } from "../../../shared";
|
|
9
|
-
import { react } from "./react";
|
|
10
|
-
import type { ShoppingCriteriaEntered } from "../enters-shopping-criteria-into-assistant/events";
|
|
11
|
-
import type { SuggestShoppingItems } from "../selects-items-relevant-to-the-shopping-criteria-/commands";
|
|
1
|
+
import { describe, it, beforeEach } from 'vitest';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
import { getInMemoryEventStore, type InMemoryEventStore, type CommandSender } from '@event-driven-io/emmett';
|
|
4
|
+
import { type ReactorContext, ReactorSpecification } from '../../../shared';
|
|
5
|
+
import { react } from './react';
|
|
6
|
+
import type { ShoppingCriteriaEntered } from '../enters-shopping-criteria-into-assistant/events';
|
|
7
|
+
import type { SuggestShoppingItems } from '../selects-items-relevant-to-the-shopping-criteria-/commands';
|
|
12
8
|
|
|
13
|
-
describe(
|
|
9
|
+
describe('SeasonalAssistant | CreatesAChatSession', () => {
|
|
14
10
|
let eventStore: InMemoryEventStore;
|
|
15
|
-
let given: ReactorSpecification<
|
|
16
|
-
ShoppingCriteriaEntered,
|
|
17
|
-
SuggestShoppingItems,
|
|
18
|
-
ReactorContext
|
|
19
|
-
>;
|
|
11
|
+
let given: ReactorSpecification<ShoppingCriteriaEntered, SuggestShoppingItems, ReactorContext>;
|
|
20
12
|
let messageBus: CommandSender;
|
|
21
13
|
|
|
22
14
|
beforeEach(() => {
|
|
23
15
|
eventStore = getInMemoryEventStore({});
|
|
24
|
-
given = ReactorSpecification.for<
|
|
25
|
-
ShoppingCriteriaEntered,
|
|
26
|
-
SuggestShoppingItems,
|
|
27
|
-
ReactorContext
|
|
28
|
-
>(
|
|
16
|
+
given = ReactorSpecification.for<ShoppingCriteriaEntered, SuggestShoppingItems, ReactorContext>(
|
|
29
17
|
() => react({ eventStore, commandSender: messageBus }),
|
|
30
18
|
(commandSender) => {
|
|
31
19
|
messageBus = commandSender;
|
|
@@ -38,25 +26,25 @@ describe("SeasonalAssistant | CreatesAChatSession", () => {
|
|
|
38
26
|
);
|
|
39
27
|
});
|
|
40
28
|
|
|
41
|
-
it(
|
|
29
|
+
it('should send SuggestShoppingItems when ShoppingCriteriaEntered is received', async () => {
|
|
42
30
|
await given([])
|
|
43
31
|
.when({
|
|
44
|
-
type:
|
|
32
|
+
type: 'ShoppingCriteriaEntered',
|
|
45
33
|
data: {
|
|
46
|
-
sessionId:
|
|
34
|
+
sessionId: 'session-abc',
|
|
47
35
|
criteria:
|
|
48
|
-
|
|
49
|
-
timestamp: new Date(
|
|
36
|
+
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
37
|
+
timestamp: new Date('2025-08-28T04:56:47.408Z'),
|
|
50
38
|
},
|
|
51
39
|
})
|
|
52
40
|
|
|
53
41
|
.then({
|
|
54
|
-
type:
|
|
55
|
-
kind:
|
|
42
|
+
type: 'SuggestShoppingItems',
|
|
43
|
+
kind: 'Command',
|
|
56
44
|
data: {
|
|
57
|
-
sessionId:
|
|
45
|
+
sessionId: 'session-abc',
|
|
58
46
|
prompt:
|
|
59
|
-
|
|
47
|
+
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
60
48
|
},
|
|
61
49
|
});
|
|
62
50
|
});
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
IllegalStateError,
|
|
5
|
-
} from "@event-driven-io/emmett";
|
|
6
|
-
import type { ShoppingCriteriaEntered } from "../enters-shopping-criteria-into-assistant/events";
|
|
7
|
-
import type { ReactorContext } from "../../../shared";
|
|
1
|
+
import { inMemoryReactor, type MessageHandlerResult, IllegalStateError } from '@event-driven-io/emmett';
|
|
2
|
+
import type { ShoppingCriteriaEntered } from '../enters-shopping-criteria-into-assistant/events';
|
|
3
|
+
import type { ReactorContext } from '../../../shared';
|
|
8
4
|
|
|
9
5
|
export const react = ({ eventStore, commandSender }: ReactorContext) =>
|
|
10
6
|
inMemoryReactor<ShoppingCriteriaEntered>({
|
|
11
|
-
processorId:
|
|
12
|
-
canHandle: [
|
|
7
|
+
processorId: 'seasonal-assistant-creates-a-chat-session-',
|
|
8
|
+
canHandle: ['ShoppingCriteriaEntered'],
|
|
13
9
|
connectionOptions: {
|
|
14
10
|
database: eventStore.database,
|
|
15
11
|
},
|
|
@@ -23,9 +19,7 @@ export const react = ({ eventStore, commandSender }: ReactorContext) =>
|
|
|
23
19
|
* - Optionally return a MessageHandlerResult for SKIP or error cases.
|
|
24
20
|
*/
|
|
25
21
|
|
|
26
|
-
throw new IllegalStateError(
|
|
27
|
-
"Not yet implemented: react in response to ShoppingCriteriaEntered",
|
|
28
|
-
);
|
|
22
|
+
throw new IllegalStateError('Not yet implemented: react in response to ShoppingCriteriaEntered');
|
|
29
23
|
|
|
30
24
|
// Example:
|
|
31
25
|
// if (event.data.status !== 'expected') {
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type EventSubscription,
|
|
4
|
-
type InMemoryEventStore,
|
|
5
|
-
} from "@event-driven-io/emmett";
|
|
6
|
-
import type { ShoppingCriteriaEntered } from "../enters-shopping-criteria-into-assistant/events";
|
|
1
|
+
import { type CommandSender, type EventSubscription, type InMemoryEventStore } from '@event-driven-io/emmett';
|
|
2
|
+
import type { ShoppingCriteriaEntered } from '../enters-shopping-criteria-into-assistant/events';
|
|
7
3
|
|
|
8
|
-
export async function register(
|
|
9
|
-
messageBus: CommandSender & EventSubscription,
|
|
10
|
-
eventStore: InMemoryEventStore,
|
|
11
|
-
) {
|
|
4
|
+
export async function register(messageBus: CommandSender & EventSubscription, eventStore: InMemoryEventStore) {
|
|
12
5
|
messageBus.subscribe(async (event: ShoppingCriteriaEntered) => {
|
|
13
6
|
/**
|
|
14
7
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
@@ -27,5 +20,5 @@ export async function register(
|
|
|
27
20
|
// });
|
|
28
21
|
|
|
29
22
|
return;
|
|
30
|
-
},
|
|
23
|
+
}, 'ShoppingCriteriaEntered');
|
|
31
24
|
}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { describe, it } from
|
|
2
|
-
import { DeciderSpecification } from
|
|
3
|
-
import { decide } from
|
|
4
|
-
import { evolve } from
|
|
5
|
-
import { initialState } from
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
3
|
+
import { decide } from './decide';
|
|
4
|
+
import { evolve } from './evolve';
|
|
5
|
+
import { initialState } from './state';
|
|
6
6
|
|
|
7
|
-
describe(
|
|
7
|
+
describe('Seasonal Assistant | enters shopping criteria into assistant', () => {
|
|
8
8
|
const given = DeciderSpecification.for({
|
|
9
9
|
decide,
|
|
10
10
|
evolve,
|
|
11
11
|
initialState,
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it(
|
|
14
|
+
it('should emit ShoppingCriteriaEntered for valid EnterShoppingCriteria', () => {
|
|
15
15
|
given([])
|
|
16
16
|
.when({
|
|
17
|
-
type:
|
|
17
|
+
type: 'EnterShoppingCriteria',
|
|
18
18
|
data: {
|
|
19
|
-
sessionId:
|
|
19
|
+
sessionId: 'shopper-123',
|
|
20
20
|
criteria:
|
|
21
|
-
|
|
21
|
+
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
22
22
|
},
|
|
23
23
|
metadata: { now: new Date() },
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
.then([
|
|
27
27
|
{
|
|
28
|
-
type:
|
|
28
|
+
type: 'ShoppingCriteriaEntered',
|
|
29
29
|
data: {
|
|
30
|
-
sessionId:
|
|
30
|
+
sessionId: 'shopper-123',
|
|
31
31
|
criteria:
|
|
32
|
-
|
|
33
|
-
timestamp: new Date(
|
|
32
|
+
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
33
|
+
timestamp: new Date('2025-08-28T04:56:47.408Z'),
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
]);
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { IllegalStateError } from
|
|
2
|
-
import type { State } from
|
|
3
|
-
import type { EnterShoppingCriteria } from
|
|
4
|
-
import type { ShoppingCriteriaEntered } from
|
|
1
|
+
import { IllegalStateError } from '@event-driven-io/emmett';
|
|
2
|
+
import type { State } from './state';
|
|
3
|
+
import type { EnterShoppingCriteria } from './commands';
|
|
4
|
+
import type { ShoppingCriteriaEntered } from './events';
|
|
5
5
|
|
|
6
|
-
export const decide = (
|
|
7
|
-
command: EnterShoppingCriteria,
|
|
8
|
-
state: State,
|
|
9
|
-
): ShoppingCriteriaEntered => {
|
|
6
|
+
export const decide = (command: EnterShoppingCriteria, state: State): ShoppingCriteriaEntered => {
|
|
10
7
|
switch (command.type) {
|
|
11
|
-
case
|
|
8
|
+
case 'EnterShoppingCriteria': {
|
|
12
9
|
/**
|
|
13
10
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
14
11
|
*
|
|
@@ -28,9 +25,9 @@ export const decide = (
|
|
|
28
25
|
// data: { ...command.data },
|
|
29
26
|
// } as ShoppingCriteriaEntered;
|
|
30
27
|
|
|
31
|
-
throw new IllegalStateError(
|
|
28
|
+
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
32
29
|
}
|
|
33
30
|
default:
|
|
34
|
-
throw new IllegalStateError(
|
|
31
|
+
throw new IllegalStateError('Unexpected command type: ' + command.type);
|
|
35
32
|
}
|
|
36
33
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { State } from
|
|
2
|
-
import type { ShoppingCriteriaEntered } from
|
|
1
|
+
import type { State } from './state';
|
|
2
|
+
import type { ShoppingCriteriaEntered } from './events';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
@@ -16,7 +16,7 @@ import type { ShoppingCriteriaEntered } from "./events";
|
|
|
16
16
|
|
|
17
17
|
export const evolve = (state: State, event: ShoppingCriteriaEntered): State => {
|
|
18
18
|
switch (event.type) {
|
|
19
|
-
case
|
|
19
|
+
case 'ShoppingCriteriaEntered': {
|
|
20
20
|
// TODO: Update state based on ShoppingCriteriaEntered
|
|
21
21
|
return {
|
|
22
22
|
...state,
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from
|
|
6
|
-
import { evolve } from "./evolve";
|
|
7
|
-
import { initialState } from "./state";
|
|
8
|
-
import { decide } from "./decide";
|
|
9
|
-
import type { EnterShoppingCriteria } from "./commands";
|
|
1
|
+
import { CommandHandler, type EventStore, type MessageHandlerResult } from '@event-driven-io/emmett';
|
|
2
|
+
import { evolve } from './evolve';
|
|
3
|
+
import { initialState } from './state';
|
|
4
|
+
import { decide } from './decide';
|
|
5
|
+
import type { EnterShoppingCriteria } from './commands';
|
|
10
6
|
|
|
11
7
|
const handler = CommandHandler({
|
|
12
8
|
evolve,
|
|
13
9
|
initialState,
|
|
14
10
|
});
|
|
15
11
|
|
|
16
|
-
export const handle = async (
|
|
17
|
-
eventStore: EventStore,
|
|
18
|
-
command: EnterShoppingCriteria,
|
|
19
|
-
): Promise<MessageHandlerResult> => {
|
|
12
|
+
export const handle = async (eventStore: EventStore, command: EnterShoppingCriteria): Promise<MessageHandlerResult> => {
|
|
20
13
|
const streamId = `shopping-session-${command.data.sessionId}`;
|
|
21
14
|
|
|
22
15
|
try {
|
|
@@ -24,8 +17,8 @@ export const handle = async (
|
|
|
24
17
|
return; // success (returns void)
|
|
25
18
|
} catch (error: any) {
|
|
26
19
|
return {
|
|
27
|
-
type:
|
|
28
|
-
reason: `Command failed: ${error?.message ??
|
|
20
|
+
type: 'SKIP',
|
|
21
|
+
reason: `Command failed: ${error?.message ?? 'Unknown'}`,
|
|
29
22
|
};
|
|
30
23
|
}
|
|
31
24
|
};
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { Mutation, Resolver, Arg, Ctx, Field, InputType } from
|
|
2
|
-
import {
|
|
3
|
-
type GraphQLContext,
|
|
4
|
-
sendCommand,
|
|
5
|
-
MutationResponse,
|
|
6
|
-
} from "../../../shared";
|
|
1
|
+
import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
2
|
+
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
7
3
|
|
|
8
4
|
@InputType()
|
|
9
5
|
export class EnterShoppingCriteriaInput {
|
|
@@ -17,13 +13,13 @@ export class EnterShoppingCriteriaInput {
|
|
|
17
13
|
export class EnterShoppingCriteriaResolver {
|
|
18
14
|
@Mutation(() => MutationResponse)
|
|
19
15
|
async enterShoppingCriteria(
|
|
20
|
-
@Arg(
|
|
16
|
+
@Arg('input', () => EnterShoppingCriteriaInput)
|
|
21
17
|
input: EnterShoppingCriteriaInput,
|
|
22
18
|
@Ctx() ctx: GraphQLContext,
|
|
23
19
|
): Promise<MutationResponse> {
|
|
24
20
|
return await sendCommand(ctx.messageBus, {
|
|
25
|
-
type:
|
|
26
|
-
kind:
|
|
21
|
+
type: 'EnterShoppingCriteria',
|
|
22
|
+
kind: 'Command',
|
|
27
23
|
data: { ...input },
|
|
28
24
|
});
|
|
29
25
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import type { CommandProcessor, EventStore } from
|
|
2
|
-
import { handle } from
|
|
3
|
-
import type { EnterShoppingCriteria } from
|
|
1
|
+
import type { CommandProcessor, EventStore } from '@event-driven-io/emmett';
|
|
2
|
+
import { handle } from './handle';
|
|
3
|
+
import type { EnterShoppingCriteria } from './commands';
|
|
4
4
|
|
|
5
5
|
export function register(messageBus: CommandProcessor, eventStore: EventStore) {
|
|
6
|
-
messageBus.handle(
|
|
7
|
-
(command: EnterShoppingCriteria) => handle(eventStore, command),
|
|
8
|
-
"EnterShoppingCriteria",
|
|
9
|
-
);
|
|
6
|
+
messageBus.handle((command: EnterShoppingCriteria) => handle(eventStore, command), 'EnterShoppingCriteria');
|
|
10
7
|
}
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { describe, it } from
|
|
2
|
-
import { DeciderSpecification } from
|
|
3
|
-
import { decide } from
|
|
4
|
-
import { evolve } from
|
|
5
|
-
import { initialState } from
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
3
|
+
import { decide } from './decide';
|
|
4
|
+
import { evolve } from './evolve';
|
|
5
|
+
import { initialState } from './state';
|
|
6
6
|
|
|
7
|
-
describe(
|
|
7
|
+
describe('Seasonal Assistant | selects items relevant to the shopping criteria ', () => {
|
|
8
8
|
const given = DeciderSpecification.for({
|
|
9
9
|
decide,
|
|
10
10
|
evolve,
|
|
11
11
|
initialState,
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it(
|
|
14
|
+
it('should emit ShoppingItemsSuggested for valid SuggestShoppingItems', () => {
|
|
15
15
|
given([])
|
|
16
16
|
.when({
|
|
17
|
-
type:
|
|
17
|
+
type: 'SuggestShoppingItems',
|
|
18
18
|
data: {
|
|
19
|
-
sessionId:
|
|
19
|
+
sessionId: 'session-abc',
|
|
20
20
|
prompt:
|
|
21
|
-
|
|
21
|
+
'I need back-to-school items for my 7-year-old daughter who loves soccer and crafts, and my 12-year-old son who is into computers and Magic the Gathering.',
|
|
22
22
|
},
|
|
23
23
|
metadata: { now: new Date() },
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
.then([
|
|
27
27
|
{
|
|
28
|
-
type:
|
|
28
|
+
type: 'ShoppingItemsSuggested',
|
|
29
29
|
data: {
|
|
30
|
-
sessionId:
|
|
30
|
+
sessionId: 'session-abc',
|
|
31
31
|
suggestedItems: [
|
|
32
32
|
{
|
|
33
|
-
productId:
|
|
34
|
-
name:
|
|
33
|
+
productId: 'prod-soccer-ball',
|
|
34
|
+
name: 'Super Soccer Ball',
|
|
35
35
|
quantity: 1,
|
|
36
|
-
reason:
|
|
36
|
+
reason: 'Perfect for your daughter who loves soccer',
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
productId:
|
|
40
|
-
name:
|
|
39
|
+
productId: 'prod-craft-kit',
|
|
40
|
+
name: 'Deluxe Craft Kit',
|
|
41
41
|
quantity: 1,
|
|
42
|
-
reason:
|
|
42
|
+
reason: 'Great for creative activities and crafts',
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
productId:
|
|
46
|
-
name:
|
|
45
|
+
productId: 'prod-laptop-bag',
|
|
46
|
+
name: 'Tech Laptop Backpack',
|
|
47
47
|
quantity: 1,
|
|
48
48
|
reason: "Essential for your son's school computer needs",
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
productId:
|
|
52
|
-
name:
|
|
51
|
+
productId: 'prod-mtg-starter',
|
|
52
|
+
name: 'Magic the Gathering Starter Set',
|
|
53
53
|
quantity: 1,
|
|
54
|
-
reason:
|
|
54
|
+
reason: 'Ideal starter set for Magic the Gathering enthusiasts',
|
|
55
55
|
},
|
|
56
56
|
],
|
|
57
57
|
},
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { IllegalStateError } from
|
|
2
|
-
import type { State } from
|
|
3
|
-
import type { SuggestShoppingItems } from
|
|
4
|
-
import type { ShoppingItemsSuggested } from
|
|
5
|
-
import type { Products } from
|
|
1
|
+
import { IllegalStateError } from '@event-driven-io/emmett';
|
|
2
|
+
import type { State } from './state';
|
|
3
|
+
import type { SuggestShoppingItems } from './commands';
|
|
4
|
+
import type { ShoppingItemsSuggested } from './events';
|
|
5
|
+
import type { Products } from '@auto-engineer/product-catalog-integration';
|
|
6
6
|
|
|
7
|
-
export const decide = (
|
|
8
|
-
command: SuggestShoppingItems,
|
|
9
|
-
state: State,
|
|
10
|
-
products?: Products,
|
|
11
|
-
): ShoppingItemsSuggested => {
|
|
7
|
+
export const decide = (command: SuggestShoppingItems, state: State, products?: Products): ShoppingItemsSuggested => {
|
|
12
8
|
switch (command.type) {
|
|
13
|
-
case
|
|
9
|
+
case 'SuggestShoppingItems': {
|
|
14
10
|
/**
|
|
15
11
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
16
12
|
*
|
|
@@ -37,9 +33,9 @@ export const decide = (
|
|
|
37
33
|
// data: { ...command.data },
|
|
38
34
|
// } as ShoppingItemsSuggested;
|
|
39
35
|
|
|
40
|
-
throw new IllegalStateError(
|
|
36
|
+
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
41
37
|
}
|
|
42
38
|
default:
|
|
43
|
-
throw new IllegalStateError(
|
|
39
|
+
throw new IllegalStateError('Unexpected command type: ' + command.type);
|
|
44
40
|
}
|
|
45
41
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Event } from
|
|
1
|
+
import type { Event } from '@event-driven-io/emmett';
|
|
2
2
|
|
|
3
3
|
export type ShoppingItemsSuggested = Event<
|
|
4
|
-
|
|
4
|
+
'ShoppingItemsSuggested',
|
|
5
5
|
{
|
|
6
6
|
sessionId: string;
|
|
7
7
|
suggestedItems: Array<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { State } from
|
|
2
|
-
import type { ShoppingItemsSuggested } from
|
|
1
|
+
import type { State } from './state';
|
|
2
|
+
import type { ShoppingItemsSuggested } from './events';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
@@ -16,7 +16,7 @@ import type { ShoppingItemsSuggested } from "./events";
|
|
|
16
16
|
|
|
17
17
|
export const evolve = (state: State, event: ShoppingItemsSuggested): State => {
|
|
18
18
|
switch (event.type) {
|
|
19
|
-
case
|
|
19
|
+
case 'ShoppingItemsSuggested': {
|
|
20
20
|
// TODO: Update state based on ShoppingItemsSuggested
|
|
21
21
|
return {
|
|
22
22
|
...state,
|
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import '@auto-engineer/product-catalog-integration';
|
|
2
2
|
|
|
3
|
-
import { AI } from
|
|
3
|
+
import { AI } from '@auto-engineer/ai-integration';
|
|
4
4
|
|
|
5
|
-
import { Products } from
|
|
5
|
+
import { Products } from '@auto-engineer/product-catalog-integration';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from
|
|
12
|
-
import { evolve } from "./evolve";
|
|
13
|
-
import { initialState } from "./state";
|
|
14
|
-
import { decide } from "./decide";
|
|
15
|
-
import type { SuggestShoppingItems } from "./commands";
|
|
7
|
+
import { CommandHandler, type EventStore, type MessageHandlerResult } from '@event-driven-io/emmett';
|
|
8
|
+
import { evolve } from './evolve';
|
|
9
|
+
import { initialState } from './state';
|
|
10
|
+
import { decide } from './decide';
|
|
11
|
+
import type { SuggestShoppingItems } from './commands';
|
|
16
12
|
|
|
17
13
|
/**
|
|
18
14
|
* ## IMPLEMENTATION INSTRUCTIONS ##
|
|
@@ -24,10 +20,7 @@ const handler = CommandHandler({
|
|
|
24
20
|
initialState,
|
|
25
21
|
});
|
|
26
22
|
|
|
27
|
-
export const handle = async (
|
|
28
|
-
eventStore: EventStore,
|
|
29
|
-
command: SuggestShoppingItems,
|
|
30
|
-
): Promise<MessageHandlerResult> => {
|
|
23
|
+
export const handle = async (eventStore: EventStore, command: SuggestShoppingItems): Promise<MessageHandlerResult> => {
|
|
31
24
|
const streamId = `shopping-session-${command.data.sessionId}`;
|
|
32
25
|
|
|
33
26
|
try {
|
|
@@ -52,8 +45,8 @@ export const handle = async (
|
|
|
52
45
|
return; // success (returns void)
|
|
53
46
|
} catch (error: any) {
|
|
54
47
|
return {
|
|
55
|
-
type:
|
|
56
|
-
reason: `Command failed: ${error?.message ??
|
|
48
|
+
type: 'SKIP',
|
|
49
|
+
reason: `Command failed: ${error?.message ?? 'Unknown'}`,
|
|
57
50
|
};
|
|
58
51
|
}
|
|
59
52
|
};
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { Mutation, Resolver, Arg, Ctx, Field, InputType } from
|
|
2
|
-
import {
|
|
3
|
-
type GraphQLContext,
|
|
4
|
-
sendCommand,
|
|
5
|
-
MutationResponse,
|
|
6
|
-
} from "../../../shared";
|
|
1
|
+
import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
2
|
+
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
7
3
|
|
|
8
4
|
@InputType()
|
|
9
5
|
export class SuggestShoppingItemsInput {
|
|
@@ -17,13 +13,13 @@ export class SuggestShoppingItemsInput {
|
|
|
17
13
|
export class SuggestShoppingItemsResolver {
|
|
18
14
|
@Mutation(() => MutationResponse)
|
|
19
15
|
async suggestShoppingItems(
|
|
20
|
-
@Arg(
|
|
16
|
+
@Arg('input', () => SuggestShoppingItemsInput)
|
|
21
17
|
input: SuggestShoppingItemsInput,
|
|
22
18
|
@Ctx() ctx: GraphQLContext,
|
|
23
19
|
): Promise<MutationResponse> {
|
|
24
20
|
return await sendCommand(ctx.messageBus, {
|
|
25
|
-
type:
|
|
26
|
-
kind:
|
|
21
|
+
type: 'SuggestShoppingItems',
|
|
22
|
+
kind: 'Command',
|
|
27
23
|
data: { ...input },
|
|
28
24
|
});
|
|
29
25
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import type { CommandProcessor, EventStore } from
|
|
2
|
-
import { handle } from
|
|
3
|
-
import type { SuggestShoppingItems } from
|
|
1
|
+
import type { CommandProcessor, EventStore } from '@event-driven-io/emmett';
|
|
2
|
+
import { handle } from './handle';
|
|
3
|
+
import type { SuggestShoppingItems } from './commands';
|
|
4
4
|
|
|
5
5
|
export function register(messageBus: CommandProcessor, eventStore: EventStore) {
|
|
6
|
-
messageBus.handle(
|
|
7
|
-
(command: SuggestShoppingItems) => handle(eventStore, command),
|
|
8
|
-
"SuggestShoppingItems",
|
|
9
|
-
);
|
|
6
|
+
messageBus.handle((command: SuggestShoppingItems) => handle(eventStore, command), 'SuggestShoppingItems');
|
|
10
7
|
}
|