@specverse/engines 4.2.0 → 4.2.2

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 (87) hide show
  1. package/assets/templates/default/specs/main.specly +65 -0
  2. package/dist/libs/instance-factories/CURVED-INTERFACE.md +278 -0
  3. package/dist/libs/instance-factories/README.md +73 -0
  4. package/dist/libs/instance-factories/applications/README.md +51 -0
  5. package/dist/libs/instance-factories/applications/generic-app.yaml +52 -0
  6. package/dist/libs/instance-factories/applications/react-app-runtime.yaml +139 -0
  7. package/dist/libs/instance-factories/applications/react-app-starter.yaml +143 -0
  8. package/dist/libs/instance-factories/applications/templates/react/env-example-generator.js +24 -2
  9. package/dist/libs/instance-factories/applications/templates/react/vite-config-generator.js +54 -33
  10. package/dist/libs/instance-factories/applications/templates/react-starter/README.md +211 -0
  11. package/dist/libs/instance-factories/applications/templates/react-starter/api-types-starter-generator.js +69 -0
  12. package/dist/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.js +1 -1
  13. package/dist/libs/instance-factories/applications/templates/react-starter/belongs-to.js +40 -0
  14. package/dist/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.js +11 -3
  15. package/dist/libs/instance-factories/applications/templates/react-starter/detail-body-composer.js +18 -16
  16. package/dist/libs/instance-factories/applications/templates/react-starter/form-body-composer.js +50 -23
  17. package/dist/libs/instance-factories/applications/templates/react-starter/helpers-emitter.js +9 -3
  18. package/dist/libs/instance-factories/applications/templates/react-starter/list-body-composer.js +17 -7
  19. package/dist/libs/instance-factories/applications/templates/react-starter/orchestrator.js +16 -5
  20. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +49 -0
  21. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +96 -0
  22. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +116 -0
  23. package/dist/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +74 -0
  24. package/dist/libs/instance-factories/applications/templates/react-starter/use-api-hooks-starter-generator.js +95 -0
  25. package/dist/libs/instance-factories/applications/templates/react-starter/view-emitter.js +26 -1
  26. package/dist/libs/instance-factories/archived/fastify-prisma.yaml +104 -0
  27. package/dist/libs/instance-factories/cli/README.md +43 -0
  28. package/dist/libs/instance-factories/cli/commander-js.yaml +55 -0
  29. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +49 -1
  30. package/dist/libs/instance-factories/communication/README.md +47 -0
  31. package/dist/libs/instance-factories/communication/event-emitter.yaml +60 -0
  32. package/dist/libs/instance-factories/communication/rabbitmq-events.yaml +87 -0
  33. package/dist/libs/instance-factories/controllers/README.md +42 -0
  34. package/dist/libs/instance-factories/controllers/fastify.yaml +139 -0
  35. package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +29 -2
  36. package/dist/libs/instance-factories/infrastructure/README.md +29 -0
  37. package/dist/libs/instance-factories/infrastructure/docker-k8s.yaml +61 -0
  38. package/dist/libs/instance-factories/orms/README.md +54 -0
  39. package/dist/libs/instance-factories/orms/prisma.yaml +89 -0
  40. package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +2 -2
  41. package/dist/libs/instance-factories/scaffolding/README.md +49 -0
  42. package/dist/libs/instance-factories/scaffolding/generic-scaffold.yaml +65 -0
  43. package/dist/libs/instance-factories/sdks/README.md +28 -0
  44. package/dist/libs/instance-factories/sdks/python-sdk.yaml +66 -0
  45. package/dist/libs/instance-factories/sdks/typescript-sdk.yaml +59 -0
  46. package/dist/libs/instance-factories/services/README.md +55 -0
  47. package/dist/libs/instance-factories/services/prisma-services.yaml +71 -0
  48. package/dist/libs/instance-factories/storage/README.md +34 -0
  49. package/dist/libs/instance-factories/storage/mongodb.yaml +79 -0
  50. package/dist/libs/instance-factories/storage/postgresql.yaml +75 -0
  51. package/dist/libs/instance-factories/storage/redis.yaml +79 -0
  52. package/dist/libs/instance-factories/testing/README.md +40 -0
  53. package/dist/libs/instance-factories/testing/vitest-tests.yaml +63 -0
  54. package/dist/libs/instance-factories/tools/README.md +70 -0
  55. package/dist/libs/instance-factories/tools/mcp.yaml +36 -0
  56. package/dist/libs/instance-factories/tools/vscode.yaml +35 -0
  57. package/dist/libs/instance-factories/validation/README.md +38 -0
  58. package/dist/libs/instance-factories/validation/zod.yaml +56 -0
  59. package/dist/realize/engines/code-generator.d.ts.map +1 -1
  60. package/dist/realize/engines/code-generator.js +3 -0
  61. package/dist/realize/engines/code-generator.js.map +1 -1
  62. package/libs/instance-factories/applications/react-app-starter.yaml +10 -17
  63. package/libs/instance-factories/applications/templates/react/env-example-generator.ts +24 -2
  64. package/libs/instance-factories/applications/templates/react/vite-config-generator.ts +54 -33
  65. package/libs/instance-factories/applications/templates/react-starter/__tests__/detail-body-composer.test.ts +5 -4
  66. package/libs/instance-factories/applications/templates/react-starter/__tests__/form-body-composer.test.ts +18 -5
  67. package/libs/instance-factories/applications/templates/react-starter/__tests__/orchestrator.test.ts +83 -62
  68. package/libs/instance-factories/applications/templates/react-starter/api-types-starter-generator.ts +98 -0
  69. package/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.ts +1 -1
  70. package/libs/instance-factories/applications/templates/react-starter/belongs-to.ts +82 -0
  71. package/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.ts +20 -5
  72. package/libs/instance-factories/applications/templates/react-starter/detail-body-composer.ts +33 -33
  73. package/libs/instance-factories/applications/templates/react-starter/form-body-composer.ts +107 -30
  74. package/libs/instance-factories/applications/templates/react-starter/helpers-emitter.ts +9 -3
  75. package/libs/instance-factories/applications/templates/react-starter/list-body-composer.ts +34 -8
  76. package/libs/instance-factories/applications/templates/react-starter/orchestrator.ts +41 -26
  77. package/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +2 -0
  78. package/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +2 -0
  79. package/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +2 -0
  80. package/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +2 -0
  81. package/libs/instance-factories/applications/templates/react-starter/use-api-hooks-starter-generator.ts +124 -0
  82. package/libs/instance-factories/applications/templates/react-starter/view-emitter.ts +58 -0
  83. package/libs/instance-factories/cli/templates/commander/command-generator.ts +49 -1
  84. package/libs/instance-factories/controllers/fastify.yaml +7 -0
  85. package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +36 -2
  86. package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +11 -4
  87. package/package.json +2 -1
@@ -0,0 +1,95 @@
1
+ function pluralize(s) {
2
+ if (/y$/.test(s) && !/[aeiou]y$/.test(s)) return s.replace(/y$/, "ies");
3
+ if (/(s|x|z|ch|sh)$/.test(s)) return s + "es";
4
+ return s + "s";
5
+ }
6
+ async function generate(context) {
7
+ const models = Object.keys(context.spec.models ?? {});
8
+ const importsAndTypes = `/**
9
+ * useApi \u2014 typed per-model React Query hooks (ReactAppStarter)
10
+ *
11
+ * Safe to edit. Users who want to reshape their API client or add
12
+ * request/response interceptors should start here. Each hook calls
13
+ * the sibling \`apiClient\` which does the actual fetch; edit
14
+ * \`apiClient.ts\` to change transport concerns (headers, auth, etc.).
15
+ */
16
+
17
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
18
+ ${models.map((m) => `import type { ${m} } from '../types/api';`).join("\n")}
19
+
20
+ const API_BASE = import.meta.env.VITE_API_BASE_URL || '';
21
+
22
+ async function fetchJSON<T = unknown>(url: string, init?: RequestInit): Promise<T> {
23
+ const res = await fetch(url, {
24
+ headers: { 'Content-Type': 'application/json' },
25
+ ...init,
26
+ });
27
+ if (!res.ok) {
28
+ throw new Error(\`\${res.status} \${res.statusText} \u2014 \${url}\`);
29
+ }
30
+ if (res.status === 204) return undefined as T;
31
+ return (await res.json()) as T;
32
+ }
33
+ `;
34
+ const hookBlocks = models.map((m) => generateModelHooks(m)).join("\n\n");
35
+ return importsAndTypes + "\n" + hookBlocks + "\n";
36
+ }
37
+ function generateModelHooks(model) {
38
+ const plural = pluralize(model);
39
+ const resource = plural.toLowerCase();
40
+ const modelLower = model.toLowerCase();
41
+ return `// \u2500\u2500\u2500 ${model} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
42
+
43
+ export function use${plural}Query() {
44
+ return useQuery({
45
+ queryKey: ['${resource}'],
46
+ queryFn: () => fetchJSON<${model}[]>(\`\${API_BASE}/api/${resource}\`),
47
+ });
48
+ }
49
+
50
+ export function use${model}Query(id: string | number | undefined) {
51
+ return useQuery({
52
+ queryKey: ['${resource}', id],
53
+ queryFn: () => fetchJSON<${model}>(\`\${API_BASE}/api/${resource}/\${id}\`),
54
+ enabled: id !== undefined && id !== null,
55
+ });
56
+ }
57
+
58
+ export function useCreate${model}Mutation() {
59
+ const qc = useQueryClient();
60
+ return useMutation({
61
+ mutationFn: (data: Partial<${model}>) =>
62
+ fetchJSON<${model}>(\`\${API_BASE}/api/${resource}\`, {
63
+ method: 'POST',
64
+ body: JSON.stringify(data),
65
+ }),
66
+ onSuccess: () => qc.invalidateQueries({ queryKey: ['${resource}'] }),
67
+ });
68
+ }
69
+
70
+ export function useUpdate${model}Mutation() {
71
+ const qc = useQueryClient();
72
+ return useMutation({
73
+ mutationFn: ({ id, data }: { id: string | number; data: Partial<${model}> }) =>
74
+ fetchJSON<${model}>(\`\${API_BASE}/api/${resource}/\${id}\`, {
75
+ method: 'PATCH',
76
+ body: JSON.stringify(data),
77
+ }),
78
+ onSuccess: () => qc.invalidateQueries({ queryKey: ['${resource}'] }),
79
+ });
80
+ }
81
+
82
+ export function useDelete${model}Mutation() {
83
+ const qc = useQueryClient();
84
+ return useMutation({
85
+ mutationFn: (id: string | number) =>
86
+ fetchJSON<void>(\`\${API_BASE}/api/${resource}/\${id}\`, { method: 'DELETE' }),
87
+ onSuccess: () => qc.invalidateQueries({ queryKey: ['${resource}'] }),
88
+ });
89
+ }`;
90
+ }
91
+ var stdin_default = generate;
92
+ export {
93
+ stdin_default as default,
94
+ generate
95
+ };
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { join, dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
+ import { extractBelongsToTargets, pluralize as pluralizeShared } from "./belongs-to.js";
4
5
  function emitView(context) {
5
6
  const skeleton = loadSkeleton(context.view.type);
6
7
  const bodyJsx = context.renderBody(context);
@@ -30,12 +31,36 @@ function loadSkeleton(viewType) {
30
31
  function buildSubstitutions(context, body) {
31
32
  const modelName = context.model.name;
32
33
  const pluralModel = pluralize(modelName);
34
+ const { imports, hooks } = buildBelongsToWiring(context);
33
35
  return {
34
36
  MODEL_NAME: modelName,
35
37
  PLURAL_MODEL: pluralModel,
36
38
  PLURAL_LOWER: pluralModel.toLowerCase(),
37
39
  SINGULAR_LOWER: modelName.toLowerCase(),
38
- BODY: body
40
+ BODY: body,
41
+ RELATED_IMPORTS: imports,
42
+ RELATED_HOOKS: hooks
43
+ };
44
+ }
45
+ function buildBelongsToWiring(context) {
46
+ const rels = extractBelongsToTargets(context.model);
47
+ if (rels.length === 0) return { imports: "", hooks: "" };
48
+ const hookImportNames = /* @__PURE__ */ new Set();
49
+ for (const rel of rels) {
50
+ hookImportNames.add(`use${pluralizeShared(rel.target)}Query`);
51
+ }
52
+ const helperImport = context.view.type.toLowerCase() === "form" ? "getEntityDisplayName" : "resolveEntityDisplayName";
53
+ const importLines = [];
54
+ importLines.push(
55
+ `import { ${[...hookImportNames].join(", ")} } from '../hooks/useApi';`
56
+ );
57
+ importLines.push(`import { ${helperImport} } from '../lib/entity-display';`);
58
+ const hookLines = rels.map(
59
+ (rel) => ` const { data: ${rel.name}Options = [] } = use${pluralizeShared(rel.target)}Query();`
60
+ );
61
+ return {
62
+ imports: importLines.join("\n"),
63
+ hooks: hookLines.join("\n")
39
64
  };
40
65
  }
41
66
  function applySubstitutions(template, subs) {
@@ -0,0 +1,104 @@
1
+ name: FastifyPrismaAPI
2
+ version: "1.0.0"
3
+ category: controller
4
+ description: "Fastify server with Prisma ORM, Zod validation, and JWT authentication"
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [fastify, prisma, typescript, rest-api]
10
+
11
+ compatibility:
12
+ specverse: ">=3.3.0"
13
+ node: ">=18.0.0"
14
+
15
+ capabilities:
16
+ provides:
17
+ - "api.rest"
18
+ - "api.rest.crud"
19
+ - "api.websocket"
20
+ requires: []
21
+
22
+ technology:
23
+ runtime: "node"
24
+ language: "typescript"
25
+ framework: "fastify"
26
+ orm: "prisma"
27
+ validation: "zod"
28
+ authentication: "jwt"
29
+
30
+ dependencies:
31
+ runtime:
32
+ - name: "fastify"
33
+ version: "^4.24.0"
34
+ - name: "@fastify/cors"
35
+ version: "^8.4.0"
36
+ - name: "@fastify/jwt"
37
+ version: "^7.2.0"
38
+ - name: "@fastify/helmet"
39
+ version: "^11.1.0"
40
+ - name: "@fastify/rate-limit"
41
+ version: "^9.0.0"
42
+ - name: "@prisma/client"
43
+ version: "^5.5.0"
44
+ - name: "zod"
45
+ version: "^3.22.0"
46
+
47
+ dev:
48
+ - name: "prisma"
49
+ version: "^5.5.0"
50
+ - name: "@types/node"
51
+ version: "^20.8.0"
52
+ - name: "typescript"
53
+ version: "^5.2.0"
54
+ - name: "tsx"
55
+ version: "^4.0.0"
56
+
57
+ codeTemplates:
58
+ routes:
59
+ engine: typescript
60
+ generator: "libs/instance-factories/backend/templates/fastify/routes-generator.ts"
61
+ outputPattern: "routes/{controller}.ts"
62
+
63
+ services:
64
+ engine: typescript
65
+ generator: "libs/instance-factories/backend/templates/prisma/services-generator.ts"
66
+ outputPattern: "services/{model}.service.ts"
67
+
68
+ schema:
69
+ engine: typescript
70
+ generator: "libs/instance-factories/backend/templates/prisma/schema-generator.ts"
71
+ outputPattern: "prisma/schema.prisma"
72
+
73
+ configuration:
74
+ server:
75
+ port: 3000
76
+ host: "0.0.0.0"
77
+ trustProxy: true
78
+ requestIdLogLabel: "reqId"
79
+ logger:
80
+ level: "info"
81
+ prettyPrint: true
82
+
83
+ orm:
84
+ provider: "postgresql"
85
+ relationMode: "foreignKeys"
86
+ log: ["query", "error", "warn"]
87
+
88
+ middleware:
89
+ cors:
90
+ origin: true
91
+ credentials: true
92
+ helmet:
93
+ enabled: true
94
+ rateLimit:
95
+ max: 100
96
+ timeWindow: "1 minute"
97
+ jwt:
98
+ secret: "${JWT_SECRET}"
99
+ sign:
100
+ expiresIn: "7d"
101
+
102
+ validation:
103
+ stripUnknown: true
104
+ abortEarly: false
@@ -0,0 +1,43 @@
1
+ # CLI Factory
2
+
3
+ Generates Commander.js CLI applications from spec command definitions.
4
+
5
+ ## Definition
6
+
7
+ | File | Description |
8
+ |------|-------------|
9
+ | `commander-js.yaml` | Commander.js v12 CLI with argument parsing, help text, and command routing |
10
+
11
+ ## Generated Output
12
+
13
+ | Generator | Output | Purpose |
14
+ |-----------|--------|---------|
15
+ | `cli-entry-generator` | `backend/src/cli/index.ts` | Main CLI entry point — registers all commands from spec |
16
+ | `command-generator` | `backend/src/cli/commands/{command}.ts` | Individual command files (one per spec command) |
17
+
18
+ The entry generator reads the spec's `commands` section and registers each as a
19
+ Commander.js command with arguments, flags, and help text. Each command file
20
+ delegates to its corresponding service for business logic.
21
+
22
+ ## Technology
23
+
24
+ - **Framework**: Commander.js ^12.0.0
25
+ - **Runtime**: Node.js with tsx for development
26
+ - **Language**: TypeScript
27
+
28
+ ## Capabilities
29
+
30
+ | Provides | Requires |
31
+ |----------|----------|
32
+ | `cli.commands` | `service.controller` |
33
+ | `cli.parser` | |
34
+ | `cli.help` | |
35
+
36
+ ## Spec Integration
37
+
38
+ Commands are defined in the spec with:
39
+ - `arguments` — positional parameters
40
+ - `flags` — optional switches
41
+ - `returns` — output format
42
+ - `exitCodes` — process exit codes
43
+ - `subcommands` — nested command trees
@@ -0,0 +1,55 @@
1
+ name: CommanderJS
2
+ version: "1.0.0"
3
+ category: cli
4
+ description: "Node.js CLI generation using Commander.js"
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [cli, commander, node, typescript]
10
+
11
+ compatibility:
12
+ specverse: ">=3.3.0"
13
+ node: ">=18.0.0"
14
+
15
+ capabilities:
16
+ provides:
17
+ - "cli.commands"
18
+ - "cli.parser"
19
+ - "cli.help"
20
+ requires:
21
+ - "service.controller"
22
+
23
+ technology:
24
+ runtime: "node"
25
+ language: "typescript"
26
+ framework: "commander"
27
+ version: "^12.0.0"
28
+
29
+ dependencies:
30
+ runtime:
31
+ - name: "commander"
32
+ version: "^12.0.0"
33
+
34
+ dev:
35
+ - name: "@types/node"
36
+ version: "^20.8.0"
37
+ - name: "typescript"
38
+ version: "^5.2.0"
39
+ - name: "tsx"
40
+ version: "^4.0.0"
41
+
42
+ codeTemplates:
43
+ cli-entry:
44
+ engine: typescript
45
+ generator: "libs/instance-factories/cli/templates/commander/cli-entry-generator.ts"
46
+ outputPattern: "{backendDir}/src/cli/index.ts"
47
+
48
+ cli-commands:
49
+ engine: typescript
50
+ generator: "libs/instance-factories/cli/templates/commander/command-generator.ts"
51
+ outputPattern: "{backendDir}/src/cli/commands/{command}.ts"
52
+
53
+ configuration:
54
+ outputStructure: "monorepo"
55
+ backendDir: "backend"
@@ -505,8 +505,56 @@ import { fileURLToPath } from 'url';`,
505
505
  }
506
506
 
507
507
  copyDir(templateDir, destDir);
508
+
509
+ // If the copied template didn't ship a specs/main.specly, load
510
+ // the canonical default spec from @specverse/engines/assets \u2014
511
+ // same file app-demo's Server Manager "new spec" action uses,
512
+ // so both entry points start a user on the same footing. The
513
+ // template can opt out of this by shipping its own spec.
514
+ const specDestPath = join(destDir, 'specs', 'main.specly');
515
+ if (!existsSync(specDestPath)) {
516
+ try {
517
+ const { createRequire } = await import('module');
518
+ const require = createRequire(import.meta.url);
519
+ const enginesPkg = require.resolve('@specverse/engines/package.json');
520
+ const canonicalSpec = join(
521
+ dirname(enginesPkg),
522
+ 'assets', 'templates', 'default', 'specs', 'main.specly'
523
+ );
524
+ if (existsSync(canonicalSpec)) {
525
+ let content = readFileSync(canonicalSpec, 'utf8');
526
+ for (const [key, val] of Object.entries(vars)) {
527
+ content = content.split(key).join(val);
528
+ }
529
+ mkdirSync(join(destDir, 'specs'), { recursive: true });
530
+ writeFileSync(specDestPath, content);
531
+ }
532
+ } catch { /* engines not installed or template missing \u2014 proceed */ }
533
+ }
534
+
535
+ // --static: flip any ReactAppRuntime mappings in the copied
536
+ // manifests to ReactAppStarter so the user gets standalone-starter
537
+ // output on first \`spv realize\` without having to re-pass the
538
+ // flag. Same semantic as \`spv realize --static\` \u2014 just applied
539
+ // at init time. Idempotent; no-op for templates without a frontend.
540
+ if (options.static) {
541
+ const manifestsDir = join(destDir, 'manifests');
542
+ if (existsSync(manifestsDir)) {
543
+ for (const f of readdirSync(manifestsDir)) {
544
+ if (!f.endsWith('.yaml') && !f.endsWith('.yml')) continue;
545
+ const p = join(manifestsDir, f);
546
+ const before = readFileSync(p, 'utf8');
547
+ const after = before.replace(
548
+ /instanceFactory:\\s*["']?ReactAppRuntime["']?/g,
549
+ 'instanceFactory: "ReactAppStarter"'
550
+ );
551
+ if (after !== before) writeFileSync(p, after, 'utf8');
552
+ }
553
+ }
554
+ }
555
+
508
556
  console.log('Project created: ' + destDir);
509
- console.log('Template: ' + templateName);
557
+ console.log('Template: ' + templateName + (options.static ? ' (static / ReactAppStarter)' : ''));
510
558
  console.log('');
511
559
 
512
560
  // Build the "Next steps" hint from the actual scripts the
@@ -0,0 +1,47 @@
1
+ # Communication Factory
2
+
3
+ Event-driven messaging infrastructure with publisher/subscriber generation.
4
+
5
+ ## Definitions
6
+
7
+ | File | Description |
8
+ |------|-------------|
9
+ | `event-emitter.yaml` | In-memory event bus using EventEmitter3 (development/testing) |
10
+ | `rabbitmq-events.yaml` | RabbitMQ AMQP bus for production pub/sub messaging |
11
+
12
+ ## Generated Output
13
+
14
+ ### EventEmitter (`eventemitter/`)
15
+
16
+ | Generator | Output | Purpose |
17
+ |-----------|--------|---------|
18
+ | `bus-generator` | `src/events/eventBus.ts` | Singleton event bus with typed event names |
19
+ | `publisher-generator` | `src/events/publishers/{event}Publisher.ts` | Per-event publisher (one per spec event) |
20
+ | `subscriber-generator` | `src/events/subscribers/{event}Subscriber.ts` | Per-event subscriber with handler logic |
21
+
22
+ ### RabbitMQ (`rabbitmq/` — defined, templates pending)
23
+
24
+ | Generator | Output | Purpose |
25
+ |-----------|--------|---------|
26
+ | `publisher-generator` | `src/events/publishers/{event}Publisher.ts` | AMQP publisher with confirms |
27
+ | `subscriber-generator` | `src/events/subscribers/{event}Subscriber.ts` | AMQP consumer with ack/nack |
28
+ | `connection-generator` | `src/events/connection.ts` | RabbitMQ connection management |
29
+
30
+ ## Technology
31
+
32
+ - **EventEmitter**: eventemitter3 ^5.0.0 (zero-dependency, in-process)
33
+ - **RabbitMQ**: amqplib ^0.10.3 (topic exchange, durable queues, prefetch)
34
+
35
+ ## Capabilities
36
+
37
+ | Provides | Requires |
38
+ |----------|----------|
39
+ | `messaging.pubsub` | (none) |
40
+ | `messaging.events` | |
41
+ | `messaging.inmemory` (EventEmitter) | |
42
+ | `messaging.queue` (RabbitMQ) | |
43
+
44
+ ## Configuration
45
+
46
+ EventEmitter: `maxListeners: 100`, `captureRejections: true`
47
+ RabbitMQ: topic exchange, durable queues, prefetch 10, persistent messages, confirm-select
@@ -0,0 +1,60 @@
1
+ name: EventEmitter
2
+ version: "2.0.0"
3
+ category: communication
4
+ description: "Typed in-memory event bus with WebSocket bridge for real-time frontend updates"
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [events, in-memory, pubsub, websocket, eventemitter, development]
10
+
11
+ compatibility:
12
+ specverse: ">=3.3.0"
13
+ node: ">=18.0.0"
14
+
15
+ capabilities:
16
+ provides:
17
+ - "messaging.pubsub"
18
+ - "messaging.events"
19
+ - "messaging.inmemory"
20
+ - "messaging.websocket"
21
+ requires: []
22
+
23
+ technology:
24
+ runtime: "node"
25
+ language: "typescript"
26
+ framework: "eventemitter3"
27
+ version: "^5.0.0"
28
+
29
+ dependencies:
30
+ runtime:
31
+ - name: "eventemitter3"
32
+ version: "^5.0.0"
33
+ - name: "@fastify/websocket"
34
+ version: "^11.0.0"
35
+
36
+ dev:
37
+ - name: "typescript"
38
+ version: "^5.2.0"
39
+
40
+ codeTemplates:
41
+ types:
42
+ engine: typescript
43
+ generator: "libs/instance-factories/communication/templates/eventemitter/types-generator.ts"
44
+ outputPattern: "{backendDir}/src/events/event-types.ts"
45
+
46
+ bus:
47
+ engine: typescript
48
+ generator: "libs/instance-factories/communication/templates/eventemitter/bus-generator.ts"
49
+ outputPattern: "{backendDir}/src/events/eventBus.ts"
50
+
51
+ websocket:
52
+ engine: typescript
53
+ generator: "libs/instance-factories/communication/templates/eventemitter/websocket-bridge-generator.ts"
54
+ outputPattern: "{backendDir}/src/events/websocket-bridge.ts"
55
+
56
+ configuration:
57
+ maxListeners: 100
58
+ captureRejections: true
59
+ errorHandling: "log"
60
+ websocket: true
@@ -0,0 +1,87 @@
1
+ name: RabbitMQEvents
2
+ version: "1.0.0"
3
+ category: communication
4
+ description: "RabbitMQ event bus for pub/sub messaging and event-driven architecture"
5
+
6
+ metadata:
7
+ author: "SpecVerse Team"
8
+ license: "MIT"
9
+ tags: [rabbitmq, events, messaging, pubsub, amqp]
10
+
11
+ compatibility:
12
+ specverse: ">=3.3.0"
13
+ node: ">=18.0.0"
14
+
15
+ capabilities:
16
+ provides:
17
+ - "messaging.pubsub"
18
+ - "messaging.events"
19
+ - "messaging.queue"
20
+ requires: []
21
+
22
+ technology:
23
+ runtime: "node"
24
+ language: "typescript"
25
+ framework: "amqplib"
26
+ version: "^0.10.3"
27
+
28
+ dependencies:
29
+ runtime:
30
+ - name: "amqplib"
31
+ version: "^0.10.3"
32
+ - name: "uuid"
33
+ version: "^9.0.0"
34
+
35
+ dev:
36
+ - name: "@types/amqplib"
37
+ version: "^0.10.4"
38
+ - name: "@types/uuid"
39
+ version: "^9.0.0"
40
+ - name: "typescript"
41
+ version: "^5.2.0"
42
+
43
+ codeTemplates:
44
+ publisher:
45
+ engine: typescript
46
+ generator: "libs/instance-factories/communication/templates/rabbitmq/publisher-generator.ts"
47
+ outputPattern: "src/events/publishers/{event}Publisher.ts"
48
+
49
+ subscriber:
50
+ engine: typescript
51
+ generator: "libs/instance-factories/communication/templates/rabbitmq/subscriber-generator.ts"
52
+ outputPattern: "src/events/subscribers/{event}Subscriber.ts"
53
+
54
+ connection:
55
+ engine: typescript
56
+ generator: "libs/instance-factories/communication/templates/rabbitmq/connection-generator.ts"
57
+ outputPattern: "src/events/connection.ts"
58
+
59
+ configuration:
60
+ connection:
61
+ protocol: "amqp"
62
+ hostname: "localhost"
63
+ port: 5672
64
+ username: "guest"
65
+ password: "guest"
66
+ vhost: "/"
67
+ heartbeat: 60
68
+
69
+ exchange:
70
+ type: "topic"
71
+ durable: true
72
+ autoDelete: false
73
+
74
+ queue:
75
+ durable: true
76
+ exclusive: false
77
+ autoDelete: false
78
+
79
+ publishing:
80
+ persistent: true
81
+ mandatory: true
82
+ confirmSelect: true
83
+
84
+ consuming:
85
+ prefetch: 10
86
+ noAck: false
87
+ exclusive: false
@@ -0,0 +1,42 @@
1
+ # Controllers Factory
2
+
3
+ Fastify REST API route handlers and server bootstrap generation.
4
+
5
+ ## Definition
6
+
7
+ | File | Description |
8
+ |------|-------------|
9
+ | `fastify.yaml` | Fastify v4 REST API server with CORS, Helmet, and rate limiting |
10
+
11
+ ## Generated Output
12
+
13
+ | Generator | Output | Purpose |
14
+ |-----------|--------|---------|
15
+ | `routes-generator` | `backend/src/routes/{controller}.ts` | Per-model route handler with CRUD endpoints |
16
+ | `meta-routes-generator` | `backend/src/routes/MetaRoutes.ts` | Meta API for spec/view metadata (serves frontend) |
17
+ | `server-generator` | `backend/src/server.ts` | Server bootstrap — registers all model routes |
18
+
19
+ The routes generator reads each controller from the spec and creates Fastify route
20
+ handlers. The server generator auto-imports and registers all model route files.
21
+ Meta routes expose spec and view metadata for the view-renderer architecture.
22
+
23
+ ## Technology
24
+
25
+ - **Framework**: Fastify ^4.24.0
26
+ - **Middleware**: @fastify/cors, @fastify/helmet, @fastify/rate-limit
27
+ - **Language**: TypeScript with tsx for development
28
+
29
+ ## Capabilities
30
+
31
+ | Provides | Requires |
32
+ |----------|----------|
33
+ | `api.rest` | `storage.database` |
34
+ | `api.rest.crud` | `validation.runtime` |
35
+ | `api.websocket` | |
36
+
37
+ ## Configuration
38
+
39
+ - Server: port 3000, host 0.0.0.0, trust proxy, structured logging
40
+ - CORS: origin true, credentials true
41
+ - Rate limit: 100 requests per minute
42
+ - Scripts: `dev` (tsx watch), `start` (node dist)