nestjs-ddd-cli 2.2.1 → 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 +24 -5
  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,796 @@
1
+ "use strict";
2
+ /**
3
+ * Domain Service Orchestration Generator
4
+ * Generates domain services for cross-aggregate operations
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.generateDomainService = generateDomainService;
44
+ exports.setupDomainServiceInfrastructure = setupDomainServiceInfrastructure;
45
+ const fs = __importStar(require("fs"));
46
+ const path = __importStar(require("path"));
47
+ const chalk_1 = __importDefault(require("chalk"));
48
+ async function generateDomainService(name, basePath, options = {}) {
49
+ console.log(chalk_1.default.bold.blue('\n🔧 Generating Domain Service\n'));
50
+ const moduleName = options.module || 'shared';
51
+ const servicePath = path.join(basePath, 'src', moduleName, 'domain', 'services');
52
+ if (!fs.existsSync(servicePath)) {
53
+ fs.mkdirSync(servicePath, { recursive: true });
54
+ }
55
+ const serviceType = options.type || 'simple';
56
+ let serviceContent;
57
+ switch (serviceType) {
58
+ case 'workflow':
59
+ serviceContent = generateWorkflowService(name);
60
+ break;
61
+ case 'policy':
62
+ serviceContent = generatePolicyService(name);
63
+ break;
64
+ default:
65
+ serviceContent = generateSimpleDomainService(name);
66
+ }
67
+ const serviceFile = path.join(servicePath, `${toKebabCase(name)}.service.ts`);
68
+ fs.writeFileSync(serviceFile, serviceContent);
69
+ console.log(chalk_1.default.green(` ✓ Created ${serviceFile}`));
70
+ console.log(chalk_1.default.bold.green('\n✅ Domain service generated successfully!\n'));
71
+ }
72
+ function generateSimpleDomainService(name) {
73
+ const className = toPascalCase(name);
74
+ return `import { Injectable } from '@nestjs/common';
75
+ import { EventEmitter2 } from '@nestjs/event-emitter';
76
+
77
+ /**
78
+ * ${className} Domain Service
79
+ * Handles cross-aggregate business logic
80
+ */
81
+ @Injectable()
82
+ export class ${className}Service {
83
+ constructor(
84
+ private readonly eventEmitter: EventEmitter2,
85
+ ) {}
86
+
87
+ /**
88
+ * Execute domain operation
89
+ */
90
+ async execute(params: ${className}Params): Promise<${className}Result> {
91
+ // Validate business rules
92
+ this.validateRules(params);
93
+
94
+ // Perform domain logic
95
+ const result = await this.performOperation(params);
96
+
97
+ // Emit domain events
98
+ this.eventEmitter.emit('${toKebabCase(name)}.completed', {
99
+ params,
100
+ result,
101
+ timestamp: new Date(),
102
+ });
103
+
104
+ return result;
105
+ }
106
+
107
+ private validateRules(params: ${className}Params): void {
108
+ // Add business rule validations
109
+ if (!params) {
110
+ throw new DomainValidationError('Invalid parameters');
111
+ }
112
+ }
113
+
114
+ private async performOperation(params: ${className}Params): Promise<${className}Result> {
115
+ // Implement domain logic
116
+ return {
117
+ success: true,
118
+ data: {},
119
+ };
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Service parameters
125
+ */
126
+ export interface ${className}Params {
127
+ [key: string]: any;
128
+ }
129
+
130
+ /**
131
+ * Service result
132
+ */
133
+ export interface ${className}Result {
134
+ success: boolean;
135
+ data: any;
136
+ error?: string;
137
+ }
138
+
139
+ /**
140
+ * Domain validation error
141
+ */
142
+ export class DomainValidationError extends Error {
143
+ constructor(message: string) {
144
+ super(message);
145
+ this.name = 'DomainValidationError';
146
+ }
147
+ }
148
+ `;
149
+ }
150
+ function generateWorkflowService(name) {
151
+ const className = toPascalCase(name);
152
+ return `import { Injectable, Logger } from '@nestjs/common';
153
+ import { EventEmitter2 } from '@nestjs/event-emitter';
154
+
155
+ /**
156
+ * ${className} Workflow Service
157
+ * Orchestrates multi-step business processes
158
+ */
159
+ @Injectable()
160
+ export class ${className}WorkflowService {
161
+ private readonly logger = new Logger(${className}WorkflowService.name);
162
+
163
+ constructor(
164
+ private readonly eventEmitter: EventEmitter2,
165
+ ) {}
166
+
167
+ /**
168
+ * Execute workflow
169
+ */
170
+ async execute(context: WorkflowContext): Promise<WorkflowResult> {
171
+ const workflow = new ${className}Workflow(context);
172
+
173
+ this.logger.log(\`Starting workflow: \${workflow.id}\`);
174
+ this.eventEmitter.emit('workflow.started', { workflowId: workflow.id, type: '${toKebabCase(name)}' });
175
+
176
+ try {
177
+ // Execute workflow steps
178
+ for (const step of workflow.steps) {
179
+ this.logger.debug(\`Executing step: \${step.name}\`);
180
+
181
+ const stepResult = await this.executeStep(step, context);
182
+
183
+ if (!stepResult.success) {
184
+ if (step.required) {
185
+ throw new WorkflowStepError(step.name, stepResult.error!);
186
+ }
187
+ this.logger.warn(\`Optional step failed: \${step.name}\`);
188
+ }
189
+
190
+ context.results[step.name] = stepResult;
191
+ this.eventEmitter.emit('workflow.step.completed', {
192
+ workflowId: workflow.id,
193
+ step: step.name,
194
+ result: stepResult,
195
+ });
196
+ }
197
+
198
+ const result: WorkflowResult = {
199
+ id: workflow.id,
200
+ status: 'completed',
201
+ results: context.results,
202
+ completedAt: new Date(),
203
+ };
204
+
205
+ this.eventEmitter.emit('workflow.completed', result);
206
+ return result;
207
+
208
+ } catch (error) {
209
+ const failedResult: WorkflowResult = {
210
+ id: workflow.id,
211
+ status: 'failed',
212
+ results: context.results,
213
+ error: (error as Error).message,
214
+ completedAt: new Date(),
215
+ };
216
+
217
+ this.eventEmitter.emit('workflow.failed', failedResult);
218
+
219
+ // Execute compensation steps
220
+ await this.compensate(workflow, context);
221
+
222
+ throw error;
223
+ }
224
+ }
225
+
226
+ private async executeStep(step: WorkflowStep, context: WorkflowContext): Promise<StepResult> {
227
+ const startTime = Date.now();
228
+
229
+ try {
230
+ const result = await step.handler(context);
231
+
232
+ return {
233
+ success: true,
234
+ data: result,
235
+ duration: Date.now() - startTime,
236
+ };
237
+ } catch (error) {
238
+ return {
239
+ success: false,
240
+ error: (error as Error).message,
241
+ duration: Date.now() - startTime,
242
+ };
243
+ }
244
+ }
245
+
246
+ private async compensate(workflow: ${className}Workflow, context: WorkflowContext): Promise<void> {
247
+ this.logger.log(\`Compensating workflow: \${workflow.id}\`);
248
+
249
+ // Execute compensation steps in reverse order
250
+ const completedSteps = Object.keys(context.results);
251
+
252
+ for (const stepName of completedSteps.reverse()) {
253
+ const step = workflow.steps.find(s => s.name === stepName);
254
+
255
+ if (step?.compensate) {
256
+ try {
257
+ await step.compensate(context);
258
+ this.logger.debug(\`Compensated step: \${stepName}\`);
259
+ } catch (error) {
260
+ this.logger.error(\`Compensation failed for step: \${stepName}\`, error);
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Workflow definition
269
+ */
270
+ class ${className}Workflow {
271
+ public readonly id: string;
272
+ public readonly steps: WorkflowStep[];
273
+
274
+ constructor(context: WorkflowContext) {
275
+ this.id = this.generateId();
276
+ this.steps = this.defineSteps();
277
+ }
278
+
279
+ private generateId(): string {
280
+ return \`wf_\${Date.now()}_\${Math.random().toString(36).substr(2, 9)}\`;
281
+ }
282
+
283
+ private defineSteps(): WorkflowStep[] {
284
+ return [
285
+ {
286
+ name: 'validate',
287
+ required: true,
288
+ handler: async (ctx) => {
289
+ // Validation logic
290
+ return { validated: true };
291
+ },
292
+ },
293
+ {
294
+ name: 'process',
295
+ required: true,
296
+ handler: async (ctx) => {
297
+ // Processing logic
298
+ return { processed: true };
299
+ },
300
+ compensate: async (ctx) => {
301
+ // Rollback processing
302
+ },
303
+ },
304
+ {
305
+ name: 'notify',
306
+ required: false,
307
+ handler: async (ctx) => {
308
+ // Notification logic
309
+ return { notified: true };
310
+ },
311
+ },
312
+ ];
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Workflow types
318
+ */
319
+ export interface WorkflowContext {
320
+ input: any;
321
+ results: Record<string, StepResult>;
322
+ metadata?: Record<string, any>;
323
+ }
324
+
325
+ export interface WorkflowStep {
326
+ name: string;
327
+ required: boolean;
328
+ handler: (context: WorkflowContext) => Promise<any>;
329
+ compensate?: (context: WorkflowContext) => Promise<void>;
330
+ }
331
+
332
+ export interface StepResult {
333
+ success: boolean;
334
+ data?: any;
335
+ error?: string;
336
+ duration: number;
337
+ }
338
+
339
+ export interface WorkflowResult {
340
+ id: string;
341
+ status: 'completed' | 'failed' | 'cancelled';
342
+ results: Record<string, StepResult>;
343
+ error?: string;
344
+ completedAt: Date;
345
+ }
346
+
347
+ export class WorkflowStepError extends Error {
348
+ constructor(stepName: string, message: string) {
349
+ super(\`Step '\${stepName}' failed: \${message}\`);
350
+ this.name = 'WorkflowStepError';
351
+ }
352
+ }
353
+ `;
354
+ }
355
+ function generatePolicyService(name) {
356
+ const className = toPascalCase(name);
357
+ return `import { Injectable } from '@nestjs/common';
358
+
359
+ /**
360
+ * ${className} Policy Service
361
+ * Encapsulates business rules and policies
362
+ */
363
+ @Injectable()
364
+ export class ${className}PolicyService {
365
+ private readonly rules: PolicyRule[] = [];
366
+
367
+ constructor() {
368
+ this.registerRules();
369
+ }
370
+
371
+ /**
372
+ * Evaluate all policies for a given context
373
+ */
374
+ evaluate(context: PolicyContext): PolicyResult {
375
+ const violations: PolicyViolation[] = [];
376
+ const warnings: PolicyWarning[] = [];
377
+
378
+ for (const rule of this.rules) {
379
+ if (!rule.condition(context)) {
380
+ continue;
381
+ }
382
+
383
+ const result = rule.evaluate(context);
384
+
385
+ if (!result.passed) {
386
+ if (rule.severity === 'error') {
387
+ violations.push({
388
+ rule: rule.name,
389
+ message: result.message || rule.message,
390
+ code: rule.code,
391
+ });
392
+ } else {
393
+ warnings.push({
394
+ rule: rule.name,
395
+ message: result.message || rule.message,
396
+ });
397
+ }
398
+ }
399
+ }
400
+
401
+ return {
402
+ passed: violations.length === 0,
403
+ violations,
404
+ warnings,
405
+ context,
406
+ };
407
+ }
408
+
409
+ /**
410
+ * Register a new policy rule
411
+ */
412
+ registerRule(rule: PolicyRule): void {
413
+ this.rules.push(rule);
414
+ }
415
+
416
+ /**
417
+ * Register default rules
418
+ */
419
+ private registerRules(): void {
420
+ // Add default policy rules
421
+ this.registerRule({
422
+ name: 'example-rule',
423
+ code: 'POLICY_001',
424
+ message: 'Example policy violation',
425
+ severity: 'error',
426
+ condition: (ctx) => true,
427
+ evaluate: (ctx) => ({
428
+ passed: true,
429
+ }),
430
+ });
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Policy types
436
+ */
437
+ export interface PolicyRule {
438
+ name: string;
439
+ code: string;
440
+ message: string;
441
+ severity: 'error' | 'warning';
442
+ condition: (context: PolicyContext) => boolean;
443
+ evaluate: (context: PolicyContext) => PolicyEvaluation;
444
+ }
445
+
446
+ export interface PolicyContext {
447
+ subject: any;
448
+ action: string;
449
+ resource: any;
450
+ environment?: Record<string, any>;
451
+ }
452
+
453
+ export interface PolicyEvaluation {
454
+ passed: boolean;
455
+ message?: string;
456
+ data?: any;
457
+ }
458
+
459
+ export interface PolicyViolation {
460
+ rule: string;
461
+ code: string;
462
+ message: string;
463
+ }
464
+
465
+ export interface PolicyWarning {
466
+ rule: string;
467
+ message: string;
468
+ }
469
+
470
+ export interface PolicyResult {
471
+ passed: boolean;
472
+ violations: PolicyViolation[];
473
+ warnings: PolicyWarning[];
474
+ context: PolicyContext;
475
+ }
476
+
477
+ /**
478
+ * Policy builder for fluent rule creation
479
+ */
480
+ export class PolicyBuilder {
481
+ private rule: Partial<PolicyRule> = {
482
+ severity: 'error',
483
+ condition: () => true,
484
+ };
485
+
486
+ name(name: string): this {
487
+ this.rule.name = name;
488
+ return this;
489
+ }
490
+
491
+ code(code: string): this {
492
+ this.rule.code = code;
493
+ return this;
494
+ }
495
+
496
+ message(message: string): this {
497
+ this.rule.message = message;
498
+ return this;
499
+ }
500
+
501
+ severity(severity: 'error' | 'warning'): this {
502
+ this.rule.severity = severity;
503
+ return this;
504
+ }
505
+
506
+ when(condition: (context: PolicyContext) => boolean): this {
507
+ this.rule.condition = condition;
508
+ return this;
509
+ }
510
+
511
+ evaluate(evaluator: (context: PolicyContext) => PolicyEvaluation): this {
512
+ this.rule.evaluate = evaluator;
513
+ return this;
514
+ }
515
+
516
+ build(): PolicyRule {
517
+ if (!this.rule.name || !this.rule.code || !this.rule.evaluate) {
518
+ throw new Error('Policy rule is incomplete');
519
+ }
520
+ return this.rule as PolicyRule;
521
+ }
522
+ }
523
+
524
+ /**
525
+ * Create a policy rule builder
526
+ */
527
+ export function policy(): PolicyBuilder {
528
+ return new PolicyBuilder();
529
+ }
530
+ `;
531
+ }
532
+ /**
533
+ * Setup domain service infrastructure
534
+ */
535
+ async function setupDomainServiceInfrastructure(basePath, options = {}) {
536
+ console.log(chalk_1.default.bold.blue('\n🔧 Setting up Domain Service Infrastructure\n'));
537
+ const sharedPath = path.join(basePath, 'src/shared/domain/services');
538
+ if (!fs.existsSync(sharedPath)) {
539
+ fs.mkdirSync(sharedPath, { recursive: true });
540
+ }
541
+ // Generate base domain service
542
+ const baseServiceContent = generateBaseDomainService();
543
+ fs.writeFileSync(path.join(sharedPath, 'domain-service.base.ts'), baseServiceContent);
544
+ console.log(chalk_1.default.green(` ✓ Created base domain service`));
545
+ // Generate saga pattern
546
+ const sagaContent = generateSagaPattern();
547
+ fs.writeFileSync(path.join(sharedPath, 'saga.ts'), sagaContent);
548
+ console.log(chalk_1.default.green(` ✓ Created saga pattern`));
549
+ console.log(chalk_1.default.bold.green('\n✅ Domain service infrastructure ready!\n'));
550
+ }
551
+ function generateBaseDomainService() {
552
+ return `/**
553
+ * Base Domain Service
554
+ * Foundation for domain services
555
+ */
556
+
557
+ import { EventEmitter2 } from '@nestjs/event-emitter';
558
+
559
+ export abstract class BaseDomainService {
560
+ constructor(protected readonly eventEmitter: EventEmitter2) {}
561
+
562
+ protected emit(event: string, payload: any): void {
563
+ this.eventEmitter.emit(event, {
564
+ ...payload,
565
+ timestamp: new Date(),
566
+ service: this.constructor.name,
567
+ });
568
+ }
569
+
570
+ protected async emitAsync(event: string, payload: any): Promise<void> {
571
+ await this.eventEmitter.emitAsync(event, {
572
+ ...payload,
573
+ timestamp: new Date(),
574
+ service: this.constructor.name,
575
+ });
576
+ }
577
+ }
578
+
579
+ /**
580
+ * Domain service result type
581
+ */
582
+ export type DomainResult<T, E = DomainError> =
583
+ | { success: true; data: T }
584
+ | { success: false; error: E };
585
+
586
+ export function success<T>(data: T): DomainResult<T> {
587
+ return { success: true, data };
588
+ }
589
+
590
+ export function failure<E>(error: E): DomainResult<never, E> {
591
+ return { success: false, error };
592
+ }
593
+
594
+ /**
595
+ * Domain error
596
+ */
597
+ export class DomainError extends Error {
598
+ constructor(
599
+ message: string,
600
+ public readonly code: string,
601
+ public readonly details?: Record<string, any>,
602
+ ) {
603
+ super(message);
604
+ this.name = 'DomainError';
605
+ }
606
+ }
607
+
608
+ /**
609
+ * Domain service decorator
610
+ */
611
+ export function DomainService(): ClassDecorator {
612
+ return function (target: Function) {
613
+ // Mark as domain service
614
+ Reflect.defineMetadata('isDomainService', true, target);
615
+ };
616
+ }
617
+ `;
618
+ }
619
+ function generateSagaPattern() {
620
+ return `/**
621
+ * Saga Pattern Implementation
622
+ * For distributed transactions across aggregates
623
+ */
624
+
625
+ import { Injectable, Logger } from '@nestjs/common';
626
+ import { EventEmitter2 } from '@nestjs/event-emitter';
627
+
628
+ /**
629
+ * Saga step definition
630
+ */
631
+ export interface SagaStep<TData = any> {
632
+ name: string;
633
+ execute: (data: TData) => Promise<any>;
634
+ compensate: (data: TData, result: any) => Promise<void>;
635
+ }
636
+
637
+ /**
638
+ * Saga execution context
639
+ */
640
+ export interface SagaContext<TData = any> {
641
+ id: string;
642
+ data: TData;
643
+ results: Map<string, any>;
644
+ completedSteps: string[];
645
+ status: 'running' | 'completed' | 'compensating' | 'failed';
646
+ }
647
+
648
+ /**
649
+ * Saga orchestrator
650
+ */
651
+ @Injectable()
652
+ export class SagaOrchestrator {
653
+ private readonly logger = new Logger(SagaOrchestrator.name);
654
+
655
+ constructor(private readonly eventEmitter: EventEmitter2) {}
656
+
657
+ /**
658
+ * Execute a saga with compensation support
659
+ */
660
+ async execute<TData>(
661
+ sagaName: string,
662
+ steps: SagaStep<TData>[],
663
+ data: TData,
664
+ ): Promise<SagaContext<TData>> {
665
+ const context: SagaContext<TData> = {
666
+ id: this.generateSagaId(),
667
+ data,
668
+ results: new Map(),
669
+ completedSteps: [],
670
+ status: 'running',
671
+ };
672
+
673
+ this.logger.log(\`Starting saga: \${sagaName} [\${context.id}]\`);
674
+ this.eventEmitter.emit('saga.started', { id: context.id, name: sagaName });
675
+
676
+ try {
677
+ for (const step of steps) {
678
+ this.logger.debug(\`Executing step: \${step.name}\`);
679
+
680
+ const result = await step.execute(data);
681
+ context.results.set(step.name, result);
682
+ context.completedSteps.push(step.name);
683
+
684
+ this.eventEmitter.emit('saga.step.completed', {
685
+ sagaId: context.id,
686
+ step: step.name,
687
+ result,
688
+ });
689
+ }
690
+
691
+ context.status = 'completed';
692
+ this.eventEmitter.emit('saga.completed', { id: context.id, name: sagaName });
693
+
694
+ return context;
695
+
696
+ } catch (error) {
697
+ this.logger.error(\`Saga failed at step: \${context.completedSteps[context.completedSteps.length - 1]}\`);
698
+ context.status = 'compensating';
699
+
700
+ await this.compensate(sagaName, steps, context);
701
+
702
+ context.status = 'failed';
703
+ this.eventEmitter.emit('saga.failed', {
704
+ id: context.id,
705
+ name: sagaName,
706
+ error: (error as Error).message,
707
+ });
708
+
709
+ throw error;
710
+ }
711
+ }
712
+
713
+ private async compensate<TData>(
714
+ sagaName: string,
715
+ steps: SagaStep<TData>[],
716
+ context: SagaContext<TData>,
717
+ ): Promise<void> {
718
+ this.logger.log(\`Compensating saga: \${sagaName} [\${context.id}]\`);
719
+
720
+ // Compensate in reverse order
721
+ for (const stepName of context.completedSteps.reverse()) {
722
+ const step = steps.find(s => s.name === stepName);
723
+
724
+ if (step) {
725
+ try {
726
+ const stepResult = context.results.get(stepName);
727
+ await step.compensate(context.data, stepResult);
728
+
729
+ this.logger.debug(\`Compensated step: \${stepName}\`);
730
+ this.eventEmitter.emit('saga.step.compensated', {
731
+ sagaId: context.id,
732
+ step: stepName,
733
+ });
734
+ } catch (compensateError) {
735
+ this.logger.error(\`Compensation failed for step: \${stepName}\`, compensateError);
736
+ // Continue with other compensations
737
+ }
738
+ }
739
+ }
740
+ }
741
+
742
+ private generateSagaId(): string {
743
+ return \`saga_\${Date.now()}_\${Math.random().toString(36).substr(2, 9)}\`;
744
+ }
745
+ }
746
+
747
+ /**
748
+ * Saga builder for fluent API
749
+ */
750
+ export class SagaBuilder<TData = any> {
751
+ private steps: SagaStep<TData>[] = [];
752
+ private name: string = '';
753
+
754
+ named(name: string): this {
755
+ this.name = name;
756
+ return this;
757
+ }
758
+
759
+ step(
760
+ name: string,
761
+ execute: (data: TData) => Promise<any>,
762
+ compensate: (data: TData, result: any) => Promise<void>,
763
+ ): this {
764
+ this.steps.push({ name, execute, compensate });
765
+ return this;
766
+ }
767
+
768
+ build(): { name: string; steps: SagaStep<TData>[] } {
769
+ return {
770
+ name: this.name,
771
+ steps: this.steps,
772
+ };
773
+ }
774
+ }
775
+
776
+ /**
777
+ * Create a saga builder
778
+ */
779
+ export function saga<TData = any>(): SagaBuilder<TData> {
780
+ return new SagaBuilder<TData>();
781
+ }
782
+ `;
783
+ }
784
+ // Helper functions
785
+ function toKebabCase(str) {
786
+ return str
787
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
788
+ .replace(/[\s_]+/g, '-')
789
+ .toLowerCase();
790
+ }
791
+ function toPascalCase(str) {
792
+ return str
793
+ .replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '')
794
+ .replace(/^(.)/, c => c.toUpperCase());
795
+ }
796
+ //# sourceMappingURL=generate-domain-service.js.map