@auto-engineer/server-generator-apollo-emmett 1.139.0 → 1.140.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.
Files changed (170) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +4 -4
  3. package/.turbo/turbo-type-check.log +1 -1
  4. package/CHANGELOG.md +17 -0
  5. package/DEBUG.md +4 -4
  6. package/dist/src/codegen/extract/data-sink.d.ts +2 -2
  7. package/dist/src/codegen/extract/data-sink.d.ts.map +1 -1
  8. package/dist/src/codegen/extract/data-sink.js +2 -2
  9. package/dist/src/codegen/extract/data-sink.js.map +1 -1
  10. package/dist/src/codegen/extract/events.d.ts +3 -3
  11. package/dist/src/codegen/extract/events.d.ts.map +1 -1
  12. package/dist/src/codegen/extract/events.js +11 -11
  13. package/dist/src/codegen/extract/events.js.map +1 -1
  14. package/dist/src/codegen/extract/gwt.d.ts +2 -2
  15. package/dist/src/codegen/extract/gwt.d.ts.map +1 -1
  16. package/dist/src/codegen/extract/gwt.js +2 -2
  17. package/dist/src/codegen/extract/gwt.js.map +1 -1
  18. package/dist/src/codegen/extract/imports.d.ts +4 -4
  19. package/dist/src/codegen/extract/imports.d.ts.map +1 -1
  20. package/dist/src/codegen/extract/imports.js +8 -8
  21. package/dist/src/codegen/extract/imports.js.map +1 -1
  22. package/dist/src/codegen/extract/messages.d.ts +2 -2
  23. package/dist/src/codegen/extract/messages.d.ts.map +1 -1
  24. package/dist/src/codegen/extract/messages.js +9 -9
  25. package/dist/src/codegen/extract/messages.js.map +1 -1
  26. package/dist/src/codegen/extract/projection.d.ts +7 -7
  27. package/dist/src/codegen/extract/projection.d.ts.map +1 -1
  28. package/dist/src/codegen/extract/projection.js +3 -3
  29. package/dist/src/codegen/extract/projection.js.map +1 -1
  30. package/dist/src/codegen/extract/query.d.ts +2 -2
  31. package/dist/src/codegen/extract/query.d.ts.map +1 -1
  32. package/dist/src/codegen/extract/query.js.map +1 -1
  33. package/dist/src/codegen/extract/slice-normalizer.d.ts +4 -4
  34. package/dist/src/codegen/extract/slice-normalizer.d.ts.map +1 -1
  35. package/dist/src/codegen/extract/slice-normalizer.js +7 -7
  36. package/dist/src/codegen/extract/slice-normalizer.js.map +1 -1
  37. package/dist/src/codegen/extract/states.d.ts +3 -3
  38. package/dist/src/codegen/extract/states.d.ts.map +1 -1
  39. package/dist/src/codegen/extract/states.js.map +1 -1
  40. package/dist/src/codegen/extract/step-converter.d.ts +7 -7
  41. package/dist/src/codegen/extract/step-converter.d.ts.map +1 -1
  42. package/dist/src/codegen/extract/step-converter.js +12 -12
  43. package/dist/src/codegen/extract/step-converter.js.map +1 -1
  44. package/dist/src/codegen/extract/step-types.d.ts +4 -4
  45. package/dist/src/codegen/extract/step-types.d.ts.map +1 -1
  46. package/dist/src/codegen/extract/step-types.js +1 -1
  47. package/dist/src/codegen/extract/step-types.js.map +1 -1
  48. package/dist/src/codegen/scaffoldFromSchema.d.ts +12 -12
  49. package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -1
  50. package/dist/src/codegen/scaffoldFromSchema.js +113 -101
  51. package/dist/src/codegen/scaffoldFromSchema.js.map +1 -1
  52. package/dist/src/codegen/templates/command/commands.specs.ts +3 -3
  53. package/dist/src/codegen/templates/command/decide.specs.specs.ts +52 -52
  54. package/dist/src/codegen/templates/command/decide.specs.ts +12 -12
  55. package/dist/src/codegen/templates/command/decide.specs.ts.ejs +1 -1
  56. package/dist/src/codegen/templates/command/events.specs.ts +3 -3
  57. package/dist/src/codegen/templates/command/evolve.specs.ts +3 -3
  58. package/dist/src/codegen/templates/command/handle.specs.ts +13 -13
  59. package/dist/src/codegen/templates/command/mutation.resolver.specs.ts +19 -19
  60. package/dist/src/codegen/templates/command/register.specs.ts +3 -3
  61. package/dist/src/codegen/templates/command/state.specs.ts +3 -3
  62. package/dist/src/codegen/templates/query/events.specs.ts +4 -4
  63. package/dist/src/codegen/templates/query/projection.specs.specs.ts +60 -60
  64. package/dist/src/codegen/templates/query/projection.specs.ts +54 -29
  65. package/dist/src/codegen/templates/query/projection.specs.ts.ejs +2 -2
  66. package/dist/src/codegen/templates/query/query.resolver.specs.ts +63 -63
  67. package/dist/src/codegen/templates/query/query.resolver.ts.ejs +1 -1
  68. package/dist/src/codegen/templates/query/state.specs.ts +9 -9
  69. package/dist/src/codegen/templates/react/react.specs.specs.ts +15 -15
  70. package/dist/src/codegen/templates/react/react.specs.ts +16 -16
  71. package/dist/src/codegen/templates/react/react.specs.ts.ejs +9 -9
  72. package/dist/src/codegen/templates/react/react.ts.ejs +5 -5
  73. package/dist/src/codegen/templates/react/react.ts.specs.ts +33 -33
  74. package/dist/src/codegen/templates/react/register.specs.ts +7 -7
  75. package/dist/src/codegen/templates/react/register.ts.ejs +4 -4
  76. package/dist/src/codegen/test-data/specVariant1.d.ts.map +1 -1
  77. package/dist/src/codegen/test-data/specVariant1.js +3 -2
  78. package/dist/src/codegen/test-data/specVariant1.js.map +1 -1
  79. package/dist/src/codegen/types.d.ts +2 -2
  80. package/dist/src/codegen/types.d.ts.map +1 -1
  81. package/dist/src/commands/generate-server.d.ts +21 -21
  82. package/dist/src/commands/generate-server.d.ts.map +1 -1
  83. package/dist/src/commands/generate-server.js +81 -63
  84. package/dist/src/commands/generate-server.js.map +1 -1
  85. package/dist/src/commands/initialize-server.d.ts.map +1 -1
  86. package/dist/src/commands/initialize-server.js +2 -2
  87. package/dist/src/commands/initialize-server.js.map +1 -1
  88. package/dist/src/domain/flows/shared/types.d.ts +14 -0
  89. package/dist/src/domain/flows/shared/types.d.ts.map +1 -0
  90. package/dist/src/domain/flows/shared/types.js +2 -0
  91. package/dist/src/domain/flows/shared/types.js.map +1 -0
  92. package/dist/src/domain/flows/shared/types.ts +15 -0
  93. package/dist/src/domain/narratives/shared/types.d.ts +14 -0
  94. package/dist/src/domain/narratives/shared/types.d.ts.map +1 -0
  95. package/dist/src/domain/narratives/shared/types.js +2 -0
  96. package/dist/src/domain/narratives/shared/types.js.map +1 -0
  97. package/dist/src/domain/narratives/shared/types.ts +15 -0
  98. package/dist/src/index.d.ts +1 -1
  99. package/dist/src/index.d.ts.map +1 -1
  100. package/dist/src/server.js +3 -3
  101. package/dist/src/server.js.map +1 -1
  102. package/dist/src/server.ts +3 -3
  103. package/dist/src/utils/loadRegisterFiles.d.ts +2 -2
  104. package/dist/src/utils/loadRegisterFiles.d.ts.map +1 -1
  105. package/dist/src/utils/loadRegisterFiles.js.map +1 -1
  106. package/dist/src/utils/loadRegisterFiles.ts +5 -5
  107. package/dist/src/utils/loadResolvers.js +1 -1
  108. package/dist/src/utils/loadResolvers.js.map +1 -1
  109. package/dist/src/utils/loadResolvers.ts +1 -1
  110. package/dist/tsconfig.tsbuildinfo +1 -1
  111. package/package.json +4 -4
  112. package/src/codegen/extract/data-sink.ts +5 -5
  113. package/src/codegen/extract/events.ts +15 -15
  114. package/src/codegen/extract/gwt.ts +4 -4
  115. package/src/codegen/extract/imports.specs.ts +19 -19
  116. package/src/codegen/extract/imports.ts +13 -13
  117. package/src/codegen/extract/messages.specs.ts +30 -30
  118. package/src/codegen/extract/messages.ts +16 -16
  119. package/src/codegen/extract/projection.specs.ts +22 -22
  120. package/src/codegen/extract/projection.ts +9 -9
  121. package/src/codegen/extract/query.ts +2 -2
  122. package/src/codegen/extract/slice-normalizer.specs.ts +11 -11
  123. package/src/codegen/extract/slice-normalizer.ts +14 -14
  124. package/src/codegen/extract/states.ts +4 -4
  125. package/src/codegen/extract/step-converter.specs.ts +9 -9
  126. package/src/codegen/extract/step-converter.ts +15 -15
  127. package/src/codegen/extract/step-types.specs.ts +12 -12
  128. package/src/codegen/extract/step-types.ts +4 -4
  129. package/src/codegen/findEventSource.specs.ts +23 -23
  130. package/src/codegen/scaffoldErrors.specs.ts +4 -4
  131. package/src/codegen/scaffoldFromSchema.filter.specs.ts +32 -32
  132. package/src/codegen/scaffoldFromSchema.ts +146 -132
  133. package/src/codegen/templates/command/commands.specs.ts +3 -3
  134. package/src/codegen/templates/command/decide.specs.specs.ts +52 -52
  135. package/src/codegen/templates/command/decide.specs.ts +12 -12
  136. package/src/codegen/templates/command/decide.specs.ts.ejs +1 -1
  137. package/src/codegen/templates/command/events.specs.ts +3 -3
  138. package/src/codegen/templates/command/evolve.specs.ts +3 -3
  139. package/src/codegen/templates/command/handle.specs.ts +13 -13
  140. package/src/codegen/templates/command/mutation.resolver.specs.ts +19 -19
  141. package/src/codegen/templates/command/register.specs.ts +3 -3
  142. package/src/codegen/templates/command/state.specs.ts +3 -3
  143. package/src/codegen/templates/query/events.specs.ts +4 -4
  144. package/src/codegen/templates/query/projection.specs.specs.ts +60 -60
  145. package/src/codegen/templates/query/projection.specs.ts +54 -29
  146. package/src/codegen/templates/query/projection.specs.ts.ejs +2 -2
  147. package/src/codegen/templates/query/query.resolver.specs.ts +63 -63
  148. package/src/codegen/templates/query/query.resolver.ts.ejs +1 -1
  149. package/src/codegen/templates/query/state.specs.ts +9 -9
  150. package/src/codegen/templates/react/react.specs.specs.ts +15 -15
  151. package/src/codegen/templates/react/react.specs.ts +16 -16
  152. package/src/codegen/templates/react/react.specs.ts.ejs +9 -9
  153. package/src/codegen/templates/react/react.ts.ejs +5 -5
  154. package/src/codegen/templates/react/react.ts.specs.ts +33 -33
  155. package/src/codegen/templates/react/register.specs.ts +7 -7
  156. package/src/codegen/templates/react/register.ts.ejs +4 -4
  157. package/src/codegen/test-data/specVariant1.json +1 -1
  158. package/src/codegen/test-data/specVariant1.ts +3 -2
  159. package/src/codegen/test-data/specVariant2.json +1 -1
  160. package/src/codegen/types.ts +2 -2
  161. package/src/commands/generate-server.specs.ts +81 -79
  162. package/src/commands/generate-server.ts +110 -88
  163. package/src/commands/initialize-server.specs.ts +4 -4
  164. package/src/commands/initialize-server.ts +5 -2
  165. package/src/domain/flows/shared/types.ts +15 -0
  166. package/src/domain/narratives/shared/types.ts +15 -0
  167. package/src/index.ts +1 -1
  168. package/src/server.ts +3 -3
  169. package/src/utils/loadRegisterFiles.ts +5 -5
  170. package/src/utils/loadResolvers.ts +1 -1
@@ -3,7 +3,7 @@ import * as path from 'node:path';
3
3
  import { dirname, join, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { type Command, defineCommandHandler, type Event } from '@auto-engineer/message-bus';
6
- import type { Model, Narrative, Slice } from '@auto-engineer/narrative';
6
+ import type { Model, Moment, Scene } from '@auto-engineer/narrative';
7
7
  import createDebug from 'debug';
8
8
 
9
9
  import fs from 'fs-extra';
@@ -25,7 +25,7 @@ const debugScaffold = createDebug('auto:server-generator-apollo-emmett:scaffold'
25
25
  const __filename = fileURLToPath(import.meta.url);
26
26
  const __dirname = dirname(__filename);
27
27
 
28
- type SliceDelta = {
28
+ type MomentDelta = {
29
29
  type: 'added' | 'removed' | 'changed';
30
30
  previous?: Record<string, unknown>;
31
31
  current?: Record<string, unknown>;
@@ -37,7 +37,7 @@ export type ChangeSet = {
37
37
  changed: string[];
38
38
  sharedTypesChanged: boolean;
39
39
  allAffected: string[];
40
- deltas: Record<string, SliceDelta>;
40
+ deltas: Record<string, MomentDelta>;
41
41
  };
42
42
 
43
43
  export type GenerationState = {
@@ -81,29 +81,29 @@ export type ServerGenerationFailedEvent = Event<
81
81
  destination: string;
82
82
  error: string;
83
83
  model: Model;
84
- flowName?: string;
85
- sliceName?: string;
86
- sliceType?: string;
84
+ sceneName?: string;
85
+ momentName?: string;
86
+ momentType?: string;
87
87
  }
88
88
  >;
89
89
 
90
- export type SliceGeneratedEvent = Event<
91
- 'SliceGenerated',
90
+ export type MomentGeneratedEvent = Event<
91
+ 'MomentGenerated',
92
92
  {
93
- flowName: string;
94
- sliceName: string;
95
- sliceType: string;
93
+ sceneName: string;
94
+ momentName: string;
95
+ momentType: string;
96
96
  schemaPath: string;
97
- slicePath: string;
97
+ momentPath: string;
98
98
  }
99
99
  >;
100
100
 
101
- export type SliceGenerationFailedEvent = Event<
102
- 'SliceGenerationFailed',
101
+ export type MomentGenerationFailedEvent = Event<
102
+ 'MomentGenerationFailed',
103
103
  {
104
- flowName: string;
105
- sliceName: string;
106
- sliceType: string;
104
+ sceneName: string;
105
+ momentName: string;
106
+ momentType: string;
107
107
  error: string;
108
108
  model: Model;
109
109
  }
@@ -112,8 +112,8 @@ export type SliceGenerationFailedEvent = Event<
112
112
  export type GenerateServerEvents =
113
113
  | ServerGeneratedEvent
114
114
  | ServerGenerationFailedEvent
115
- | SliceGeneratedEvent
116
- | SliceGenerationFailedEvent;
115
+ | MomentGeneratedEvent
116
+ | MomentGenerationFailedEvent;
117
117
 
118
118
  export const commandHandler = defineCommandHandler({
119
119
  name: 'GenerateServer',
@@ -125,8 +125,8 @@ export const commandHandler = defineCommandHandler({
125
125
  events: [
126
126
  { name: 'ServerGenerated', displayName: 'Back End Built' },
127
127
  { name: 'ServerGenerationFailed', displayName: 'Back End Build Failed' },
128
- { name: 'SliceGenerated', displayName: 'Slice Generated' },
129
- { name: 'SliceGenerationFailed', displayName: 'Slice Generation Failed' },
128
+ { name: 'MomentGenerated', displayName: 'Moment Generated' },
129
+ { name: 'MomentGenerationFailed', displayName: 'Moment Generation Failed' },
130
130
  ],
131
131
  fields: {
132
132
  model: {
@@ -202,23 +202,24 @@ async function cleanStaleCompiledFiles(serverDir: string): Promise<void> {
202
202
  async function generateAndWriteScaffold(
203
203
  spec: Model,
204
204
  serverDir: string,
205
- affectedSliceIds?: Set<string>,
205
+ affectedMomentIds?: Set<string>,
206
206
  ): Promise<{ duplicateCommands: DuplicateCommandInfo[]; fieldIssues: FieldIssue[] }> {
207
- const domainFlowsPath = join(serverDir, 'src', 'domain', 'flows');
207
+ const domainNarrativesPath = join(serverDir, 'src', 'domain', 'narratives');
208
208
  debugScaffold('Generating scaffold file plans');
209
- debugScaffold(' Domain flows path: %s', domainFlowsPath);
210
- debugScaffold(' Number of flows: %d', spec.narratives?.length || 0);
209
+ debugScaffold(' Domain scenes path: %s', domainNarrativesPath);
210
+ debugScaffold(' Number of scenes: %d', spec.scenes?.length || 0);
211
211
 
212
212
  const {
213
213
  plans: filePlans,
214
214
  duplicateCommands,
215
215
  fieldIssues,
216
216
  } = await generateScaffoldFilePlans(
217
- spec.narratives,
217
+ spec.scenes,
218
218
  spec.messages,
219
219
  spec.integrations,
220
- domainFlowsPath,
221
- affectedSliceIds,
220
+ domainNarrativesPath,
221
+ affectedMomentIds,
222
+ spec.narratives,
222
223
  );
223
224
 
224
225
  debugScaffold('Generated %d file plans', filePlans.length);
@@ -254,7 +255,7 @@ async function copyAllFiles(serverDir: string): Promise<void> {
254
255
  }
255
256
 
256
257
  export async function writeHealthResolver(serverDir: string): Promise<void> {
257
- const healthDir = path.join(serverDir, 'src', 'domain', 'flows', 'health');
258
+ const healthDir = path.join(serverDir, 'src', 'domain', 'narratives', 'health');
258
259
  const resolverPath = path.join(healthDir, 'query.resolver.ts');
259
260
  await fs.ensureDir(healthDir);
260
261
  await writeFile(
@@ -311,9 +312,9 @@ function stripAnsiCodes(text: string): string {
311
312
  export function createServerFailureEvent(command: GenerateServerCommand, error: unknown): ServerGenerationFailedEvent {
312
313
  debug('Server generation failed with error: %O', error);
313
314
 
314
- let flowName: string | undefined;
315
- let sliceName: string | undefined;
316
- let sliceType: string | undefined;
315
+ let sceneName: string | undefined;
316
+ let momentName: string | undefined;
317
+ let momentType: string | undefined;
317
318
  let templateFile: string | undefined;
318
319
  let errorMessage: string;
319
320
 
@@ -321,9 +322,9 @@ export function createServerFailureEvent(command: GenerateServerCommand, error:
321
322
  let current: unknown = error;
322
323
  while (current instanceof Error) {
323
324
  if (current instanceof ScaffoldError) {
324
- flowName = current.flowName;
325
- sliceName = current.sliceName;
326
- sliceType = current.sliceType;
325
+ sceneName = current.sceneName;
326
+ momentName = current.momentName;
327
+ momentType = current.momentType;
327
328
  }
328
329
  if (current instanceof TemplateRenderError) {
329
330
  templateFile = current.templateFile;
@@ -345,9 +346,9 @@ export function createServerFailureEvent(command: GenerateServerCommand, error:
345
346
  destination: command.data.destination,
346
347
  error: errorMessage,
347
348
  model: command.data.model,
348
- flowName,
349
- sliceName,
350
- sliceType,
349
+ sceneName,
350
+ momentName,
351
+ momentType,
351
352
  },
352
353
  timestamp: new Date(),
353
354
  requestId: command.requestId,
@@ -363,19 +364,21 @@ function findRootCause(error: Error): Error {
363
364
  return current;
364
365
  }
365
366
 
366
- export function createSliceGeneratedEvent(
367
- flow: Narrative,
368
- slice: Slice,
367
+ export function createMomentGeneratedEvent(
368
+ scene: Scene,
369
+ slice: Moment,
369
370
  command: GenerateServerCommand,
370
- ): SliceGeneratedEvent {
371
+ sceneDirName?: string,
372
+ ): MomentGeneratedEvent {
373
+ const dirName = sceneDirName ?? toKebabCase(scene.name);
371
374
  return {
372
- type: 'SliceGenerated',
375
+ type: 'MomentGenerated',
373
376
  data: {
374
- flowName: flow.name,
375
- sliceName: slice.name,
376
- sliceType: slice.type,
377
+ sceneName: scene.name,
378
+ momentName: slice.name,
379
+ momentType: slice.type,
377
380
  schemaPath: deriveModelPath(command.data.destination),
378
- slicePath: ensureDirPath('./server/src/domain/flows', toKebabCase(flow.name), toKebabCase(slice.name)),
381
+ momentPath: ensureDirPath('./server/src/domain/narratives', dirName, toKebabCase(slice.name)),
379
382
  },
380
383
  timestamp: new Date(),
381
384
  requestId: command.requestId,
@@ -383,15 +386,30 @@ export function createSliceGeneratedEvent(
383
386
  };
384
387
  }
385
388
 
386
- export function emitSliceGenerationFailedForDuplicates(
389
+ function buildSceneToNarrativeMap(narratives: Model['narratives']): Map<string, string> {
390
+ const map = new Map<string, string>();
391
+ for (const narrative of narratives) {
392
+ for (const sceneId of narrative.sceneIds) {
393
+ map.set(sceneId, narrative.name);
394
+ }
395
+ }
396
+ return map;
397
+ }
398
+
399
+ function getSceneDirName(scene: Scene, sceneToNarrative: Map<string, string>): string {
400
+ const narrativeName = scene.id ? sceneToNarrative.get(scene.id) : undefined;
401
+ return narrativeName ? `${toKebabCase(narrativeName)}_${toKebabCase(scene.name)}` : toKebabCase(scene.name);
402
+ }
403
+
404
+ export function emitMomentGenerationFailedForDuplicates(
387
405
  duplicateCommands: DuplicateCommandInfo[],
388
406
  spec: Model,
389
407
  command: GenerateServerCommand,
390
408
  events: GenerateServerEvents[],
391
409
  ): void {
392
410
  for (const dup of duplicateCommands) {
393
- for (const flow of spec.narratives) {
394
- for (const slice of flow.slices) {
411
+ for (const scene of spec.scenes) {
412
+ for (const slice of scene.moments) {
395
413
  if (slice.type !== 'command') continue;
396
414
  const gwtSpecs = slice.server?.specs;
397
415
  if (!Array.isArray(gwtSpecs)) continue;
@@ -400,14 +418,14 @@ export function emitSliceGenerationFailedForDuplicates(
400
418
  rule.examples?.some((ex) => ex.steps?.some((step) => step.keyword === 'When' && step.text === dup.command)),
401
419
  ),
402
420
  );
403
- if (hasCommand && (flow.name !== dup.existingFlow || slice.name !== dup.existingSlice)) {
404
- const event: SliceGenerationFailedEvent = {
405
- type: 'SliceGenerationFailed',
421
+ if (hasCommand && (scene.name !== dup.existingScene || slice.name !== dup.existingMoment)) {
422
+ const event: MomentGenerationFailedEvent = {
423
+ type: 'MomentGenerationFailed',
406
424
  data: {
407
- flowName: flow.name,
408
- sliceName: slice.name,
409
- sliceType: slice.type,
410
- error: `Duplicate command handler: '${dup.command}' is already registered in ${dup.existingFlow}/${dup.existingSlice}`,
425
+ sceneName: scene.name,
426
+ momentName: slice.name,
427
+ momentType: slice.type,
428
+ error: `Duplicate command handler: '${dup.command}' is already registered in ${dup.existingScene}/${dup.existingMoment}`,
411
429
  model: spec,
412
430
  },
413
431
  timestamp: new Date(),
@@ -415,7 +433,7 @@ export function emitSliceGenerationFailedForDuplicates(
415
433
  correlationId: command.correlationId,
416
434
  };
417
435
  events.push(event);
418
- debug('SliceGenerationFailed: %s.%s - duplicate command %s', flow.name, slice.name, dup.command);
436
+ debug('MomentGenerationFailed: %s.%s - duplicate command %s', scene.name, slice.name, dup.command);
419
437
  }
420
438
  }
421
439
  }
@@ -423,15 +441,15 @@ export function emitSliceGenerationFailedForDuplicates(
423
441
  }
424
442
 
425
443
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: nested iteration over model structure is inherent to the task
426
- export function emitSliceGenerationFailedForFieldIssues(
444
+ export function emitMomentGenerationFailedForFieldIssues(
427
445
  fieldIssues: FieldIssue[],
428
446
  spec: Model,
429
447
  command: GenerateServerCommand,
430
448
  events: GenerateServerEvents[],
431
449
  ): void {
432
450
  for (const issue of fieldIssues) {
433
- for (const flow of spec.narratives) {
434
- for (const slice of flow.slices) {
451
+ for (const scene of spec.scenes) {
452
+ for (const slice of scene.moments) {
435
453
  if (slice.type === 'experience') continue;
436
454
 
437
455
  const gwtSpecs = slice.server?.specs;
@@ -454,11 +472,11 @@ export function emitSliceGenerationFailedForFieldIssues(
454
472
 
455
473
  if (usesMessageViaGwt || usesMessageViaData) {
456
474
  events.push({
457
- type: 'SliceGenerationFailed',
475
+ type: 'MomentGenerationFailed',
458
476
  data: {
459
- flowName: flow.name,
460
- sliceName: slice.name,
461
- sliceType: slice.type,
477
+ sceneName: scene.name,
478
+ momentName: slice.name,
479
+ momentType: slice.type,
462
480
  error: issue.error,
463
481
  model: spec,
464
482
  },
@@ -473,29 +491,31 @@ export function emitSliceGenerationFailedForFieldIssues(
473
491
  }
474
492
 
475
493
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: nested iteration over model structure is inherent to the task
476
- export function emitSliceGeneratedForAll(
494
+ export function emitMomentGeneratedForAll(
477
495
  spec: Model,
478
496
  command: GenerateServerCommand,
479
497
  events: GenerateServerEvents[],
480
498
  duplicateCommands: DuplicateCommandInfo[] = [],
481
499
  fieldIssues: FieldIssue[] = [],
482
500
  ): void {
483
- if (Array.isArray(spec.narratives) && spec.narratives.length > 0) {
484
- for (const flow of spec.narratives) {
485
- if (Array.isArray(flow.slices) && flow.slices.length > 0) {
486
- for (const slice of flow.slices) {
501
+ const sceneToNarrative = buildSceneToNarrativeMap(spec.narratives);
502
+ if (Array.isArray(spec.scenes) && spec.scenes.length > 0) {
503
+ for (const scene of spec.scenes) {
504
+ const sceneDirName = getSceneDirName(scene, sceneToNarrative);
505
+ if (Array.isArray(scene.moments) && scene.moments.length > 0) {
506
+ for (const slice of scene.moments) {
487
507
  if (slice.type === 'experience') continue;
488
- events.push(createSliceGeneratedEvent(flow, slice, command));
489
- debug('SliceGenerated: %s.%s', flow.name, slice.name);
508
+ events.push(createMomentGeneratedEvent(scene, slice, command, sceneDirName));
509
+ debug('MomentGenerated: %s.%s', scene.name, slice.name);
490
510
  }
491
511
  }
492
512
  }
493
513
  }
494
- emitSliceGenerationFailedForDuplicates(duplicateCommands, spec, command, events);
495
- emitSliceGenerationFailedForFieldIssues(fieldIssues, spec, command, events);
514
+ emitMomentGenerationFailedForDuplicates(duplicateCommands, spec, command, events);
515
+ emitMomentGenerationFailedForFieldIssues(fieldIssues, spec, command, events);
496
516
  }
497
517
 
498
- export function emitSliceGeneratedForAffected(
518
+ export function emitMomentGeneratedForAffected(
499
519
  spec: Model,
500
520
  affectedIds: Set<string>,
501
521
  command: GenerateServerCommand,
@@ -503,18 +523,20 @@ export function emitSliceGeneratedForAffected(
503
523
  duplicateCommands: DuplicateCommandInfo[] = [],
504
524
  fieldIssues: FieldIssue[] = [],
505
525
  ): void {
506
- for (const flow of spec.narratives) {
507
- for (const slice of flow.slices) {
526
+ const sceneToNarrative = buildSceneToNarrativeMap(spec.narratives);
527
+ for (const scene of spec.scenes) {
528
+ const sceneDirName = getSceneDirName(scene, sceneToNarrative);
529
+ for (const slice of scene.moments) {
508
530
  if (slice.type === 'experience') continue;
509
- const sliceId = `${toKebabCase(flow.name)}/${toKebabCase(slice.name)}`;
531
+ const sliceId = `${sceneDirName}/${toKebabCase(slice.name)}`;
510
532
  if (affectedIds.has(sliceId)) {
511
- events.push(createSliceGeneratedEvent(flow, slice, command));
512
- debug('SliceGenerated (incremental): %s.%s', flow.name, slice.name);
533
+ events.push(createMomentGeneratedEvent(scene, slice, command, sceneDirName));
534
+ debug('MomentGenerated (incremental): %s.%s', scene.name, slice.name);
513
535
  }
514
536
  }
515
537
  }
516
- emitSliceGenerationFailedForDuplicates(duplicateCommands, spec, command, events);
517
- emitSliceGenerationFailedForFieldIssues(fieldIssues, spec, command, events);
538
+ emitMomentGenerationFailedForDuplicates(duplicateCommands, spec, command, events);
539
+ emitMomentGenerationFailedForFieldIssues(fieldIssues, spec, command, events);
518
540
  }
519
541
 
520
542
  export async function handleGenerateServerCommandInternal(
@@ -547,25 +569,25 @@ export async function handleGenerateServerCommandInternal(
547
569
  await cleanServerDir(serverDir);
548
570
  await copyAllFiles(serverDir);
549
571
  const { duplicateCommands, fieldIssues } = await generateAndWriteScaffold(spec, serverDir);
550
- emitSliceGeneratedForAll(spec, command, events, duplicateCommands, fieldIssues);
572
+ emitMomentGeneratedForAll(spec, command, events, duplicateCommands, fieldIssues);
551
573
  await writeConfigurationFiles(serverDir);
552
574
  } else if (changeSet.allAffected.length === 0 && changeSet.removed.length === 0) {
553
575
  debug('No changes detected, skipping scaffold generation');
554
- emitSliceGeneratedForAll(spec, command, events);
576
+ emitMomentGeneratedForAll(spec, command, events);
555
577
  } else {
556
578
  debug('Incremental generation mode');
557
579
 
558
580
  for (const sliceId of changeSet.removed) {
559
- const [flowDir, sliceDir] = sliceId.split('/');
560
- await fs.remove(join(serverDir, 'src/domain/flows', flowDir, sliceDir));
561
- debug('Removed slice directory: %s/%s', flowDir, sliceDir);
581
+ const [sceneDir, momentDir] = sliceId.split('/');
582
+ await fs.remove(join(serverDir, 'src/domain/narratives', sceneDir, momentDir));
583
+ debug('Removed slice directory: %s/%s', sceneDir, momentDir);
562
584
  }
563
585
 
564
586
  await copyAllFiles(serverDir);
565
587
 
566
588
  const affectedIds = new Set(changeSet.allAffected);
567
589
  const { duplicateCommands, fieldIssues } = await generateAndWriteScaffold(spec, serverDir, affectedIds);
568
- emitSliceGeneratedForAffected(spec, affectedIds, command, events, duplicateCommands, fieldIssues);
590
+ emitMomentGeneratedForAffected(spec, affectedIds, command, events, duplicateCommands, fieldIssues);
569
591
  await writeConfigurationFiles(serverDir);
570
592
  }
571
593
 
@@ -41,7 +41,7 @@ describe('handleInitializeServerInternal', () => {
41
41
  'src/utils/loadResolvers.ts',
42
42
  'src/domain/shared/types.ts',
43
43
  'src/domain/shared/index.ts',
44
- 'src/domain/flows/health/query.resolver.ts',
44
+ 'src/domain/narratives/health/query.resolver.ts',
45
45
  ];
46
46
 
47
47
  for (const file of expectedFiles) {
@@ -79,7 +79,7 @@ describe('handleInitializeServerInternal', () => {
79
79
  await handleInitializeServerInternal(command);
80
80
 
81
81
  const content = await readFile(
82
- join(tempDir, 'server', 'src', 'domain', 'flows', 'health', 'query.resolver.ts'),
82
+ join(tempDir, 'server', 'src', 'domain', 'narratives', 'health', 'query.resolver.ts'),
83
83
  'utf8',
84
84
  );
85
85
  expect(content).toContain('HealthResolver');
@@ -111,14 +111,14 @@ describe('handleInitializeServerInternal', () => {
111
111
  const sentinel = 'CUSTOM_CONTENT_SHOULD_NOT_BE_OVERWRITTEN';
112
112
  await fs.writeFile(join(serverDir, 'src', 'server.ts'), sentinel);
113
113
  await fs.writeFile(join(serverDir, 'src', 'domain', 'shared', 'types.ts'), sentinel);
114
- await fs.writeFile(join(serverDir, 'src', 'domain', 'flows', 'health', 'query.resolver.ts'), sentinel);
114
+ await fs.writeFile(join(serverDir, 'src', 'domain', 'narratives', 'health', 'query.resolver.ts'), sentinel);
115
115
  await fs.writeFile(join(serverDir, 'vitest.config.ts'), sentinel);
116
116
 
117
117
  await handleInitializeServerInternal(command);
118
118
 
119
119
  expect(await readFile(join(serverDir, 'src', 'server.ts'), 'utf8')).toBe(sentinel);
120
120
  expect(await readFile(join(serverDir, 'src', 'domain', 'shared', 'types.ts'), 'utf8')).toBe(sentinel);
121
- expect(await readFile(join(serverDir, 'src', 'domain', 'flows', 'health', 'query.resolver.ts'), 'utf8')).toBe(
121
+ expect(await readFile(join(serverDir, 'src', 'domain', 'narratives', 'health', 'query.resolver.ts'), 'utf8')).toBe(
122
122
  sentinel,
123
123
  );
124
124
  expect(await readFile(join(serverDir, 'vitest.config.ts'), 'utf8')).toBe(sentinel);
@@ -242,7 +242,7 @@ async function start() {
242
242
  schema: { autoMigration: 'CreateOrUpdate' },
243
243
  });
244
244
 
245
- const resolvers = await loadResolvers('src/domain/flows/**/*.resolver.{ts,js}');
245
+ const resolvers = await loadResolvers('src/domain/narratives/**/*.resolver.{ts,js}');
246
246
  type ResolverClass = new (...args: unknown[]) => unknown;
247
247
  const schema = await buildSchema({
248
248
  resolvers: resolvers as unknown as [ResolverClass, ...ResolverClass[]],
@@ -367,7 +367,10 @@ export async function handleInitializeServerInternal(
367
367
  await writeIfMissing(join(serverDir, 'src', 'utils', 'index.ts'), UTILS_INDEX_TS);
368
368
  await writeIfMissing(join(serverDir, 'src', 'domain', 'shared', 'types.ts'), TYPES_TS);
369
369
  await writeIfMissing(join(serverDir, 'src', 'domain', 'shared', 'index.ts'), SHARED_INDEX_TS);
370
- await writeIfMissing(join(serverDir, 'src', 'domain', 'flows', 'health', 'query.resolver.ts'), HEALTH_RESOLVER_TS);
370
+ await writeIfMissing(
371
+ join(serverDir, 'src', 'domain', 'narratives', 'health', 'query.resolver.ts'),
372
+ HEALTH_RESOLVER_TS,
373
+ );
371
374
 
372
375
  return {
373
376
  type: 'ServerInitialized',
@@ -0,0 +1,15 @@
1
+ import 'reflect-metadata';
2
+ import type { CommandSender, EventStore, InMemoryDatabase } from '@event-driven-io/emmett';
3
+
4
+ export interface ReactorContext {
5
+ eventStore: EventStore;
6
+ commandSender: CommandSender;
7
+ database: InMemoryDatabase;
8
+ [key: string]: unknown;
9
+ }
10
+
11
+ export interface GraphQLContext {
12
+ eventStore: EventStore;
13
+ messageBus: CommandSender;
14
+ database: InMemoryDatabase;
15
+ }
@@ -0,0 +1,15 @@
1
+ import 'reflect-metadata';
2
+ import type { CommandSender, EventStore, InMemoryDatabase } from '@event-driven-io/emmett';
3
+
4
+ export interface ReactorContext {
5
+ eventStore: EventStore;
6
+ commandSender: CommandSender;
7
+ database: InMemoryDatabase;
8
+ [key: string]: unknown;
9
+ }
10
+
11
+ export interface GraphQLContext {
12
+ eventStore: EventStore;
13
+ messageBus: CommandSender;
14
+ database: InMemoryDatabase;
15
+ }
package/src/index.ts CHANGED
@@ -5,9 +5,9 @@ export const COMMANDS = [generateServerHandler, initializeServerHandler];
5
5
  export type {
6
6
  GenerateServerCommand,
7
7
  GenerateServerEvents,
8
+ MomentGeneratedEvent,
8
9
  ServerGeneratedEvent,
9
10
  ServerGenerationFailedEvent,
10
- SliceGeneratedEvent,
11
11
  } from './commands/generate-server';
12
12
  export type {
13
13
  InitializeServerCommand,
package/src/server.ts CHANGED
@@ -7,8 +7,8 @@ import { buildSchema } from 'type-graphql';
7
7
  import { loadProjections, loadRegisterFiles, loadResolvers } from './utils';
8
8
 
9
9
  async function start() {
10
- const loadedProjections = await loadProjections('src/domain/flows/**/projection.{ts,js}');
11
- const registrations = await loadRegisterFiles('src/domain/flows/**/register.{ts,js}');
10
+ const loadedProjections = await loadProjections('src/domain/narratives/**/projection.{ts,js}');
11
+ const registrations = await loadRegisterFiles('src/domain/narratives/**/register.{ts,js}');
12
12
 
13
13
  const messageBus = getInMemoryMessageBus();
14
14
  const database = getInMemoryDatabase();
@@ -63,7 +63,7 @@ async function start() {
63
63
  };
64
64
  process.on('SIGINT', () => void shutdown());
65
65
  process.on('SIGTERM', () => void shutdown());
66
- const resolvers = await loadResolvers('src/domain/flows/**/*.resolver.{ts,js}');
66
+ const resolvers = await loadResolvers('src/domain/narratives/**/*.resolver.{ts,js}');
67
67
  type ResolverClass = new (...args: unknown[]) => unknown;
68
68
  const schema = await buildSchema({
69
69
  resolvers: resolvers as unknown as [ResolverClass, ...ResolverClass[]],
@@ -2,11 +2,11 @@ import path from 'node:path';
2
2
  import type { CommandProcessor, EventStore } from '@event-driven-io/emmett';
3
3
  import fg from 'fast-glob';
4
4
 
5
- export interface SliceRegistration {
5
+ export interface MomentRegistration {
6
6
  register: (messageBus: CommandProcessor, eventStore: EventStore) => Promise<unknown> | undefined;
7
7
  }
8
8
 
9
- export async function loadRegisterFiles(source: string): Promise<SliceRegistration[]> {
9
+ export async function loadRegisterFiles(source: string): Promise<MomentRegistration[]> {
10
10
  const files = await fg(source, { absolute: true });
11
11
 
12
12
  const modules = await Promise.all(
@@ -18,9 +18,9 @@ export async function loadRegisterFiles(source: string): Promise<SliceRegistrati
18
18
  typeof mod === 'object' &&
19
19
  mod !== null &&
20
20
  'register' in mod &&
21
- typeof (mod as SliceRegistration).register === 'function'
21
+ typeof (mod as MomentRegistration).register === 'function'
22
22
  ) {
23
- return mod as SliceRegistration;
23
+ return mod as MomentRegistration;
24
24
  }
25
25
 
26
26
  console.warn('⚠️ Skipping invalid register.ts at', file);
@@ -32,7 +32,7 @@ export async function loadRegisterFiles(source: string): Promise<SliceRegistrati
32
32
  }),
33
33
  );
34
34
 
35
- return modules.filter((m): m is SliceRegistration => m !== null);
35
+ return modules.filter((m): m is MomentRegistration => m !== null);
36
36
  }
37
37
 
38
38
  function pathToFileUrl(filePath: string): URL {
@@ -28,7 +28,7 @@ export async function loadResolvers(source: string): Promise<Resolver[]> {
28
28
  }
29
29
 
30
30
  if (allResolvers.length === 0) {
31
- throw new Error('❌ No resolvers found for any slices.');
31
+ throw new Error('❌ No resolvers found for any moments.');
32
32
  }
33
33
  return allResolvers;
34
34
  }