nestjs-ddd-cli 2.2.0 → 3.2.1

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 (254) hide show
  1. package/README.md +247 -408
  2. package/ddd.schema.json +111 -0
  3. package/dist/commands/aggregate-validator.d.ts +9 -0
  4. package/dist/commands/aggregate-validator.js +953 -0
  5. package/dist/commands/aggregate-validator.js.map +1 -0
  6. package/dist/commands/ai-assist.d.ts +8 -0
  7. package/dist/commands/ai-assist.js +337 -0
  8. package/dist/commands/ai-assist.js.map +1 -0
  9. package/dist/commands/api-contracts.d.ts +9 -0
  10. package/dist/commands/api-contracts.js +1368 -0
  11. package/dist/commands/api-contracts.js.map +1 -0
  12. package/dist/commands/api-docs.d.ts +8 -0
  13. package/dist/commands/api-docs.js +408 -0
  14. package/dist/commands/api-docs.js.map +1 -0
  15. package/dist/commands/api-versioning.d.ts +11 -0
  16. package/dist/commands/api-versioning.js +643 -0
  17. package/dist/commands/api-versioning.js.map +1 -0
  18. package/dist/commands/audit-logging.d.ts +9 -0
  19. package/dist/commands/audit-logging.js +1129 -0
  20. package/dist/commands/audit-logging.js.map +1 -0
  21. package/dist/commands/batch-generate.d.ts +10 -0
  22. package/dist/commands/batch-generate.js +405 -0
  23. package/dist/commands/batch-generate.js.map +1 -0
  24. package/dist/commands/caching-strategies.d.ts +9 -0
  25. package/dist/commands/caching-strategies.js +874 -0
  26. package/dist/commands/caching-strategies.js.map +1 -0
  27. package/dist/commands/code-analyzer.d.ts +42 -0
  28. package/dist/commands/code-analyzer.js +474 -0
  29. package/dist/commands/code-analyzer.js.map +1 -0
  30. package/dist/commands/database-seeding.d.ts +6 -0
  31. package/dist/commands/database-seeding.js +621 -0
  32. package/dist/commands/database-seeding.js.map +1 -0
  33. package/dist/commands/db-optimization.d.ts +7 -0
  34. package/dist/commands/db-optimization.js +687 -0
  35. package/dist/commands/db-optimization.js.map +1 -0
  36. package/dist/commands/dependency-graph.d.ts +6 -0
  37. package/dist/commands/dependency-graph.js +329 -0
  38. package/dist/commands/dependency-graph.js.map +1 -0
  39. package/dist/commands/doctor-enhanced.d.ts +22 -0
  40. package/dist/commands/doctor-enhanced.js +543 -0
  41. package/dist/commands/doctor-enhanced.js.map +1 -0
  42. package/dist/commands/doctor.d.ts +4 -0
  43. package/dist/commands/doctor.js +151 -0
  44. package/dist/commands/doctor.js.map +1 -0
  45. package/dist/commands/env-manager.d.ts +6 -0
  46. package/dist/commands/env-manager.js +419 -0
  47. package/dist/commands/env-manager.js.map +1 -0
  48. package/dist/commands/event-sourcing-full.d.ts +10 -0
  49. package/dist/commands/event-sourcing-full.js +1107 -0
  50. package/dist/commands/event-sourcing-full.js.map +1 -0
  51. package/dist/commands/feature-flags.d.ts +9 -0
  52. package/dist/commands/feature-flags.js +824 -0
  53. package/dist/commands/feature-flags.js.map +1 -0
  54. package/dist/commands/filter-dsl.d.ts +10 -0
  55. package/dist/commands/filter-dsl.js +1407 -0
  56. package/dist/commands/filter-dsl.js.map +1 -0
  57. package/dist/commands/generate-all.js +485 -32
  58. package/dist/commands/generate-all.js.map +1 -1
  59. package/dist/commands/generate-deployment.d.ts +8 -0
  60. package/dist/commands/generate-deployment.js +746 -0
  61. package/dist/commands/generate-deployment.js.map +1 -0
  62. package/dist/commands/generate-domain-service.d.ts +14 -0
  63. package/dist/commands/generate-domain-service.js +796 -0
  64. package/dist/commands/generate-domain-service.js.map +1 -0
  65. package/dist/commands/generate-entity.js +82 -24
  66. package/dist/commands/generate-entity.js.map +1 -1
  67. package/dist/commands/generate-from-schema.d.ts +56 -0
  68. package/dist/commands/generate-from-schema.js +222 -0
  69. package/dist/commands/generate-from-schema.js.map +1 -0
  70. package/dist/commands/generate-orchestrator.d.ts +14 -0
  71. package/dist/commands/generate-orchestrator.js +887 -0
  72. package/dist/commands/generate-orchestrator.js.map +1 -0
  73. package/dist/commands/generate-repository.d.ts +14 -0
  74. package/dist/commands/generate-repository.js +1019 -0
  75. package/dist/commands/generate-repository.js.map +1 -0
  76. package/dist/commands/generate-shared.d.ts +4 -0
  77. package/dist/commands/generate-shared.js +388 -0
  78. package/dist/commands/generate-shared.js.map +1 -0
  79. package/dist/commands/generate-value-object.d.ts +32 -0
  80. package/dist/commands/generate-value-object.js +700 -0
  81. package/dist/commands/generate-value-object.js.map +1 -0
  82. package/dist/commands/graphql-subscriptions.d.ts +6 -0
  83. package/dist/commands/graphql-subscriptions.js +607 -0
  84. package/dist/commands/graphql-subscriptions.js.map +1 -0
  85. package/dist/commands/graphql-types.d.ts +5 -0
  86. package/dist/commands/graphql-types.js +423 -0
  87. package/dist/commands/graphql-types.js.map +1 -0
  88. package/dist/commands/health-probes-advanced.d.ts +6 -0
  89. package/dist/commands/health-probes-advanced.js +655 -0
  90. package/dist/commands/health-probes-advanced.js.map +1 -0
  91. package/dist/commands/i18n-setup.d.ts +10 -0
  92. package/dist/commands/i18n-setup.js +677 -0
  93. package/dist/commands/i18n-setup.js.map +1 -0
  94. package/dist/commands/init-config.d.ts +6 -0
  95. package/dist/commands/init-config.js +370 -0
  96. package/dist/commands/init-config.js.map +1 -0
  97. package/dist/commands/init-project.js +56 -6
  98. package/dist/commands/init-project.js.map +1 -1
  99. package/dist/commands/interactive-scaffold.d.ts +5 -0
  100. package/dist/commands/interactive-scaffold.js +271 -0
  101. package/dist/commands/interactive-scaffold.js.map +1 -0
  102. package/dist/commands/metrics-prometheus.d.ts +6 -0
  103. package/dist/commands/metrics-prometheus.js +681 -0
  104. package/dist/commands/metrics-prometheus.js.map +1 -0
  105. package/dist/commands/migration-engine.d.ts +6 -0
  106. package/dist/commands/migration-engine.js +446 -0
  107. package/dist/commands/migration-engine.js.map +1 -0
  108. package/dist/commands/migration.d.ts +12 -0
  109. package/dist/commands/migration.js +484 -0
  110. package/dist/commands/migration.js.map +1 -0
  111. package/dist/commands/monorepo.d.ts +8 -0
  112. package/dist/commands/monorepo.js +483 -0
  113. package/dist/commands/monorepo.js.map +1 -0
  114. package/dist/commands/multi-database.d.ts +5 -0
  115. package/dist/commands/multi-database.js +439 -0
  116. package/dist/commands/multi-database.js.map +1 -0
  117. package/dist/commands/observability-tracing.d.ts +10 -0
  118. package/dist/commands/observability-tracing.js +740 -0
  119. package/dist/commands/observability-tracing.js.map +1 -0
  120. package/dist/commands/openapi-export.d.ts +8 -0
  121. package/dist/commands/openapi-export.js +359 -0
  122. package/dist/commands/openapi-export.js.map +1 -0
  123. package/dist/commands/perf-analyzer.d.ts +8 -0
  124. package/dist/commands/perf-analyzer.js +423 -0
  125. package/dist/commands/perf-analyzer.js.map +1 -0
  126. package/dist/commands/rate-limiting.d.ts +10 -0
  127. package/dist/commands/rate-limiting.js +953 -0
  128. package/dist/commands/rate-limiting.js.map +1 -0
  129. package/dist/commands/recipe-plugin.d.ts +56 -0
  130. package/dist/commands/recipe-plugin.js +315 -0
  131. package/dist/commands/recipe-plugin.js.map +1 -0
  132. package/dist/commands/recipe.d.ts +6 -0
  133. package/dist/commands/recipe.js +3941 -0
  134. package/dist/commands/recipe.js.map +1 -0
  135. package/dist/commands/recipes/elasticsearch.recipe.d.ts +1 -0
  136. package/dist/commands/recipes/elasticsearch.recipe.js +761 -0
  137. package/dist/commands/recipes/elasticsearch.recipe.js.map +1 -0
  138. package/dist/commands/recipes/event-sourcing.recipe.d.ts +1 -0
  139. package/dist/commands/recipes/event-sourcing.recipe.js +889 -0
  140. package/dist/commands/recipes/event-sourcing.recipe.js.map +1 -0
  141. package/dist/commands/recipes/index.d.ts +7 -0
  142. package/dist/commands/recipes/index.js +24 -0
  143. package/dist/commands/recipes/index.js.map +1 -0
  144. package/dist/commands/recipes/message-queue.recipe.d.ts +1 -0
  145. package/dist/commands/recipes/message-queue.recipe.js +706 -0
  146. package/dist/commands/recipes/message-queue.recipe.js.map +1 -0
  147. package/dist/commands/recipes/middleware.recipe.d.ts +1 -0
  148. package/dist/commands/recipes/middleware.recipe.js +383 -0
  149. package/dist/commands/recipes/middleware.recipe.js.map +1 -0
  150. package/dist/commands/recipes/multi-tenancy.recipe.d.ts +1 -0
  151. package/dist/commands/recipes/multi-tenancy.recipe.js +520 -0
  152. package/dist/commands/recipes/multi-tenancy.recipe.js.map +1 -0
  153. package/dist/commands/recipes/oauth2.recipe.d.ts +1 -0
  154. package/dist/commands/recipes/oauth2.recipe.js +472 -0
  155. package/dist/commands/recipes/oauth2.recipe.js.map +1 -0
  156. package/dist/commands/recipes/websocket.recipe.d.ts +1 -0
  157. package/dist/commands/recipes/websocket.recipe.js +453 -0
  158. package/dist/commands/recipes/websocket.recipe.js.map +1 -0
  159. package/dist/commands/resilience-patterns.d.ts +13 -0
  160. package/dist/commands/resilience-patterns.js +1029 -0
  161. package/dist/commands/resilience-patterns.js.map +1 -0
  162. package/dist/commands/security-patterns.d.ts +11 -0
  163. package/dist/commands/security-patterns.js +2233 -0
  164. package/dist/commands/security-patterns.js.map +1 -0
  165. package/dist/commands/template-debug.d.ts +27 -0
  166. package/dist/commands/template-debug.js +388 -0
  167. package/dist/commands/template-debug.js.map +1 -0
  168. package/dist/commands/test-factory-full.d.ts +9 -0
  169. package/dist/commands/test-factory-full.js +1570 -0
  170. package/dist/commands/test-factory-full.js.map +1 -0
  171. package/dist/commands/test-scaffold.d.ts +7 -0
  172. package/dist/commands/test-scaffold.js +621 -0
  173. package/dist/commands/test-scaffold.js.map +1 -0
  174. package/dist/index.js +1088 -0
  175. package/dist/index.js.map +1 -1
  176. package/dist/templates/ai-context/CLAUDE.md.hbs +158 -0
  177. package/dist/templates/ai-context/conventions.md.hbs +154 -0
  178. package/dist/templates/command/create-command.hbs +6 -14
  179. package/dist/templates/command/delete-command.hbs +19 -0
  180. package/dist/templates/command/update-command.hbs +24 -0
  181. package/dist/templates/controller/controller.hbs +64 -17
  182. package/dist/templates/dto/create-dto.hbs +29 -5
  183. package/dist/templates/dto/filter-dto.hbs +52 -0
  184. package/dist/templates/dto/filter-query.dto.hbs +148 -0
  185. package/dist/templates/dto/paginated-response.dto.hbs +29 -0
  186. package/dist/templates/dto/pagination-query.dto.hbs +30 -0
  187. package/dist/templates/dto/response-dto.hbs +38 -0
  188. package/dist/templates/dto/update-dto.hbs +11 -0
  189. package/dist/templates/entity/entity.hbs +32 -1
  190. package/dist/templates/event/domain-event.hbs +33 -7
  191. package/dist/templates/event/event-handler.hbs +40 -0
  192. package/dist/templates/exception/base-exceptions.hbs +69 -0
  193. package/dist/templates/exception/entity-not-found.exception.hbs +7 -0
  194. package/dist/templates/mapper/mapper.hbs +49 -24
  195. package/dist/templates/module/module.hbs +34 -10
  196. package/dist/templates/orm-entity/orm-entity.hbs +63 -12
  197. package/dist/templates/prisma/prisma-mapper.hbs +71 -0
  198. package/dist/templates/prisma/prisma-repository.hbs +114 -0
  199. package/dist/templates/prisma/prisma-schema.hbs +20 -0
  200. package/dist/templates/prisma/prisma-service.hbs +51 -0
  201. package/dist/templates/query/get-all.query.hbs +50 -0
  202. package/dist/templates/query/get-by-id.query.hbs +31 -0
  203. package/dist/templates/repository/repository.hbs +55 -13
  204. package/dist/templates/resolver/graphql-input.hbs +54 -0
  205. package/dist/templates/resolver/graphql-type.hbs +58 -0
  206. package/dist/templates/resolver/pagination-args.hbs +33 -0
  207. package/dist/templates/resolver/resolver.hbs +62 -0
  208. package/dist/templates/shared/prisma-query-builder.util.hbs +189 -0
  209. package/dist/templates/shared/query-builder.util.hbs +218 -0
  210. package/dist/templates/test/controller.spec.hbs +124 -0
  211. package/dist/templates/test/repository.spec.hbs +158 -0
  212. package/dist/templates/test/usecase.spec.hbs +116 -0
  213. package/dist/templates/usecase/create-usecase.hbs +19 -7
  214. package/dist/templates/usecase/delete-usecase.hbs +17 -0
  215. package/dist/templates/usecase/update-usecase.hbs +31 -0
  216. package/dist/utils/config.utils.d.ts +45 -0
  217. package/dist/utils/config.utils.js +211 -0
  218. package/dist/utils/config.utils.js.map +1 -0
  219. package/dist/utils/error.utils.d.ts +145 -0
  220. package/dist/utils/error.utils.js +422 -0
  221. package/dist/utils/error.utils.js.map +1 -0
  222. package/dist/utils/field.utils.d.ts +54 -0
  223. package/dist/utils/field.utils.js +389 -0
  224. package/dist/utils/field.utils.js.map +1 -0
  225. package/dist/utils/file.utils.d.ts +19 -8
  226. package/dist/utils/file.utils.js +135 -4
  227. package/dist/utils/file.utils.js.map +1 -1
  228. package/dist/utils/idempotency.utils.d.ts +123 -0
  229. package/dist/utils/idempotency.utils.js +444 -0
  230. package/dist/utils/idempotency.utils.js.map +1 -0
  231. package/dist/utils/naming.utils.js +26 -3
  232. package/dist/utils/naming.utils.js.map +1 -1
  233. package/dist/utils/performance.utils.d.ts +37 -0
  234. package/dist/utils/performance.utils.js +158 -0
  235. package/dist/utils/performance.utils.js.map +1 -0
  236. package/dist/utils/relation.utils.d.ts +92 -0
  237. package/dist/utils/relation.utils.js +388 -0
  238. package/dist/utils/relation.utils.js.map +1 -0
  239. package/dist/utils/rollback.utils.d.ts +49 -0
  240. package/dist/utils/rollback.utils.js +306 -0
  241. package/dist/utils/rollback.utils.js.map +1 -0
  242. package/dist/utils/schema.utils.d.ts +123 -0
  243. package/dist/utils/schema.utils.js +419 -0
  244. package/dist/utils/schema.utils.js.map +1 -0
  245. package/dist/utils/security.utils.d.ts +57 -0
  246. package/dist/utils/security.utils.js +315 -0
  247. package/dist/utils/security.utils.js.map +1 -0
  248. package/dist/utils/template-engine.utils.d.ts +80 -0
  249. package/dist/utils/template-engine.utils.js +463 -0
  250. package/dist/utils/template-engine.utils.js.map +1 -0
  251. package/dist/utils/validation-registry.utils.d.ts +160 -0
  252. package/dist/utils/validation-registry.utils.js +526 -0
  253. package/dist/utils/validation-registry.utils.js.map +1 -0
  254. package/package.json +3 -1
@@ -0,0 +1,887 @@
1
+ "use strict";
2
+ /**
3
+ * Application Layer Use Case Orchestrator Generator
4
+ * Generates standardized use case handlers with transaction management
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.generateOrchestrator = generateOrchestrator;
44
+ exports.setupOrchestratorInfrastructure = setupOrchestratorInfrastructure;
45
+ const fs = __importStar(require("fs"));
46
+ const path = __importStar(require("path"));
47
+ const chalk_1 = __importDefault(require("chalk"));
48
+ async function generateOrchestrator(name, basePath, options = {}) {
49
+ console.log(chalk_1.default.bold.blue('\n🎭 Generating Use Case Orchestrator\n'));
50
+ const moduleName = options.module || 'shared';
51
+ const orchestratorType = options.type || 'command';
52
+ const orchestratorPath = path.join(basePath, 'src', moduleName, 'application', 'orchestrators');
53
+ if (!fs.existsSync(orchestratorPath)) {
54
+ fs.mkdirSync(orchestratorPath, { recursive: true });
55
+ }
56
+ let content;
57
+ switch (orchestratorType) {
58
+ case 'query':
59
+ content = generateQueryOrchestrator(name);
60
+ break;
61
+ case 'saga':
62
+ content = generateSagaOrchestrator(name);
63
+ break;
64
+ default:
65
+ content = generateCommandOrchestrator(name);
66
+ }
67
+ const fileName = `${toKebabCase(name)}.orchestrator.ts`;
68
+ const filePath = path.join(orchestratorPath, fileName);
69
+ fs.writeFileSync(filePath, content);
70
+ console.log(chalk_1.default.green(` ✓ Created ${filePath}`));
71
+ console.log(chalk_1.default.bold.green('\n✅ Orchestrator generated successfully!\n'));
72
+ }
73
+ function generateCommandOrchestrator(name) {
74
+ const className = toPascalCase(name);
75
+ return `import { Injectable, Logger } from '@nestjs/common';
76
+ import { EventEmitter2 } from '@nestjs/event-emitter';
77
+ import { DataSource } from 'typeorm';
78
+
79
+ /**
80
+ * ${className} Command Orchestrator
81
+ * Handles command execution with transaction management and event publishing
82
+ */
83
+ @Injectable()
84
+ export class ${className}Orchestrator {
85
+ private readonly logger = new Logger(${className}Orchestrator.name);
86
+
87
+ constructor(
88
+ private readonly dataSource: DataSource,
89
+ private readonly eventEmitter: EventEmitter2,
90
+ ) {}
91
+
92
+ /**
93
+ * Execute the ${name} command
94
+ */
95
+ async execute(command: ${className}Command): Promise<${className}Result> {
96
+ const correlationId = this.generateCorrelationId();
97
+
98
+ this.logger.log(\`Executing ${name} command [\${correlationId}]\`);
99
+
100
+ // Validate command
101
+ const validationResult = await this.validate(command);
102
+ if (!validationResult.valid) {
103
+ return {
104
+ success: false,
105
+ error: {
106
+ code: 'VALIDATION_ERROR',
107
+ message: validationResult.message,
108
+ details: validationResult.errors,
109
+ },
110
+ };
111
+ }
112
+
113
+ // Execute in transaction
114
+ const queryRunner = this.dataSource.createQueryRunner();
115
+ await queryRunner.connect();
116
+ await queryRunner.startTransaction();
117
+
118
+ try {
119
+ // Pre-execution hooks
120
+ await this.beforeExecute(command, correlationId);
121
+
122
+ // Execute command logic
123
+ const result = await this.executeCommand(command, queryRunner);
124
+
125
+ // Commit transaction
126
+ await queryRunner.commitTransaction();
127
+
128
+ // Post-execution hooks
129
+ await this.afterExecute(command, result, correlationId);
130
+
131
+ // Publish domain events
132
+ await this.publishEvents(result.events || [], correlationId);
133
+
134
+ return {
135
+ success: true,
136
+ data: result.data,
137
+ correlationId,
138
+ };
139
+
140
+ } catch (error) {
141
+ await queryRunner.rollbackTransaction();
142
+
143
+ this.logger.error(\`Command failed [\${correlationId}]: \${(error as Error).message}\`);
144
+
145
+ // Publish failure event
146
+ this.eventEmitter.emit('command.failed', {
147
+ command: '${name}',
148
+ correlationId,
149
+ error: (error as Error).message,
150
+ timestamp: new Date(),
151
+ });
152
+
153
+ return {
154
+ success: false,
155
+ error: {
156
+ code: 'EXECUTION_ERROR',
157
+ message: (error as Error).message,
158
+ },
159
+ correlationId,
160
+ };
161
+
162
+ } finally {
163
+ await queryRunner.release();
164
+ }
165
+ }
166
+
167
+ private async validate(command: ${className}Command): Promise<ValidationResult> {
168
+ // Add validation logic
169
+ return { valid: true };
170
+ }
171
+
172
+ private async beforeExecute(command: ${className}Command, correlationId: string): Promise<void> {
173
+ this.eventEmitter.emit('command.executing', {
174
+ command: '${name}',
175
+ correlationId,
176
+ timestamp: new Date(),
177
+ });
178
+ }
179
+
180
+ private async executeCommand(
181
+ command: ${className}Command,
182
+ queryRunner: any,
183
+ ): Promise<ExecutionResult> {
184
+ // Implement command execution logic
185
+ return {
186
+ data: {},
187
+ events: [],
188
+ };
189
+ }
190
+
191
+ private async afterExecute(
192
+ command: ${className}Command,
193
+ result: ExecutionResult,
194
+ correlationId: string,
195
+ ): Promise<void> {
196
+ this.eventEmitter.emit('command.executed', {
197
+ command: '${name}',
198
+ correlationId,
199
+ result: result.data,
200
+ timestamp: new Date(),
201
+ });
202
+ }
203
+
204
+ private async publishEvents(events: DomainEvent[], correlationId: string): Promise<void> {
205
+ for (const event of events) {
206
+ this.eventEmitter.emit(event.type, {
207
+ ...event.payload,
208
+ correlationId,
209
+ timestamp: new Date(),
210
+ });
211
+ }
212
+ }
213
+
214
+ private generateCorrelationId(): string {
215
+ return \`cmd_\${Date.now()}_\${Math.random().toString(36).substr(2, 9)}\`;
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Command input
221
+ */
222
+ export interface ${className}Command {
223
+ [key: string]: any;
224
+ }
225
+
226
+ /**
227
+ * Command result
228
+ */
229
+ export interface ${className}Result {
230
+ success: boolean;
231
+ data?: any;
232
+ error?: {
233
+ code: string;
234
+ message: string;
235
+ details?: any;
236
+ };
237
+ correlationId?: string;
238
+ }
239
+
240
+ /**
241
+ * Validation result
242
+ */
243
+ interface ValidationResult {
244
+ valid: boolean;
245
+ message?: string;
246
+ errors?: Record<string, string[]>;
247
+ }
248
+
249
+ /**
250
+ * Execution result
251
+ */
252
+ interface ExecutionResult {
253
+ data: any;
254
+ events?: DomainEvent[];
255
+ }
256
+
257
+ /**
258
+ * Domain event
259
+ */
260
+ interface DomainEvent {
261
+ type: string;
262
+ payload: any;
263
+ }
264
+ `;
265
+ }
266
+ function generateQueryOrchestrator(name) {
267
+ const className = toPascalCase(name);
268
+ return `import { Injectable, Logger } from '@nestjs/common';
269
+ import { EventEmitter2 } from '@nestjs/event-emitter';
270
+
271
+ /**
272
+ * ${className} Query Orchestrator
273
+ * Handles query execution with caching and optimization
274
+ */
275
+ @Injectable()
276
+ export class ${className}QueryOrchestrator {
277
+ private readonly logger = new Logger(${className}QueryOrchestrator.name);
278
+ private readonly cache = new Map<string, CacheEntry>();
279
+
280
+ constructor(
281
+ private readonly eventEmitter: EventEmitter2,
282
+ ) {}
283
+
284
+ /**
285
+ * Execute the ${name} query
286
+ */
287
+ async execute(query: ${className}Query): Promise<${className}QueryResult> {
288
+ const cacheKey = this.generateCacheKey(query);
289
+
290
+ // Check cache
291
+ if (query.useCache !== false) {
292
+ const cached = this.getFromCache(cacheKey);
293
+ if (cached) {
294
+ this.logger.debug(\`Cache hit for query: \${cacheKey}\`);
295
+ return {
296
+ success: true,
297
+ data: cached,
298
+ fromCache: true,
299
+ };
300
+ }
301
+ }
302
+
303
+ try {
304
+ // Execute query
305
+ const result = await this.executeQuery(query);
306
+
307
+ // Cache result
308
+ if (query.useCache !== false && result) {
309
+ this.setCache(cacheKey, result, query.cacheTtl);
310
+ }
311
+
312
+ return {
313
+ success: true,
314
+ data: result,
315
+ fromCache: false,
316
+ };
317
+
318
+ } catch (error) {
319
+ this.logger.error(\`Query failed: \${(error as Error).message}\`);
320
+
321
+ return {
322
+ success: false,
323
+ error: {
324
+ code: 'QUERY_ERROR',
325
+ message: (error as Error).message,
326
+ },
327
+ };
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Execute paginated query
333
+ */
334
+ async executePaginated(
335
+ query: ${className}Query,
336
+ pagination: PaginationParams,
337
+ ): Promise<PaginatedResult<any>> {
338
+ const { page = 1, pageSize = 10 } = pagination;
339
+
340
+ const result = await this.executeQuery({
341
+ ...query,
342
+ skip: (page - 1) * pageSize,
343
+ take: pageSize,
344
+ });
345
+
346
+ const total = await this.count(query);
347
+ const totalPages = Math.ceil(total / pageSize);
348
+
349
+ return {
350
+ items: result || [],
351
+ total,
352
+ page,
353
+ pageSize,
354
+ totalPages,
355
+ hasNext: page < totalPages,
356
+ hasPrev: page > 1,
357
+ };
358
+ }
359
+
360
+ private async executeQuery(query: ${className}Query): Promise<any> {
361
+ // Implement query execution logic
362
+ return null;
363
+ }
364
+
365
+ private async count(query: ${className}Query): Promise<number> {
366
+ // Implement count logic
367
+ return 0;
368
+ }
369
+
370
+ private generateCacheKey(query: ${className}Query): string {
371
+ return \`${toKebabCase(name)}:\${JSON.stringify(query)}\`;
372
+ }
373
+
374
+ private getFromCache(key: string): any | null {
375
+ const entry = this.cache.get(key);
376
+ if (!entry) return null;
377
+
378
+ if (Date.now() > entry.expiresAt) {
379
+ this.cache.delete(key);
380
+ return null;
381
+ }
382
+
383
+ return entry.data;
384
+ }
385
+
386
+ private setCache(key: string, data: any, ttl: number = 60000): void {
387
+ this.cache.set(key, {
388
+ data,
389
+ expiresAt: Date.now() + ttl,
390
+ });
391
+ }
392
+
393
+ /**
394
+ * Invalidate cache
395
+ */
396
+ invalidateCache(pattern?: string): void {
397
+ if (pattern) {
398
+ for (const key of this.cache.keys()) {
399
+ if (key.includes(pattern)) {
400
+ this.cache.delete(key);
401
+ }
402
+ }
403
+ } else {
404
+ this.cache.clear();
405
+ }
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Query input
411
+ */
412
+ export interface ${className}Query {
413
+ [key: string]: any;
414
+ useCache?: boolean;
415
+ cacheTtl?: number;
416
+ skip?: number;
417
+ take?: number;
418
+ }
419
+
420
+ /**
421
+ * Query result
422
+ */
423
+ export interface ${className}QueryResult {
424
+ success: boolean;
425
+ data?: any;
426
+ fromCache?: boolean;
427
+ error?: {
428
+ code: string;
429
+ message: string;
430
+ };
431
+ }
432
+
433
+ /**
434
+ * Cache entry
435
+ */
436
+ interface CacheEntry {
437
+ data: any;
438
+ expiresAt: number;
439
+ }
440
+
441
+ /**
442
+ * Pagination params
443
+ */
444
+ interface PaginationParams {
445
+ page?: number;
446
+ pageSize?: number;
447
+ }
448
+
449
+ /**
450
+ * Paginated result
451
+ */
452
+ interface PaginatedResult<T> {
453
+ items: T[];
454
+ total: number;
455
+ page: number;
456
+ pageSize: number;
457
+ totalPages: number;
458
+ hasNext: boolean;
459
+ hasPrev: boolean;
460
+ }
461
+ `;
462
+ }
463
+ function generateSagaOrchestrator(name) {
464
+ const className = toPascalCase(name);
465
+ return `import { Injectable, Logger } from '@nestjs/common';
466
+ import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
467
+
468
+ /**
469
+ * ${className} Saga Orchestrator
470
+ * Coordinates long-running business processes
471
+ */
472
+ @Injectable()
473
+ export class ${className}SagaOrchestrator {
474
+ private readonly logger = new Logger(${className}SagaOrchestrator.name);
475
+ private readonly sagas = new Map<string, SagaState>();
476
+
477
+ constructor(
478
+ private readonly eventEmitter: EventEmitter2,
479
+ ) {}
480
+
481
+ /**
482
+ * Start a new saga
483
+ */
484
+ async start(input: ${className}SagaInput): Promise<string> {
485
+ const sagaId = this.generateSagaId();
486
+
487
+ const state: SagaState = {
488
+ id: sagaId,
489
+ status: 'started',
490
+ input,
491
+ currentStep: 0,
492
+ steps: this.defineSteps(),
493
+ completedSteps: [],
494
+ results: new Map(),
495
+ startedAt: new Date(),
496
+ };
497
+
498
+ this.sagas.set(sagaId, state);
499
+
500
+ this.logger.log(\`Starting saga [\${sagaId}]\`);
501
+ this.eventEmitter.emit('saga.${toKebabCase(name)}.started', { sagaId, input });
502
+
503
+ // Execute first step
504
+ await this.executeNextStep(sagaId);
505
+
506
+ return sagaId;
507
+ }
508
+
509
+ /**
510
+ * Handle step completion event
511
+ */
512
+ @OnEvent('saga.${toKebabCase(name)}.step.completed')
513
+ async onStepCompleted(event: StepCompletedEvent): Promise<void> {
514
+ const state = this.sagas.get(event.sagaId);
515
+ if (!state) return;
516
+
517
+ state.results.set(event.stepName, event.result);
518
+ state.completedSteps.push(event.stepName);
519
+ state.currentStep++;
520
+
521
+ if (state.currentStep >= state.steps.length) {
522
+ await this.completeSaga(event.sagaId);
523
+ } else {
524
+ await this.executeNextStep(event.sagaId);
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Handle step failure event
530
+ */
531
+ @OnEvent('saga.${toKebabCase(name)}.step.failed')
532
+ async onStepFailed(event: StepFailedEvent): Promise<void> {
533
+ const state = this.sagas.get(event.sagaId);
534
+ if (!state) return;
535
+
536
+ this.logger.error(\`Step failed in saga [\${event.sagaId}]: \${event.error}\`);
537
+
538
+ state.status = 'compensating';
539
+ await this.compensate(event.sagaId);
540
+ }
541
+
542
+ private async executeNextStep(sagaId: string): Promise<void> {
543
+ const state = this.sagas.get(sagaId);
544
+ if (!state) return;
545
+
546
+ const step = state.steps[state.currentStep];
547
+
548
+ this.logger.debug(\`Executing step: \${step.name} [\${sagaId}]\`);
549
+
550
+ try {
551
+ const result = await step.execute(state.input, state.results);
552
+
553
+ this.eventEmitter.emit('saga.${toKebabCase(name)}.step.completed', {
554
+ sagaId,
555
+ stepName: step.name,
556
+ result,
557
+ });
558
+ } catch (error) {
559
+ this.eventEmitter.emit('saga.${toKebabCase(name)}.step.failed', {
560
+ sagaId,
561
+ stepName: step.name,
562
+ error: (error as Error).message,
563
+ });
564
+ }
565
+ }
566
+
567
+ private async compensate(sagaId: string): Promise<void> {
568
+ const state = this.sagas.get(sagaId);
569
+ if (!state) return;
570
+
571
+ this.logger.log(\`Compensating saga [\${sagaId}]\`);
572
+
573
+ for (const stepName of state.completedSteps.reverse()) {
574
+ const step = state.steps.find(s => s.name === stepName);
575
+ if (step?.compensate) {
576
+ try {
577
+ await step.compensate(state.input, state.results);
578
+ this.logger.debug(\`Compensated step: \${stepName}\`);
579
+ } catch (error) {
580
+ this.logger.error(\`Compensation failed for \${stepName}: \${(error as Error).message}\`);
581
+ }
582
+ }
583
+ }
584
+
585
+ state.status = 'failed';
586
+ state.completedAt = new Date();
587
+
588
+ this.eventEmitter.emit('saga.${toKebabCase(name)}.failed', {
589
+ sagaId,
590
+ completedSteps: state.completedSteps,
591
+ });
592
+ }
593
+
594
+ private async completeSaga(sagaId: string): Promise<void> {
595
+ const state = this.sagas.get(sagaId);
596
+ if (!state) return;
597
+
598
+ state.status = 'completed';
599
+ state.completedAt = new Date();
600
+
601
+ this.logger.log(\`Saga completed [\${sagaId}]\`);
602
+
603
+ this.eventEmitter.emit('saga.${toKebabCase(name)}.completed', {
604
+ sagaId,
605
+ results: Object.fromEntries(state.results),
606
+ duration: state.completedAt.getTime() - state.startedAt.getTime(),
607
+ });
608
+ }
609
+
610
+ private defineSteps(): SagaStep[] {
611
+ return [
612
+ {
613
+ name: 'validate',
614
+ execute: async (input, results) => {
615
+ // Validation logic
616
+ return { validated: true };
617
+ },
618
+ },
619
+ {
620
+ name: 'process',
621
+ execute: async (input, results) => {
622
+ // Processing logic
623
+ return { processed: true };
624
+ },
625
+ compensate: async (input, results) => {
626
+ // Rollback processing
627
+ },
628
+ },
629
+ {
630
+ name: 'notify',
631
+ execute: async (input, results) => {
632
+ // Notification logic
633
+ return { notified: true };
634
+ },
635
+ },
636
+ ];
637
+ }
638
+
639
+ private generateSagaId(): string {
640
+ return \`saga_\${Date.now()}_\${Math.random().toString(36).substr(2, 9)}\`;
641
+ }
642
+
643
+ /**
644
+ * Get saga state
645
+ */
646
+ getState(sagaId: string): SagaState | undefined {
647
+ return this.sagas.get(sagaId);
648
+ }
649
+ }
650
+
651
+ /**
652
+ * Saga types
653
+ */
654
+ export interface ${className}SagaInput {
655
+ [key: string]: any;
656
+ }
657
+
658
+ interface SagaState {
659
+ id: string;
660
+ status: 'started' | 'running' | 'compensating' | 'completed' | 'failed';
661
+ input: any;
662
+ currentStep: number;
663
+ steps: SagaStep[];
664
+ completedSteps: string[];
665
+ results: Map<string, any>;
666
+ startedAt: Date;
667
+ completedAt?: Date;
668
+ }
669
+
670
+ interface SagaStep {
671
+ name: string;
672
+ execute: (input: any, results: Map<string, any>) => Promise<any>;
673
+ compensate?: (input: any, results: Map<string, any>) => Promise<void>;
674
+ }
675
+
676
+ interface StepCompletedEvent {
677
+ sagaId: string;
678
+ stepName: string;
679
+ result: any;
680
+ }
681
+
682
+ interface StepFailedEvent {
683
+ sagaId: string;
684
+ stepName: string;
685
+ error: string;
686
+ }
687
+ `;
688
+ }
689
+ /**
690
+ * Setup orchestrator infrastructure
691
+ */
692
+ async function setupOrchestratorInfrastructure(basePath, options = {}) {
693
+ console.log(chalk_1.default.bold.blue('\n🎭 Setting up Orchestrator Infrastructure\n'));
694
+ const sharedPath = path.join(basePath, 'src/shared/application');
695
+ if (!fs.existsSync(sharedPath)) {
696
+ fs.mkdirSync(sharedPath, { recursive: true });
697
+ }
698
+ // Generate base orchestrator
699
+ const baseContent = generateBaseOrchestrator();
700
+ fs.writeFileSync(path.join(sharedPath, 'orchestrator.base.ts'), baseContent);
701
+ console.log(chalk_1.default.green(` ✓ Created base orchestrator`));
702
+ // Generate pipeline pattern
703
+ const pipelineContent = generatePipeline();
704
+ fs.writeFileSync(path.join(sharedPath, 'pipeline.ts'), pipelineContent);
705
+ console.log(chalk_1.default.green(` ✓ Created pipeline pattern`));
706
+ console.log(chalk_1.default.bold.green('\n✅ Orchestrator infrastructure ready!\n'));
707
+ }
708
+ function generateBaseOrchestrator() {
709
+ return `/**
710
+ * Base Orchestrator
711
+ * Foundation for use case orchestrators
712
+ */
713
+
714
+ import { Logger } from '@nestjs/common';
715
+ import { EventEmitter2 } from '@nestjs/event-emitter';
716
+
717
+ export abstract class BaseOrchestrator<TInput, TOutput> {
718
+ protected abstract readonly logger: Logger;
719
+
720
+ constructor(protected readonly eventEmitter: EventEmitter2) {}
721
+
722
+ /**
723
+ * Execute orchestrated operation
724
+ */
725
+ abstract execute(input: TInput): Promise<OrchestratorResult<TOutput>>;
726
+
727
+ protected success(data: TOutput, correlationId?: string): OrchestratorResult<TOutput> {
728
+ return {
729
+ success: true,
730
+ data,
731
+ correlationId,
732
+ };
733
+ }
734
+
735
+ protected failure(error: OrchestratorError, correlationId?: string): OrchestratorResult<TOutput> {
736
+ return {
737
+ success: false,
738
+ error,
739
+ correlationId,
740
+ };
741
+ }
742
+
743
+ protected generateCorrelationId(): string {
744
+ return \`orch_\${Date.now()}_\${Math.random().toString(36).substr(2, 9)}\`;
745
+ }
746
+ }
747
+
748
+ /**
749
+ * Orchestrator result
750
+ */
751
+ export interface OrchestratorResult<T> {
752
+ success: boolean;
753
+ data?: T;
754
+ error?: OrchestratorError;
755
+ correlationId?: string;
756
+ }
757
+
758
+ /**
759
+ * Orchestrator error
760
+ */
761
+ export interface OrchestratorError {
762
+ code: string;
763
+ message: string;
764
+ details?: any;
765
+ }
766
+
767
+ /**
768
+ * Orchestrator decorator
769
+ */
770
+ export function Orchestrator(): ClassDecorator {
771
+ return function (target: Function) {
772
+ Reflect.defineMetadata('isOrchestrator', true, target);
773
+ };
774
+ }
775
+ `;
776
+ }
777
+ function generatePipeline() {
778
+ return `/**
779
+ * Pipeline Pattern
780
+ * For building request/response pipelines
781
+ */
782
+
783
+ /**
784
+ * Pipeline step interface
785
+ */
786
+ export interface PipelineStep<TContext> {
787
+ execute(context: TContext, next: () => Promise<void>): Promise<void>;
788
+ }
789
+
790
+ /**
791
+ * Pipeline builder
792
+ */
793
+ export class Pipeline<TContext> {
794
+ private steps: PipelineStep<TContext>[] = [];
795
+
796
+ use(step: PipelineStep<TContext>): this {
797
+ this.steps.push(step);
798
+ return this;
799
+ }
800
+
801
+ async execute(context: TContext): Promise<TContext> {
802
+ let index = 0;
803
+
804
+ const next = async (): Promise<void> => {
805
+ if (index < this.steps.length) {
806
+ const step = this.steps[index++];
807
+ await step.execute(context, next);
808
+ }
809
+ };
810
+
811
+ await next();
812
+ return context;
813
+ }
814
+ }
815
+
816
+ /**
817
+ * Create a pipeline
818
+ */
819
+ export function pipeline<TContext>(): Pipeline<TContext> {
820
+ return new Pipeline<TContext>();
821
+ }
822
+
823
+ /**
824
+ * Common pipeline steps
825
+ */
826
+ export class LoggingStep<TContext> implements PipelineStep<TContext> {
827
+ constructor(private readonly logger: any) {}
828
+
829
+ async execute(context: TContext, next: () => Promise<void>): Promise<void> {
830
+ const start = Date.now();
831
+ this.logger.log('Pipeline started');
832
+
833
+ await next();
834
+
835
+ this.logger.log(\`Pipeline completed in \${Date.now() - start}ms\`);
836
+ }
837
+ }
838
+
839
+ export class ValidationStep<TContext extends { input: any; errors?: string[] }> implements PipelineStep<TContext> {
840
+ constructor(private readonly validator: (input: any) => string[]) {}
841
+
842
+ async execute(context: TContext, next: () => Promise<void>): Promise<void> {
843
+ const errors = this.validator(context.input);
844
+
845
+ if (errors.length > 0) {
846
+ context.errors = errors;
847
+ return;
848
+ }
849
+
850
+ await next();
851
+ }
852
+ }
853
+
854
+ export class TransactionStep<TContext> implements PipelineStep<TContext> {
855
+ constructor(private readonly dataSource: any) {}
856
+
857
+ async execute(context: TContext, next: () => Promise<void>): Promise<void> {
858
+ const queryRunner = this.dataSource.createQueryRunner();
859
+ await queryRunner.connect();
860
+ await queryRunner.startTransaction();
861
+
862
+ try {
863
+ await next();
864
+ await queryRunner.commitTransaction();
865
+ } catch (error) {
866
+ await queryRunner.rollbackTransaction();
867
+ throw error;
868
+ } finally {
869
+ await queryRunner.release();
870
+ }
871
+ }
872
+ }
873
+ `;
874
+ }
875
+ // Helper functions
876
+ function toKebabCase(str) {
877
+ return str
878
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
879
+ .replace(/[\s_]+/g, '-')
880
+ .toLowerCase();
881
+ }
882
+ function toPascalCase(str) {
883
+ return str
884
+ .replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '')
885
+ .replace(/^(.)/, c => c.toUpperCase());
886
+ }
887
+ //# sourceMappingURL=generate-orchestrator.js.map