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.
- package/README.md +247 -408
- package/ddd.schema.json +111 -0
- package/dist/commands/aggregate-validator.d.ts +9 -0
- package/dist/commands/aggregate-validator.js +953 -0
- package/dist/commands/aggregate-validator.js.map +1 -0
- package/dist/commands/ai-assist.d.ts +8 -0
- package/dist/commands/ai-assist.js +337 -0
- package/dist/commands/ai-assist.js.map +1 -0
- package/dist/commands/api-contracts.d.ts +9 -0
- package/dist/commands/api-contracts.js +1368 -0
- package/dist/commands/api-contracts.js.map +1 -0
- package/dist/commands/api-docs.d.ts +8 -0
- package/dist/commands/api-docs.js +408 -0
- package/dist/commands/api-docs.js.map +1 -0
- package/dist/commands/api-versioning.d.ts +11 -0
- package/dist/commands/api-versioning.js +643 -0
- package/dist/commands/api-versioning.js.map +1 -0
- package/dist/commands/audit-logging.d.ts +9 -0
- package/dist/commands/audit-logging.js +1129 -0
- package/dist/commands/audit-logging.js.map +1 -0
- package/dist/commands/batch-generate.d.ts +10 -0
- package/dist/commands/batch-generate.js +405 -0
- package/dist/commands/batch-generate.js.map +1 -0
- package/dist/commands/caching-strategies.d.ts +9 -0
- package/dist/commands/caching-strategies.js +874 -0
- package/dist/commands/caching-strategies.js.map +1 -0
- package/dist/commands/code-analyzer.d.ts +42 -0
- package/dist/commands/code-analyzer.js +474 -0
- package/dist/commands/code-analyzer.js.map +1 -0
- package/dist/commands/database-seeding.d.ts +6 -0
- package/dist/commands/database-seeding.js +621 -0
- package/dist/commands/database-seeding.js.map +1 -0
- package/dist/commands/db-optimization.d.ts +7 -0
- package/dist/commands/db-optimization.js +687 -0
- package/dist/commands/db-optimization.js.map +1 -0
- package/dist/commands/dependency-graph.d.ts +6 -0
- package/dist/commands/dependency-graph.js +329 -0
- package/dist/commands/dependency-graph.js.map +1 -0
- package/dist/commands/doctor-enhanced.d.ts +22 -0
- package/dist/commands/doctor-enhanced.js +543 -0
- package/dist/commands/doctor-enhanced.js.map +1 -0
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.js +151 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/env-manager.d.ts +6 -0
- package/dist/commands/env-manager.js +419 -0
- package/dist/commands/env-manager.js.map +1 -0
- package/dist/commands/event-sourcing-full.d.ts +10 -0
- package/dist/commands/event-sourcing-full.js +1107 -0
- package/dist/commands/event-sourcing-full.js.map +1 -0
- package/dist/commands/feature-flags.d.ts +9 -0
- package/dist/commands/feature-flags.js +824 -0
- package/dist/commands/feature-flags.js.map +1 -0
- package/dist/commands/filter-dsl.d.ts +10 -0
- package/dist/commands/filter-dsl.js +1407 -0
- package/dist/commands/filter-dsl.js.map +1 -0
- package/dist/commands/generate-all.js +485 -32
- package/dist/commands/generate-all.js.map +1 -1
- package/dist/commands/generate-deployment.d.ts +8 -0
- package/dist/commands/generate-deployment.js +746 -0
- package/dist/commands/generate-deployment.js.map +1 -0
- package/dist/commands/generate-domain-service.d.ts +14 -0
- package/dist/commands/generate-domain-service.js +796 -0
- package/dist/commands/generate-domain-service.js.map +1 -0
- package/dist/commands/generate-entity.js +82 -24
- package/dist/commands/generate-entity.js.map +1 -1
- package/dist/commands/generate-from-schema.d.ts +56 -0
- package/dist/commands/generate-from-schema.js +222 -0
- package/dist/commands/generate-from-schema.js.map +1 -0
- package/dist/commands/generate-orchestrator.d.ts +14 -0
- package/dist/commands/generate-orchestrator.js +887 -0
- package/dist/commands/generate-orchestrator.js.map +1 -0
- package/dist/commands/generate-repository.d.ts +14 -0
- package/dist/commands/generate-repository.js +1019 -0
- package/dist/commands/generate-repository.js.map +1 -0
- package/dist/commands/generate-shared.d.ts +4 -0
- package/dist/commands/generate-shared.js +388 -0
- package/dist/commands/generate-shared.js.map +1 -0
- package/dist/commands/generate-value-object.d.ts +32 -0
- package/dist/commands/generate-value-object.js +700 -0
- package/dist/commands/generate-value-object.js.map +1 -0
- package/dist/commands/graphql-subscriptions.d.ts +6 -0
- package/dist/commands/graphql-subscriptions.js +607 -0
- package/dist/commands/graphql-subscriptions.js.map +1 -0
- package/dist/commands/graphql-types.d.ts +5 -0
- package/dist/commands/graphql-types.js +423 -0
- package/dist/commands/graphql-types.js.map +1 -0
- package/dist/commands/health-probes-advanced.d.ts +6 -0
- package/dist/commands/health-probes-advanced.js +655 -0
- package/dist/commands/health-probes-advanced.js.map +1 -0
- package/dist/commands/i18n-setup.d.ts +10 -0
- package/dist/commands/i18n-setup.js +677 -0
- package/dist/commands/i18n-setup.js.map +1 -0
- package/dist/commands/init-config.d.ts +6 -0
- package/dist/commands/init-config.js +370 -0
- package/dist/commands/init-config.js.map +1 -0
- package/dist/commands/init-project.js +56 -6
- package/dist/commands/init-project.js.map +1 -1
- package/dist/commands/interactive-scaffold.d.ts +5 -0
- package/dist/commands/interactive-scaffold.js +271 -0
- package/dist/commands/interactive-scaffold.js.map +1 -0
- package/dist/commands/metrics-prometheus.d.ts +6 -0
- package/dist/commands/metrics-prometheus.js +681 -0
- package/dist/commands/metrics-prometheus.js.map +1 -0
- package/dist/commands/migration-engine.d.ts +6 -0
- package/dist/commands/migration-engine.js +446 -0
- package/dist/commands/migration-engine.js.map +1 -0
- package/dist/commands/migration.d.ts +12 -0
- package/dist/commands/migration.js +484 -0
- package/dist/commands/migration.js.map +1 -0
- package/dist/commands/monorepo.d.ts +8 -0
- package/dist/commands/monorepo.js +483 -0
- package/dist/commands/monorepo.js.map +1 -0
- package/dist/commands/multi-database.d.ts +5 -0
- package/dist/commands/multi-database.js +439 -0
- package/dist/commands/multi-database.js.map +1 -0
- package/dist/commands/observability-tracing.d.ts +10 -0
- package/dist/commands/observability-tracing.js +740 -0
- package/dist/commands/observability-tracing.js.map +1 -0
- package/dist/commands/openapi-export.d.ts +8 -0
- package/dist/commands/openapi-export.js +359 -0
- package/dist/commands/openapi-export.js.map +1 -0
- package/dist/commands/perf-analyzer.d.ts +8 -0
- package/dist/commands/perf-analyzer.js +423 -0
- package/dist/commands/perf-analyzer.js.map +1 -0
- package/dist/commands/rate-limiting.d.ts +10 -0
- package/dist/commands/rate-limiting.js +953 -0
- package/dist/commands/rate-limiting.js.map +1 -0
- package/dist/commands/recipe-plugin.d.ts +56 -0
- package/dist/commands/recipe-plugin.js +315 -0
- package/dist/commands/recipe-plugin.js.map +1 -0
- package/dist/commands/recipe.d.ts +6 -0
- package/dist/commands/recipe.js +3941 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.d.ts +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.js +761 -0
- package/dist/commands/recipes/elasticsearch.recipe.js.map +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.d.ts +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.js +889 -0
- package/dist/commands/recipes/event-sourcing.recipe.js.map +1 -0
- package/dist/commands/recipes/index.d.ts +7 -0
- package/dist/commands/recipes/index.js +24 -0
- package/dist/commands/recipes/index.js.map +1 -0
- package/dist/commands/recipes/message-queue.recipe.d.ts +1 -0
- package/dist/commands/recipes/message-queue.recipe.js +706 -0
- package/dist/commands/recipes/message-queue.recipe.js.map +1 -0
- package/dist/commands/recipes/middleware.recipe.d.ts +1 -0
- package/dist/commands/recipes/middleware.recipe.js +383 -0
- package/dist/commands/recipes/middleware.recipe.js.map +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.d.ts +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js +520 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js.map +1 -0
- package/dist/commands/recipes/oauth2.recipe.d.ts +1 -0
- package/dist/commands/recipes/oauth2.recipe.js +472 -0
- package/dist/commands/recipes/oauth2.recipe.js.map +1 -0
- package/dist/commands/recipes/websocket.recipe.d.ts +1 -0
- package/dist/commands/recipes/websocket.recipe.js +453 -0
- package/dist/commands/recipes/websocket.recipe.js.map +1 -0
- package/dist/commands/resilience-patterns.d.ts +13 -0
- package/dist/commands/resilience-patterns.js +1029 -0
- package/dist/commands/resilience-patterns.js.map +1 -0
- package/dist/commands/security-patterns.d.ts +11 -0
- package/dist/commands/security-patterns.js +2233 -0
- package/dist/commands/security-patterns.js.map +1 -0
- package/dist/commands/template-debug.d.ts +27 -0
- package/dist/commands/template-debug.js +388 -0
- package/dist/commands/template-debug.js.map +1 -0
- package/dist/commands/test-factory-full.d.ts +9 -0
- package/dist/commands/test-factory-full.js +1570 -0
- package/dist/commands/test-factory-full.js.map +1 -0
- package/dist/commands/test-scaffold.d.ts +7 -0
- package/dist/commands/test-scaffold.js +621 -0
- package/dist/commands/test-scaffold.js.map +1 -0
- package/dist/index.js +1088 -0
- package/dist/index.js.map +1 -1
- package/dist/templates/ai-context/CLAUDE.md.hbs +158 -0
- package/dist/templates/ai-context/conventions.md.hbs +154 -0
- package/dist/templates/command/create-command.hbs +6 -14
- package/dist/templates/command/delete-command.hbs +19 -0
- package/dist/templates/command/update-command.hbs +24 -0
- package/dist/templates/controller/controller.hbs +64 -17
- package/dist/templates/dto/create-dto.hbs +29 -5
- package/dist/templates/dto/filter-dto.hbs +52 -0
- package/dist/templates/dto/filter-query.dto.hbs +148 -0
- package/dist/templates/dto/paginated-response.dto.hbs +29 -0
- package/dist/templates/dto/pagination-query.dto.hbs +30 -0
- package/dist/templates/dto/response-dto.hbs +38 -0
- package/dist/templates/dto/update-dto.hbs +11 -0
- package/dist/templates/entity/entity.hbs +32 -1
- package/dist/templates/event/domain-event.hbs +33 -7
- package/dist/templates/event/event-handler.hbs +40 -0
- package/dist/templates/exception/base-exceptions.hbs +69 -0
- package/dist/templates/exception/entity-not-found.exception.hbs +7 -0
- package/dist/templates/mapper/mapper.hbs +49 -24
- package/dist/templates/module/module.hbs +34 -10
- package/dist/templates/orm-entity/orm-entity.hbs +63 -12
- package/dist/templates/prisma/prisma-mapper.hbs +71 -0
- package/dist/templates/prisma/prisma-repository.hbs +114 -0
- package/dist/templates/prisma/prisma-schema.hbs +20 -0
- package/dist/templates/prisma/prisma-service.hbs +51 -0
- package/dist/templates/query/get-all.query.hbs +50 -0
- package/dist/templates/query/get-by-id.query.hbs +31 -0
- package/dist/templates/repository/repository.hbs +55 -13
- package/dist/templates/resolver/graphql-input.hbs +54 -0
- package/dist/templates/resolver/graphql-type.hbs +58 -0
- package/dist/templates/resolver/pagination-args.hbs +33 -0
- package/dist/templates/resolver/resolver.hbs +62 -0
- package/dist/templates/shared/prisma-query-builder.util.hbs +189 -0
- package/dist/templates/shared/query-builder.util.hbs +218 -0
- package/dist/templates/test/controller.spec.hbs +124 -0
- package/dist/templates/test/repository.spec.hbs +158 -0
- package/dist/templates/test/usecase.spec.hbs +116 -0
- package/dist/templates/usecase/create-usecase.hbs +19 -7
- package/dist/templates/usecase/delete-usecase.hbs +17 -0
- package/dist/templates/usecase/update-usecase.hbs +31 -0
- package/dist/utils/config.utils.d.ts +45 -0
- package/dist/utils/config.utils.js +211 -0
- package/dist/utils/config.utils.js.map +1 -0
- package/dist/utils/error.utils.d.ts +145 -0
- package/dist/utils/error.utils.js +422 -0
- package/dist/utils/error.utils.js.map +1 -0
- package/dist/utils/field.utils.d.ts +54 -0
- package/dist/utils/field.utils.js +389 -0
- package/dist/utils/field.utils.js.map +1 -0
- package/dist/utils/file.utils.d.ts +19 -8
- package/dist/utils/file.utils.js +135 -4
- package/dist/utils/file.utils.js.map +1 -1
- package/dist/utils/idempotency.utils.d.ts +123 -0
- package/dist/utils/idempotency.utils.js +444 -0
- package/dist/utils/idempotency.utils.js.map +1 -0
- package/dist/utils/naming.utils.js +26 -3
- package/dist/utils/naming.utils.js.map +1 -1
- package/dist/utils/performance.utils.d.ts +37 -0
- package/dist/utils/performance.utils.js +158 -0
- package/dist/utils/performance.utils.js.map +1 -0
- package/dist/utils/relation.utils.d.ts +92 -0
- package/dist/utils/relation.utils.js +388 -0
- package/dist/utils/relation.utils.js.map +1 -0
- package/dist/utils/rollback.utils.d.ts +49 -0
- package/dist/utils/rollback.utils.js +306 -0
- package/dist/utils/rollback.utils.js.map +1 -0
- package/dist/utils/schema.utils.d.ts +123 -0
- package/dist/utils/schema.utils.js +419 -0
- package/dist/utils/schema.utils.js.map +1 -0
- package/dist/utils/security.utils.d.ts +57 -0
- package/dist/utils/security.utils.js +315 -0
- package/dist/utils/security.utils.js.map +1 -0
- package/dist/utils/template-engine.utils.d.ts +80 -0
- package/dist/utils/template-engine.utils.js +463 -0
- package/dist/utils/template-engine.utils.js.map +1 -0
- package/dist/utils/validation-registry.utils.d.ts +160 -0
- package/dist/utils/validation-registry.utils.js +526 -0
- package/dist/utils/validation-registry.utils.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.applyMessageQueueRecipe = applyMessageQueueRecipe;
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
+
const file_utils_1 = require("../../utils/file.utils");
|
|
43
|
+
async function applyMessageQueueRecipe(basePath) {
|
|
44
|
+
const sharedPath = path.join(basePath, 'src/shared');
|
|
45
|
+
const mqPath = path.join(sharedPath, 'messaging');
|
|
46
|
+
await (0, file_utils_1.ensureDir)(mqPath);
|
|
47
|
+
await (0, file_utils_1.ensureDir)(path.join(mqPath, 'producers'));
|
|
48
|
+
await (0, file_utils_1.ensureDir)(path.join(mqPath, 'consumers'));
|
|
49
|
+
await (0, file_utils_1.ensureDir)(path.join(mqPath, 'decorators'));
|
|
50
|
+
// Message types
|
|
51
|
+
const messageTypesContent = `export interface Message<T = any> {
|
|
52
|
+
id: string;
|
|
53
|
+
type: string;
|
|
54
|
+
payload: T;
|
|
55
|
+
metadata: MessageMetadata;
|
|
56
|
+
timestamp: Date;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface MessageMetadata {
|
|
60
|
+
correlationId?: string;
|
|
61
|
+
causationId?: string;
|
|
62
|
+
userId?: string;
|
|
63
|
+
tenantId?: string;
|
|
64
|
+
retryCount?: number;
|
|
65
|
+
maxRetries?: number;
|
|
66
|
+
priority?: number;
|
|
67
|
+
headers?: Record<string, string>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface MessageHandler<T = any> {
|
|
71
|
+
handle(message: Message<T>): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface PublishOptions {
|
|
75
|
+
exchange?: string;
|
|
76
|
+
routingKey?: string;
|
|
77
|
+
persistent?: boolean;
|
|
78
|
+
priority?: number;
|
|
79
|
+
expiration?: number;
|
|
80
|
+
headers?: Record<string, any>;
|
|
81
|
+
delay?: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ConsumeOptions {
|
|
85
|
+
queue: string;
|
|
86
|
+
prefetch?: number;
|
|
87
|
+
noAck?: boolean;
|
|
88
|
+
exclusive?: boolean;
|
|
89
|
+
deadLetterExchange?: string;
|
|
90
|
+
deadLetterRoutingKey?: string;
|
|
91
|
+
retryDelay?: number;
|
|
92
|
+
maxRetries?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type ExchangeType = "direct" | "topic" | "fanout" | "headers";
|
|
96
|
+
|
|
97
|
+
export interface ExchangeConfig {
|
|
98
|
+
name: string;
|
|
99
|
+
type: ExchangeType;
|
|
100
|
+
durable?: boolean;
|
|
101
|
+
autoDelete?: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface QueueConfig {
|
|
105
|
+
name: string;
|
|
106
|
+
durable?: boolean;
|
|
107
|
+
exclusive?: boolean;
|
|
108
|
+
autoDelete?: boolean;
|
|
109
|
+
deadLetterExchange?: string;
|
|
110
|
+
deadLetterRoutingKey?: string;
|
|
111
|
+
messageTtl?: number;
|
|
112
|
+
maxLength?: number;
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'message.types.ts'), messageTypesContent);
|
|
116
|
+
// RabbitMQ Connection
|
|
117
|
+
const connectionContent = `import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from "@nestjs/common";
|
|
118
|
+
import * as amqp from "amqplib";
|
|
119
|
+
|
|
120
|
+
export interface RabbitMQConfig {
|
|
121
|
+
url: string;
|
|
122
|
+
heartbeat?: number;
|
|
123
|
+
reconnectDelay?: number;
|
|
124
|
+
maxReconnectAttempts?: number;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@Injectable()
|
|
128
|
+
export class RabbitMQConnection implements OnModuleInit, OnModuleDestroy {
|
|
129
|
+
private readonly logger = new Logger(RabbitMQConnection.name);
|
|
130
|
+
private connection: amqp.Connection | null = null;
|
|
131
|
+
private channel: amqp.Channel | null = null;
|
|
132
|
+
private reconnectAttempts = 0;
|
|
133
|
+
private isConnecting = false;
|
|
134
|
+
|
|
135
|
+
private config: RabbitMQConfig = {
|
|
136
|
+
url: process.env.RABBITMQ_URL || "amqp://localhost:5672",
|
|
137
|
+
heartbeat: 60,
|
|
138
|
+
reconnectDelay: 5000,
|
|
139
|
+
maxReconnectAttempts: 10,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
async onModuleInit() {
|
|
143
|
+
await this.connect();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async onModuleDestroy() {
|
|
147
|
+
await this.disconnect();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async connect(): Promise<void> {
|
|
151
|
+
if (this.isConnecting) return;
|
|
152
|
+
this.isConnecting = true;
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
this.connection = await amqp.connect(this.config.url, {
|
|
156
|
+
heartbeat: this.config.heartbeat,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
this.connection.on("error", (err) => {
|
|
160
|
+
this.logger.error("RabbitMQ connection error:", err.message);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
this.connection.on("close", () => {
|
|
164
|
+
this.logger.warn("RabbitMQ connection closed, attempting reconnect...");
|
|
165
|
+
this.scheduleReconnect();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
this.channel = await this.connection.createChannel();
|
|
169
|
+
this.reconnectAttempts = 0;
|
|
170
|
+
this.logger.log("Connected to RabbitMQ");
|
|
171
|
+
} catch (error) {
|
|
172
|
+
this.logger.error("Failed to connect to RabbitMQ:", error);
|
|
173
|
+
this.scheduleReconnect();
|
|
174
|
+
} finally {
|
|
175
|
+
this.isConnecting = false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private scheduleReconnect() {
|
|
180
|
+
if (this.reconnectAttempts >= (this.config.maxReconnectAttempts || 10)) {
|
|
181
|
+
this.logger.error("Max reconnection attempts reached");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.reconnectAttempts++;
|
|
186
|
+
setTimeout(() => this.connect(), this.config.reconnectDelay);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async disconnect(): Promise<void> {
|
|
190
|
+
try {
|
|
191
|
+
if (this.channel) {
|
|
192
|
+
await this.channel.close();
|
|
193
|
+
this.channel = null;
|
|
194
|
+
}
|
|
195
|
+
if (this.connection) {
|
|
196
|
+
await this.connection.close();
|
|
197
|
+
this.connection = null;
|
|
198
|
+
}
|
|
199
|
+
this.logger.log("Disconnected from RabbitMQ");
|
|
200
|
+
} catch (error) {
|
|
201
|
+
this.logger.error("Error disconnecting from RabbitMQ:", error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getChannel(): amqp.Channel {
|
|
206
|
+
if (!this.channel) {
|
|
207
|
+
throw new Error("RabbitMQ channel not available");
|
|
208
|
+
}
|
|
209
|
+
return this.channel;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
isConnected(): boolean {
|
|
213
|
+
return this.channel !== null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
`;
|
|
217
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'rabbitmq.connection.ts'), connectionContent);
|
|
218
|
+
// Message Producer
|
|
219
|
+
const producerContent = `import { Injectable, Logger } from "@nestjs/common";
|
|
220
|
+
import { v4 as uuid } from "uuid";
|
|
221
|
+
import { RabbitMQConnection } from "../rabbitmq.connection";
|
|
222
|
+
import { Message, MessageMetadata, PublishOptions, ExchangeConfig, ExchangeType } from "../message.types";
|
|
223
|
+
|
|
224
|
+
@Injectable()
|
|
225
|
+
export class MessageProducer {
|
|
226
|
+
private readonly logger = new Logger(MessageProducer.name);
|
|
227
|
+
private declaredExchanges: Set<string> = new Set();
|
|
228
|
+
|
|
229
|
+
constructor(private connection: RabbitMQConnection) {}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Publish a message to an exchange
|
|
233
|
+
*/
|
|
234
|
+
async publish<T>(
|
|
235
|
+
type: string,
|
|
236
|
+
payload: T,
|
|
237
|
+
options: PublishOptions = {}
|
|
238
|
+
): Promise<string> {
|
|
239
|
+
const channel = this.connection.getChannel();
|
|
240
|
+
const messageId = uuid();
|
|
241
|
+
|
|
242
|
+
const message: Message<T> = {
|
|
243
|
+
id: messageId,
|
|
244
|
+
type,
|
|
245
|
+
payload,
|
|
246
|
+
metadata: {
|
|
247
|
+
correlationId: options.headers?.correlationId,
|
|
248
|
+
priority: options.priority,
|
|
249
|
+
},
|
|
250
|
+
timestamp: new Date(),
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const exchange = options.exchange || "events";
|
|
254
|
+
const routingKey = options.routingKey || type;
|
|
255
|
+
|
|
256
|
+
await this.ensureExchange(exchange, "topic");
|
|
257
|
+
|
|
258
|
+
const content = Buffer.from(JSON.stringify(message));
|
|
259
|
+
|
|
260
|
+
channel.publish(exchange, routingKey, content, {
|
|
261
|
+
persistent: options.persistent !== false,
|
|
262
|
+
messageId,
|
|
263
|
+
timestamp: Date.now(),
|
|
264
|
+
contentType: "application/json",
|
|
265
|
+
priority: options.priority,
|
|
266
|
+
expiration: options.expiration?.toString(),
|
|
267
|
+
headers: options.headers,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
this.logger.debug(\`Published message \${messageId} to \${exchange}:\${routingKey}\`);
|
|
271
|
+
return messageId;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Publish directly to a queue
|
|
276
|
+
*/
|
|
277
|
+
async sendToQueue<T>(
|
|
278
|
+
queue: string,
|
|
279
|
+
type: string,
|
|
280
|
+
payload: T,
|
|
281
|
+
metadata?: Partial<MessageMetadata>
|
|
282
|
+
): Promise<string> {
|
|
283
|
+
const channel = this.connection.getChannel();
|
|
284
|
+
const messageId = uuid();
|
|
285
|
+
|
|
286
|
+
const message: Message<T> = {
|
|
287
|
+
id: messageId,
|
|
288
|
+
type,
|
|
289
|
+
payload,
|
|
290
|
+
metadata: {
|
|
291
|
+
...metadata,
|
|
292
|
+
},
|
|
293
|
+
timestamp: new Date(),
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const content = Buffer.from(JSON.stringify(message));
|
|
297
|
+
|
|
298
|
+
channel.sendToQueue(queue, content, {
|
|
299
|
+
persistent: true,
|
|
300
|
+
messageId,
|
|
301
|
+
timestamp: Date.now(),
|
|
302
|
+
contentType: "application/json",
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
this.logger.debug(\`Sent message \${messageId} to queue \${queue}\`);
|
|
306
|
+
return messageId;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Publish with delay using dead-letter exchange
|
|
311
|
+
*/
|
|
312
|
+
async publishDelayed<T>(
|
|
313
|
+
type: string,
|
|
314
|
+
payload: T,
|
|
315
|
+
delayMs: number,
|
|
316
|
+
options: PublishOptions = {}
|
|
317
|
+
): Promise<string> {
|
|
318
|
+
const channel = this.connection.getChannel();
|
|
319
|
+
const messageId = uuid();
|
|
320
|
+
const delayQueue = \`delay.\${delayMs}.\${options.routingKey || type}\`;
|
|
321
|
+
const targetExchange = options.exchange || "events";
|
|
322
|
+
|
|
323
|
+
// Create delay queue that forwards to target exchange after TTL
|
|
324
|
+
await channel.assertQueue(delayQueue, {
|
|
325
|
+
durable: true,
|
|
326
|
+
deadLetterExchange: targetExchange,
|
|
327
|
+
deadLetterRoutingKey: options.routingKey || type,
|
|
328
|
+
messageTtl: delayMs,
|
|
329
|
+
expires: delayMs + 60000,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const message: Message<T> = {
|
|
333
|
+
id: messageId,
|
|
334
|
+
type,
|
|
335
|
+
payload,
|
|
336
|
+
metadata: {
|
|
337
|
+
correlationId: options.headers?.correlationId,
|
|
338
|
+
},
|
|
339
|
+
timestamp: new Date(),
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const content = Buffer.from(JSON.stringify(message));
|
|
343
|
+
|
|
344
|
+
channel.sendToQueue(delayQueue, content, {
|
|
345
|
+
persistent: true,
|
|
346
|
+
messageId,
|
|
347
|
+
contentType: "application/json",
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
this.logger.debug(\`Published delayed message \${messageId} (delay: \${delayMs}ms)\`);
|
|
351
|
+
return messageId;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Ensure exchange exists
|
|
356
|
+
*/
|
|
357
|
+
private async ensureExchange(name: string, type: ExchangeType): Promise<void> {
|
|
358
|
+
if (this.declaredExchanges.has(name)) return;
|
|
359
|
+
|
|
360
|
+
const channel = this.connection.getChannel();
|
|
361
|
+
await channel.assertExchange(name, type, { durable: true });
|
|
362
|
+
this.declaredExchanges.add(name);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Create exchange with config
|
|
367
|
+
*/
|
|
368
|
+
async createExchange(config: ExchangeConfig): Promise<void> {
|
|
369
|
+
const channel = this.connection.getChannel();
|
|
370
|
+
await channel.assertExchange(config.name, config.type, {
|
|
371
|
+
durable: config.durable !== false,
|
|
372
|
+
autoDelete: config.autoDelete || false,
|
|
373
|
+
});
|
|
374
|
+
this.declaredExchanges.add(config.name);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
`;
|
|
378
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'producers/message.producer.ts'), producerContent);
|
|
379
|
+
// Message Consumer
|
|
380
|
+
const consumerContent = `import { Injectable, Logger, OnModuleInit } from "@nestjs/common";
|
|
381
|
+
import * as amqp from "amqplib";
|
|
382
|
+
import { RabbitMQConnection } from "../rabbitmq.connection";
|
|
383
|
+
import { Message, ConsumeOptions, QueueConfig } from "../message.types";
|
|
384
|
+
|
|
385
|
+
export type MessageHandlerFn<T = any> = (message: Message<T>) => Promise<void>;
|
|
386
|
+
|
|
387
|
+
interface RegisteredHandler {
|
|
388
|
+
queue: string;
|
|
389
|
+
handler: MessageHandlerFn;
|
|
390
|
+
options: ConsumeOptions;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@Injectable()
|
|
394
|
+
export class MessageConsumer implements OnModuleInit {
|
|
395
|
+
private readonly logger = new Logger(MessageConsumer.name);
|
|
396
|
+
private handlers: Map<string, RegisteredHandler[]> = new Map();
|
|
397
|
+
private declaredQueues: Set<string> = new Set();
|
|
398
|
+
|
|
399
|
+
constructor(private connection: RabbitMQConnection) {}
|
|
400
|
+
|
|
401
|
+
async onModuleInit() {
|
|
402
|
+
// Start consuming after connection is established
|
|
403
|
+
setTimeout(() => this.startConsuming(), 1000);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Register a message handler
|
|
408
|
+
*/
|
|
409
|
+
registerHandler(
|
|
410
|
+
messageType: string,
|
|
411
|
+
handler: MessageHandlerFn,
|
|
412
|
+
options: ConsumeOptions
|
|
413
|
+
): void {
|
|
414
|
+
if (!this.handlers.has(messageType)) {
|
|
415
|
+
this.handlers.set(messageType, []);
|
|
416
|
+
}
|
|
417
|
+
this.handlers.get(messageType)!.push({ queue: options.queue, handler, options });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Create and configure a queue
|
|
422
|
+
*/
|
|
423
|
+
async createQueue(config: QueueConfig): Promise<void> {
|
|
424
|
+
const channel = this.connection.getChannel();
|
|
425
|
+
|
|
426
|
+
await channel.assertQueue(config.name, {
|
|
427
|
+
durable: config.durable !== false,
|
|
428
|
+
exclusive: config.exclusive || false,
|
|
429
|
+
autoDelete: config.autoDelete || false,
|
|
430
|
+
deadLetterExchange: config.deadLetterExchange,
|
|
431
|
+
deadLetterRoutingKey: config.deadLetterRoutingKey,
|
|
432
|
+
messageTtl: config.messageTtl,
|
|
433
|
+
maxLength: config.maxLength,
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
this.declaredQueues.add(config.name);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Bind queue to exchange
|
|
441
|
+
*/
|
|
442
|
+
async bindQueue(queue: string, exchange: string, routingKey: string): Promise<void> {
|
|
443
|
+
const channel = this.connection.getChannel();
|
|
444
|
+
await channel.bindQueue(queue, exchange, routingKey);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Start consuming from all registered handlers
|
|
449
|
+
*/
|
|
450
|
+
private async startConsuming(): Promise<void> {
|
|
451
|
+
if (!this.connection.isConnected()) {
|
|
452
|
+
this.logger.warn("Connection not ready, retrying in 1s...");
|
|
453
|
+
setTimeout(() => this.startConsuming(), 1000);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
for (const [messageType, handlers] of this.handlers) {
|
|
458
|
+
for (const { queue, handler, options } of handlers) {
|
|
459
|
+
await this.consume(queue, handler, options);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Consume messages from a queue
|
|
466
|
+
*/
|
|
467
|
+
private async consume(
|
|
468
|
+
queue: string,
|
|
469
|
+
handler: MessageHandlerFn,
|
|
470
|
+
options: ConsumeOptions
|
|
471
|
+
): Promise<void> {
|
|
472
|
+
const channel = this.connection.getChannel();
|
|
473
|
+
|
|
474
|
+
// Ensure queue exists
|
|
475
|
+
await channel.assertQueue(queue, { durable: true });
|
|
476
|
+
|
|
477
|
+
// Set prefetch
|
|
478
|
+
if (options.prefetch) {
|
|
479
|
+
await channel.prefetch(options.prefetch);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Set up dead letter queue if configured
|
|
483
|
+
if (options.deadLetterExchange) {
|
|
484
|
+
const dlqName = \`\${queue}.dlq\`;
|
|
485
|
+
await channel.assertQueue(dlqName, { durable: true });
|
|
486
|
+
await channel.bindQueue(
|
|
487
|
+
dlqName,
|
|
488
|
+
options.deadLetterExchange,
|
|
489
|
+
options.deadLetterRoutingKey || queue
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
this.logger.log(\`Starting consumer for queue: \${queue}\`);
|
|
494
|
+
|
|
495
|
+
channel.consume(
|
|
496
|
+
queue,
|
|
497
|
+
async (msg: amqp.ConsumeMessage | null) => {
|
|
498
|
+
if (!msg) return;
|
|
499
|
+
|
|
500
|
+
try {
|
|
501
|
+
const message: Message = JSON.parse(msg.content.toString());
|
|
502
|
+
await handler(message);
|
|
503
|
+
channel.ack(msg);
|
|
504
|
+
this.logger.debug(\`Processed message \${message.id} from \${queue}\`);
|
|
505
|
+
} catch (error) {
|
|
506
|
+
this.logger.error(\`Error processing message from \${queue}:\`, error);
|
|
507
|
+
await this.handleFailure(channel, msg, options);
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
{ noAck: options.noAck || false }
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Handle message processing failure
|
|
516
|
+
*/
|
|
517
|
+
private async handleFailure(
|
|
518
|
+
channel: amqp.Channel,
|
|
519
|
+
msg: amqp.ConsumeMessage,
|
|
520
|
+
options: ConsumeOptions
|
|
521
|
+
): Promise<void> {
|
|
522
|
+
const retryCount = (msg.properties.headers?.["x-retry-count"] || 0) + 1;
|
|
523
|
+
const maxRetries = options.maxRetries || 3;
|
|
524
|
+
|
|
525
|
+
if (retryCount <= maxRetries) {
|
|
526
|
+
// Retry with delay
|
|
527
|
+
const retryDelay = options.retryDelay || 5000;
|
|
528
|
+
const retryQueue = \`\${options.queue}.retry\`;
|
|
529
|
+
|
|
530
|
+
await channel.assertQueue(retryQueue, {
|
|
531
|
+
durable: true,
|
|
532
|
+
deadLetterExchange: "",
|
|
533
|
+
deadLetterRoutingKey: options.queue,
|
|
534
|
+
messageTtl: retryDelay * retryCount,
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
channel.sendToQueue(retryQueue, msg.content, {
|
|
538
|
+
persistent: true,
|
|
539
|
+
headers: {
|
|
540
|
+
...msg.properties.headers,
|
|
541
|
+
"x-retry-count": retryCount,
|
|
542
|
+
"x-original-queue": options.queue,
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
this.logger.warn(\`Retrying message (attempt \${retryCount}/\${maxRetries})\`);
|
|
547
|
+
} else {
|
|
548
|
+
// Send to dead letter queue
|
|
549
|
+
this.logger.error(\`Message exceeded max retries, sending to DLQ\`);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
channel.ack(msg);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
`;
|
|
556
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'consumers/message.consumer.ts'), consumerContent);
|
|
557
|
+
// Subscribe decorator
|
|
558
|
+
const subscribeDecoratorContent = `import { SetMetadata } from "@nestjs/common";
|
|
559
|
+
import { ConsumeOptions } from "../message.types";
|
|
560
|
+
|
|
561
|
+
export const SUBSCRIBE_METADATA = "message:subscribe";
|
|
562
|
+
|
|
563
|
+
export interface SubscribeConfig extends Partial<ConsumeOptions> {
|
|
564
|
+
messageType: string;
|
|
565
|
+
queue: string;
|
|
566
|
+
exchange?: string;
|
|
567
|
+
routingKey?: string;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Decorator to subscribe a method to a message type
|
|
572
|
+
*/
|
|
573
|
+
export function Subscribe(config: SubscribeConfig): MethodDecorator {
|
|
574
|
+
return SetMetadata(SUBSCRIBE_METADATA, config);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Decorator to mark a class as a message handler
|
|
579
|
+
*/
|
|
580
|
+
export function MessageHandler(): ClassDecorator {
|
|
581
|
+
return (target) => {
|
|
582
|
+
Reflect.defineMetadata("message:handler", true, target);
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
`;
|
|
586
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'decorators/subscribe.decorator.ts'), subscribeDecoratorContent);
|
|
587
|
+
// Messaging module
|
|
588
|
+
const moduleContent = `import { Module, Global, DynamicModule, OnModuleInit } from "@nestjs/common";
|
|
589
|
+
import { DiscoveryModule, DiscoveryService, MetadataScanner } from "@nestjs/core";
|
|
590
|
+
import { RabbitMQConnection, RabbitMQConfig } from "./rabbitmq.connection";
|
|
591
|
+
import { MessageProducer } from "./producers/message.producer";
|
|
592
|
+
import { MessageConsumer } from "./consumers/message.consumer";
|
|
593
|
+
import { SUBSCRIBE_METADATA, SubscribeConfig } from "./decorators/subscribe.decorator";
|
|
594
|
+
|
|
595
|
+
export interface MessagingModuleOptions {
|
|
596
|
+
config?: Partial<RabbitMQConfig>;
|
|
597
|
+
exchanges?: Array<{ name: string; type: "direct" | "topic" | "fanout" }>;
|
|
598
|
+
queues?: Array<{ name: string; exchange: string; routingKey: string }>;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
@Global()
|
|
602
|
+
@Module({})
|
|
603
|
+
export class MessagingModule implements OnModuleInit {
|
|
604
|
+
static options: MessagingModuleOptions;
|
|
605
|
+
|
|
606
|
+
constructor(
|
|
607
|
+
private discovery: DiscoveryService,
|
|
608
|
+
private scanner: MetadataScanner,
|
|
609
|
+
private consumer: MessageConsumer,
|
|
610
|
+
private producer: MessageProducer
|
|
611
|
+
) {}
|
|
612
|
+
|
|
613
|
+
static forRoot(options: MessagingModuleOptions = {}): DynamicModule {
|
|
614
|
+
MessagingModule.options = options;
|
|
615
|
+
|
|
616
|
+
return {
|
|
617
|
+
module: MessagingModule,
|
|
618
|
+
imports: [DiscoveryModule],
|
|
619
|
+
providers: [
|
|
620
|
+
RabbitMQConnection,
|
|
621
|
+
MessageProducer,
|
|
622
|
+
MessageConsumer,
|
|
623
|
+
],
|
|
624
|
+
exports: [MessageProducer, MessageConsumer, RabbitMQConnection],
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
async onModuleInit() {
|
|
629
|
+
// Set up exchanges
|
|
630
|
+
for (const exchange of MessagingModule.options.exchanges || []) {
|
|
631
|
+
await this.producer.createExchange({
|
|
632
|
+
name: exchange.name,
|
|
633
|
+
type: exchange.type,
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Set up queues and bindings
|
|
638
|
+
for (const queue of MessagingModule.options.queues || []) {
|
|
639
|
+
await this.consumer.createQueue({ name: queue.name });
|
|
640
|
+
await this.consumer.bindQueue(queue.name, queue.exchange, queue.routingKey);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Discover and register handlers
|
|
644
|
+
this.discoverHandlers();
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private discoverHandlers() {
|
|
648
|
+
const providers = this.discovery.getProviders();
|
|
649
|
+
|
|
650
|
+
providers
|
|
651
|
+
.filter((wrapper) => wrapper.instance && wrapper.metatype)
|
|
652
|
+
.forEach((wrapper) => {
|
|
653
|
+
const { instance } = wrapper;
|
|
654
|
+
|
|
655
|
+
this.scanner.scanFromPrototype(
|
|
656
|
+
instance,
|
|
657
|
+
Object.getPrototypeOf(instance),
|
|
658
|
+
(methodName) => {
|
|
659
|
+
const methodRef = instance[methodName];
|
|
660
|
+
const metadata = Reflect.getMetadata(
|
|
661
|
+
SUBSCRIBE_METADATA,
|
|
662
|
+
methodRef
|
|
663
|
+
) as SubscribeConfig | undefined;
|
|
664
|
+
|
|
665
|
+
if (metadata) {
|
|
666
|
+
this.consumer.registerHandler(
|
|
667
|
+
metadata.messageType,
|
|
668
|
+
methodRef.bind(instance),
|
|
669
|
+
{
|
|
670
|
+
queue: metadata.queue,
|
|
671
|
+
prefetch: metadata.prefetch,
|
|
672
|
+
maxRetries: metadata.maxRetries,
|
|
673
|
+
retryDelay: metadata.retryDelay,
|
|
674
|
+
deadLetterExchange: metadata.deadLetterExchange,
|
|
675
|
+
}
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
);
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
`;
|
|
684
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'messaging.module.ts'), moduleContent);
|
|
685
|
+
// Index exports
|
|
686
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'index.ts'), `export * from "./message.types";
|
|
687
|
+
export * from "./rabbitmq.connection";
|
|
688
|
+
export * from "./producers/message.producer";
|
|
689
|
+
export * from "./consumers/message.consumer";
|
|
690
|
+
export * from "./decorators/subscribe.decorator";
|
|
691
|
+
export * from "./messaging.module";
|
|
692
|
+
`);
|
|
693
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'producers/index.ts'), `export * from "./message.producer";
|
|
694
|
+
`);
|
|
695
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'consumers/index.ts'), `export * from "./message.consumer";
|
|
696
|
+
`);
|
|
697
|
+
await (0, file_utils_1.writeFile)(path.join(mqPath, 'decorators/index.ts'), `export * from "./subscribe.decorator";
|
|
698
|
+
`);
|
|
699
|
+
console.log(chalk_1.default.green(' ✓ Message types and interfaces'));
|
|
700
|
+
console.log(chalk_1.default.green(' ✓ RabbitMQ connection manager with reconnection'));
|
|
701
|
+
console.log(chalk_1.default.green(' ✓ Message producer (publish, sendToQueue, delayed)'));
|
|
702
|
+
console.log(chalk_1.default.green(' ✓ Message consumer with retry and DLQ'));
|
|
703
|
+
console.log(chalk_1.default.green(' ✓ @Subscribe decorator'));
|
|
704
|
+
console.log(chalk_1.default.green(' ✓ Messaging module with auto-discovery'));
|
|
705
|
+
}
|
|
706
|
+
//# sourceMappingURL=message-queue.recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-queue.recipe.js","sourceRoot":"","sources":["../../../src/commands/recipes/message-queue.recipe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function applyMiddlewareRecipe(basePath: string): Promise<void>;
|