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,953 @@
1
+ "use strict";
2
+ /**
3
+ * Aggregate Root & Command Handler Validator Generator
4
+ * Generates comprehensive validators for aggregates
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.setupAggregateValidator = setupAggregateValidator;
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ async function setupAggregateValidator(basePath, options = {}) {
48
+ console.log(chalk_1.default.bold.blue('\n✅ Setting up Aggregate Validator Framework\n'));
49
+ const sharedPath = path.join(basePath, 'src/shared/domain/validation');
50
+ if (!fs.existsSync(sharedPath)) {
51
+ fs.mkdirSync(sharedPath, { recursive: true });
52
+ }
53
+ // Generate aggregate root base
54
+ const aggregateContent = generateAggregateRoot();
55
+ fs.writeFileSync(path.join(sharedPath, 'aggregate-root.ts'), aggregateContent);
56
+ console.log(chalk_1.default.green(` ✓ Created aggregate root base`));
57
+ // Generate invariant validator
58
+ const invariantContent = generateInvariantValidator();
59
+ fs.writeFileSync(path.join(sharedPath, 'invariant.validator.ts'), invariantContent);
60
+ console.log(chalk_1.default.green(` ✓ Created invariant validator`));
61
+ // Generate state machine
62
+ const stateMachineContent = generateStateMachine();
63
+ fs.writeFileSync(path.join(sharedPath, 'state-machine.ts'), stateMachineContent);
64
+ console.log(chalk_1.default.green(` ✓ Created state machine`));
65
+ // Generate business rules engine
66
+ const rulesContent = generateBusinessRulesEngine();
67
+ fs.writeFileSync(path.join(sharedPath, 'business-rules.ts'), rulesContent);
68
+ console.log(chalk_1.default.green(` ✓ Created business rules engine`));
69
+ // Generate command validator
70
+ const commandContent = generateCommandValidator();
71
+ fs.writeFileSync(path.join(sharedPath, 'command.validator.ts'), commandContent);
72
+ console.log(chalk_1.default.green(` ✓ Created command validator`));
73
+ console.log(chalk_1.default.bold.green('\n✅ Aggregate validator framework ready!\n'));
74
+ }
75
+ function generateAggregateRoot() {
76
+ return `/**
77
+ * Aggregate Root Base
78
+ * Foundation for all aggregate roots with invariant validation
79
+ */
80
+
81
+ import { InvariantValidator, InvariantRule } from './invariant.validator';
82
+
83
+ export interface DomainEvent {
84
+ eventType: string;
85
+ aggregateId: string;
86
+ aggregateType: string;
87
+ timestamp: Date;
88
+ version: number;
89
+ payload: any;
90
+ }
91
+
92
+ /**
93
+ * Base Aggregate Root
94
+ */
95
+ export abstract class AggregateRoot<TId = string> {
96
+ private _id: TId;
97
+ private _version: number = 0;
98
+ private _domainEvents: DomainEvent[] = [];
99
+ private _invariantValidator: InvariantValidator<this>;
100
+
101
+ protected constructor(id: TId) {
102
+ this._id = id;
103
+ this._invariantValidator = new InvariantValidator<this>();
104
+ this.registerInvariants(this._invariantValidator);
105
+ }
106
+
107
+ get id(): TId {
108
+ return this._id;
109
+ }
110
+
111
+ get version(): number {
112
+ return this._version;
113
+ }
114
+
115
+ /**
116
+ * Register aggregate invariants
117
+ * Override in subclass to define invariants
118
+ */
119
+ protected abstract registerInvariants(validator: InvariantValidator<this>): void;
120
+
121
+ /**
122
+ * Validate all invariants
123
+ */
124
+ protected validateInvariants(): void {
125
+ const result = this._invariantValidator.validate(this);
126
+ if (!result.valid) {
127
+ throw new InvariantViolationError(result.violations);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Apply a domain event
133
+ */
134
+ protected apply(event: Omit<DomainEvent, 'version' | 'timestamp' | 'aggregateId' | 'aggregateType'>): void {
135
+ const fullEvent: DomainEvent = {
136
+ ...event,
137
+ aggregateId: String(this._id),
138
+ aggregateType: this.constructor.name,
139
+ version: this._version + 1,
140
+ timestamp: new Date(),
141
+ };
142
+
143
+ this.when(fullEvent);
144
+ this._domainEvents.push(fullEvent);
145
+ this._version++;
146
+
147
+ // Validate invariants after state change
148
+ this.validateInvariants();
149
+ }
150
+
151
+ /**
152
+ * Handle event application
153
+ * Override to implement event handlers
154
+ */
155
+ protected abstract when(event: DomainEvent): void;
156
+
157
+ /**
158
+ * Load aggregate from event history
159
+ */
160
+ public loadFromHistory(events: DomainEvent[]): void {
161
+ for (const event of events) {
162
+ this.when(event);
163
+ this._version = event.version;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Get uncommitted domain events
169
+ */
170
+ public getUncommittedEvents(): DomainEvent[] {
171
+ return [...this._domainEvents];
172
+ }
173
+
174
+ /**
175
+ * Clear uncommitted events after persistence
176
+ */
177
+ public markEventsAsCommitted(): void {
178
+ this._domainEvents = [];
179
+ }
180
+
181
+ /**
182
+ * Check if aggregate has uncommitted changes
183
+ */
184
+ public hasUncommittedChanges(): boolean {
185
+ return this._domainEvents.length > 0;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Invariant violation error
191
+ */
192
+ export class InvariantViolationError extends Error {
193
+ constructor(public readonly violations: string[]) {
194
+ super(\`Invariant violations: \${violations.join(', ')}\`);
195
+ this.name = 'InvariantViolationError';
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Entity base class
201
+ */
202
+ export abstract class Entity<TId = string> {
203
+ protected readonly _id: TId;
204
+
205
+ protected constructor(id: TId) {
206
+ this._id = id;
207
+ }
208
+
209
+ get id(): TId {
210
+ return this._id;
211
+ }
212
+
213
+ equals(entity: Entity<TId>): boolean {
214
+ if (entity === null || entity === undefined) {
215
+ return false;
216
+ }
217
+ if (this === entity) {
218
+ return true;
219
+ }
220
+ return this._id === entity._id;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Aggregate factory interface
226
+ */
227
+ export interface AggregateFactory<T extends AggregateRoot, TId = string> {
228
+ create(id: TId, ...args: any[]): T;
229
+ reconstitute(id: TId, events: DomainEvent[]): T;
230
+ }
231
+ `;
232
+ }
233
+ function generateInvariantValidator() {
234
+ return `/**
235
+ * Invariant Validator
236
+ * Validates aggregate invariants and business rules
237
+ */
238
+
239
+ export interface InvariantRule<T> {
240
+ name: string;
241
+ description?: string;
242
+ check: (aggregate: T) => boolean;
243
+ message: string | ((aggregate: T) => string);
244
+ }
245
+
246
+ export interface ValidationResult {
247
+ valid: boolean;
248
+ violations: string[];
249
+ warnings: string[];
250
+ }
251
+
252
+ /**
253
+ * Invariant Validator
254
+ */
255
+ export class InvariantValidator<T> {
256
+ private rules: InvariantRule<T>[] = [];
257
+ private warningRules: InvariantRule<T>[] = [];
258
+
259
+ /**
260
+ * Add invariant rule
261
+ */
262
+ addRule(rule: InvariantRule<T>): this {
263
+ this.rules.push(rule);
264
+ return this;
265
+ }
266
+
267
+ /**
268
+ * Add warning rule (doesn't fail validation)
269
+ */
270
+ addWarning(rule: InvariantRule<T>): this {
271
+ this.warningRules.push(rule);
272
+ return this;
273
+ }
274
+
275
+ /**
276
+ * Validate aggregate against all rules
277
+ */
278
+ validate(aggregate: T): ValidationResult {
279
+ const violations: string[] = [];
280
+ const warnings: string[] = [];
281
+
282
+ // Check invariant rules
283
+ for (const rule of this.rules) {
284
+ if (!rule.check(aggregate)) {
285
+ const message = typeof rule.message === 'function'
286
+ ? rule.message(aggregate)
287
+ : rule.message;
288
+ violations.push(\`[\${rule.name}] \${message}\`);
289
+ }
290
+ }
291
+
292
+ // Check warning rules
293
+ for (const rule of this.warningRules) {
294
+ if (!rule.check(aggregate)) {
295
+ const message = typeof rule.message === 'function'
296
+ ? rule.message(aggregate)
297
+ : rule.message;
298
+ warnings.push(\`[\${rule.name}] \${message}\`);
299
+ }
300
+ }
301
+
302
+ return {
303
+ valid: violations.length === 0,
304
+ violations,
305
+ warnings,
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Validate and throw on violation
311
+ */
312
+ validateOrThrow(aggregate: T): void {
313
+ const result = this.validate(aggregate);
314
+ if (!result.valid) {
315
+ throw new InvariantError(result.violations);
316
+ }
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Invariant error
322
+ */
323
+ export class InvariantError extends Error {
324
+ constructor(public readonly violations: string[]) {
325
+ super(violations.join('; '));
326
+ this.name = 'InvariantError';
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Invariant builder for fluent API
332
+ */
333
+ export class InvariantBuilder<T> {
334
+ private rule: Partial<InvariantRule<T>> = {};
335
+
336
+ named(name: string): this {
337
+ this.rule.name = name;
338
+ return this;
339
+ }
340
+
341
+ describedAs(description: string): this {
342
+ this.rule.description = description;
343
+ return this;
344
+ }
345
+
346
+ check(predicate: (aggregate: T) => boolean): this {
347
+ this.rule.check = predicate;
348
+ return this;
349
+ }
350
+
351
+ withMessage(message: string | ((aggregate: T) => string)): this {
352
+ this.rule.message = message;
353
+ return this;
354
+ }
355
+
356
+ build(): InvariantRule<T> {
357
+ if (!this.rule.name || !this.rule.check || !this.rule.message) {
358
+ throw new Error('Invariant rule is incomplete');
359
+ }
360
+ return this.rule as InvariantRule<T>;
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Create invariant builder
366
+ */
367
+ export function invariant<T>(): InvariantBuilder<T> {
368
+ return new InvariantBuilder<T>();
369
+ }
370
+
371
+ /**
372
+ * Common invariant rules factory
373
+ */
374
+ export const CommonInvariants = {
375
+ notNull<T, K extends keyof T>(field: K): InvariantRule<T> {
376
+ return {
377
+ name: \`\${String(field)}-not-null\`,
378
+ check: (aggregate) => aggregate[field] !== null && aggregate[field] !== undefined,
379
+ message: \`\${String(field)} cannot be null\`,
380
+ };
381
+ },
382
+
383
+ notEmpty<T, K extends keyof T>(field: K): InvariantRule<T> {
384
+ return {
385
+ name: \`\${String(field)}-not-empty\`,
386
+ check: (aggregate) => {
387
+ const value = aggregate[field];
388
+ if (typeof value === 'string') return value.length > 0;
389
+ if (Array.isArray(value)) return value.length > 0;
390
+ return value !== null && value !== undefined;
391
+ },
392
+ message: \`\${String(field)} cannot be empty\`,
393
+ };
394
+ },
395
+
396
+ positive<T, K extends keyof T>(field: K): InvariantRule<T> {
397
+ return {
398
+ name: \`\${String(field)}-positive\`,
399
+ check: (aggregate) => (aggregate[field] as unknown as number) > 0,
400
+ message: \`\${String(field)} must be positive\`,
401
+ };
402
+ },
403
+
404
+ nonNegative<T, K extends keyof T>(field: K): InvariantRule<T> {
405
+ return {
406
+ name: \`\${String(field)}-non-negative\`,
407
+ check: (aggregate) => (aggregate[field] as unknown as number) >= 0,
408
+ message: \`\${String(field)} cannot be negative\`,
409
+ };
410
+ },
411
+
412
+ inRange<T, K extends keyof T>(field: K, min: number, max: number): InvariantRule<T> {
413
+ return {
414
+ name: \`\${String(field)}-in-range\`,
415
+ check: (aggregate) => {
416
+ const value = aggregate[field] as unknown as number;
417
+ return value >= min && value <= max;
418
+ },
419
+ message: \`\${String(field)} must be between \${min} and \${max}\`,
420
+ };
421
+ },
422
+
423
+ validState<T>(validStates: string[], stateField: keyof T): InvariantRule<T> {
424
+ return {
425
+ name: 'valid-state',
426
+ check: (aggregate) => validStates.includes(String(aggregate[stateField])),
427
+ message: (aggregate) => \`Invalid state: \${aggregate[stateField]}. Valid states: \${validStates.join(', ')}\`,
428
+ };
429
+ },
430
+ };
431
+ `;
432
+ }
433
+ function generateStateMachine() {
434
+ return `/**
435
+ * State Machine
436
+ * Manages state transitions with validation
437
+ */
438
+
439
+ export interface StateTransition<TState extends string, TEvent extends string> {
440
+ from: TState | TState[];
441
+ event: TEvent;
442
+ to: TState;
443
+ guard?: () => boolean;
444
+ action?: () => void;
445
+ }
446
+
447
+ export interface StateMachineConfig<TState extends string, TEvent extends string> {
448
+ initial: TState;
449
+ transitions: StateTransition<TState, TEvent>[];
450
+ onEnter?: Partial<Record<TState, () => void>>;
451
+ onExit?: Partial<Record<TState, () => void>>;
452
+ }
453
+
454
+ /**
455
+ * State Machine
456
+ */
457
+ export class StateMachine<TState extends string, TEvent extends string> {
458
+ private currentState: TState;
459
+ private readonly config: StateMachineConfig<TState, TEvent>;
460
+ private history: { from: TState; event: TEvent; to: TState; timestamp: Date }[] = [];
461
+
462
+ constructor(config: StateMachineConfig<TState, TEvent>) {
463
+ this.config = config;
464
+ this.currentState = config.initial;
465
+ }
466
+
467
+ /**
468
+ * Get current state
469
+ */
470
+ get state(): TState {
471
+ return this.currentState;
472
+ }
473
+
474
+ /**
475
+ * Check if transition is allowed
476
+ */
477
+ canTransition(event: TEvent): boolean {
478
+ return this.findTransition(event) !== undefined;
479
+ }
480
+
481
+ /**
482
+ * Get allowed events from current state
483
+ */
484
+ getAllowedEvents(): TEvent[] {
485
+ return this.config.transitions
486
+ .filter(t => this.matchesFrom(t.from, this.currentState))
487
+ .filter(t => !t.guard || t.guard())
488
+ .map(t => t.event);
489
+ }
490
+
491
+ /**
492
+ * Trigger a transition
493
+ */
494
+ transition(event: TEvent): TState {
495
+ const transition = this.findTransition(event);
496
+
497
+ if (!transition) {
498
+ throw new InvalidTransitionError(this.currentState, event);
499
+ }
500
+
501
+ const fromState = this.currentState;
502
+
503
+ // Execute exit action
504
+ if (this.config.onExit?.[fromState]) {
505
+ this.config.onExit[fromState]!();
506
+ }
507
+
508
+ // Execute transition action
509
+ if (transition.action) {
510
+ transition.action();
511
+ }
512
+
513
+ // Update state
514
+ this.currentState = transition.to;
515
+
516
+ // Execute enter action
517
+ if (this.config.onEnter?.[this.currentState]) {
518
+ this.config.onEnter[this.currentState]!();
519
+ }
520
+
521
+ // Record history
522
+ this.history.push({
523
+ from: fromState,
524
+ event,
525
+ to: this.currentState,
526
+ timestamp: new Date(),
527
+ });
528
+
529
+ return this.currentState;
530
+ }
531
+
532
+ /**
533
+ * Get transition history
534
+ */
535
+ getHistory(): { from: TState; event: TEvent; to: TState; timestamp: Date }[] {
536
+ return [...this.history];
537
+ }
538
+
539
+ /**
540
+ * Check if in a specific state
541
+ */
542
+ isInState(state: TState): boolean {
543
+ return this.currentState === state;
544
+ }
545
+
546
+ /**
547
+ * Reset to initial state
548
+ */
549
+ reset(): void {
550
+ this.currentState = this.config.initial;
551
+ this.history = [];
552
+ }
553
+
554
+ private findTransition(event: TEvent): StateTransition<TState, TEvent> | undefined {
555
+ return this.config.transitions.find(t => {
556
+ if (!this.matchesFrom(t.from, this.currentState)) return false;
557
+ if (t.event !== event) return false;
558
+ if (t.guard && !t.guard()) return false;
559
+ return true;
560
+ });
561
+ }
562
+
563
+ private matchesFrom(from: TState | TState[], currentState: TState): boolean {
564
+ if (Array.isArray(from)) {
565
+ return from.includes(currentState);
566
+ }
567
+ return from === currentState;
568
+ }
569
+ }
570
+
571
+ /**
572
+ * Invalid transition error
573
+ */
574
+ export class InvalidTransitionError extends Error {
575
+ constructor(
576
+ public readonly fromState: string,
577
+ public readonly event: string,
578
+ ) {
579
+ super(\`Cannot transition from '\${fromState}' with event '\${event}'\`);
580
+ this.name = 'InvalidTransitionError';
581
+ }
582
+ }
583
+
584
+ /**
585
+ * State machine builder
586
+ */
587
+ export class StateMachineBuilder<TState extends string, TEvent extends string> {
588
+ private config: StateMachineConfig<TState, TEvent> = {
589
+ initial: '' as TState,
590
+ transitions: [],
591
+ onEnter: {},
592
+ onExit: {},
593
+ };
594
+
595
+ initial(state: TState): this {
596
+ this.config.initial = state;
597
+ return this;
598
+ }
599
+
600
+ transition(from: TState | TState[], event: TEvent, to: TState): this {
601
+ this.config.transitions.push({ from, event, to });
602
+ return this;
603
+ }
604
+
605
+ transitionWithGuard(
606
+ from: TState | TState[],
607
+ event: TEvent,
608
+ to: TState,
609
+ guard: () => boolean,
610
+ ): this {
611
+ this.config.transitions.push({ from, event, to, guard });
612
+ return this;
613
+ }
614
+
615
+ onEnter(state: TState, action: () => void): this {
616
+ this.config.onEnter![state] = action;
617
+ return this;
618
+ }
619
+
620
+ onExit(state: TState, action: () => void): this {
621
+ this.config.onExit![state] = action;
622
+ return this;
623
+ }
624
+
625
+ build(): StateMachine<TState, TEvent> {
626
+ return new StateMachine(this.config);
627
+ }
628
+ }
629
+
630
+ /**
631
+ * Create state machine builder
632
+ */
633
+ export function stateMachine<TState extends string, TEvent extends string>(): StateMachineBuilder<TState, TEvent> {
634
+ return new StateMachineBuilder<TState, TEvent>();
635
+ }
636
+ `;
637
+ }
638
+ function generateBusinessRulesEngine() {
639
+ return `/**
640
+ * Business Rules Engine
641
+ * Centralized business rule validation
642
+ */
643
+
644
+ export interface BusinessRule<TContext = any> {
645
+ name: string;
646
+ description?: string;
647
+ priority?: number;
648
+ condition: (context: TContext) => boolean;
649
+ action: (context: TContext) => void | Promise<void>;
650
+ onFailure?: (context: TContext) => void;
651
+ }
652
+
653
+ export interface RuleResult {
654
+ rule: string;
655
+ passed: boolean;
656
+ message?: string;
657
+ }
658
+
659
+ /**
660
+ * Business Rules Engine
661
+ */
662
+ export class BusinessRulesEngine<TContext = any> {
663
+ private rules: BusinessRule<TContext>[] = [];
664
+
665
+ /**
666
+ * Add a rule
667
+ */
668
+ addRule(rule: BusinessRule<TContext>): this {
669
+ this.rules.push(rule);
670
+ this.sortRules();
671
+ return this;
672
+ }
673
+
674
+ /**
675
+ * Remove a rule
676
+ */
677
+ removeRule(name: string): this {
678
+ this.rules = this.rules.filter(r => r.name !== name);
679
+ return this;
680
+ }
681
+
682
+ /**
683
+ * Evaluate all rules
684
+ */
685
+ async evaluate(context: TContext): Promise<RuleResult[]> {
686
+ const results: RuleResult[] = [];
687
+
688
+ for (const rule of this.rules) {
689
+ try {
690
+ const passed = rule.condition(context);
691
+
692
+ if (passed) {
693
+ await rule.action(context);
694
+ } else if (rule.onFailure) {
695
+ rule.onFailure(context);
696
+ }
697
+
698
+ results.push({
699
+ rule: rule.name,
700
+ passed,
701
+ });
702
+ } catch (error) {
703
+ results.push({
704
+ rule: rule.name,
705
+ passed: false,
706
+ message: (error as Error).message,
707
+ });
708
+ }
709
+ }
710
+
711
+ return results;
712
+ }
713
+
714
+ /**
715
+ * Evaluate and throw on first failure
716
+ */
717
+ async evaluateStrict(context: TContext): Promise<void> {
718
+ for (const rule of this.rules) {
719
+ if (!rule.condition(context)) {
720
+ throw new BusinessRuleViolationError(rule.name, rule.description);
721
+ }
722
+ await rule.action(context);
723
+ }
724
+ }
725
+
726
+ /**
727
+ * Check if all rules pass without executing actions
728
+ */
729
+ check(context: TContext): boolean {
730
+ return this.rules.every(rule => rule.condition(context));
731
+ }
732
+
733
+ /**
734
+ * Get failing rules
735
+ */
736
+ getFailingRules(context: TContext): BusinessRule<TContext>[] {
737
+ return this.rules.filter(rule => !rule.condition(context));
738
+ }
739
+
740
+ private sortRules(): void {
741
+ this.rules.sort((a, b) => (b.priority || 0) - (a.priority || 0));
742
+ }
743
+ }
744
+
745
+ /**
746
+ * Business rule violation error
747
+ */
748
+ export class BusinessRuleViolationError extends Error {
749
+ constructor(
750
+ public readonly ruleName: string,
751
+ public readonly ruleDescription?: string,
752
+ ) {
753
+ super(\`Business rule '\${ruleName}' violated\${ruleDescription ? \`: \${ruleDescription}\` : ''}\`);
754
+ this.name = 'BusinessRuleViolationError';
755
+ }
756
+ }
757
+
758
+ /**
759
+ * Rule builder
760
+ */
761
+ export class RuleBuilder<TContext = any> {
762
+ private rule: Partial<BusinessRule<TContext>> = {};
763
+
764
+ named(name: string): this {
765
+ this.rule.name = name;
766
+ return this;
767
+ }
768
+
769
+ describedAs(description: string): this {
770
+ this.rule.description = description;
771
+ return this;
772
+ }
773
+
774
+ withPriority(priority: number): this {
775
+ this.rule.priority = priority;
776
+ return this;
777
+ }
778
+
779
+ when(condition: (context: TContext) => boolean): this {
780
+ this.rule.condition = condition;
781
+ return this;
782
+ }
783
+
784
+ then(action: (context: TContext) => void | Promise<void>): this {
785
+ this.rule.action = action;
786
+ return this;
787
+ }
788
+
789
+ otherwise(handler: (context: TContext) => void): this {
790
+ this.rule.onFailure = handler;
791
+ return this;
792
+ }
793
+
794
+ build(): BusinessRule<TContext> {
795
+ if (!this.rule.name || !this.rule.condition || !this.rule.action) {
796
+ throw new Error('Business rule is incomplete');
797
+ }
798
+ return this.rule as BusinessRule<TContext>;
799
+ }
800
+ }
801
+
802
+ /**
803
+ * Create rule builder
804
+ */
805
+ export function rule<TContext = any>(): RuleBuilder<TContext> {
806
+ return new RuleBuilder<TContext>();
807
+ }
808
+ `;
809
+ }
810
+ function generateCommandValidator() {
811
+ return `/**
812
+ * Command Validator
813
+ * Validates commands before execution
814
+ */
815
+
816
+ import { validate, ValidationError } from 'class-validator';
817
+ import { plainToClass } from 'class-transformer';
818
+
819
+ export interface CommandValidationResult {
820
+ valid: boolean;
821
+ errors: CommandValidationError[];
822
+ }
823
+
824
+ export interface CommandValidationError {
825
+ property: string;
826
+ constraints: Record<string, string>;
827
+ value?: any;
828
+ }
829
+
830
+ /**
831
+ * Command Validator
832
+ */
833
+ export class CommandValidator {
834
+ /**
835
+ * Validate a command object
836
+ */
837
+ async validate<T extends object>(
838
+ command: T,
839
+ commandClass?: new () => T,
840
+ ): Promise<CommandValidationResult> {
841
+ const instance = commandClass
842
+ ? plainToClass(commandClass, command)
843
+ : command;
844
+
845
+ const errors = await validate(instance as object);
846
+
847
+ return {
848
+ valid: errors.length === 0,
849
+ errors: this.formatErrors(errors),
850
+ };
851
+ }
852
+
853
+ /**
854
+ * Validate and throw on error
855
+ */
856
+ async validateOrThrow<T extends object>(
857
+ command: T,
858
+ commandClass?: new () => T,
859
+ ): Promise<void> {
860
+ const result = await this.validate(command, commandClass);
861
+
862
+ if (!result.valid) {
863
+ throw new CommandValidationException(result.errors);
864
+ }
865
+ }
866
+
867
+ private formatErrors(errors: ValidationError[]): CommandValidationError[] {
868
+ return errors.map(error => ({
869
+ property: error.property,
870
+ constraints: error.constraints || {},
871
+ value: error.value,
872
+ }));
873
+ }
874
+ }
875
+
876
+ /**
877
+ * Command validation exception
878
+ */
879
+ export class CommandValidationException extends Error {
880
+ constructor(public readonly errors: CommandValidationError[]) {
881
+ super(\`Command validation failed: \${errors.map(e => e.property).join(', ')}\`);
882
+ this.name = 'CommandValidationException';
883
+ }
884
+
885
+ toJSON() {
886
+ return {
887
+ name: this.name,
888
+ message: this.message,
889
+ errors: this.errors,
890
+ };
891
+ }
892
+ }
893
+
894
+ /**
895
+ * Command handler decorator with validation
896
+ */
897
+ export function ValidateCommand(commandClass: new () => any): MethodDecorator {
898
+ return function (
899
+ target: any,
900
+ propertyKey: string | symbol,
901
+ descriptor: PropertyDescriptor,
902
+ ) {
903
+ const originalMethod = descriptor.value;
904
+ const validator = new CommandValidator();
905
+
906
+ descriptor.value = async function (...args: any[]) {
907
+ const command = args[0];
908
+ await validator.validateOrThrow(command, commandClass);
909
+ return originalMethod.apply(this, args);
910
+ };
911
+
912
+ return descriptor;
913
+ };
914
+ }
915
+
916
+ /**
917
+ * Pre-condition decorator
918
+ */
919
+ export function PreCondition(
920
+ condition: (command: any) => boolean,
921
+ message: string,
922
+ ): MethodDecorator {
923
+ return function (
924
+ target: any,
925
+ propertyKey: string | symbol,
926
+ descriptor: PropertyDescriptor,
927
+ ) {
928
+ const originalMethod = descriptor.value;
929
+
930
+ descriptor.value = async function (...args: any[]) {
931
+ const command = args[0];
932
+ if (!condition(command)) {
933
+ throw new PreConditionFailedError(message);
934
+ }
935
+ return originalMethod.apply(this, args);
936
+ };
937
+
938
+ return descriptor;
939
+ };
940
+ }
941
+
942
+ /**
943
+ * Pre-condition failed error
944
+ */
945
+ export class PreConditionFailedError extends Error {
946
+ constructor(message: string) {
947
+ super(message);
948
+ this.name = 'PreConditionFailedError';
949
+ }
950
+ }
951
+ `;
952
+ }
953
+ //# sourceMappingURL=aggregate-validator.js.map