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,740 @@
1
+ "use strict";
2
+ /**
3
+ * Distributed Tracing & Observability Generator
4
+ * OpenTelemetry integration for microservices
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.setupObservability = setupObservability;
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ async function setupObservability(basePath, options = {}) {
48
+ console.log(chalk_1.default.bold.blue('\n📊 Setting up Observability & Tracing\n'));
49
+ const sharedPath = path.join(basePath, 'src/shared/observability');
50
+ if (!fs.existsSync(sharedPath)) {
51
+ fs.mkdirSync(sharedPath, { recursive: true });
52
+ }
53
+ // Generate tracing setup
54
+ fs.writeFileSync(path.join(sharedPath, 'tracing.setup.ts'), generateTracingSetup(options));
55
+ console.log(chalk_1.default.green(` ✓ Created tracing setup`));
56
+ // Generate span decorator
57
+ fs.writeFileSync(path.join(sharedPath, 'span.decorator.ts'), generateSpanDecorator());
58
+ console.log(chalk_1.default.green(` ✓ Created span decorator`));
59
+ // Generate trace interceptor
60
+ fs.writeFileSync(path.join(sharedPath, 'trace.interceptor.ts'), generateTraceInterceptor());
61
+ console.log(chalk_1.default.green(` ✓ Created trace interceptor`));
62
+ // Generate context propagation
63
+ fs.writeFileSync(path.join(sharedPath, 'trace-context.ts'), generateTraceContext());
64
+ console.log(chalk_1.default.green(` ✓ Created trace context`));
65
+ // Generate metrics collector
66
+ fs.writeFileSync(path.join(sharedPath, 'metrics.ts'), generateMetrics());
67
+ console.log(chalk_1.default.green(` ✓ Created metrics`));
68
+ // Generate observability module
69
+ fs.writeFileSync(path.join(sharedPath, 'observability.module.ts'), generateObservabilityModule());
70
+ console.log(chalk_1.default.green(` ✓ Created observability module`));
71
+ console.log(chalk_1.default.bold.green('\n✅ Observability & tracing ready!\n'));
72
+ }
73
+ function generateTracingSetup(options) {
74
+ const provider = options.provider || 'otlp';
75
+ const serviceName = options.serviceName || 'my-service';
76
+ return `/**
77
+ * OpenTelemetry Tracing Setup
78
+ * Initialize distributed tracing for the application
79
+ */
80
+
81
+ import { NodeSDK } from '@opentelemetry/sdk-node';
82
+ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
83
+ import { Resource } from '@opentelemetry/resources';
84
+ import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
85
+ import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
86
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
87
+ import { trace, context, SpanKind, SpanStatusCode, Span } from '@opentelemetry/api';
88
+
89
+ export interface TracingConfig {
90
+ serviceName: string;
91
+ serviceVersion?: string;
92
+ environment?: string;
93
+ exporterUrl?: string;
94
+ samplingRatio?: number;
95
+ }
96
+
97
+ const DEFAULT_CONFIG: TracingConfig = {
98
+ serviceName: '${serviceName}',
99
+ serviceVersion: '1.0.0',
100
+ environment: process.env.NODE_ENV || 'development',
101
+ exporterUrl: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces',
102
+ samplingRatio: 1.0,
103
+ };
104
+
105
+ let sdk: NodeSDK | null = null;
106
+
107
+ /**
108
+ * Initialize OpenTelemetry tracing
109
+ */
110
+ export async function initTracing(config: Partial<TracingConfig> = {}): Promise<void> {
111
+ const finalConfig = { ...DEFAULT_CONFIG, ...config };
112
+
113
+ const exporter = new OTLPTraceExporter({
114
+ url: finalConfig.exporterUrl,
115
+ });
116
+
117
+ sdk = new NodeSDK({
118
+ resource: new Resource({
119
+ [SemanticResourceAttributes.SERVICE_NAME]: finalConfig.serviceName,
120
+ [SemanticResourceAttributes.SERVICE_VERSION]: finalConfig.serviceVersion,
121
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: finalConfig.environment,
122
+ }),
123
+ spanProcessor: new BatchSpanProcessor(exporter),
124
+ instrumentations: [
125
+ getNodeAutoInstrumentations({
126
+ '@opentelemetry/instrumentation-fs': { enabled: false },
127
+ }),
128
+ ],
129
+ });
130
+
131
+ await sdk.start();
132
+ console.log('Tracing initialized for', finalConfig.serviceName);
133
+
134
+ // Graceful shutdown
135
+ process.on('SIGTERM', async () => {
136
+ await sdk?.shutdown();
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Shutdown tracing
142
+ */
143
+ export async function shutdownTracing(): Promise<void> {
144
+ await sdk?.shutdown();
145
+ }
146
+
147
+ /**
148
+ * Get the tracer
149
+ */
150
+ export function getTracer(name: string = 'default') {
151
+ return trace.getTracer(name);
152
+ }
153
+
154
+ /**
155
+ * Create a new span
156
+ */
157
+ export function createSpan(
158
+ name: string,
159
+ options: {
160
+ kind?: SpanKind;
161
+ attributes?: Record<string, string | number | boolean>;
162
+ } = {},
163
+ ): Span {
164
+ const tracer = getTracer();
165
+ return tracer.startSpan(name, {
166
+ kind: options.kind || SpanKind.INTERNAL,
167
+ attributes: options.attributes,
168
+ });
169
+ }
170
+
171
+ /**
172
+ * Run a function within a span
173
+ */
174
+ export async function withSpan<T>(
175
+ name: string,
176
+ fn: (span: Span) => Promise<T>,
177
+ options: {
178
+ kind?: SpanKind;
179
+ attributes?: Record<string, string | number | boolean>;
180
+ } = {},
181
+ ): Promise<T> {
182
+ const tracer = getTracer();
183
+ const span = tracer.startSpan(name, {
184
+ kind: options.kind || SpanKind.INTERNAL,
185
+ attributes: options.attributes,
186
+ });
187
+
188
+ try {
189
+ const result = await context.with(trace.setSpan(context.active(), span), () => fn(span));
190
+ span.setStatus({ code: SpanStatusCode.OK });
191
+ return result;
192
+ } catch (error) {
193
+ span.setStatus({
194
+ code: SpanStatusCode.ERROR,
195
+ message: (error as Error).message,
196
+ });
197
+ span.recordException(error as Error);
198
+ throw error;
199
+ } finally {
200
+ span.end();
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Get current span
206
+ */
207
+ export function getCurrentSpan(): Span | undefined {
208
+ return trace.getSpan(context.active());
209
+ }
210
+
211
+ /**
212
+ * Add attributes to current span
213
+ */
214
+ export function addSpanAttributes(attributes: Record<string, string | number | boolean>): void {
215
+ const span = getCurrentSpan();
216
+ if (span) {
217
+ span.setAttributes(attributes);
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Record an event on current span
223
+ */
224
+ export function recordSpanEvent(name: string, attributes?: Record<string, string | number | boolean>): void {
225
+ const span = getCurrentSpan();
226
+ if (span) {
227
+ span.addEvent(name, attributes);
228
+ }
229
+ }
230
+ `;
231
+ }
232
+ function generateSpanDecorator() {
233
+ return `/**
234
+ * Span Decorator
235
+ * Automatically create spans for methods
236
+ */
237
+
238
+ import { trace, SpanKind, SpanStatusCode, context } from '@opentelemetry/api';
239
+
240
+ export interface SpanOptions {
241
+ name?: string;
242
+ kind?: SpanKind;
243
+ attributes?: Record<string, string | number | boolean>;
244
+ recordArgs?: boolean;
245
+ recordResult?: boolean;
246
+ }
247
+
248
+ /**
249
+ * Span decorator for automatic span creation
250
+ */
251
+ export function Span(options: SpanOptions = {}): MethodDecorator {
252
+ return function (
253
+ target: any,
254
+ propertyKey: string | symbol,
255
+ descriptor: PropertyDescriptor,
256
+ ) {
257
+ const originalMethod = descriptor.value;
258
+ const className = target.constructor.name;
259
+ const methodName = String(propertyKey);
260
+ const spanName = options.name || \`\${className}.\${methodName}\`;
261
+
262
+ descriptor.value = async function (...args: any[]) {
263
+ const tracer = trace.getTracer('application');
264
+ const span = tracer.startSpan(spanName, {
265
+ kind: options.kind || SpanKind.INTERNAL,
266
+ attributes: {
267
+ 'code.function': methodName,
268
+ 'code.namespace': className,
269
+ ...options.attributes,
270
+ },
271
+ });
272
+
273
+ if (options.recordArgs) {
274
+ try {
275
+ span.setAttribute('args', JSON.stringify(args));
276
+ } catch {
277
+ // Ignore serialization errors
278
+ }
279
+ }
280
+
281
+ try {
282
+ const result = await context.with(
283
+ trace.setSpan(context.active(), span),
284
+ () => originalMethod.apply(this, args),
285
+ );
286
+
287
+ if (options.recordResult) {
288
+ try {
289
+ span.setAttribute('result', JSON.stringify(result));
290
+ } catch {
291
+ // Ignore serialization errors
292
+ }
293
+ }
294
+
295
+ span.setStatus({ code: SpanStatusCode.OK });
296
+ return result;
297
+ } catch (error) {
298
+ span.setStatus({
299
+ code: SpanStatusCode.ERROR,
300
+ message: (error as Error).message,
301
+ });
302
+ span.recordException(error as Error);
303
+ throw error;
304
+ } finally {
305
+ span.end();
306
+ }
307
+ };
308
+
309
+ return descriptor;
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Trace incoming requests
315
+ */
316
+ export function TraceIncoming(options: SpanOptions = {}): MethodDecorator {
317
+ return Span({ ...options, kind: SpanKind.SERVER });
318
+ }
319
+
320
+ /**
321
+ * Trace outgoing requests
322
+ */
323
+ export function TraceOutgoing(options: SpanOptions = {}): MethodDecorator {
324
+ return Span({ ...options, kind: SpanKind.CLIENT });
325
+ }
326
+
327
+ /**
328
+ * Trace internal operations
329
+ */
330
+ export function TraceInternal(options: SpanOptions = {}): MethodDecorator {
331
+ return Span({ ...options, kind: SpanKind.INTERNAL });
332
+ }
333
+ `;
334
+ }
335
+ function generateTraceInterceptor() {
336
+ return `/**
337
+ * Trace Interceptor
338
+ * Automatically trace all HTTP requests
339
+ */
340
+
341
+ import {
342
+ Injectable,
343
+ NestInterceptor,
344
+ ExecutionContext,
345
+ CallHandler,
346
+ } from '@nestjs/common';
347
+ import { Observable } from 'rxjs';
348
+ import { tap } from 'rxjs/operators';
349
+ import { trace, SpanKind, SpanStatusCode, context } from '@opentelemetry/api';
350
+
351
+ @Injectable()
352
+ export class TraceInterceptor implements NestInterceptor {
353
+ intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
354
+ const request = ctx.switchToHttp().getRequest();
355
+ const response = ctx.switchToHttp().getResponse();
356
+ const tracer = trace.getTracer('http');
357
+
358
+ const span = tracer.startSpan(\`HTTP \${request.method} \${request.route?.path || request.path}\`, {
359
+ kind: SpanKind.SERVER,
360
+ attributes: {
361
+ 'http.method': request.method,
362
+ 'http.url': request.url,
363
+ 'http.route': request.route?.path,
364
+ 'http.user_agent': request.headers['user-agent'],
365
+ 'http.client_ip': request.ip,
366
+ },
367
+ });
368
+
369
+ // Add trace headers for propagation
370
+ const traceId = span.spanContext().traceId;
371
+ const spanId = span.spanContext().spanId;
372
+ response.setHeader('X-Trace-Id', traceId);
373
+ response.setHeader('X-Span-Id', spanId);
374
+
375
+ return context.with(trace.setSpan(context.active(), span), () => {
376
+ return next.handle().pipe(
377
+ tap({
378
+ next: () => {
379
+ span.setAttribute('http.status_code', response.statusCode);
380
+ span.setStatus({ code: SpanStatusCode.OK });
381
+ },
382
+ error: (error) => {
383
+ span.setAttribute('http.status_code', error.status || 500);
384
+ span.setStatus({
385
+ code: SpanStatusCode.ERROR,
386
+ message: error.message,
387
+ });
388
+ span.recordException(error);
389
+ },
390
+ complete: () => {
391
+ span.end();
392
+ },
393
+ }),
394
+ );
395
+ });
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Trace context middleware
401
+ */
402
+ export function traceContextMiddleware(req: any, res: any, next: () => void): void {
403
+ const tracer = trace.getTracer('http');
404
+ const span = tracer.startSpan(\`\${req.method} \${req.path}\`, {
405
+ kind: SpanKind.SERVER,
406
+ });
407
+
408
+ req.span = span;
409
+ req.traceId = span.spanContext().traceId;
410
+
411
+ res.on('finish', () => {
412
+ span.setAttribute('http.status_code', res.statusCode);
413
+ span.end();
414
+ });
415
+
416
+ context.with(trace.setSpan(context.active(), span), next);
417
+ }
418
+ `;
419
+ }
420
+ function generateTraceContext() {
421
+ return `/**
422
+ * Trace Context Propagation
423
+ * Handle trace context across service boundaries
424
+ */
425
+
426
+ import { trace, context, propagation, SpanContext } from '@opentelemetry/api';
427
+
428
+ export interface TraceHeaders {
429
+ 'traceparent'?: string;
430
+ 'tracestate'?: string;
431
+ 'x-trace-id'?: string;
432
+ 'x-span-id'?: string;
433
+ 'x-request-id'?: string;
434
+ }
435
+
436
+ /**
437
+ * Extract trace context from headers
438
+ */
439
+ export function extractTraceContext(headers: Record<string, string | string[] | undefined>): void {
440
+ const carrier: Record<string, string> = {};
441
+
442
+ for (const [key, value] of Object.entries(headers)) {
443
+ if (typeof value === 'string') {
444
+ carrier[key.toLowerCase()] = value;
445
+ } else if (Array.isArray(value) && value.length > 0) {
446
+ carrier[key.toLowerCase()] = value[0];
447
+ }
448
+ }
449
+
450
+ propagation.extract(context.active(), carrier);
451
+ }
452
+
453
+ /**
454
+ * Inject trace context into headers
455
+ */
456
+ export function injectTraceContext(headers: Record<string, string> = {}): Record<string, string> {
457
+ propagation.inject(context.active(), headers);
458
+ return headers;
459
+ }
460
+
461
+ /**
462
+ * Get current trace ID
463
+ */
464
+ export function getCurrentTraceId(): string | undefined {
465
+ const span = trace.getSpan(context.active());
466
+ return span?.spanContext().traceId;
467
+ }
468
+
469
+ /**
470
+ * Get current span ID
471
+ */
472
+ export function getCurrentSpanId(): string | undefined {
473
+ const span = trace.getSpan(context.active());
474
+ return span?.spanContext().spanId;
475
+ }
476
+
477
+ /**
478
+ * Create trace headers for outgoing requests
479
+ */
480
+ export function createTraceHeaders(): TraceHeaders {
481
+ const headers: TraceHeaders = {};
482
+ injectTraceContext(headers as any);
483
+
484
+ const traceId = getCurrentTraceId();
485
+ const spanId = getCurrentSpanId();
486
+
487
+ if (traceId) headers['x-trace-id'] = traceId;
488
+ if (spanId) headers['x-span-id'] = spanId;
489
+
490
+ return headers;
491
+ }
492
+
493
+ /**
494
+ * Correlation ID manager
495
+ */
496
+ export class CorrelationIdManager {
497
+ private static readonly CORRELATION_ID_KEY = 'correlation-id';
498
+
499
+ static get(): string | undefined {
500
+ const span = trace.getSpan(context.active());
501
+ return span?.spanContext().traceId;
502
+ }
503
+
504
+ static set(id: string): void {
505
+ const span = trace.getSpan(context.active());
506
+ span?.setAttribute(this.CORRELATION_ID_KEY, id);
507
+ }
508
+
509
+ static generate(): string {
510
+ return \`\${Date.now()}-\${Math.random().toString(36).substr(2, 9)}\`;
511
+ }
512
+ }
513
+
514
+ /**
515
+ * Request context for passing trace info
516
+ */
517
+ export class RequestContext {
518
+ private static readonly storage = new Map<string, any>();
519
+
520
+ static set(key: string, value: any): void {
521
+ const traceId = getCurrentTraceId() || 'default';
522
+ const contextKey = \`\${traceId}:\${key}\`;
523
+ this.storage.set(contextKey, value);
524
+ }
525
+
526
+ static get<T>(key: string): T | undefined {
527
+ const traceId = getCurrentTraceId() || 'default';
528
+ const contextKey = \`\${traceId}:\${key}\`;
529
+ return this.storage.get(contextKey) as T;
530
+ }
531
+
532
+ static clear(): void {
533
+ const traceId = getCurrentTraceId() || 'default';
534
+ for (const key of this.storage.keys()) {
535
+ if (key.startsWith(\`\${traceId}:\`)) {
536
+ this.storage.delete(key);
537
+ }
538
+ }
539
+ }
540
+ }
541
+ `;
542
+ }
543
+ function generateMetrics() {
544
+ return `/**
545
+ * Metrics Collection
546
+ * Custom metrics for observability
547
+ */
548
+
549
+ import { metrics, Counter, Histogram, UpDownCounter, Gauge } from '@opentelemetry/api';
550
+
551
+ export interface MetricLabels {
552
+ [key: string]: string | number;
553
+ }
554
+
555
+ /**
556
+ * Metrics registry
557
+ */
558
+ export class MetricsRegistry {
559
+ private readonly meter = metrics.getMeter('application');
560
+ private readonly counters = new Map<string, Counter>();
561
+ private readonly histograms = new Map<string, Histogram>();
562
+ private readonly gauges = new Map<string, any>();
563
+
564
+ /**
565
+ * Get or create a counter
566
+ */
567
+ counter(name: string, description?: string): Counter {
568
+ let counter = this.counters.get(name);
569
+ if (!counter) {
570
+ counter = this.meter.createCounter(name, { description });
571
+ this.counters.set(name, counter);
572
+ }
573
+ return counter;
574
+ }
575
+
576
+ /**
577
+ * Get or create a histogram
578
+ */
579
+ histogram(name: string, description?: string): Histogram {
580
+ let histogram = this.histograms.get(name);
581
+ if (!histogram) {
582
+ histogram = this.meter.createHistogram(name, { description });
583
+ this.histograms.set(name, histogram);
584
+ }
585
+ return histogram;
586
+ }
587
+
588
+ /**
589
+ * Increment a counter
590
+ */
591
+ increment(name: string, value: number = 1, labels?: MetricLabels): void {
592
+ this.counter(name).add(value, labels);
593
+ }
594
+
595
+ /**
596
+ * Record a histogram value
597
+ */
598
+ record(name: string, value: number, labels?: MetricLabels): void {
599
+ this.histogram(name).record(value, labels);
600
+ }
601
+
602
+ /**
603
+ * Time a function execution
604
+ */
605
+ async time<T>(name: string, fn: () => Promise<T>, labels?: MetricLabels): Promise<T> {
606
+ const start = Date.now();
607
+ try {
608
+ return await fn();
609
+ } finally {
610
+ this.record(name, Date.now() - start, labels);
611
+ }
612
+ }
613
+ }
614
+
615
+ /**
616
+ * Default metrics registry
617
+ */
618
+ export const metricsRegistry = new MetricsRegistry();
619
+
620
+ /**
621
+ * Metric decorator
622
+ */
623
+ export function Metric(name: string, type: 'counter' | 'histogram' = 'histogram'): MethodDecorator {
624
+ return function (
625
+ target: any,
626
+ propertyKey: string | symbol,
627
+ descriptor: PropertyDescriptor,
628
+ ) {
629
+ const originalMethod = descriptor.value;
630
+
631
+ descriptor.value = async function (...args: any[]) {
632
+ const labels = {
633
+ class: target.constructor.name,
634
+ method: String(propertyKey),
635
+ };
636
+
637
+ if (type === 'counter') {
638
+ metricsRegistry.increment(name, 1, labels);
639
+ return originalMethod.apply(this, args);
640
+ }
641
+
642
+ return metricsRegistry.time(\`\${name}_duration_ms\`, () => originalMethod.apply(this, args), labels);
643
+ };
644
+
645
+ return descriptor;
646
+ };
647
+ }
648
+
649
+ /**
650
+ * Common application metrics
651
+ */
652
+ export const AppMetrics = {
653
+ httpRequestsTotal: (method: string, path: string, status: number) => {
654
+ metricsRegistry.increment('http_requests_total', 1, { method, path, status: String(status) });
655
+ },
656
+
657
+ httpRequestDuration: (method: string, path: string, durationMs: number) => {
658
+ metricsRegistry.record('http_request_duration_ms', durationMs, { method, path });
659
+ },
660
+
661
+ dbQueryDuration: (operation: string, table: string, durationMs: number) => {
662
+ metricsRegistry.record('db_query_duration_ms', durationMs, { operation, table });
663
+ },
664
+
665
+ externalCallDuration: (service: string, operation: string, durationMs: number) => {
666
+ metricsRegistry.record('external_call_duration_ms', durationMs, { service, operation });
667
+ },
668
+
669
+ errorCount: (type: string, service: string) => {
670
+ metricsRegistry.increment('errors_total', 1, { type, service });
671
+ },
672
+
673
+ cacheHit: (cache: string) => {
674
+ metricsRegistry.increment('cache_hits_total', 1, { cache });
675
+ },
676
+
677
+ cacheMiss: (cache: string) => {
678
+ metricsRegistry.increment('cache_misses_total', 1, { cache });
679
+ },
680
+ };
681
+ `;
682
+ }
683
+ function generateObservabilityModule() {
684
+ return `import { Module, Global, DynamicModule, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
685
+ import { APP_INTERCEPTOR } from '@nestjs/core';
686
+ import { TraceInterceptor } from './trace.interceptor';
687
+ import { initTracing, shutdownTracing, TracingConfig } from './tracing.setup';
688
+ import { MetricsRegistry, metricsRegistry } from './metrics';
689
+
690
+ export interface ObservabilityModuleOptions {
691
+ tracing?: Partial<TracingConfig>;
692
+ enableHttpTracing?: boolean;
693
+ }
694
+
695
+ @Global()
696
+ @Module({})
697
+ export class ObservabilityModule implements OnModuleInit, OnModuleDestroy {
698
+ static options: ObservabilityModuleOptions = {};
699
+
700
+ static forRoot(options: ObservabilityModuleOptions = {}): DynamicModule {
701
+ this.options = options;
702
+
703
+ const providers: any[] = [
704
+ {
705
+ provide: 'OBSERVABILITY_OPTIONS',
706
+ useValue: options,
707
+ },
708
+ {
709
+ provide: MetricsRegistry,
710
+ useValue: metricsRegistry,
711
+ },
712
+ ];
713
+
714
+ if (options.enableHttpTracing !== false) {
715
+ providers.push({
716
+ provide: APP_INTERCEPTOR,
717
+ useClass: TraceInterceptor,
718
+ });
719
+ }
720
+
721
+ return {
722
+ module: ObservabilityModule,
723
+ providers,
724
+ exports: [MetricsRegistry],
725
+ };
726
+ }
727
+
728
+ async onModuleInit() {
729
+ if (ObservabilityModule.options.tracing) {
730
+ await initTracing(ObservabilityModule.options.tracing);
731
+ }
732
+ }
733
+
734
+ async onModuleDestroy() {
735
+ await shutdownTracing();
736
+ }
737
+ }
738
+ `;
739
+ }
740
+ //# sourceMappingURL=observability-tracing.js.map