rabbitmq-sdk 0.0.1-security → 1.2.0
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.
Potentially problematic release.
This version of rabbitmq-sdk might be problematic. Click here for more details.
- package/.eslintrc.js +23 -0
- package/.kiro/specs/sdk-rabbitmq/design.md +369 -0
- package/.kiro/specs/sdk-rabbitmq/requirements.md +97 -0
- package/.kiro/specs/sdk-rabbitmq/tasks.md +248 -0
- package/README.md +273 -5
- package/bun.lock +790 -0
- package/config.example.json +13 -0
- package/dist/components/ConfigurationManager.d.ts +35 -0
- package/dist/components/ConfigurationManager.d.ts.map +1 -0
- package/dist/components/ConfigurationManager.js +118 -0
- package/dist/components/ConfigurationManager.js.map +1 -0
- package/dist/components/ConnectionManager.d.ts +93 -0
- package/dist/components/ConnectionManager.d.ts.map +1 -0
- package/dist/components/ConnectionManager.js +349 -0
- package/dist/components/ConnectionManager.js.map +1 -0
- package/dist/components/DLQHandler.d.ts +81 -0
- package/dist/components/DLQHandler.d.ts.map +1 -0
- package/dist/components/DLQHandler.js +228 -0
- package/dist/components/DLQHandler.js.map +1 -0
- package/dist/components/Logger.d.ts +77 -0
- package/dist/components/Logger.d.ts.map +1 -0
- package/dist/components/Logger.js +193 -0
- package/dist/components/Logger.js.map +1 -0
- package/dist/components/MessagePublisher.d.ts +49 -0
- package/dist/components/MessagePublisher.d.ts.map +1 -0
- package/dist/components/MessagePublisher.js +158 -0
- package/dist/components/MessagePublisher.js.map +1 -0
- package/dist/components/MessageSubscriber.d.ts +108 -0
- package/dist/components/MessageSubscriber.d.ts.map +1 -0
- package/dist/components/MessageSubscriber.js +503 -0
- package/dist/components/MessageSubscriber.js.map +1 -0
- package/dist/components/ResourceCreator.d.ts +89 -0
- package/dist/components/ResourceCreator.d.ts.map +1 -0
- package/dist/components/ResourceCreator.js +352 -0
- package/dist/components/ResourceCreator.js.map +1 -0
- package/dist/components/SdkRabbitmq.d.ts +103 -0
- package/dist/components/SdkRabbitmq.d.ts.map +1 -0
- package/dist/components/SdkRabbitmq.js +364 -0
- package/dist/components/SdkRabbitmq.js.map +1 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +20 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/IConfiguration.d.ts +35 -0
- package/dist/interfaces/IConfiguration.d.ts.map +1 -0
- package/dist/interfaces/IConfiguration.js +3 -0
- package/dist/interfaces/IConfiguration.js.map +1 -0
- package/dist/interfaces/IConnection.d.ts +21 -0
- package/dist/interfaces/IConnection.d.ts.map +1 -0
- package/dist/interfaces/IConnection.js +3 -0
- package/dist/interfaces/IConnection.js.map +1 -0
- package/dist/interfaces/IDLQ.d.ts +12 -0
- package/dist/interfaces/IDLQ.d.ts.map +1 -0
- package/dist/interfaces/IDLQ.js +3 -0
- package/dist/interfaces/IDLQ.js.map +1 -0
- package/dist/interfaces/IErrors.d.ts +33 -0
- package/dist/interfaces/IErrors.d.ts.map +1 -0
- package/dist/interfaces/IErrors.js +56 -0
- package/dist/interfaces/IErrors.js.map +1 -0
- package/dist/interfaces/ILogger.d.ts +14 -0
- package/dist/interfaces/ILogger.d.ts.map +1 -0
- package/dist/interfaces/ILogger.js +3 -0
- package/dist/interfaces/ILogger.js.map +1 -0
- package/dist/interfaces/IMessage.d.ts +52 -0
- package/dist/interfaces/IMessage.d.ts.map +1 -0
- package/dist/interfaces/IMessage.js +3 -0
- package/dist/interfaces/IMessage.js.map +1 -0
- package/dist/interfaces/IResource.d.ts +31 -0
- package/dist/interfaces/IResource.d.ts.map +1 -0
- package/dist/interfaces/IResource.js +3 -0
- package/dist/interfaces/IResource.js.map +1 -0
- package/dist/interfaces/ISdkRabbitmq.d.ts +17 -0
- package/dist/interfaces/ISdkRabbitmq.d.ts.map +1 -0
- package/dist/interfaces/ISdkRabbitmq.js +3 -0
- package/dist/interfaces/ISdkRabbitmq.js.map +1 -0
- package/dist/interfaces/index.d.ts +9 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +33 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/utils/configSchema.d.ts +8 -0
- package/dist/utils/configSchema.d.ts.map +1 -0
- package/dist/utils/configSchema.js +51 -0
- package/dist/utils/configSchema.js.map +1 -0
- package/docker-compose.yml +24 -0
- package/example.ts +65 -0
- package/examples/README-dynamic-routing.md +155 -0
- package/examples/bind-unbind-example.js +56 -0
- package/examples/test-chatbot-exchange.ts +83 -0
- package/examples/test-dynamic-routing-flow.js +299 -0
- package/examples/test-dynamic-routing-flow.ts +355 -0
- package/examples/test-no-disconnect.ts +0 -0
- package/examples/test-raw-rabbitmq.js +68 -0
- package/examples/test-same-channel.ts +81 -0
- package/examples/test-schedule-flow.ts +713 -0
- package/examples/test-simple-greeting.ts +66 -0
- package/examples/test-simple-schedule.ts +76 -0
- package/examples/test-wildcard.ts +364 -0
- package/jest.config.js +17 -0
- package/package.json +42 -4
- package/preinstall.js +1 -0
- package/prompts/test-dynamic-routing-flow.md +46 -0
- package/run.js +4 -0
- package/scripts/run-dynamic-routing-test.ts +31 -0
- package/src/.gitkeep +1 -0
- package/src/components/.gitkeep +1 -0
- package/src/components/ConfigurationManager.ts +104 -0
- package/src/components/ConnectionManager.ts +357 -0
- package/src/components/DLQHandler.ts +271 -0
- package/src/components/Logger.ts +224 -0
- package/src/components/MessagePublisher.ts +180 -0
- package/src/components/MessageSubscriber.ts +597 -0
- package/src/components/ResourceCreator.ts +411 -0
- package/src/components/SdkRabbitmq.ts +443 -0
- package/src/components/__tests__/ConfigurationManager.test.ts +357 -0
- package/src/components/__tests__/ConnectionManager.test.ts +387 -0
- package/src/components/__tests__/DLQHandler.test.ts +399 -0
- package/src/components/__tests__/Logger.test.ts +354 -0
- package/src/components/__tests__/MessagePublisher.test.ts +337 -0
- package/src/components/__tests__/MessageSubscriber.test.ts +542 -0
- package/src/components/__tests__/ResourceCreator.test.ts +465 -0
- package/src/components/__tests__/SdkRabbitmq.integration.test.ts +433 -0
- package/src/components/index.ts +8 -0
- package/src/index.ts +11 -0
- package/src/interfaces/.gitkeep +1 -0
- package/src/interfaces/IConfiguration.ts +38 -0
- package/src/interfaces/IConnection.ts +27 -0
- package/src/interfaces/IDLQ.ts +13 -0
- package/src/interfaces/IErrors.ts +53 -0
- package/src/interfaces/ILogger.ts +16 -0
- package/src/interfaces/IMessage.ts +65 -0
- package/src/interfaces/IResource.ts +35 -0
- package/src/interfaces/ISdkRabbitmq.ts +26 -0
- package/src/interfaces/index.ts +23 -0
- package/src/utils/.gitkeep +1 -0
- package/src/utils/configSchema.ts +58 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
// amqplib types are used via ConnectionManager
|
|
2
|
+
import { IResourceCreator, QueueOptions, ExchangeOptions } from '../interfaces/IResource';
|
|
3
|
+
import { ConnectionManager } from './ConnectionManager';
|
|
4
|
+
import { Logger } from './Logger';
|
|
5
|
+
import { IConfiguration } from '../interfaces/IConfiguration';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ResourceCreator handles automatic creation of exchanges, queues, and bindings
|
|
9
|
+
* Implements caching and existence checking to avoid duplicate creation attempts
|
|
10
|
+
*/
|
|
11
|
+
export class ResourceCreator implements IResourceCreator {
|
|
12
|
+
private connectionManager: ConnectionManager;
|
|
13
|
+
private createdExchanges = new Set<string>();
|
|
14
|
+
private createdQueues = new Set<string>();
|
|
15
|
+
private createdBindings = new Set<string>();
|
|
16
|
+
private existingExchanges = new Set<string>();
|
|
17
|
+
private existingQueues = new Set<string>();
|
|
18
|
+
private logger: Logger;
|
|
19
|
+
|
|
20
|
+
constructor(connectionManager: ConnectionManager, config?: IConfiguration['logging']) {
|
|
21
|
+
this.connectionManager = connectionManager;
|
|
22
|
+
this.logger = Logger.createComponentLogger('ResourceCreator', config);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check if exchange exists without creating it
|
|
27
|
+
* @param exchange Exchange name
|
|
28
|
+
* @returns Promise<boolean> indicating if exchange exists
|
|
29
|
+
*/
|
|
30
|
+
private async checkExchangeExists(exchange: string): Promise<boolean> {
|
|
31
|
+
if (this.existingExchanges.has(exchange)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return this.connectionManager.executeOperation(async () => {
|
|
36
|
+
const connection = this.connectionManager.getConnection();
|
|
37
|
+
if (!connection) {
|
|
38
|
+
throw new Error('No active connection to RabbitMQ');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const channel = await (connection as any).createChannel();
|
|
43
|
+
|
|
44
|
+
// Use checkExchange to verify existence without creating
|
|
45
|
+
await channel.checkExchange(exchange);
|
|
46
|
+
await channel.close();
|
|
47
|
+
|
|
48
|
+
// Cache that exchange exists
|
|
49
|
+
this.existingExchanges.add(exchange);
|
|
50
|
+
return true;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// Exchange doesn't exist or other error
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check if queue exists without creating it
|
|
60
|
+
* @param queue Queue name
|
|
61
|
+
* @returns Promise<boolean> indicating if queue exists
|
|
62
|
+
*/
|
|
63
|
+
private async checkQueueExists(queue: string): Promise<boolean> {
|
|
64
|
+
if (this.existingQueues.has(queue)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this.connectionManager.executeOperation(async () => {
|
|
69
|
+
const connection = this.connectionManager.getConnection();
|
|
70
|
+
if (!connection) {
|
|
71
|
+
throw new Error('No active connection to RabbitMQ');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const channel = await (connection as any).createChannel();
|
|
76
|
+
|
|
77
|
+
// Use checkQueue to verify existence without creating
|
|
78
|
+
await channel.checkQueue(queue);
|
|
79
|
+
await channel.close();
|
|
80
|
+
|
|
81
|
+
// Cache that queue exists
|
|
82
|
+
this.existingQueues.add(queue);
|
|
83
|
+
return true;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
// Queue doesn't exist or other error
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Ensure exchange exists, create if it doesn't
|
|
93
|
+
* @param exchange Exchange name
|
|
94
|
+
* @param type Exchange type (default: 'direct')
|
|
95
|
+
* @param options Exchange options
|
|
96
|
+
*/
|
|
97
|
+
public async ensureExchange(
|
|
98
|
+
exchange: string,
|
|
99
|
+
type: string = 'topic',
|
|
100
|
+
options: ExchangeOptions = {}
|
|
101
|
+
): Promise<void> {
|
|
102
|
+
if (!exchange) {
|
|
103
|
+
throw new Error('Exchange name is required');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const exchangeKey = `${exchange}:${type}`;
|
|
107
|
+
|
|
108
|
+
// Check cache first
|
|
109
|
+
if (this.createdExchanges.has(exchangeKey)) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check if exchange already exists
|
|
114
|
+
try {
|
|
115
|
+
const exists = await this.checkExchangeExists(exchange);
|
|
116
|
+
if (exists) {
|
|
117
|
+
this.createdExchanges.add(exchangeKey);
|
|
118
|
+
this.logger.info(`Exchange already exists`, { exchange, type });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.logger.warn(`Could not check exchange existence`, {
|
|
123
|
+
exchange,
|
|
124
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this.connectionManager.executeOperation(async () => {
|
|
129
|
+
const connection = this.connectionManager.getConnection();
|
|
130
|
+
if (!connection) {
|
|
131
|
+
throw new Error('No active connection to RabbitMQ');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const channel = await (connection as any).createChannel();
|
|
136
|
+
|
|
137
|
+
// Set default options
|
|
138
|
+
const exchangeOptions = {
|
|
139
|
+
durable: true,
|
|
140
|
+
autoDelete: false,
|
|
141
|
+
...options
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
await channel.assertExchange(exchange, type, exchangeOptions);
|
|
145
|
+
await channel.close();
|
|
146
|
+
|
|
147
|
+
// Cache successful creation
|
|
148
|
+
this.createdExchanges.add(exchangeKey);
|
|
149
|
+
this.existingExchanges.add(exchange);
|
|
150
|
+
|
|
151
|
+
this.logger.logOperation('createExchange', `Exchange created successfully`, {
|
|
152
|
+
exchange,
|
|
153
|
+
type,
|
|
154
|
+
options: exchangeOptions
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
this.logger.logError(`Failed to ensure exchange`, error as Error, { exchange, type });
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Ensure queue exists, create if it doesn't
|
|
165
|
+
* @param queue Queue name
|
|
166
|
+
* @param options Queue options
|
|
167
|
+
*/
|
|
168
|
+
public async ensureQueue(queue: string, options: QueueOptions = {}): Promise<void> {
|
|
169
|
+
if (!queue) {
|
|
170
|
+
throw new Error('Queue name is required');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Check cache first
|
|
174
|
+
if (this.createdQueues.has(queue)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check if queue already exists
|
|
179
|
+
try {
|
|
180
|
+
const exists = await this.checkQueueExists(queue);
|
|
181
|
+
if (exists) {
|
|
182
|
+
this.createdQueues.add(queue);
|
|
183
|
+
this.logger.info(`Queue already exists`, { queue });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
this.logger.warn(`Could not check queue existence`, {
|
|
188
|
+
queue,
|
|
189
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return this.connectionManager.executeOperation(async () => {
|
|
194
|
+
const connection = this.connectionManager.getConnection();
|
|
195
|
+
if (!connection) {
|
|
196
|
+
throw new Error('No active connection to RabbitMQ');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const channel = await (connection as any).createChannel();
|
|
201
|
+
|
|
202
|
+
// Set default options
|
|
203
|
+
const queueOptions = {
|
|
204
|
+
durable: true,
|
|
205
|
+
exclusive: false,
|
|
206
|
+
autoDelete: false,
|
|
207
|
+
...options
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
await channel.assertQueue(queue, queueOptions);
|
|
211
|
+
await channel.close();
|
|
212
|
+
|
|
213
|
+
// Cache successful creation
|
|
214
|
+
this.createdQueues.add(queue);
|
|
215
|
+
this.existingQueues.add(queue);
|
|
216
|
+
|
|
217
|
+
this.logger.logOperation('createQueue', `Queue created successfully`, {
|
|
218
|
+
queue,
|
|
219
|
+
options: queueOptions
|
|
220
|
+
});
|
|
221
|
+
} catch (error) {
|
|
222
|
+
this.logger.logError(`Failed to ensure queue`, error as Error, { queue });
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Bind queue to exchange with routing key
|
|
230
|
+
* @param queue Queue name
|
|
231
|
+
* @param exchange Exchange name
|
|
232
|
+
* @param routingKey Routing key for binding
|
|
233
|
+
*/
|
|
234
|
+
public async bindQueue(queue: string, exchange: string, routingKey: string): Promise<void> {
|
|
235
|
+
if (!queue) {
|
|
236
|
+
throw new Error('Queue name is required');
|
|
237
|
+
}
|
|
238
|
+
if (!exchange) {
|
|
239
|
+
throw new Error('Exchange name is required');
|
|
240
|
+
}
|
|
241
|
+
if (!routingKey) {
|
|
242
|
+
throw new Error('Routing key is required');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const bindingKey = `${queue}:${exchange}:${routingKey}`;
|
|
246
|
+
|
|
247
|
+
// Check cache first
|
|
248
|
+
if (this.createdBindings.has(bindingKey)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return this.connectionManager.executeOperation(async () => {
|
|
253
|
+
const connection = this.connectionManager.getConnection();
|
|
254
|
+
if (!connection) {
|
|
255
|
+
throw new Error('No active connection to RabbitMQ');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const channel = await (connection as any).createChannel();
|
|
260
|
+
|
|
261
|
+
await channel.bindQueue(queue, exchange, routingKey);
|
|
262
|
+
await channel.close();
|
|
263
|
+
|
|
264
|
+
// Cache successful binding
|
|
265
|
+
this.createdBindings.add(bindingKey);
|
|
266
|
+
|
|
267
|
+
this.logger.logOperation('bindQueue', `Queue bound to exchange successfully`, {
|
|
268
|
+
queue,
|
|
269
|
+
exchange,
|
|
270
|
+
routingKey
|
|
271
|
+
});
|
|
272
|
+
} catch (error) {
|
|
273
|
+
this.logger.logError(`Failed to bind queue to exchange`, error as Error, {
|
|
274
|
+
queue,
|
|
275
|
+
exchange,
|
|
276
|
+
routingKey
|
|
277
|
+
});
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Unbind queue from exchange with routing key
|
|
285
|
+
* @param queue Queue name
|
|
286
|
+
* @param exchange Exchange name
|
|
287
|
+
* @param routingKey Routing key for unbinding
|
|
288
|
+
*/
|
|
289
|
+
public async unbindQueue(queue: string, exchange: string, routingKey: string): Promise<void> {
|
|
290
|
+
if (!queue) {
|
|
291
|
+
throw new Error('Queue name is required');
|
|
292
|
+
}
|
|
293
|
+
if (!exchange) {
|
|
294
|
+
throw new Error('Exchange name is required');
|
|
295
|
+
}
|
|
296
|
+
if (!routingKey) {
|
|
297
|
+
throw new Error('Routing key is required');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const bindingKey = `${queue}:${exchange}:${routingKey}`;
|
|
301
|
+
|
|
302
|
+
return this.connectionManager.executeOperation(async () => {
|
|
303
|
+
const connection = this.connectionManager.getConnection();
|
|
304
|
+
if (!connection) {
|
|
305
|
+
throw new Error('No active connection to RabbitMQ');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const channel = await (connection as any).createChannel();
|
|
310
|
+
|
|
311
|
+
await channel.unbindQueue(queue, exchange, routingKey);
|
|
312
|
+
await channel.close();
|
|
313
|
+
|
|
314
|
+
// Remove from cache if it exists
|
|
315
|
+
this.createdBindings.delete(bindingKey);
|
|
316
|
+
|
|
317
|
+
this.logger.logOperation('unbindQueue', `Queue unbound from exchange successfully`, {
|
|
318
|
+
queue,
|
|
319
|
+
exchange,
|
|
320
|
+
routingKey
|
|
321
|
+
});
|
|
322
|
+
} catch (error) {
|
|
323
|
+
this.logger.logError(`Failed to unbind queue from exchange`, error as Error, {
|
|
324
|
+
queue,
|
|
325
|
+
exchange,
|
|
326
|
+
routingKey
|
|
327
|
+
});
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Clear all caches (useful for testing or reset scenarios)
|
|
335
|
+
*/
|
|
336
|
+
public clearCache(): void {
|
|
337
|
+
this.createdExchanges.clear();
|
|
338
|
+
this.createdQueues.clear();
|
|
339
|
+
this.createdBindings.clear();
|
|
340
|
+
this.existingExchanges.clear();
|
|
341
|
+
this.existingQueues.clear();
|
|
342
|
+
this.logger.info('ResourceCreator cache cleared');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Get cache statistics for monitoring
|
|
347
|
+
*/
|
|
348
|
+
public getCacheStats(): {
|
|
349
|
+
created: { exchanges: number; queues: number; bindings: number };
|
|
350
|
+
existing: { exchanges: number; queues: number };
|
|
351
|
+
} {
|
|
352
|
+
return {
|
|
353
|
+
created: {
|
|
354
|
+
exchanges: this.createdExchanges.size,
|
|
355
|
+
queues: this.createdQueues.size,
|
|
356
|
+
bindings: this.createdBindings.size
|
|
357
|
+
},
|
|
358
|
+
existing: {
|
|
359
|
+
exchanges: this.existingExchanges.size,
|
|
360
|
+
queues: this.existingQueues.size
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Validate resource name format
|
|
367
|
+
* @param name Resource name to validate
|
|
368
|
+
* @param type Resource type for error messages
|
|
369
|
+
*/
|
|
370
|
+
private validateResourceName(name: string, type: string): void {
|
|
371
|
+
if (!name || typeof name !== 'string') {
|
|
372
|
+
throw new Error(`${type} name must be a non-empty string`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (name.length > 255) {
|
|
376
|
+
throw new Error(`${type} name cannot exceed 255 characters`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// RabbitMQ naming conventions
|
|
380
|
+
const invalidChars = /[^a-zA-Z0-9._-]/;
|
|
381
|
+
if (invalidChars.test(name)) {
|
|
382
|
+
throw new Error(`${type} name contains invalid characters. Only alphanumeric, dots, hyphens, and underscores are allowed`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Enhanced ensure exchange with validation
|
|
388
|
+
*/
|
|
389
|
+
public async ensureExchangeWithValidation(
|
|
390
|
+
exchange: string,
|
|
391
|
+
type: string = 'topic',
|
|
392
|
+
options: ExchangeOptions = {}
|
|
393
|
+
): Promise<void> {
|
|
394
|
+
this.validateResourceName(exchange, 'Exchange');
|
|
395
|
+
|
|
396
|
+
const validTypes = ['direct', 'topic', 'fanout', 'headers'];
|
|
397
|
+
if (!validTypes.includes(type)) {
|
|
398
|
+
throw new Error(`Invalid exchange type '${type}'. Valid types: ${validTypes.join(', ')}`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return this.ensureExchange(exchange, type, options);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Enhanced ensure queue with validation
|
|
406
|
+
*/
|
|
407
|
+
public async ensureQueueWithValidation(queue: string, options: QueueOptions = {}): Promise<void> {
|
|
408
|
+
this.validateResourceName(queue, 'Queue');
|
|
409
|
+
return this.ensureQueue(queue, options);
|
|
410
|
+
}
|
|
411
|
+
}
|