create-auto-app 0.8.4 → 0.8.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 (41) hide show
  1. package/package.json +2 -2
  2. package/templates/shopping-app/.context/schema.graphql +4 -4
  3. package/templates/shopping-app/.context/schema.json +54 -62
  4. package/templates/shopping-app/.context/server/server/package.json +1 -2
  5. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.specs.ts +0 -1
  6. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/events.ts +0 -1
  7. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/creates-a-chat-session/react.specs.ts +0 -1
  8. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.specs.ts +0 -1
  9. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/events.ts +0 -1
  10. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria/decide.ts +1 -1
  11. package/templates/shopping-app/.context/server/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria/handle.ts +2 -2
  12. package/templates/shopping-app/auto.config.ts +19 -11
  13. package/templates/shopping-app/example-integrations/ai-chat-completion/package.json +1 -2
  14. package/templates/shopping-app/example-integrations/cart/package.json +1 -2
  15. package/templates/shopping-app/example-integrations/cart-api/package.json +1 -2
  16. package/templates/shopping-app/example-integrations/product-catalogue/package.json +1 -2
  17. package/templates/shopping-app/example-integrations/product-catalogue-api/package.json +1 -2
  18. package/templates/shopping-app/flows/shopping-assistant.flow.ts +80 -97
  19. package/templates/shopping-app/package.json +4 -2
  20. package/templates/shopping-app/server/package.json +2 -1
  21. package/templates/shopping-app/server/scripts/generate-schema.ts +1 -1
  22. package/templates/shopping-app/server/src/integrations/index.ts +1 -1
  23. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/client/client.gen.ts +199 -0
  24. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/client/index.ts +25 -0
  25. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/client/types.gen.ts +232 -0
  26. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/client/utils.gen.ts +419 -0
  27. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/client.gen.ts +18 -0
  28. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/core/auth.gen.ts +42 -0
  29. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/core/bodySerializer.gen.ts +92 -0
  30. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/core/params.gen.ts +153 -0
  31. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/core/pathSerializer.gen.ts +181 -0
  32. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/core/types.gen.ts +120 -0
  33. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/index.ts +2 -0
  34. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/types.gen.ts +133 -0
  35. package/templates/shopping-app/server/src/integrations/product-catalogue/generated/product-catalog/zod.gen.ts +62 -0
  36. package/templates/shopping-app/server/src/integrations/product-catalogue/index.ts +1 -0
  37. package/templates/shopping-app/server/src/integrations/product-catalogue/product-catalogue-integration.ts +211 -0
  38. package/templates/shopping-app/tsconfig.json +3 -1
  39. package/templates/shopping-app/turbo.json +19 -0
  40. package/templates/shopping-app/client/postcss.config.js +0 -6
  41. package/templates/shopping-app/server/src/integrations/product-catalogue-integration.ts +0 -363
@@ -23,7 +23,6 @@ type ShoppingCriteriaEntered = Event<
23
23
  {
24
24
  sessionId: string;
25
25
  criteria: string;
26
- timestamp: Date;
27
26
  }
28
27
  >;
29
28
 
@@ -32,7 +31,6 @@ type ItemsAddedToCart = Event<
32
31
  {
33
32
  sessionId: string;
34
33
  items: { productId: string; quantity: number }[];
35
- timestamp: Date;
36
34
  }
37
35
  >;
38
36
 
@@ -76,8 +74,6 @@ type AddItemsToCart = Command<
76
74
  }
77
75
  >;
78
76
 
79
- // Using generic DSL instead of typed builders
80
-
81
77
  flow('Seasonal Assistant', () => {
82
78
  commandSlice('enters shopping criteria into assistant')
83
79
  .client(() => {
@@ -111,14 +107,11 @@ flow('Seasonal Assistant', () => {
111
107
  criteria:
112
108
  '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.',
113
109
  })
114
- .then<ShoppingCriteriaEntered>([
115
- {
116
- sessionId: 'shopper-123',
117
- criteria:
118
- '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.',
119
- timestamp: new Date(),
120
- },
121
- ]);
110
+ .then<ShoppingCriteriaEntered>({
111
+ sessionId: 'shopper-123',
112
+ criteria:
113
+ '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.',
114
+ });
122
115
  });
123
116
  });
124
117
  });
@@ -127,21 +120,16 @@ flow('Seasonal Assistant', () => {
127
120
  specs('When shopping criteria are entered, request wishlist creation', () => {
128
121
  rule('Shopping criteria should trigger item suggestion', () => {
129
122
  example('Criteria entered triggers wishlist creation')
130
- .when<ShoppingCriteriaEntered>([
131
- {
132
- sessionId: 'session-abc',
133
- criteria:
134
- '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.',
135
- timestamp: new Date(),
136
- },
137
- ])
138
- .then<SuggestShoppingItems>([
139
- {
140
- sessionId: 'session-abc',
141
- prompt:
142
- '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.',
143
- },
144
- ]);
123
+ .when<ShoppingCriteriaEntered>({
124
+ sessionId: 'session-abc',
125
+ criteria:
126
+ '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.',
127
+ })
128
+ .then<SuggestShoppingItems>({
129
+ sessionId: 'session-abc',
130
+ prompt:
131
+ '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.',
132
+ });
145
133
  });
146
134
  });
147
135
  });
@@ -161,80 +149,76 @@ flow('Seasonal Assistant', () => {
161
149
  specs('When chat is triggered, AI suggests items based on product catalog', () => {
162
150
  rule('AI should suggest relevant items from available products', () => {
163
151
  example('Product catalog with matching items generates suggestions')
164
- .given<Products>([
165
- {
166
- products: [
167
- {
168
- productId: 'prod-soccer-ball',
169
- name: 'Super Soccer Ball',
170
- category: 'Sports',
171
- price: 10,
172
- tags: ['soccer', 'sports'],
173
- imageUrl: 'https://example.com/soccer-ball.jpg',
174
- },
175
- {
176
- productId: 'prod-craft-kit',
177
- name: 'Deluxe Craft Kit',
178
- category: 'Arts & Crafts',
179
- price: 25,
180
- tags: ['crafts', 'art', 'creative'],
181
- imageUrl: 'https://example.com/craft-kit.jpg',
182
- },
183
- {
184
- productId: 'prod-laptop-bag',
185
- name: 'Tech Laptop Backpack',
186
- category: 'School Supplies',
187
- price: 45,
188
- tags: ['computers', 'tech', 'school'],
189
- imageUrl: 'https://example.com/laptop-bag.jpg',
190
- },
191
- {
192
- productId: 'prod-mtg-starter',
193
- name: 'Magic the Gathering Starter Set',
194
- category: 'Games',
195
- price: 30,
196
- tags: ['magic', 'tcg', 'games'],
197
- imageUrl: 'https://example.com/mtg-starter.jpg',
198
- },
199
- ],
200
- },
201
- ])
152
+ .given<Products>({
153
+ products: [
154
+ {
155
+ productId: 'prod-soccer-ball',
156
+ name: 'Super Soccer Ball',
157
+ category: 'Sports',
158
+ price: 10,
159
+ tags: ['soccer', 'sports'],
160
+ imageUrl: 'https://example.com/soccer-ball.jpg',
161
+ },
162
+ {
163
+ productId: 'prod-craft-kit',
164
+ name: 'Deluxe Craft Kit',
165
+ category: 'Arts & Crafts',
166
+ price: 25,
167
+ tags: ['crafts', 'art', 'creative'],
168
+ imageUrl: 'https://example.com/craft-kit.jpg',
169
+ },
170
+ {
171
+ productId: 'prod-laptop-bag',
172
+ name: 'Tech Laptop Backpack',
173
+ category: 'School Supplies',
174
+ price: 45,
175
+ tags: ['computers', 'tech', 'school'],
176
+ imageUrl: 'https://example.com/laptop-bag.jpg',
177
+ },
178
+ {
179
+ productId: 'prod-mtg-starter',
180
+ name: 'Magic the Gathering Starter Set',
181
+ category: 'Games',
182
+ price: 30,
183
+ tags: ['magic', 'tcg', 'games'],
184
+ imageUrl: 'https://example.com/mtg-starter.jpg',
185
+ },
186
+ ],
187
+ })
202
188
  .when<SuggestShoppingItems>({
203
189
  sessionId: 'session-abc',
204
190
  prompt:
205
191
  '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.',
206
192
  })
207
- .then<ShoppingItemsSuggested>([
208
- {
209
- sessionId: 'session-abc',
210
- suggestedItems: [
211
- {
212
- productId: 'prod-soccer-ball',
213
- name: 'Super Soccer Ball',
214
- quantity: 1,
215
- reason: 'Perfect for your daughter who loves soccer',
216
- },
217
- {
218
- productId: 'prod-craft-kit',
219
- name: 'Deluxe Craft Kit',
220
- quantity: 1,
221
- reason: 'Great for creative activities and crafts',
222
- },
223
- {
224
- productId: 'prod-laptop-bag',
225
- name: 'Tech Laptop Backpack',
226
- quantity: 1,
227
- reason: `Essential for your son's school computer needs`,
228
- },
229
- {
230
- productId: 'prod-mtg-starter',
231
- name: 'Magic the Gathering Starter Set',
232
- quantity: 1,
233
- reason: 'Ideal starter set for Magic the Gathering enthusiasts',
234
- },
235
- ],
236
- },
237
- ]);
193
+ .then<ShoppingItemsSuggested>({
194
+ sessionId: 'session-abc',
195
+ suggestedItems: [
196
+ {
197
+ productId: 'prod-soccer-ball',
198
+ name: 'Super Soccer Ball',
199
+ quantity: 1,
200
+ reason: 'Perfect for your daughter who loves soccer',
201
+ },
202
+ {
203
+ productId: 'prod-craft-kit',
204
+ name: 'Deluxe Craft Kit',
205
+ quantity: 1,
206
+ reason: 'Great for creative activities and crafts',
207
+ },
208
+ {
209
+ productId: 'prod-laptop-bag',
210
+ name: 'Tech Laptop Backpack',
211
+ quantity: 1,
212
+ reason: `Essential for your son's school computer needs`,
213
+ },
214
+ {
215
+ productId: 'prod-mtg-starter',
216
+ name: 'Magic the Gathering Starter Set',
217
+ quantity: 1,
218
+ reason: 'Ideal starter set for Magic the Gathering enthusiasts',
219
+ },
220
+ ],
221
+ });
238
222
  });
239
223
  });
240
224
  });
@@ -358,7 +342,6 @@ flow('Seasonal Assistant', () => {
358
342
  { productId: 'prod-laptop-bag', quantity: 1 },
359
343
  { productId: 'prod-mtg-starter', quantity: 1 },
360
344
  ],
361
- timestamp: new Date(),
362
345
  });
363
346
  });
364
347
  });
@@ -3,7 +3,8 @@
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "scripts": {
6
- "auto": "auto",
6
+ "DISABLE-auto": "node ../../packages/cli/dist/bin/auto.js",
7
+ "DISABLE-auto:debug": "DEBUG=flow:*,cli:*,auto*,ai*,-*file-syncer node ../../packages/cli/dist/bin/auto.js",
7
8
  "start": "dotenv -e .env -- pnpm --parallel start",
8
9
  "build": "tsc",
9
10
  "start:ecommerce-site": "cd examples/ecommerce-site && pnpm start",
@@ -22,7 +23,8 @@
22
23
  "@auto-engineer/message-bus": "workspace:*",
23
24
  "@auto-engineer/server-checks": "workspace:*",
24
25
  "@auto-engineer/server-generator-apollo-emmett": "workspace:*",
25
- "@auto-engineer/server-implementer": "workspace:*"
26
+ "@auto-engineer/server-implementer": "workspace:*",
27
+ "zod": "^3.25.76"
26
28
  },
27
29
  "devDependencies": {
28
30
  "@types/node": "^24.3.1",
@@ -19,7 +19,8 @@
19
19
  "fast-glob": "^3.3.3",
20
20
  "reflect-metadata": "^0.2.2",
21
21
  "apollo-server": "^3.13.0",
22
- "uuid": "^10.0.0"
22
+ "uuid": "^10.0.0",
23
+ "zod": "^3.25.67"
23
24
  },
24
25
  "devDependencies": {}
25
26
  }
@@ -14,7 +14,7 @@ async function main() {
14
14
  });
15
15
  const printedSchema = printSchema(schema);
16
16
 
17
- const contextDir = path.resolve('/Users/sam/WebstormProjects/top/my-shop', '.context');
17
+ const contextDir = path.resolve('../.context');
18
18
  const schemaPath = path.join(contextDir, 'schema.graphql');
19
19
  await writeFile(schemaPath, printedSchema, 'utf-8');
20
20
 
@@ -1,3 +1,3 @@
1
1
  export * from './ai-integration';
2
2
  export * from './cart-integration';
3
- export * from './product-catalogue-integration';
3
+ export * from './product-catalogue';
@@ -0,0 +1,199 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+
3
+ import type { Client, Config, ResolvedRequestOptions } from './types.gen';
4
+ import {
5
+ buildUrl,
6
+ createConfig,
7
+ createInterceptors,
8
+ getParseAs,
9
+ mergeConfigs,
10
+ mergeHeaders,
11
+ setAuthParams,
12
+ } from './utils.gen';
13
+
14
+ type ReqInit = Omit<RequestInit, 'body' | 'headers'> & {
15
+ body?: any;
16
+ headers: ReturnType<typeof mergeHeaders>;
17
+ };
18
+
19
+ export const createClient = (config: Config = {}): Client => {
20
+ let _config = mergeConfigs(createConfig(), config);
21
+
22
+ const getConfig = (): Config => ({ ..._config });
23
+
24
+ const setConfig = (config: Config): Config => {
25
+ _config = mergeConfigs(_config, config);
26
+ return getConfig();
27
+ };
28
+
29
+ const interceptors = createInterceptors<
30
+ Request,
31
+ Response,
32
+ unknown,
33
+ ResolvedRequestOptions
34
+ >();
35
+
36
+ const request: Client['request'] = async (options) => {
37
+ const opts = {
38
+ ..._config,
39
+ ...options,
40
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
41
+ headers: mergeHeaders(_config.headers, options.headers),
42
+ serializedBody: undefined,
43
+ };
44
+
45
+ if (opts.security) {
46
+ await setAuthParams({
47
+ ...opts,
48
+ security: opts.security,
49
+ });
50
+ }
51
+
52
+ if (opts.requestValidator) {
53
+ await opts.requestValidator(opts);
54
+ }
55
+
56
+ if (opts.body && opts.bodySerializer) {
57
+ opts.serializedBody = opts.bodySerializer(opts.body);
58
+ }
59
+
60
+ // remove Content-Type header if body is empty to avoid sending invalid requests
61
+ if (opts.serializedBody === undefined || opts.serializedBody === '') {
62
+ opts.headers.delete('Content-Type');
63
+ }
64
+
65
+ const url = buildUrl(opts);
66
+ const requestInit: ReqInit = {
67
+ redirect: 'follow',
68
+ ...opts,
69
+ body: opts.serializedBody,
70
+ };
71
+
72
+ let request = new Request(url, requestInit);
73
+
74
+ for (const fn of interceptors.request._fns) {
75
+ if (fn) {
76
+ request = await fn(request, opts);
77
+ }
78
+ }
79
+
80
+ // fetch must be assigned here, otherwise it would throw the error:
81
+ // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
82
+ const _fetch = opts.fetch!;
83
+ let response = await _fetch(request);
84
+
85
+ for (const fn of interceptors.response._fns) {
86
+ if (fn) {
87
+ response = await fn(response, request, opts);
88
+ }
89
+ }
90
+
91
+ const result = {
92
+ request,
93
+ response,
94
+ };
95
+
96
+ if (response.ok) {
97
+ if (
98
+ response.status === 204 ||
99
+ response.headers.get('Content-Length') === '0'
100
+ ) {
101
+ return opts.responseStyle === 'data'
102
+ ? {}
103
+ : {
104
+ data: {},
105
+ ...result,
106
+ };
107
+ }
108
+
109
+ const parseAs =
110
+ (opts.parseAs === 'auto'
111
+ ? getParseAs(response.headers.get('Content-Type'))
112
+ : opts.parseAs) ?? 'json';
113
+
114
+ let data: any;
115
+ switch (parseAs) {
116
+ case 'arrayBuffer':
117
+ case 'blob':
118
+ case 'formData':
119
+ case 'json':
120
+ case 'text':
121
+ data = await response[parseAs]();
122
+ break;
123
+ case 'stream':
124
+ return opts.responseStyle === 'data'
125
+ ? response.body
126
+ : {
127
+ data: response.body,
128
+ ...result,
129
+ };
130
+ }
131
+
132
+ if (parseAs === 'json') {
133
+ if (opts.responseValidator) {
134
+ await opts.responseValidator(data);
135
+ }
136
+
137
+ if (opts.responseTransformer) {
138
+ data = await opts.responseTransformer(data);
139
+ }
140
+ }
141
+
142
+ return opts.responseStyle === 'data'
143
+ ? data
144
+ : {
145
+ data,
146
+ ...result,
147
+ };
148
+ }
149
+
150
+ const textError = await response.text();
151
+ let jsonError: unknown;
152
+
153
+ try {
154
+ jsonError = JSON.parse(textError);
155
+ } catch {
156
+ // noop
157
+ }
158
+
159
+ const error = jsonError ?? textError;
160
+ let finalError = error;
161
+
162
+ for (const fn of interceptors.error._fns) {
163
+ if (fn) {
164
+ finalError = (await fn(error, response, request, opts)) as string;
165
+ }
166
+ }
167
+
168
+ finalError = finalError || ({} as string);
169
+
170
+ if (opts.throwOnError) {
171
+ throw finalError;
172
+ }
173
+
174
+ // TODO: we probably want to return error and improve types
175
+ return opts.responseStyle === 'data'
176
+ ? undefined
177
+ : {
178
+ error: finalError,
179
+ ...result,
180
+ };
181
+ };
182
+
183
+ return {
184
+ buildUrl,
185
+ connect: (options) => request({ ...options, method: 'CONNECT' }),
186
+ delete: (options) => request({ ...options, method: 'DELETE' }),
187
+ get: (options) => request({ ...options, method: 'GET' }),
188
+ getConfig,
189
+ head: (options) => request({ ...options, method: 'HEAD' }),
190
+ interceptors,
191
+ options: (options) => request({ ...options, method: 'OPTIONS' }),
192
+ patch: (options) => request({ ...options, method: 'PATCH' }),
193
+ post: (options) => request({ ...options, method: 'POST' }),
194
+ put: (options) => request({ ...options, method: 'PUT' }),
195
+ request,
196
+ setConfig,
197
+ trace: (options) => request({ ...options, method: 'TRACE' }),
198
+ };
199
+ };
@@ -0,0 +1,25 @@
1
+ // This file is auto-generated by @hey-api/openapi-ts
2
+
3
+ export type { Auth } from '../core/auth.gen';
4
+ export type { QuerySerializerOptions } from '../core/bodySerializer.gen';
5
+ export {
6
+ formDataBodySerializer,
7
+ jsonBodySerializer,
8
+ urlSearchParamsBodySerializer,
9
+ } from '../core/bodySerializer.gen';
10
+ export { buildClientParams } from '../core/params.gen';
11
+ export { createClient } from './client.gen';
12
+ export type {
13
+ Client,
14
+ ClientOptions,
15
+ Config,
16
+ CreateClientConfig,
17
+ Options,
18
+ OptionsLegacyParser,
19
+ RequestOptions,
20
+ RequestResult,
21
+ ResolvedRequestOptions,
22
+ ResponseStyle,
23
+ TDataShape,
24
+ } from './types.gen';
25
+ export { createConfig, mergeHeaders } from './utils.gen';