@specverse/engines 4.1.28 → 4.2.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 (237) hide show
  1. package/assets/examples/manifests/frontend-only.yaml +3 -6
  2. package/assets/examples/manifests/fullstack-app.yaml +5 -7
  3. package/assets/examples/manifests/fullstack-monorepo.yaml +3 -6
  4. package/dist/inference/comprehensive-engine.d.ts.map +1 -1
  5. package/dist/inference/comprehensive-engine.js +3 -19
  6. package/dist/inference/comprehensive-engine.js.map +1 -1
  7. package/dist/inference/core/rule-engine.d.ts +31 -0
  8. package/dist/inference/core/rule-engine.d.ts.map +1 -1
  9. package/dist/inference/core/rule-engine.js +117 -33
  10. package/dist/inference/core/rule-engine.js.map +1 -1
  11. package/dist/inference/core/rule-file-types.d.ts +0 -2
  12. package/dist/inference/core/rule-file-types.d.ts.map +1 -1
  13. package/dist/inference/core/rule-file-types.js +3 -6
  14. package/dist/inference/core/rule-file-types.js.map +1 -1
  15. package/dist/inference/core/rule-loader.d.ts +5 -15
  16. package/dist/inference/core/rule-loader.d.ts.map +1 -1
  17. package/dist/inference/core/rule-loader.js +43 -132
  18. package/dist/inference/core/rule-loader.js.map +1 -1
  19. package/dist/inference/core/types.d.ts +0 -6
  20. package/dist/inference/core/types.d.ts.map +1 -1
  21. package/dist/inference/core/types.js +0 -4
  22. package/dist/inference/core/types.js.map +1 -1
  23. package/dist/inference/logical/generators/component-type-resolver.d.ts +0 -26
  24. package/dist/inference/logical/generators/component-type-resolver.d.ts.map +1 -1
  25. package/dist/inference/logical/generators/component-type-resolver.js +0 -19
  26. package/dist/inference/logical/generators/component-type-resolver.js.map +1 -1
  27. package/dist/inference/logical/generators/specialist-view-expander.d.ts +1 -17
  28. package/dist/inference/logical/generators/specialist-view-expander.d.ts.map +1 -1
  29. package/dist/inference/logical/generators/specialist-view-expander.js +0 -15
  30. package/dist/inference/logical/generators/specialist-view-expander.js.map +1 -1
  31. package/dist/inference/logical/generators/view-generator.d.ts +4 -14
  32. package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
  33. package/dist/inference/logical/generators/view-generator.js +6 -26
  34. package/dist/inference/logical/generators/view-generator.js.map +1 -1
  35. package/dist/inference/logical/index.d.ts +2 -2
  36. package/dist/inference/logical/index.d.ts.map +1 -1
  37. package/dist/inference/logical/logical-engine.d.ts.map +1 -1
  38. package/dist/inference/logical/logical-engine.js +17 -80
  39. package/dist/inference/logical/logical-engine.js.map +1 -1
  40. package/dist/inference/quint-transpiler.d.ts +5 -3
  41. package/dist/inference/quint-transpiler.d.ts.map +1 -1
  42. package/dist/inference/quint-transpiler.js +11 -6
  43. package/dist/inference/quint-transpiler.js.map +1 -1
  44. package/dist/libs/instance-factories/applications/templates/generic/main-generator.js +3 -3
  45. package/dist/libs/instance-factories/applications/templates/react/api-client-generator.js +16 -6
  46. package/dist/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.js +110 -0
  47. package/dist/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.js +121 -0
  48. package/dist/libs/instance-factories/applications/templates/react-starter/detail-body-composer.js +78 -0
  49. package/dist/libs/instance-factories/applications/templates/react-starter/form-body-composer.js +190 -0
  50. package/dist/libs/instance-factories/applications/templates/react-starter/helpers-emitter.js +45 -0
  51. package/dist/libs/instance-factories/applications/templates/react-starter/html-to-jsx.js +192 -0
  52. package/dist/libs/instance-factories/applications/templates/react-starter/list-body-composer.js +46 -0
  53. package/dist/libs/instance-factories/applications/templates/react-starter/orchestrator.js +30 -0
  54. package/dist/libs/instance-factories/applications/templates/react-starter/package-json-generator.js +38 -0
  55. package/dist/libs/instance-factories/applications/templates/react-starter/regen-safety.js +89 -0
  56. package/dist/libs/instance-factories/applications/templates/react-starter/view-emitter.js +56 -0
  57. package/dist/libs/instance-factories/applications/templates/react-starter/views-generator.js +66 -0
  58. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +14 -11
  59. package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +11 -3
  60. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +27 -17
  61. package/dist/libs/instance-factories/shared/path-resolver.js +1 -1
  62. package/dist/realize/index.d.ts.map +1 -1
  63. package/dist/realize/index.js +15 -22
  64. package/dist/realize/index.js.map +1 -1
  65. package/dist/registry/utils/manifest-adapter.d.ts +8 -1
  66. package/dist/registry/utils/manifest-adapter.d.ts.map +1 -1
  67. package/dist/registry/utils/manifest-adapter.js +8 -1
  68. package/dist/registry/utils/manifest-adapter.js.map +1 -1
  69. package/libs/instance-factories/applications/react-app-starter.yaml +150 -0
  70. package/libs/instance-factories/applications/templates/generic/main-generator.ts +3 -3
  71. package/libs/instance-factories/applications/templates/react/api-client-generator.ts +16 -6
  72. package/libs/instance-factories/applications/templates/react-starter/README.md +211 -0
  73. package/libs/instance-factories/applications/templates/react-starter/__tests__/dashboard-body-composer.test.ts +153 -0
  74. package/libs/instance-factories/applications/templates/react-starter/__tests__/detail-body-composer.test.ts +145 -0
  75. package/libs/instance-factories/applications/templates/react-starter/__tests__/form-body-composer.test.ts +175 -0
  76. package/libs/instance-factories/applications/templates/react-starter/__tests__/helpers-emitter.test.ts +55 -0
  77. package/libs/instance-factories/applications/templates/react-starter/__tests__/html-to-jsx.test.ts +140 -0
  78. package/libs/instance-factories/applications/templates/react-starter/__tests__/list-body-composer.test.ts +146 -0
  79. package/libs/instance-factories/applications/templates/react-starter/__tests__/orchestrator.test.ts +163 -0
  80. package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p2-factory-imports.test.ts +116 -0
  81. package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p3-rendered-output.test.ts +183 -0
  82. package/libs/instance-factories/applications/templates/react-starter/__tests__/regen-safety.test.ts +144 -0
  83. package/libs/instance-factories/applications/templates/react-starter/__tests__/starter-generators.test.ts +114 -0
  84. package/libs/instance-factories/applications/templates/react-starter/__tests__/view-emitter.test.ts +107 -0
  85. package/libs/instance-factories/applications/templates/react-starter/__tests__/views-generator.test.ts +139 -0
  86. package/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.ts +141 -0
  87. package/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.ts +174 -0
  88. package/libs/instance-factories/applications/templates/react-starter/detail-body-composer.ts +135 -0
  89. package/libs/instance-factories/applications/templates/react-starter/form-body-composer.ts +306 -0
  90. package/libs/instance-factories/applications/templates/react-starter/helpers-emitter.ts +60 -0
  91. package/libs/instance-factories/applications/templates/react-starter/html-to-jsx.ts +334 -0
  92. package/libs/instance-factories/applications/templates/react-starter/list-body-composer.ts +120 -0
  93. package/libs/instance-factories/applications/templates/react-starter/orchestrator.ts +80 -0
  94. package/libs/instance-factories/applications/templates/react-starter/package-json-generator.ts +57 -0
  95. package/libs/instance-factories/applications/templates/react-starter/regen-safety.ts +157 -0
  96. package/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +47 -0
  97. package/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +94 -0
  98. package/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +114 -0
  99. package/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +72 -0
  100. package/libs/instance-factories/applications/templates/react-starter/view-emitter.ts +151 -0
  101. package/libs/instance-factories/applications/templates/react-starter/views-generator.ts +137 -0
  102. package/libs/instance-factories/cli/templates/commander/command-generator.ts +14 -11
  103. package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +11 -3
  104. package/libs/instance-factories/services/templates/prisma/controller-generator.ts +27 -17
  105. package/libs/instance-factories/shared/path-resolver.ts +8 -2
  106. package/package.json +3 -3
  107. package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +0 -530
  108. package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +0 -73
  109. package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +0 -99
  110. package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +0 -49
  111. package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +0 -156
  112. package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +0 -935
  113. package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +0 -143
  114. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +0 -646
  115. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +0 -65
  116. package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +0 -143
  117. package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +0 -143
  118. package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +0 -355
  119. package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +0 -91
  120. package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +0 -79
  121. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js.bak +0 -244
  122. package/dist/libs/instance-factories/views/index.js +0 -48
  123. package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +0 -742
  124. package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +0 -824
  125. package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +0 -719
  126. package/dist/libs/instance-factories/views/templates/react/app-generator.js +0 -45
  127. package/dist/libs/instance-factories/views/templates/react/components-generator.js +0 -820
  128. package/dist/libs/instance-factories/views/templates/react/forms-generator.js +0 -275
  129. package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +0 -46
  130. package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +0 -81
  131. package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +0 -9
  132. package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +0 -23
  133. package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +0 -21
  134. package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +0 -299
  135. package/dist/libs/instance-factories/views/templates/react/router-generator.js +0 -136
  136. package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +0 -107
  137. package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +0 -187
  138. package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +0 -7
  139. package/dist/libs/instance-factories/views/templates/react/types-generator.js +0 -56
  140. package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +0 -27
  141. package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +0 -29
  142. package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +0 -261
  143. package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +0 -34
  144. package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -800
  145. package/dist/libs/instance-factories/views/templates/shared/base-generator.js +0 -305
  146. package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +0 -517
  147. package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
  148. package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +0 -445
  149. package/dist/libs/instance-factories/views/templates/shared/index.js +0 -80
  150. package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +0 -210
  151. package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +0 -492
  152. package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -321
  153. package/dist/realize/index.js.bak +0 -758
  154. package/libs/instance-factories/applications/react-app.yaml +0 -186
  155. package/libs/instance-factories/applications/templates/react/_view-components-source.ts +0 -555
  156. package/libs/instance-factories/applications/templates/react/app-tsx-generator.ts +0 -94
  157. package/libs/instance-factories/applications/templates/react/field-helpers-generator.ts +0 -106
  158. package/libs/instance-factories/applications/templates/react/package-json-generator.ts +0 -57
  159. package/libs/instance-factories/applications/templates/react/pattern-adapter-generator.ts +0 -179
  160. package/libs/instance-factories/applications/templates/react/react-pattern-adapter.tsx +0 -1347
  161. package/libs/instance-factories/applications/templates/react/relationship-field-generator.ts +0 -150
  162. package/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.ts +0 -704
  163. package/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.ts +0 -84
  164. package/libs/instance-factories/applications/templates/react/view-dashboard-generator.ts +0 -150
  165. package/libs/instance-factories/applications/templates/react/view-detail-generator.ts +0 -150
  166. package/libs/instance-factories/applications/templates/react/view-form-generator.ts +0 -362
  167. package/libs/instance-factories/applications/templates/react/view-list-generator.ts +0 -98
  168. package/libs/instance-factories/applications/templates/react/view-router-generator.ts +0 -89
  169. package/libs/instance-factories/views/README.md +0 -62
  170. package/libs/instance-factories/views/index.d.ts +0 -13
  171. package/libs/instance-factories/views/index.d.ts.map +0 -1
  172. package/libs/instance-factories/views/index.js +0 -18
  173. package/libs/instance-factories/views/index.js.map +0 -1
  174. package/libs/instance-factories/views/index.ts +0 -45
  175. package/libs/instance-factories/views/react-components.yaml +0 -129
  176. package/libs/instance-factories/views/templates/ARCHITECTURE.md +0 -198
  177. package/libs/instance-factories/views/templates/react/adapters/antd-adapter.ts +0 -869
  178. package/libs/instance-factories/views/templates/react/adapters/mui-adapter.ts +0 -953
  179. package/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.ts +0 -806
  180. package/libs/instance-factories/views/templates/react/app-generator.ts +0 -55
  181. package/libs/instance-factories/views/templates/react/components-generator.ts +0 -938
  182. package/libs/instance-factories/views/templates/react/forms-generator.ts +0 -325
  183. package/libs/instance-factories/views/templates/react/frontend-package-json-generator.ts +0 -57
  184. package/libs/instance-factories/views/templates/react/hooks-generator.ts +0 -106
  185. package/libs/instance-factories/views/templates/react/index-css-generator.ts +0 -14
  186. package/libs/instance-factories/views/templates/react/index-html-generator.ts +0 -34
  187. package/libs/instance-factories/views/templates/react/main-tsx-generator.ts +0 -29
  188. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts +0 -152
  189. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts.map +0 -1
  190. package/libs/instance-factories/views/templates/react/react-component-generator.js +0 -398
  191. package/libs/instance-factories/views/templates/react/react-component-generator.js.map +0 -1
  192. package/libs/instance-factories/views/templates/react/react-component-generator.ts +0 -533
  193. package/libs/instance-factories/views/templates/react/router-generator.ts +0 -197
  194. package/libs/instance-factories/views/templates/react/router-generic-generator.ts +0 -132
  195. package/libs/instance-factories/views/templates/react/shared-utils-generator.ts +0 -196
  196. package/libs/instance-factories/views/templates/react/spec-json-generator.ts +0 -17
  197. package/libs/instance-factories/views/templates/react/types-generator.ts +0 -76
  198. package/libs/instance-factories/views/templates/react/views-metadata-generator.ts +0 -42
  199. package/libs/instance-factories/views/templates/react/vite-config-generator.ts +0 -38
  200. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.d.ts.map +0 -1
  201. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js.map +0 -1
  202. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.ts +0 -474
  203. package/libs/instance-factories/views/templates/shared/__tests__/composite-patterns.test.ts +0 -242
  204. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts +0 -77
  205. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts.map +0 -1
  206. package/libs/instance-factories/views/templates/shared/adapter-types.js +0 -47
  207. package/libs/instance-factories/views/templates/shared/adapter-types.js.map +0 -1
  208. package/libs/instance-factories/views/templates/shared/adapter-types.ts +0 -142
  209. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts +0 -63
  210. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts.map +0 -1
  211. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -822
  212. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js.map +0 -1
  213. package/libs/instance-factories/views/templates/shared/atomic-components-registry.ts +0 -908
  214. package/libs/instance-factories/views/templates/shared/base-generator.d.ts +0 -247
  215. package/libs/instance-factories/views/templates/shared/base-generator.d.ts.map +0 -1
  216. package/libs/instance-factories/views/templates/shared/base-generator.js +0 -363
  217. package/libs/instance-factories/views/templates/shared/base-generator.js.map +0 -1
  218. package/libs/instance-factories/views/templates/shared/base-generator.ts +0 -608
  219. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts +0 -254
  220. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts.map +0 -1
  221. package/libs/instance-factories/views/templates/shared/component-metadata.js +0 -602
  222. package/libs/instance-factories/views/templates/shared/component-metadata.js.map +0 -1
  223. package/libs/instance-factories/views/templates/shared/component-metadata.ts +0 -803
  224. package/libs/instance-factories/views/templates/shared/composite-pattern-types.ts +0 -250
  225. package/libs/instance-factories/views/templates/shared/composite-patterns.ts +0 -535
  226. package/libs/instance-factories/views/templates/shared/index.ts +0 -68
  227. package/libs/instance-factories/views/templates/shared/pattern-validator.ts +0 -279
  228. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts +0 -149
  229. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts.map +0 -1
  230. package/libs/instance-factories/views/templates/shared/property-mapper.js +0 -580
  231. package/libs/instance-factories/views/templates/shared/property-mapper.js.map +0 -1
  232. package/libs/instance-factories/views/templates/shared/property-mapper.ts +0 -700
  233. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts +0 -143
  234. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts.map +0 -1
  235. package/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -420
  236. package/libs/instance-factories/views/templates/shared/syntax-mapper.js.map +0 -1
  237. package/libs/instance-factories/views/templates/shared/syntax-mapper.ts +0 -539
@@ -0,0 +1,137 @@
1
+ /**
2
+ * View files generator for ReactAppStarter
3
+ *
4
+ * Called by the realize engine. Iterates over the expanded spec's
5
+ * models × view types, dispatches to the right composer, and returns
6
+ * a filename → source map. Realize writes each file.
7
+ *
8
+ * Also emits the local helpers library (src/lib/entity-display.ts)
9
+ * so generated projects have zero @specverse/runtime runtime deps.
10
+ */
11
+
12
+ import { emitView, type EmitContext, type ModelSpec, type ViewSpec, type RenderBodyFn } from './view-emitter.js';
13
+ import { composeListBody } from './list-body-composer.js';
14
+ import { composeDetailBody } from './detail-body-composer.js';
15
+ import { composeFormBody } from './form-body-composer.js';
16
+ import { composeDashboardBody } from './dashboard-body-composer.js';
17
+ import { emitEntityDisplay } from './helpers-emitter.js';
18
+
19
+ /**
20
+ * The four primary view types Factory B currently emits. Specialist
21
+ * types (board, timeline, calendar, etc.) are not yet implemented —
22
+ * if the expanded spec declares one, we skip it and log a TODO.
23
+ * These users can add composers under Phase 2e.
24
+ */
25
+ const PRIMARY_VIEW_TYPES = ['list', 'detail', 'form', 'dashboard'] as const;
26
+ type PrimaryViewType = typeof PRIMARY_VIEW_TYPES[number];
27
+
28
+ const COMPOSER_BY_TYPE: Record<PrimaryViewType, RenderBodyFn> = {
29
+ list: composeListBody,
30
+ detail: composeDetailBody,
31
+ form: composeFormBody,
32
+ dashboard: composeDashboardBody,
33
+ };
34
+
35
+ /** Generator contract — the shape realize expects. */
36
+ export interface ViewsGeneratorContext {
37
+ /** The expanded spec (post-inference). */
38
+ spec: ExpandedSpec;
39
+ /** The resolved manifest configuration. Not currently read by this
40
+ * generator but passed by realize for parity with other generators. */
41
+ manifest?: unknown;
42
+ }
43
+
44
+ export interface ExpandedSpec {
45
+ /** Models keyed by name. */
46
+ models?: Record<string, ModelSpec>;
47
+ /** Views keyed by view name (e.g. "PostListView"). */
48
+ views?: Record<string, ViewSpec & { type: string; model?: string }>;
49
+ }
50
+
51
+ export interface GeneratedFiles {
52
+ [relativePath: string]: string;
53
+ }
54
+
55
+ /**
56
+ * Generate all view files + local helpers.
57
+ *
58
+ * Paths are RELATIVE to the frontend root (`frontendDir` in the
59
+ * manifest). Realize prepends the absolute output path when writing.
60
+ */
61
+ export async function generate(context: ViewsGeneratorContext): Promise<GeneratedFiles> {
62
+ const files: GeneratedFiles = {};
63
+ const spec = context.spec;
64
+ const models = spec.models ?? {};
65
+ const viewsBySpec = spec.views ?? {};
66
+
67
+ // Group the spec's views by model+type so we can decide, for each
68
+ // (model, type) pair, whether to use the user's view spec or emit
69
+ // a default.
70
+ const viewIndex = indexViews(viewsBySpec);
71
+ const skippedSpecialists: string[] = [];
72
+
73
+ for (const [modelName, model] of Object.entries(models)) {
74
+ for (const viewType of PRIMARY_VIEW_TYPES) {
75
+ const viewName = `${modelName}${capitalize(viewType)}View`;
76
+ // Prefer a user-defined view of that shape if one exists; fall
77
+ // back to a synthesized default.
78
+ const view = viewIndex.get(viewName) ?? synthesizeDefault(modelName, viewType);
79
+ const source = emitView({
80
+ view,
81
+ viewName,
82
+ model,
83
+ modelSchemas: models,
84
+ renderBody: COMPOSER_BY_TYPE[viewType],
85
+ });
86
+ files[`src/views/${viewName}.tsx`] = source;
87
+ }
88
+ }
89
+
90
+ // Surface any specialist-type views the user declared but we can't
91
+ // emit yet. The runtime (ReactAppRuntime) handles these; in starter
92
+ // kit mode the user has to write them manually for now.
93
+ for (const [name, view] of Object.entries(viewsBySpec)) {
94
+ if (!PRIMARY_VIEW_TYPES.includes(view.type as PrimaryViewType)) {
95
+ skippedSpecialists.push(`${name} (type=${view.type})`);
96
+ }
97
+ }
98
+ if (skippedSpecialists.length > 0) {
99
+ console.warn(
100
+ `[ReactAppStarter] Skipped ${skippedSpecialists.length} specialist view(s) — ` +
101
+ `implement composers for: ${[...new Set(Object.values(viewsBySpec)
102
+ .filter(v => !PRIMARY_VIEW_TYPES.includes(v.type as PrimaryViewType))
103
+ .map(v => v.type))].join(', ')}. ` +
104
+ `Skipped: ${skippedSpecialists.join(', ')}`
105
+ );
106
+ }
107
+
108
+ // Local helpers
109
+ files['src/lib/entity-display.ts'] = emitEntityDisplay();
110
+
111
+ return files;
112
+ }
113
+
114
+ // ──────────────────────────────────────────────────────────────────────
115
+ // Helpers
116
+ // ──────────────────────────────────────────────────────────────────────
117
+
118
+ function indexViews(
119
+ views: Record<string, ViewSpec & { type: string; model?: string }>
120
+ ): Map<string, ViewSpec & { type: string; model?: string }> {
121
+ const out = new Map<string, ViewSpec & { type: string; model?: string }>();
122
+ for (const [name, view] of Object.entries(views)) {
123
+ out.set(name, view);
124
+ }
125
+ return out;
126
+ }
127
+
128
+ function synthesizeDefault(modelName: string, viewType: PrimaryViewType): ViewSpec {
129
+ return {
130
+ type: viewType,
131
+ model: modelName,
132
+ };
133
+ }
134
+
135
+ function capitalize(s: string): string {
136
+ return s.charAt(0).toUpperCase() + s.slice(1);
137
+ }
@@ -393,22 +393,25 @@ import type { ParserEngine, InferenceEngine, RealizeEngine } from '@specverse/ty
393
393
  process.exit(1);
394
394
  }
395
395
 
396
- // Runtime mode (default): swap ReactApp ReactAppRuntime in manifest
396
+ // --static ejects to a standalone starter kit (ReactAppStarter).
397
+ // Default: whatever the manifest declares (ReactAppRuntime in the
398
+ // shipped templates). The swap is a convenience only — users can
399
+ // achieve the same by editing their manifest directly.
397
400
  let effectiveManifestPath = manifestPath;
398
- if (!options.static) {
401
+ if (options.static) {
399
402
  const manifestContent = readFileSync(manifestPath, 'utf8');
400
- if (/instanceFactory:\\s*["']?ReactApp["']?\\s*$/m.test(manifestContent)) {
403
+ if (/instanceFactory:\\s*["']?ReactAppRuntime["']?\\s*$/m.test(manifestContent)) {
401
404
  const { tmpdir } = await import('os');
402
- const runtimeManifest = manifestContent.replace(
403
- /instanceFactory:\\s*["']?ReactApp["']?\\s*$/gm,
404
- 'instanceFactory: "ReactAppRuntime"'
405
+ const staticManifest = manifestContent.replace(
406
+ /instanceFactory:\\s*["']?ReactAppRuntime["']?\\s*$/gm,
407
+ 'instanceFactory: "ReactAppStarter"'
405
408
  );
406
- effectiveManifestPath = join(tmpdir(), 'specverse-runtime-manifest.yaml');
407
- writeFileSync(effectiveManifestPath, runtimeManifest, 'utf8');
408
- console.log(' Using runtime mode (slim frontend with @specverse/runtime)');
409
+ effectiveManifestPath = join(tmpdir(), 'specverse-static-manifest.yaml');
410
+ writeFileSync(effectiveManifestPath, staticManifest, 'utf8');
411
+ console.log(' Using static mode (standalone starter kit — ReactAppStarter)');
412
+ } else {
413
+ console.log(' Using static mode (manifest factory unchanged)');
409
414
  }
410
- } else {
411
- console.log(' Using static mode (full frontend generation)');
412
415
  }
413
416
 
414
417
  const realizeEngine = registry.getEngineForCapability('realize') as RealizeEngine;
@@ -82,8 +82,11 @@ fastify.get('/api/runtime/info', async () => ({
82
82
  services: ${JSON.stringify(servicesList)}
83
83
  }));
84
84
 
85
- ${hasEvents ? `// Event history endpoint
86
- fastify.get('/api/events', async () => eventBus.getHistory());` : ''}
85
+ ${hasEvents ? `// Event history endpoint — runtime introspection, not part of
86
+ // the user's API surface. Lives under /api/runtime/ so it doesn't
87
+ // collide with the auto-generated Event model route (spec models
88
+ // named "Event" produce a GET /api/events of their own).
89
+ fastify.get('/api/runtime/events', async () => eventBus.getHistory());` : ''}
87
90
 
88
91
  // Register routes
89
92
  ${routeImports}
@@ -102,7 +105,12 @@ const start = async () => {
102
105
  ${hasEvents ? ` // Register WebSocket bridge for real-time frontend events
103
106
  await registerWebSocketBridge(fastify);` : ''}
104
107
  const port = parseInt(process.env.PORT || '3000');
105
- await fastify.listen({ port, host: '0.0.0.0' });
108
+ // Listen on :: (IPv6 wildcard) instead of 0.0.0.0 so the server
109
+ // accepts both IPv6 and IPv4-mapped connections. Node resolves
110
+ // 'localhost' to ::1 first; if the backend only binds IPv4, the
111
+ // vite dev-server WS proxy hits ECONNREFUSED on ::1 and doesn't
112
+ // fall back to 127.0.0.1 cleanly. Binding :: fixes both cases.
113
+ await fastify.listen({ port, host: '::' });
106
114
  console.log(\`Server running at http://localhost:\${port}\`);
107
115
  console.log(\`API endpoints: ${modelNames.map((n: string) => `/api/${n.toLowerCase()}s`).join(', ')}\`);
108
116
  ${hasEvents ? ` console.log(\`WebSocket: ws://localhost:\${port}/ws\`);
@@ -282,39 +282,49 @@ function generateEvolveMethod(model: any, modelName: string, modelVar: string, p
282
282
 
283
283
  return `
284
284
  /**
285
- * Evolve ${modelName} through lifecycle
285
+ * Evolve ${modelName} through lifecycle "${lifecycleName}"
286
286
  * States: ${states.join(' → ')}
287
+ *
288
+ * Accepts either the client shape { toState, lifecycleName? } or
289
+ * the direct column shape { ${lifecycleName}: ... }. The frontend
290
+ * runtime's useTransitionStateMutation always sends the former; the
291
+ * realized smoke-parity script can send either.
287
292
  */
288
293
  public async evolve(id: string, data: any): Promise<any> {
289
- // Validate input
290
- const validationResult = this.validate(data, { operation: 'evolve' });
291
- if (!validationResult.valid) {
292
- throw new Error(\`Validation failed: \${validationResult.errors.join(', ')}\`);
293
- }
294
-
295
294
  // Get current record to check lifecycle state
296
295
  const current = await ${prismaDelegate}.findUnique({ where: { id: parseId(id) } });
297
296
  if (!current) {
298
297
  throw new Error('${modelName} not found');
299
298
  }
300
299
 
300
+ // Normalize input: translate client { toState: X } shape to the
301
+ // lifecycle's actual column name. If the caller already sent the
302
+ // column directly, keep whatever they sent.
303
+ const targetLifecycle = data?.lifecycleName || '${lifecycleName}';
304
+ const targetState = data?.toState ?? data?.state ?? data?.[targetLifecycle];
305
+ if (!targetState) {
306
+ throw new Error('evolve requires toState (or ${lifecycleName}) in the request body');
307
+ }
308
+
301
309
  ${states.length > 0 ? `
302
- // Validate lifecycle transition
303
- const currentState = (current as any).${lifecycleName};
304
- const newState = data.${lifecycleName};
305
- if (newState) {
306
- const validTransitions: Record<string, string[]> = ${JSON.stringify(validTransitions)};
307
- const allowed = validTransitions[currentState] || [];
308
- if (!allowed.includes(newState)) {
309
- throw new Error(\`Invalid transition: \${currentState} → \${newState}. Allowed: \${allowed.join(', ') || 'none'}\`);
310
- }
310
+ // Validate lifecycle transition against declared flow
311
+ const currentState = (current as any)[targetLifecycle];
312
+ const validTransitions: Record<string, string[]> = ${JSON.stringify(validTransitions)};
313
+ const allowed = validTransitions[currentState] || [];
314
+ if (!allowed.includes(targetState)) {
315
+ throw new Error(\`Invalid transition: \${currentState} → \${targetState}. Allowed: \${allowed.join(', ') || 'none'}\`);
311
316
  }
312
317
  ` : ''}
313
318
 
319
+ // Build the Prisma update payload — only the lifecycle column
320
+ // changes. Strips toState/lifecycleName/state so Prisma doesn't
321
+ // reject unknown fields.
322
+ const updateData: any = { [targetLifecycle]: targetState };
323
+
314
324
  // Update record
315
325
  const ${modelVar} = await ${prismaDelegate}.update({
316
326
  where: { id: parseId(id) },
317
- data${generateIncludeRelationships(model)}
327
+ data: updateData${generateIncludeRelationships(model)}
318
328
  });
319
329
 
320
330
  // Publish CURED event
@@ -93,9 +93,15 @@ export function getApiBaseUrl(config: PathResolverConfig & { apiBaseUrl?: string
93
93
  return '${VITE_API_BASE_URL}'; // Environment variable placeholder
94
94
  }
95
95
 
96
- // In monorepo mode, default to local backend
96
+ // In monorepo mode, default to local backend.
97
+ // Use explicit 127.0.0.1 (not `localhost`) to avoid Node's
98
+ // happy-eyeballs IPv6→IPv4 fallback. The vite dev-server WS proxy
99
+ // doesn't handle that fallback for WebSocket upgrades — it would
100
+ // try `[::1]:3000`, get ECONNREFUSED if the backend isn't on IPv6,
101
+ // and log the error instead of retrying on 127.0.0.1. Pinning
102
+ // 127.0.0.1 in the proxy target sidesteps that entirely.
97
103
  const port = (config as any).serverPort || 3000;
98
- return `http://localhost:${port}`;
104
+ return `http://127.0.0.1:${port}`;
99
105
  }
100
106
 
101
107
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "4.1.28",
4
- "description": "SpecVerse toolchain \u2014 parser, inference, realize, generators, AI, registry",
3
+ "version": "4.2.0",
4
+ "description": "SpecVerse toolchain parser, inference, realize, generators, AI, registry",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -65,4 +65,4 @@
65
65
  "access": "public"
66
66
  },
67
67
  "license": "MIT"
68
- }
68
+ }