@specverse/engines 4.1.5 → 4.1.7

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 (122) hide show
  1. package/dist/libs/instance-factories/applications/templates/generic/backend-env-generator.js +22 -0
  2. package/dist/libs/instance-factories/applications/templates/generic/backend-package-json-generator.js +66 -0
  3. package/dist/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.js +54 -0
  4. package/dist/libs/instance-factories/applications/templates/generic/main-generator.js +290 -0
  5. package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +530 -0
  6. package/dist/libs/instance-factories/applications/templates/react/api-client-generator.js +437 -0
  7. package/dist/libs/instance-factories/applications/templates/react/api-types-generator.js +146 -0
  8. package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +73 -0
  9. package/dist/libs/instance-factories/applications/templates/react/env-example-generator.js +18 -0
  10. package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +99 -0
  11. package/dist/libs/instance-factories/applications/templates/react/gitignore-generator.js +35 -0
  12. package/dist/libs/instance-factories/applications/templates/react/index-css-generator.js +9 -0
  13. package/dist/libs/instance-factories/applications/templates/react/index-html-generator.js +23 -0
  14. package/dist/libs/instance-factories/applications/templates/react/main-tsx-generator.js +29 -0
  15. package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +49 -0
  16. package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +156 -0
  17. package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +935 -0
  18. package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +143 -0
  19. package/dist/libs/instance-factories/applications/templates/react/runtime-app-tsx-generator.js +101 -0
  20. package/dist/libs/instance-factories/applications/templates/react/runtime-package-json-generator.js +50 -0
  21. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +646 -0
  22. package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +65 -0
  23. package/dist/libs/instance-factories/applications/templates/react/tsconfig-generator.js +28 -0
  24. package/dist/libs/instance-factories/applications/templates/react/use-api-hooks-generator.js +132 -0
  25. package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +143 -0
  26. package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +143 -0
  27. package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +355 -0
  28. package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +91 -0
  29. package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +79 -0
  30. package/dist/libs/instance-factories/applications/templates/react/vite-config-generator.js +42 -0
  31. package/dist/libs/instance-factories/cli/templates/commander/cli-bin-wrapper-generator.js +11 -0
  32. package/dist/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +111 -0
  33. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +928 -0
  34. package/dist/libs/instance-factories/communication/templates/eventemitter/bus-generator.js +83 -0
  35. package/dist/libs/instance-factories/communication/templates/eventemitter/publisher-generator.js +91 -0
  36. package/dist/libs/instance-factories/communication/templates/eventemitter/subscriber-generator.js +86 -0
  37. package/dist/libs/instance-factories/controllers/templates/fastify/meta-routes-generator.js +93 -0
  38. package/dist/libs/instance-factories/controllers/templates/fastify/routes-generator.js +280 -0
  39. package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +125 -0
  40. package/dist/libs/instance-factories/infrastructure/templates/docker-k8s/infrastructure-generator.js +25 -0
  41. package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +371 -0
  42. package/dist/libs/instance-factories/orms/templates/prisma/services-generator.js +266 -0
  43. package/dist/libs/instance-factories/scaffolding/templates/generic/env-example-generator.js +51 -0
  44. package/dist/libs/instance-factories/scaffolding/templates/generic/env-generator.js +61 -0
  45. package/dist/libs/instance-factories/scaffolding/templates/generic/gitignore-generator.js +59 -0
  46. package/dist/libs/instance-factories/scaffolding/templates/generic/package-json-generator.js +126 -0
  47. package/dist/libs/instance-factories/scaffolding/templates/generic/readme-generator.js +159 -0
  48. package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.js +56 -0
  49. package/dist/libs/instance-factories/scaffolding/templates/generic/tsconfig-react-generator.js +37 -0
  50. package/dist/libs/instance-factories/sdks/templates/python/sdk-generator.js +29 -0
  51. package/dist/libs/instance-factories/sdks/templates/typescript/sdk-generator.js +28 -0
  52. package/dist/libs/instance-factories/services/templates/memory/generate-interpreter.js +14 -0
  53. package/dist/libs/instance-factories/services/templates/memory/step-conventions-memory.js +415 -0
  54. package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +177 -0
  55. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +413 -0
  56. package/dist/libs/instance-factories/services/templates/prisma/service-generator.js +243 -0
  57. package/dist/libs/instance-factories/services/templates/prisma/step-conventions.js +264 -0
  58. package/dist/libs/instance-factories/services/templates/shared-patterns.js +24 -0
  59. package/dist/libs/instance-factories/shared/path-resolver.js +59 -0
  60. package/dist/libs/instance-factories/storage/templates/mongodb/config-generator.js +13 -0
  61. package/dist/libs/instance-factories/storage/templates/mongodb/docker-generator.js +16 -0
  62. package/dist/libs/instance-factories/storage/templates/postgresql/config-generator.js +45 -0
  63. package/dist/libs/instance-factories/storage/templates/postgresql/docker-generator.js +46 -0
  64. package/dist/libs/instance-factories/storage/templates/redis/config-generator.js +14 -0
  65. package/dist/libs/instance-factories/storage/templates/redis/docker-generator.js +16 -0
  66. package/dist/libs/instance-factories/test-generation.js +145 -0
  67. package/dist/libs/instance-factories/testing/templates/vitest/tests-generator.js +30 -0
  68. package/dist/libs/instance-factories/tools/templates/mcp/mcp-server-generator.js +149 -0
  69. package/dist/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.js +232 -0
  70. package/dist/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.js +49 -0
  71. package/dist/libs/instance-factories/tools/templates/mcp/static/src/index.js +18 -0
  72. package/dist/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.js +0 -0
  73. package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.js +97 -0
  74. package/dist/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.js +64 -0
  75. package/dist/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.js +182 -0
  76. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.js +1210 -0
  77. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.js +172 -0
  78. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.js +240 -0
  79. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.js +147 -0
  80. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.js +281 -0
  81. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.js +409 -0
  82. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.js +414 -0
  83. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.js +467 -0
  84. package/dist/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.js +135 -0
  85. package/dist/libs/instance-factories/tools/templates/mcp/static/src/types/index.js +0 -0
  86. package/dist/libs/instance-factories/tools/templates/vscode/static/extension.js +965 -0
  87. package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js +238 -0
  88. package/dist/libs/instance-factories/validation/templates/zod/validation-generator.js +25 -0
  89. package/dist/libs/instance-factories/views/index.js +48 -0
  90. package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +742 -0
  91. package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +824 -0
  92. package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +719 -0
  93. package/dist/libs/instance-factories/views/templates/react/app-generator.js +45 -0
  94. package/dist/libs/instance-factories/views/templates/react/components-generator.js +779 -0
  95. package/dist/libs/instance-factories/views/templates/react/forms-generator.js +285 -0
  96. package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +46 -0
  97. package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +111 -0
  98. package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +9 -0
  99. package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +23 -0
  100. package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +21 -0
  101. package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +299 -0
  102. package/dist/libs/instance-factories/views/templates/react/router-generator.js +136 -0
  103. package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +107 -0
  104. package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +179 -0
  105. package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +7 -0
  106. package/dist/libs/instance-factories/views/templates/react/types-generator.js +56 -0
  107. package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +27 -0
  108. package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +29 -0
  109. package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +261 -0
  110. package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +34 -0
  111. package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +800 -0
  112. package/dist/libs/instance-factories/views/templates/shared/base-generator.js +305 -0
  113. package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +517 -0
  114. package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
  115. package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +445 -0
  116. package/dist/libs/instance-factories/views/templates/shared/index.js +80 -0
  117. package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +210 -0
  118. package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +492 -0
  119. package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +321 -0
  120. package/dist/realize/index.js +36 -12
  121. package/dist/realize/index.js.map +1 -1
  122. package/package.json +3 -2
@@ -0,0 +1,437 @@
1
+ async function generate(context) {
2
+ const { manifest } = context;
3
+ const apiPattern = detectApiPattern(manifest);
4
+ return generateApiClient(apiPattern);
5
+ }
6
+ function detectApiPattern(manifest) {
7
+ const routingCapability = manifest.capabilityMappings?.find(
8
+ (mapping) => mapping.capability === "api.rest"
9
+ );
10
+ if (!routingCapability) {
11
+ return "rest";
12
+ }
13
+ const instanceFactory = routingCapability.instanceFactory;
14
+ const restFactories = ["FastifyAPI", "ExpressAPI", "NestJSAPI", "FastifyPrismaAPI"];
15
+ const controllerFactories = ["ControllerAPI", "RuntimeAPI"];
16
+ if (restFactories.includes(instanceFactory)) {
17
+ return "rest";
18
+ } else if (controllerFactories.includes(instanceFactory)) {
19
+ return "controller";
20
+ }
21
+ return "rest";
22
+ }
23
+ function generateApiClient(pattern) {
24
+ const commonImports = `/**
25
+ * API Client
26
+ *
27
+ * HTTP client for interacting with the backend API
28
+ * Generated based on backend routing instance factory
29
+ */
30
+
31
+ import type { ApiResponse, RuntimeInfo, ModelSchema, View, Service, Behavior, Entity, Operation } from '../types/api';
32
+
33
+ // Get API URL from query parameter or default to proxy
34
+ const urlParams = new URLSearchParams(window.location.search);
35
+ const apiUrl = urlParams.get('api');
36
+
37
+ // API base URL
38
+ export const API_BASE = apiUrl ? \`\${apiUrl}/api\` : '/api';
39
+
40
+ // WebSocket URL - preserve path and use wss:// for https://
41
+ export const WS_URL = apiUrl
42
+ ? \`\${apiUrl.replace(/^http/, 'ws')}/ws\`
43
+ : \`\${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}/\${window.location.host}/ws\`;
44
+
45
+ /**
46
+ * Generic API request helper
47
+ */
48
+ async function apiRequest<T = any>(
49
+ method: string,
50
+ path: string,
51
+ body: any = null
52
+ ): Promise<T> {
53
+ const options: RequestInit = {
54
+ method,
55
+ headers: { 'Content-Type': 'application/json' }
56
+ };
57
+
58
+ if (body) {
59
+ options.body = JSON.stringify(body);
60
+ }
61
+
62
+ const response = await fetch(\`\${API_BASE}\${path}\`, options);
63
+
64
+ if (!response.ok) {
65
+ throw new Error(\`API request failed: \${response.statusText}\`);
66
+ }
67
+
68
+ return await response.json();
69
+ }
70
+
71
+ /**
72
+ * Get full specification object
73
+ */
74
+ export async function getSpec(): Promise<any> {
75
+ return apiRequest('GET', '/spec');
76
+ }
77
+
78
+ /**
79
+ * Get runtime information
80
+ */
81
+ export async function getRuntimeInfo(): Promise<RuntimeInfo> {
82
+ return apiRequest<RuntimeInfo>('GET', '/runtime/info');
83
+ }`;
84
+ const metaFunctions = `
85
+ /**
86
+ * Get all views
87
+ */
88
+ export async function getViews(): Promise<View[]> {
89
+ const result = await apiRequest<{ views: View[] }>('GET', '/views');
90
+ return result.views || [];
91
+ }
92
+
93
+ /**
94
+ * Get all services
95
+ */
96
+ export async function getServices(): Promise<Service[]> {
97
+ const result = await apiRequest<{ services: Service[] }>('GET', '/services');
98
+ return result.services || [];
99
+ }
100
+
101
+ /**
102
+ * Get operations for a controller
103
+ */
104
+ export async function getControllerOperations(controllerName: string): Promise<Operation[]> {
105
+ const result = await apiRequest<{ operations: Operation[] }>('GET', \`/controllers/\${controllerName}/operations\`);
106
+ return result.operations || [];
107
+ }
108
+
109
+ /**
110
+ * Get behaviors for a model
111
+ */
112
+ export async function getBehaviors(modelName: string): Promise<Behavior[]> {
113
+ const result = await apiRequest<{ behaviors: Behavior[] }>('GET', \`/behaviors/\${modelName}\`);
114
+ return result.behaviors || [];
115
+ }
116
+
117
+ /**
118
+ * Get event history
119
+ */
120
+ export async function getEventHistory(limit: number = 100): Promise<Array<{
121
+ eventName: string;
122
+ payload: any;
123
+ timestamp: string;
124
+ }>> {
125
+ const result = await apiRequest<{
126
+ history: Array<{ eventName: string; payload: any; timestamp: string }>;
127
+ }>('GET', \`/events/history?limit=\${limit}\`);
128
+ return result.history || [];
129
+ }
130
+
131
+ /**
132
+ * Get diagram types
133
+ */
134
+ export async function getDiagramTypes(): Promise<string[]> {
135
+ const result = await apiRequest<{ types: string[] }>('GET', '/diagrams/types');
136
+ return result.types || [];
137
+ }
138
+
139
+ /**
140
+ * Generate diagram
141
+ */
142
+ export async function generateDiagram(
143
+ type: string,
144
+ direction: 'TB' | 'LR' = 'TB'
145
+ ): Promise<string> {
146
+ const result = await apiRequest<{ success: boolean; diagram?: string; error?: string }>(
147
+ 'GET',
148
+ \`/diagrams/\${type}?direction=\${direction}\`
149
+ );
150
+
151
+ if (!result.success || !result.diagram) {
152
+ throw new Error(result.error || 'Failed to generate diagram');
153
+ }
154
+
155
+ return result.diagram;
156
+ }`;
157
+ if (pattern === "rest") {
158
+ return `${commonImports}
159
+
160
+ /**
161
+ * Get model schema
162
+ */
163
+ export async function getModelSchema(modelName: string): Promise<ModelSchema> {
164
+ const spec = await getSpec();
165
+
166
+ // Find model \u2014 check components wrapper and top-level models
167
+ let model: any = null;
168
+ if (spec.components) {
169
+ for (const component of Object.values(spec.components)) {
170
+ const models = (component as any).models || {};
171
+ if (models[modelName]) { model = models[modelName]; break; }
172
+ }
173
+ }
174
+ if (!model && spec.models) {
175
+ model = spec.models[modelName];
176
+ }
177
+
178
+ if (model) {
179
+ // Normalize array-format attributes to object format
180
+ // Inference outputs [{name:'id', type:'UUID',...}] but runtime expects {id: {type:'UUID',...}}
181
+ let attributes = model.attributes || {};
182
+ if (Array.isArray(attributes)) {
183
+ const obj: Record<string, any> = {};
184
+ for (const attr of attributes) {
185
+ if (attr.name) obj[attr.name] = attr;
186
+ }
187
+ attributes = obj;
188
+ }
189
+
190
+ // Normalize array-format relationships
191
+ let relationships = model.relationships || {};
192
+ if (Array.isArray(relationships)) {
193
+ const obj: Record<string, any> = {};
194
+ for (const rel of relationships) {
195
+ if (rel.name) obj[rel.name] = { ...rel, targetModel: rel.target || rel.targetModel };
196
+ }
197
+ relationships = obj;
198
+ }
199
+
200
+ // Normalize array-format lifecycles
201
+ let lifecycles = model.lifecycles || {};
202
+ if (Array.isArray(lifecycles)) {
203
+ const obj: Record<string, any> = {};
204
+ for (const lc of lifecycles) {
205
+ if (lc.name) obj[lc.name] = lc;
206
+ }
207
+ lifecycles = obj;
208
+ }
209
+
210
+ return { name: modelName, attributes, relationships, lifecycles } as ModelSchema;
211
+ }
212
+
213
+ // Empty schema \u2014 component will still render with no field info
214
+ return { name: modelName, attributes: {}, relationships: {}, lifecycles: {} } as ModelSchema;
215
+ }
216
+
217
+ /**
218
+ * List all entities for a model
219
+ */
220
+ export async function listEntities(controllerName: string): Promise<Entity[]> {
221
+ try {
222
+ // Extract model name from controller name (e.g., "AuthorController" -> "authors")
223
+ const modelName = controllerName
224
+ .replace(/Controller$/, '')
225
+ .toLowerCase() + 's';
226
+
227
+ const entities = await apiRequest<Entity[]>('GET', \`/\${modelName}\`);
228
+ return entities || [];
229
+ } catch (error) {
230
+ // Model endpoint might not exist
231
+ return [];
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Execute a controller operation
237
+ * Maps CURVED operations to standard REST endpoints
238
+ */
239
+ export async function executeOperation(
240
+ controllerName: string,
241
+ operationName: string,
242
+ params: Record<string, any>
243
+ ): Promise<ApiResponse> {
244
+ // Extract model name from controller name (e.g., "AuthorController" -> "authors")
245
+ const modelName = controllerName
246
+ .replace(/Controller$/, '')
247
+ .toLowerCase() + 's';
248
+
249
+ let method: string;
250
+ let path: string;
251
+
252
+ switch (operationName) {
253
+ case 'create':
254
+ method = 'POST';
255
+ path = \`/\${modelName}\`;
256
+ break;
257
+
258
+ case 'update':
259
+ method = 'PUT';
260
+ path = \`/\${modelName}/\${params.id}\`;
261
+ // Remove id from body
262
+ const { id: _id, ...updateData } = params;
263
+ params = updateData;
264
+ break;
265
+
266
+ case 'retrieve':
267
+ method = 'GET';
268
+ path = \`/\${modelName}/\${params.id}\`;
269
+ params = {};
270
+ break;
271
+
272
+ case 'retrieve_many':
273
+ case 'list':
274
+ method = 'GET';
275
+ path = \`/\${modelName}\`;
276
+ params = {};
277
+ break;
278
+
279
+ case 'delete':
280
+ method = 'DELETE';
281
+ path = \`/\${modelName}/\${params.id}\`;
282
+ params = {};
283
+ break;
284
+
285
+ case 'validate':
286
+ method = 'POST';
287
+ path = \`/\${modelName}/validate\`;
288
+ break;
289
+
290
+ case 'evolve':
291
+ method = 'POST';
292
+ path = \`/\${modelName}/\${params.id}/evolve\`;
293
+ break;
294
+
295
+ default:
296
+ // Custom operation
297
+ method = 'POST';
298
+ path = \`/\${modelName}/\${operationName}\`;
299
+ }
300
+
301
+ return apiRequest<ApiResponse>(method, path, Object.keys(params).length > 0 ? params : null);
302
+ }
303
+
304
+ /**
305
+ * Transition entity lifecycle state
306
+ */
307
+ export async function transitionState(
308
+ modelName: string,
309
+ entityId: string,
310
+ toState: string,
311
+ lifecycleName?: string
312
+ ): Promise<ApiResponse> {
313
+ const body: any = { toState };
314
+ if (lifecycleName) {
315
+ body.lifecycleName = lifecycleName;
316
+ }
317
+
318
+ const resource = modelName.toLowerCase() + 's';
319
+ return apiRequest<ApiResponse>(
320
+ 'POST',
321
+ \`/\${resource}/\${entityId}/transition\`,
322
+ body
323
+ );
324
+ }
325
+
326
+ /**
327
+ * Get available transitions for an entity
328
+ */
329
+ export async function getAvailableTransitions(
330
+ modelName: string,
331
+ entityId: string,
332
+ lifecycleName?: string
333
+ ): Promise<string[]> {
334
+ const resource = modelName.toLowerCase() + 's';
335
+ const url = lifecycleName
336
+ ? \`/\${resource}/\${entityId}/transitions?lifecycleName=\${lifecycleName}\`
337
+ : \`/\${resource}/\${entityId}/transitions\`;
338
+
339
+ const result = await apiRequest<{ transitions: string[] }>('GET', url);
340
+ return result.transitions || [];
341
+ }
342
+ ${metaFunctions}
343
+ `;
344
+ } else {
345
+ return `${commonImports}
346
+
347
+ /**
348
+ * Get model schema
349
+ */
350
+ export async function getModelSchema(modelName: string): Promise<ModelSchema> {
351
+ return apiRequest<ModelSchema>('GET', \`/models/\${modelName}/schema\`);
352
+ }
353
+
354
+ /**
355
+ * List all entities for a model via its controller
356
+ * Returns empty array if controller doesn't exist (not all models have controllers)
357
+ */
358
+ export async function listEntities(controllerName: string): Promise<Entity[]> {
359
+ try {
360
+ const result = await apiRequest<ApiResponse<{ entities: Entity[] }>>(
361
+ 'POST',
362
+ \`/controllers/\${controllerName}/list\`,
363
+ {}
364
+ );
365
+
366
+ if (!result.success) {
367
+ // Controller might not exist for this model
368
+ return [];
369
+ }
370
+
371
+ return result.data?.entities || [];
372
+ } catch (error) {
373
+ // Controller doesn't exist for this model - this is normal
374
+ // Not all models have controllers
375
+ // Silently return empty array (this is expected behavior)
376
+ return [];
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Execute a controller operation
382
+ */
383
+ export async function executeOperation(
384
+ controllerName: string,
385
+ operationName: string,
386
+ params: Record<string, any>
387
+ ): Promise<ApiResponse> {
388
+ return apiRequest<ApiResponse>(
389
+ 'POST',
390
+ \`/controllers/\${controllerName}/\${operationName}\`,
391
+ params
392
+ );
393
+ }
394
+
395
+ /**
396
+ * Transition entity lifecycle state
397
+ */
398
+ export async function transitionState(
399
+ modelName: string,
400
+ entityId: string,
401
+ toState: string,
402
+ lifecycleName?: string
403
+ ): Promise<ApiResponse> {
404
+ const body: any = { toState };
405
+ if (lifecycleName) {
406
+ body.lifecycleName = lifecycleName;
407
+ }
408
+
409
+ return apiRequest<ApiResponse>(
410
+ 'POST',
411
+ \`/lifecycle/\${modelName}/\${entityId}/transition\`,
412
+ body
413
+ );
414
+ }
415
+
416
+ /**
417
+ * Get available transitions for an entity
418
+ */
419
+ export async function getAvailableTransitions(
420
+ modelName: string,
421
+ entityId: string,
422
+ lifecycleName?: string
423
+ ): Promise<string[]> {
424
+ const url = lifecycleName
425
+ ? \`/lifecycle/\${modelName}/\${entityId}/transitions?lifecycleName=\${lifecycleName}\`
426
+ : \`/lifecycle/\${modelName}/\${entityId}/transitions\`;
427
+
428
+ const result = await apiRequest<{ transitions: string[] }>('GET', url);
429
+ return result.transitions || [];
430
+ }
431
+ ${metaFunctions}
432
+ `;
433
+ }
434
+ }
435
+ export {
436
+ generate
437
+ };
@@ -0,0 +1,146 @@
1
+ async function generate(context) {
2
+ return `/**
3
+ * API Types
4
+ *
5
+ * Shared type definitions for API interactions
6
+ */
7
+
8
+ export interface RuntimeInfo {
9
+ models: string[];
10
+ controllers: string[];
11
+ controllerModels?: Record<string, string>; // Controller name -> Model name mapping
12
+ events: string[];
13
+ services: string[];
14
+ views?: string[];
15
+ operations?: Record<string, (Operation | string)[]>;
16
+ specFile?: string;
17
+ }
18
+
19
+ export interface Operation {
20
+ name: string;
21
+ description?: string;
22
+ parameters?: Record<string, any>;
23
+ returns?: string;
24
+ requires?: string[];
25
+ ensures?: string[];
26
+ publishes?: string[];
27
+ }
28
+
29
+ export interface Event {
30
+ eventName: string;
31
+ data: any;
32
+ timestamp: Date;
33
+ }
34
+
35
+ export interface ModelSchema {
36
+ name: string;
37
+ description?: string;
38
+ attributes: Record<string, AttributeDefinition>;
39
+ relationships?: Record<string, RelationshipDefinition>;
40
+ lifecycles?: Record<string, LifecycleDefinition>;
41
+ behaviors?: Record<string, BehaviorDefinition>;
42
+ }
43
+
44
+ export interface AttributeDefinition {
45
+ type: string;
46
+ required?: boolean;
47
+ default?: any;
48
+ auto?: string;
49
+ unique?: boolean;
50
+ }
51
+
52
+ export interface RelationshipDefinition {
53
+ type: 'belongsTo' | 'hasMany' | 'hasOne';
54
+ model: string;
55
+ targetModel?: string;
56
+ foreignKey?: string;
57
+ }
58
+
59
+ export interface LifecycleDefinition {
60
+ initial?: string;
61
+ states?: Record<string, any>;
62
+ flow?: string;
63
+ }
64
+
65
+ export interface BehaviorDefinition {
66
+ description?: string;
67
+ parameters?: Record<string, any>;
68
+ returns?: string;
69
+ requires?: string[];
70
+ ensures?: string[];
71
+ publishes?: string[];
72
+ }
73
+
74
+ export interface Entity {
75
+ id: string;
76
+ data: Record<string, any>;
77
+ metadata?: {
78
+ lifecycleStates?: Record<string, string>;
79
+ [key: string]: any;
80
+ };
81
+ }
82
+
83
+ export interface View {
84
+ name: string;
85
+ description?: string;
86
+ type: string;
87
+ model?: string | string[]; // Legacy: model-based views
88
+ controller?: string; // New: controller-based views
89
+ related?: Array<{ model: string }>; // Related models for multi-model views
90
+ columns?: string[]; // Column names for list/table views
91
+ sections?: any[]; // Sections for dashboard views
92
+ uiComponents?: Record<string, any>;
93
+ subscribesTo?: string[];
94
+ properties?: Record<string, any>;
95
+ }
96
+
97
+ export interface Service {
98
+ name: string;
99
+ description?: string;
100
+ subscribesTo: string[];
101
+ subscribes_to?: string[];
102
+ operations: ServiceOperation[];
103
+ }
104
+
105
+ export interface ServiceOperation {
106
+ name: string;
107
+ description?: string;
108
+ parameters?: Record<string, any>;
109
+ returns?: string;
110
+ requires?: string[];
111
+ ensures?: string[];
112
+ publishes?: string[];
113
+ }
114
+
115
+ export interface Behavior {
116
+ name: string;
117
+ description?: string;
118
+ parameters?: Record<string, any>;
119
+ returns?: string;
120
+ requires?: string[];
121
+ ensures?: string[];
122
+ publishes?: string[];
123
+ }
124
+
125
+ export interface WebSocketMessage {
126
+ id?: string;
127
+ type: 'subscribe' | 'unsubscribe' | 'execute' | 'transition' | 'query';
128
+ payload: any;
129
+ }
130
+
131
+ export interface WebSocketResponse {
132
+ id?: string;
133
+ type: 'event' | 'result' | 'error' | 'reload';
134
+ payload: any;
135
+ }
136
+
137
+ export interface ApiResponse<T = any> {
138
+ success: boolean;
139
+ data?: T;
140
+ error?: string;
141
+ }
142
+ `;
143
+ }
144
+ export {
145
+ generate
146
+ };
@@ -0,0 +1,73 @@
1
+ function generateAppTsx(context) {
2
+ const { spec } = context;
3
+ let viewList = [];
4
+ if (spec.views) {
5
+ viewList = Array.isArray(spec.views) ? spec.views : Object.entries(spec.views).map(([name, def]) => ({ name, ...def }));
6
+ }
7
+ const modelViews = /* @__PURE__ */ new Map();
8
+ const dashboardView = viewList.find((v) => v.type === "dashboard")?.name || null;
9
+ for (const view of viewList) {
10
+ const model = Array.isArray(view.model) ? view.model[0] : view.model || view.primaryModel;
11
+ if (!model) continue;
12
+ if (!modelViews.has(model)) modelViews.set(model, { other: [] });
13
+ const entry = modelViews.get(model);
14
+ const type = view.type || "list";
15
+ if (type === "list") entry.list = view.name;
16
+ else if (type === "detail") entry.detail = view.name;
17
+ else if (type === "form") entry.form = view.name;
18
+ else if (type !== "dashboard") entry.other.push(view.name);
19
+ }
20
+ const imports = viewList.map((v) => `import ${v.name} from './components/${v.name}';`).join("\n");
21
+ const routes = viewList.map((v) => {
22
+ const path = `/${v.name.toLowerCase().replace("view", "")}`;
23
+ return ` <Route path="${path}" element={<${v.name} />} />`;
24
+ }).join("\n");
25
+ const defaultView = dashboardView || viewList[0]?.name || "div";
26
+ const defaultElement = defaultView === "div" ? '<div className="p-8">Welcome</div>' : `<${defaultView} />`;
27
+ const navGroups = Array.from(modelViews.entries()).map(([model, views]) => {
28
+ const lower = model.charAt(0).toLowerCase() + model.slice(1);
29
+ const listPath = views.list ? `/${views.list.toLowerCase().replace("view", "")}` : "";
30
+ const formPath = views.form ? `/${views.form.toLowerCase().replace("view", "")}` : "";
31
+ return ` <div>
32
+ <h3 className="px-3 text-xs font-semibold text-gray-400 uppercase tracking-wider mb-1">${model}s</h3>
33
+ ${listPath ? ` <a href="${listPath}" className="block px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100 rounded">Browse</a>` : ""}
34
+ ${formPath ? ` <a href="${formPath}" className="block px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100 rounded">+ New</a>` : ""}
35
+ </div>`;
36
+ }).join("\n");
37
+ return `import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
38
+ ${imports}
39
+
40
+ function App() {
41
+ return (
42
+ <Router>
43
+ <div className="flex min-h-screen bg-gray-50">
44
+ {/* Sidebar */}
45
+ <aside className="w-56 bg-white border-r border-gray-200 p-4 space-y-5">
46
+ <div>
47
+ <h1 className="text-lg font-bold text-gray-900">SpecVerse App</h1>
48
+ <p className="text-xs text-gray-400">Generated from specification</p>
49
+ </div>
50
+ ${dashboardView ? ` <a href="/dashboard" className="block px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded">Dashboard</a>` : ""}
51
+ ${navGroups}
52
+ </aside>
53
+
54
+ {/* Main content */}
55
+ <main className="flex-1 overflow-auto">
56
+ <Routes>
57
+ <Route path="/" element={${defaultElement}} />
58
+ ${dashboardView ? ` <Route path="/dashboard" element={<${dashboardView} />} />` : ""}
59
+ ${routes}
60
+ <Route path="*" element={<div className="p-8"><h1 className="text-2xl">404 - Not Found</h1></div>} />
61
+ </Routes>
62
+ </main>
63
+ </div>
64
+ </Router>
65
+ );
66
+ }
67
+
68
+ export default App;
69
+ `;
70
+ }
71
+ export {
72
+ generateAppTsx as default
73
+ };
@@ -0,0 +1,18 @@
1
+ import { getApiBaseUrl, getPathConfig } from "../../../shared/path-resolver.js";
2
+ function generateEnvExample(context) {
3
+ const pathConfig = getPathConfig(context);
4
+ const defaultApiUrl = getApiBaseUrl(pathConfig);
5
+ return `# API Configuration
6
+ # Base URL for backend API
7
+ VITE_API_BASE_URL=${defaultApiUrl}
8
+
9
+ # API Path Prefix
10
+ VITE_API_PREFIX=/api
11
+
12
+ # Application Mode
13
+ VITE_APP_MODE=development
14
+ `;
15
+ }
16
+ export {
17
+ generateEnvExample as default
18
+ };