@auto-engineer/server-generator-nestjs 1.28.0 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @auto-engineer/server-generator-nestjs
2
2
 
3
+ ## 1.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`2ef9632`](https://github.com/BeOnAuto/auto-engineer/commit/2ef9632a2db081f201981422f2ba26b026fa7277) Thanks [@SamHatoum](https://github.com/SamHatoum)! - ### react-component-implementer
8
+ - Add staging workflow with `writeStagedStory`, `checkStagedTypes`, and `promoteFromStaging`
9
+ - Add MCP connection pool and browser pool for resource reuse
10
+ - Add context filtering and system prompt caching to reduce tokens
11
+ - Add ts-service for type-aware error feedback with property suggestions
12
+ - Parallelize type checking and browser validation
13
+ - Replace score-based visual evaluation with binary ACK/NACK criteria
14
+ - Enable incremental TypeScript checking in staging
15
+
16
+ ### pipeline
17
+ - Add `.declare().accepts()` builder for AcceptsDescriptor type
18
+ - Show source commands in pipeline graph
19
+
20
+ ### job-graph-processor
21
+ - Add `hasFailedJobs` utility and discriminate GraphProcessed vs GraphProcessingFailed
22
+ - Bridge context.emit in command handler for downstream event routing
23
+
24
+ ### server-generator-apollo-emmett
25
+ - Add cleanServerDir to preserve node_modules during regeneration
26
+ - Accept Model directly instead of modelPath
27
+
28
+ ### server-generator-nestjs
29
+ - Accept Model directly instead of modelPath
30
+
31
+ ### generate-react-client
32
+ - Lock in overwrite behavior for copyStarter
33
+
34
+ ### narrative
35
+ - Remove export-schema command
36
+
37
+ ### global
38
+ - Remove references to information-architect and model-diff packages
39
+ - Fix biome lint errors for CI compliance
40
+ - Update examples and configuration files
41
+
42
+ ### Patch Changes
43
+
44
+ - Updated dependencies [[`2ef9632`](https://github.com/BeOnAuto/auto-engineer/commit/2ef9632a2db081f201981422f2ba26b026fa7277)]:
45
+ - @auto-engineer/narrative@1.29.0
46
+
3
47
  ## 1.28.0
4
48
 
5
49
  ### Minor Changes
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "ts-node": "^10.9.2",
41
41
  "type-fest": "^4.41.0",
42
42
  "uuid": "^11.0.0",
43
- "@auto-engineer/narrative": "1.28.0"
43
+ "@auto-engineer/narrative": "1.29.0"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
@@ -52,9 +52,9 @@
52
52
  "tsx": "^4.19.2",
53
53
  "typescript": "^5.8.3",
54
54
  "vitest": "^3.2.4",
55
- "@auto-engineer/cli": "1.28.0"
55
+ "@auto-engineer/cli": "1.29.0"
56
56
  },
57
- "version": "1.28.0",
57
+ "version": "1.29.0",
58
58
  "scripts": {
59
59
  "generate:server": "tsx src/cli/index.ts",
60
60
  "-DISABLE-build": "tsc && tsx ../../scripts/fix-esm-imports.ts && rm -rf dist/src/codegen/templates && mkdir -p dist/src/codegen && cp -r src/codegen/templates dist/src/codegen/templates && cp -r src/shared dist/src",
@@ -198,8 +198,8 @@ export function consolidateEntityFields(
198
198
  const fields = Array.from(fieldMap.values());
199
199
  markPrimaryKeyAndIndexes(fields, fieldMap, flow.name);
200
200
 
201
- const entityName = pascalCase(flow.name) + 'Entity';
202
- const tableName = camelCase(flow.name) + 's';
201
+ const entityName = `${pascalCase(flow.name)}Entity`;
202
+ const tableName = `${camelCase(flow.name)}s`;
203
203
 
204
204
  debug('Consolidated entity: %s with %d fields', entityName, fields.length);
205
205
  debug(' Enum imports: %o', Array.from(enumsUsed));
@@ -88,7 +88,7 @@ export function parseGraphQlRequest(request: string): ParsedGraphQlQuery {
88
88
  }
89
89
 
90
90
  const baseName = field.name.value;
91
- const returnType = pascalCase(baseName) + 'View';
91
+ const returnType = `${pascalCase(baseName)}View`;
92
92
 
93
93
  return {
94
94
  queryName: baseName,
@@ -1,11 +1,11 @@
1
+ import fs from 'node:fs/promises';
2
+ import path, { dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import type { Model, Narrative, Slice } from '@auto-engineer/narrative';
2
5
  import { camelCase, pascalCase } from 'change-case';
3
6
  import createDebug from 'debug';
4
7
  import ejs from 'ejs';
5
- import fs from 'fs/promises';
6
- import path, { dirname } from 'path';
7
8
  import prettier from 'prettier';
8
- import { fileURLToPath } from 'url';
9
9
  import { ensureDirExists, ensureDirPath, toKebabCase } from './utils/path.js';
10
10
 
11
11
  const debug = createDebug('auto:server-generator-nestjs:scaffold');
@@ -372,7 +372,6 @@ async function generateFilesForSlice(
372
372
  flow: Narrative,
373
373
  sliceDir: string,
374
374
  messages: MessageDefinition[],
375
- flows: Narrative[],
376
375
  unionToEnumName: Map<string, string>,
377
376
  integrations?: Model['integrations'],
378
377
  ): Promise<FilePlan[]> {
@@ -519,15 +518,7 @@ export async function generateScaffoldFilePlans(
519
518
 
520
519
  for (const slice of flow.slices) {
521
520
  const sliceDir = ensureDirPath(flowDir, toKebabCase(slice.name));
522
- const plans = await generateFilesForSlice(
523
- slice,
524
- flow,
525
- sliceDir,
526
- messages ?? [],
527
- flows,
528
- unionToEnumName,
529
- integrations,
530
- );
521
+ const plans = await generateFilesForSlice(slice, flow, sliceDir, messages ?? [], unionToEnumName, integrations);
531
522
  allPlans.push(...plans);
532
523
  }
533
524
 
@@ -1,6 +1,6 @@
1
- import { existsSync } from 'fs';
2
- import { mkdir } from 'fs/promises';
3
- import path from 'path';
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir } from 'node:fs/promises';
3
+ import path from 'node:path';
4
4
 
5
5
  export function toKebabCase(str: string): string {
6
6
  return str
@@ -1,18 +1,16 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
1
5
  import { type Command, defineCommandHandler, type Event } from '@auto-engineer/message-bus';
2
6
  import type { Model } from '@auto-engineer/narrative';
3
7
  import createDebug from 'debug';
4
8
  import { execa } from 'execa';
5
- import { existsSync } from 'fs';
6
- import { readFile, writeFile } from 'fs/promises';
7
9
  import fs from 'fs-extra';
8
- import * as path from 'path';
9
- import { dirname, join, resolve } from 'path';
10
- import { fileURLToPath } from 'url';
11
10
  import { generateScaffoldFilePlans, writeScaffoldFilePlans } from '../codegen/scaffoldFromSchema.js';
12
11
  import { ensureDirExists, ensureDirPath, toKebabCase } from '../codegen/utils/path.js';
13
12
 
14
13
  const debug = createDebug('auto:server-generator-nestjs');
15
- const debugModel = createDebug('auto:server-generator-nestjs:schema');
16
14
  const debugFiles = createDebug('auto:server-generator-nestjs:files');
17
15
  const debugDeps = createDebug('auto:server-generator-nestjs:deps');
18
16
  const debugScaffold = createDebug('auto:server-generator-nestjs:scaffold');
@@ -23,11 +21,21 @@ const __dirname = dirname(__filename);
23
21
  export type GenerateServerCommand = Command<
24
22
  'GenerateServer',
25
23
  {
26
- modelPath: string;
24
+ model: Model;
27
25
  destination: string;
28
26
  }
29
27
  >;
30
28
 
29
+ function deriveModelPath(destination: string): string {
30
+ return join(resolve(destination), '.context', 'schema.json');
31
+ }
32
+
33
+ async function writeModelToDisk(model: Model, destination: string): Promise<void> {
34
+ const modelPath = deriveModelPath(destination);
35
+ await fs.ensureDir(dirname(modelPath));
36
+ await writeFile(modelPath, JSON.stringify(model, null, 2), 'utf8');
37
+ }
38
+
31
39
  export type ServerGeneratedEvent = Event<
32
40
  'ServerGenerated',
33
41
  {
@@ -68,8 +76,8 @@ export const commandHandler = defineCommandHandler({
68
76
  icon: 'server',
69
77
  events: ['ServerGenerated', 'ServerGenerationFailed', 'SliceGenerated'],
70
78
  fields: {
71
- modelPath: {
72
- description: 'Path to the json model file',
79
+ model: {
80
+ description: 'The model object',
73
81
  required: true,
74
82
  },
75
83
  destination: {
@@ -77,7 +85,7 @@ export const commandHandler = defineCommandHandler({
77
85
  required: true,
78
86
  },
79
87
  },
80
- examples: ['$ auto generate:server --model-path=.context/model.json --destination=.'],
88
+ examples: ['$ auto generate:server --destination=.'],
81
89
  handle: async (command: Command): Promise<GenerateServerEvents | GenerateServerEvents[]> => {
82
90
  const typedCommand = command as GenerateServerCommand;
83
91
  const result = await handleGenerateServerCommandInternal(typedCommand);
@@ -93,58 +101,6 @@ export const commandHandler = defineCommandHandler({
93
101
  },
94
102
  });
95
103
 
96
- async function validateModelFile(
97
- absModel: string,
98
- command: GenerateServerCommand,
99
- ): Promise<ServerGenerationFailedEvent | null> {
100
- if (!existsSync(absModel)) {
101
- debug('Model file not found at %s', absModel);
102
- return {
103
- type: 'ServerGenerationFailed',
104
- data: {
105
- modelPath: command.data.modelPath,
106
- destination: command.data.destination,
107
- error: `Model file not found at ${absModel}`,
108
- },
109
- timestamp: new Date(),
110
- requestId: command.requestId,
111
- correlationId: command.correlationId,
112
- };
113
- }
114
- return null;
115
- }
116
-
117
- async function readAndParseModel(absModel: string): Promise<Model> {
118
- debugModel('Reading model file from %s', absModel);
119
- const content = await readFile(absModel, 'utf8');
120
-
121
- debugModel('Model content length: %d bytes', content.length);
122
- const spec = JSON.parse(content) as Model;
123
-
124
- debugModel('Parsed model:');
125
- debugModel(' Flows: %d', spec.narratives?.length || 0);
126
- debugModel(' Messages: %d', spec.messages?.length || 0);
127
- debugModel(' Integrations: %d', spec.integrations?.length ?? 0);
128
-
129
- logFlowDetails(spec);
130
- return spec;
131
- }
132
-
133
- function logFlowDetails(spec: Model): void {
134
- if (spec.narratives !== undefined && spec.narratives.length > 0) {
135
- debugModel(
136
- 'Flow names: %o',
137
- spec.narratives.map((f) => f.name),
138
- );
139
- spec.narratives.forEach((flow) => {
140
- debugModel(' Flow "%s" has %d slices', flow.name, flow.slices?.length || 0);
141
- flow.slices?.forEach((slice) => {
142
- debugModel(' Slice: %s (type: %s)', slice.name, slice.type);
143
- });
144
- });
145
- }
146
- }
147
-
148
104
  async function cleanStaleCompiledFiles(serverDir: string): Promise<void> {
149
105
  const sharedTypesDir = join(serverDir, 'src', 'domain', 'shared');
150
106
  debugScaffold('Cleaning stale compiled files from %s', sharedTypesDir);
@@ -233,7 +189,7 @@ function createServerSuccessEvent(
233
189
  return {
234
190
  type: 'ServerGenerated',
235
191
  data: {
236
- modelPath: command.data.modelPath,
192
+ modelPath: deriveModelPath(command.data.destination),
237
193
  destination: command.data.destination,
238
194
  serverDir,
239
195
  contextSchemaGraphQL: join(absDest, '.context', 'schema.graphql'),
@@ -249,7 +205,7 @@ function createServerFailureEvent(command: GenerateServerCommand, error: unknown
249
205
  return {
250
206
  type: 'ServerGenerationFailed',
251
207
  data: {
252
- modelPath: command.data.modelPath,
208
+ modelPath: deriveModelPath(command.data.destination),
253
209
  destination: command.data.destination,
254
210
  error: error instanceof Error ? error.message : 'Unknown error occurred',
255
211
  },
@@ -262,29 +218,24 @@ function createServerFailureEvent(command: GenerateServerCommand, error: unknown
262
218
  export async function handleGenerateServerCommandInternal(
263
219
  command: GenerateServerCommand,
264
220
  ): Promise<GenerateServerEvents[]> {
265
- const { modelPath, destination } = command.data;
221
+ const { model, destination } = command.data;
266
222
  const events: GenerateServerEvents[] = [];
267
223
 
268
224
  debug('Starting server generation');
269
- debug('Model path: %s', modelPath);
270
225
  debug('Destination: %s', destination);
271
226
 
272
227
  try {
273
228
  const absDest = resolve(destination);
274
- const absModel = resolve(modelPath);
275
229
 
276
230
  debug('Resolved paths:');
277
231
  debug(' Absolute destination: %s', absDest);
278
- debug(' Absolute model: %s', absModel);
279
232
 
280
- const validationError = await validateModelFile(absModel, command);
281
- if (validationError) return [validationError];
233
+ const spec = model;
282
234
 
283
- const spec = await readAndParseModel(absModel);
235
+ await writeModelToDisk(spec, destination);
284
236
 
285
237
  const serverDir = join(absDest, 'server');
286
238
  debug('Server directory: %s', serverDir);
287
- debug('🔄 Generating server... %s', serverDir);
288
239
 
289
240
  debug('Clearing existing server directory if it exists');
290
241
  await fs.remove(serverDir);
@@ -308,7 +259,7 @@ export async function handleGenerateServerCommandInternal(
308
259
  flowName: flow.name,
309
260
  sliceName: slice.name,
310
261
  sliceType: slice.type,
311
- schemaPath: command.data.modelPath,
262
+ schemaPath: deriveModelPath(command.data.destination),
312
263
  slicePath: ensureDirPath('./server/src/domain', toKebabCase(flow.name), toKebabCase(slice.name)),
313
264
  },
314
265
  timestamp: new Date(),
@@ -342,7 +293,7 @@ async function copyRootFilesFromSrc(from: string, to: string): Promise<void> {
342
293
  debugFiles('copyRootFilesFromSrc: from=%s, to=%s', from, to);
343
294
 
344
295
  const fromStat = await fs.stat(from).catch(() => undefined);
345
- if (fromStat !== undefined && fromStat.isFile()) {
296
+ if (fromStat?.isFile()) {
346
297
  debugFiles(' Source is a file, copying directly');
347
298
  await fs.ensureDir(to);
348
299
  const destFile = path.join(to, path.basename(from));
@@ -1,6 +1,6 @@
1
+ import { join } from 'node:path';
1
2
  import { Migrator } from '@mikro-orm/migrations';
2
3
  import { defineConfig } from '@mikro-orm/sqlite';
3
- import { join } from 'path';
4
4
 
5
5
  export default defineConfig({
6
6
  entities: [],