@onebun/core 0.1.2 → 0.1.3
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/package.json +1 -1
- package/src/{application.test.ts → application/application.test.ts} +6 -5
- package/src/{application.ts → application/application.ts} +131 -12
- package/src/application/index.ts +9 -0
- package/src/{multi-service-application.test.ts → application/multi-service-application.test.ts} +2 -1
- package/src/{multi-service-application.ts → application/multi-service-application.ts} +2 -1
- package/src/{multi-service.types.ts → application/multi-service.types.ts} +1 -1
- package/src/{decorators.test.ts → decorators/decorators.test.ts} +2 -1
- package/src/{decorators.ts → decorators/decorators.ts} +3 -2
- package/src/decorators/index.ts +15 -0
- package/src/index.ts +47 -134
- package/src/module/index.ts +12 -0
- package/src/{module.test.ts → module/module.test.ts} +3 -2
- package/src/{module.ts → module/module.ts} +6 -5
- package/src/queue/adapters/index.ts +8 -0
- package/src/queue/adapters/memory.adapter.test.ts +405 -0
- package/src/queue/adapters/memory.adapter.ts +509 -0
- package/src/queue/adapters/redis.adapter.ts +673 -0
- package/src/queue/cron-expression.test.ts +145 -0
- package/src/queue/cron-expression.ts +115 -0
- package/src/queue/cron-parser.test.ts +185 -0
- package/src/queue/cron-parser.ts +287 -0
- package/src/queue/decorators.test.ts +292 -0
- package/src/queue/decorators.ts +493 -0
- package/src/queue/docs-examples.test.ts +449 -0
- package/src/queue/guards.test.ts +309 -0
- package/src/queue/guards.ts +307 -0
- package/src/queue/index.ts +118 -0
- package/src/queue/pattern-matcher.test.ts +191 -0
- package/src/queue/pattern-matcher.ts +252 -0
- package/src/queue/queue.service.ts +421 -0
- package/src/queue/scheduler.test.ts +235 -0
- package/src/queue/scheduler.ts +379 -0
- package/src/queue/types.ts +502 -0
- package/src/redis/index.ts +8 -0
- package/src/{env-resolver.ts → service-client/env-resolver.ts} +1 -1
- package/src/service-client/index.ts +10 -0
- package/src/{service-client.test.ts → service-client/service-client.test.ts} +3 -2
- package/src/{service-client.ts → service-client/service-client.ts} +1 -1
- package/src/{service-definition.test.ts → service-client/service-definition.test.ts} +3 -2
- package/src/{service-definition.ts → service-client/service-definition.ts} +2 -2
- package/src/testing/index.ts +7 -0
- package/src/types.ts +34 -5
- package/src/websocket/index.ts +50 -0
- package/src/{ws-decorators.ts → websocket/ws-decorators.ts} +2 -1
- package/src/{ws-integration.test.ts → websocket/ws-integration.test.ts} +3 -2
- package/src/{ws-service-definition.ts → websocket/ws-service-definition.ts} +2 -1
- package/src/{ws-storage-redis.ts → websocket/ws-storage-redis.ts} +1 -1
- /package/src/{metadata.test.ts → decorators/metadata.test.ts} +0 -0
- /package/src/{metadata.ts → decorators/metadata.ts} +0 -0
- /package/src/{config.service.test.ts → module/config.service.test.ts} +0 -0
- /package/src/{config.service.ts → module/config.service.ts} +0 -0
- /package/src/{controller.test.ts → module/controller.test.ts} +0 -0
- /package/src/{controller.ts → module/controller.ts} +0 -0
- /package/src/{service.test.ts → module/service.test.ts} +0 -0
- /package/src/{service.ts → module/service.ts} +0 -0
- /package/src/{redis-client.ts → redis/redis-client.ts} +0 -0
- /package/src/{shared-redis.ts → redis/shared-redis.ts} +0 -0
- /package/src/{env-resolver.test.ts → service-client/env-resolver.test.ts} +0 -0
- /package/src/{service-client.types.ts → service-client/service-client.types.ts} +0 -0
- /package/src/{test-utils.test.ts → testing/test-utils.test.ts} +0 -0
- /package/src/{test-utils.ts → testing/test-utils.ts} +0 -0
- /package/src/{ws-base-gateway.test.ts → websocket/ws-base-gateway.test.ts} +0 -0
- /package/src/{ws-base-gateway.ts → websocket/ws-base-gateway.ts} +0 -0
- /package/src/{ws-client.test.ts → websocket/ws-client.test.ts} +0 -0
- /package/src/{ws-client.ts → websocket/ws-client.ts} +0 -0
- /package/src/{ws-client.types.ts → websocket/ws-client.types.ts} +0 -0
- /package/src/{ws-decorators.test.ts → websocket/ws-decorators.test.ts} +0 -0
- /package/src/{ws-guards.test.ts → websocket/ws-guards.test.ts} +0 -0
- /package/src/{ws-guards.ts → websocket/ws-guards.ts} +0 -0
- /package/src/{ws-handler.ts → websocket/ws-handler.ts} +0 -0
- /package/src/{ws-pattern-matcher.test.ts → websocket/ws-pattern-matcher.test.ts} +0 -0
- /package/src/{ws-pattern-matcher.ts → websocket/ws-pattern-matcher.ts} +0 -0
- /package/src/{ws-socketio-protocol.test.ts → websocket/ws-socketio-protocol.test.ts} +0 -0
- /package/src/{ws-socketio-protocol.ts → websocket/ws-socketio-protocol.ts} +0 -0
- /package/src/{ws-storage-memory.test.ts → websocket/ws-storage-memory.test.ts} +0 -0
- /package/src/{ws-storage-memory.ts → websocket/ws-storage-memory.ts} +0 -0
- /package/src/{ws-storage.ts → websocket/ws-storage.ts} +0 -0
- /package/src/{ws.types.ts → websocket/ws.types.ts} +0 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queue Decorators
|
|
3
|
+
*
|
|
4
|
+
* Unified decorators for queue message handling and scheduling.
|
|
5
|
+
* These decorators work with any queue adapter (memory, redis, nats, jetstream).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
SubscribeOptions,
|
|
10
|
+
CronDecoratorOptions,
|
|
11
|
+
IntervalDecoratorOptions,
|
|
12
|
+
TimeoutDecoratorOptions,
|
|
13
|
+
MessageGuard,
|
|
14
|
+
MessageGuardConstructor,
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
import { defineMetadata, getMetadata } from '../decorators/metadata';
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Metadata Keys
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export const QUEUE_METADATA = {
|
|
24
|
+
SUBSCRIBE: 'queue:subscribe',
|
|
25
|
+
SUBSCRIBE_OPTIONS: 'queue:subscribe:options',
|
|
26
|
+
CRON: 'queue:cron',
|
|
27
|
+
INTERVAL: 'queue:interval',
|
|
28
|
+
TIMEOUT: 'queue:timeout',
|
|
29
|
+
GUARDS: 'queue:guards',
|
|
30
|
+
ON_READY: 'queue:on_ready',
|
|
31
|
+
ON_ERROR: 'queue:on_error',
|
|
32
|
+
ON_MESSAGE_FAILED: 'queue:on_message_failed',
|
|
33
|
+
ON_MESSAGE_RECEIVED: 'queue:on_message_received',
|
|
34
|
+
ON_MESSAGE_PROCESSED: 'queue:on_message_processed',
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Subscribe Decorator
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe handler metadata
|
|
43
|
+
*/
|
|
44
|
+
export interface SubscribeMetadata {
|
|
45
|
+
pattern: string;
|
|
46
|
+
options?: SubscribeOptions;
|
|
47
|
+
propertyKey: string | symbol;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Decorator for subscribing to queue messages
|
|
52
|
+
*
|
|
53
|
+
* @param pattern - Message pattern to subscribe to (supports wildcards)
|
|
54
|
+
* @param options - Subscription options
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Simple subscription with auto-ack
|
|
59
|
+
* \@Subscribe('orders.created')
|
|
60
|
+
* async handleOrderCreated(message: Message<OrderData>) {
|
|
61
|
+
* await this.processOrder(message.data);
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* // Subscription with manual ack
|
|
65
|
+
* \@Subscribe('orders.*', { ackMode: 'manual', group: 'order-processors' })
|
|
66
|
+
* async handleOrder(message: Message<OrderData>) {
|
|
67
|
+
* try {
|
|
68
|
+
* await this.processOrder(message.data);
|
|
69
|
+
* await message.ack();
|
|
70
|
+
* } catch (error) {
|
|
71
|
+
* await message.nack(true); // requeue
|
|
72
|
+
* }
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* // Multi-level wildcard
|
|
76
|
+
* \@Subscribe('events.#')
|
|
77
|
+
* async handleAllEvents(message: Message<EventData>) {
|
|
78
|
+
* console.log('Event:', message.pattern, message.data);
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
83
|
+
export function Subscribe(pattern: string, options?: SubscribeOptions): MethodDecorator {
|
|
84
|
+
return (target, propertyKey, descriptor) => {
|
|
85
|
+
// Get existing subscriptions or create new array
|
|
86
|
+
const subscriptions: SubscribeMetadata[] =
|
|
87
|
+
getMetadata(QUEUE_METADATA.SUBSCRIBE, target.constructor) || [];
|
|
88
|
+
|
|
89
|
+
// Add this subscription
|
|
90
|
+
subscriptions.push({
|
|
91
|
+
pattern,
|
|
92
|
+
options,
|
|
93
|
+
propertyKey,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Store metadata
|
|
97
|
+
defineMetadata(QUEUE_METADATA.SUBSCRIBE, subscriptions, target.constructor);
|
|
98
|
+
|
|
99
|
+
return descriptor;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Scheduling Decorators
|
|
105
|
+
// ============================================================================
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Cron job metadata
|
|
109
|
+
*/
|
|
110
|
+
export interface CronMetadata {
|
|
111
|
+
expression: string;
|
|
112
|
+
options: CronDecoratorOptions;
|
|
113
|
+
propertyKey: string | symbol;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Decorator for cron-based scheduled jobs
|
|
118
|
+
*
|
|
119
|
+
* The decorated method should return the data to be published.
|
|
120
|
+
*
|
|
121
|
+
* @param expression - Cron expression (5 or 6 fields)
|
|
122
|
+
* @param options - Cron options including the pattern to publish to
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* import { CronExpression } from '\@onebun/core';
|
|
127
|
+
*
|
|
128
|
+
* // Daily report at 9 AM
|
|
129
|
+
* \@Cron('0 0 9 * * *', { pattern: 'reports.daily' })
|
|
130
|
+
* getDailyReportData(): ReportData {
|
|
131
|
+
* return { type: 'daily', date: new Date() };
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* // Using CronExpression enum
|
|
135
|
+
* \@Cron(CronExpression.EVERY_HOUR, { pattern: 'health.check' })
|
|
136
|
+
* getHealthData(): HealthData {
|
|
137
|
+
* return { status: 'ok', timestamp: Date.now() };
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
142
|
+
export function Cron(expression: string, options: CronDecoratorOptions): MethodDecorator {
|
|
143
|
+
return (target, propertyKey, descriptor) => {
|
|
144
|
+
const cronJobs: CronMetadata[] = getMetadata(QUEUE_METADATA.CRON, target.constructor) || [];
|
|
145
|
+
|
|
146
|
+
cronJobs.push({
|
|
147
|
+
expression,
|
|
148
|
+
options: {
|
|
149
|
+
...options,
|
|
150
|
+
name: options.name ?? String(propertyKey),
|
|
151
|
+
},
|
|
152
|
+
propertyKey,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
defineMetadata(QUEUE_METADATA.CRON, cronJobs, target.constructor);
|
|
156
|
+
|
|
157
|
+
return descriptor;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Interval job metadata
|
|
163
|
+
*/
|
|
164
|
+
export interface IntervalMetadata {
|
|
165
|
+
milliseconds: number;
|
|
166
|
+
options: IntervalDecoratorOptions;
|
|
167
|
+
propertyKey: string | symbol;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Decorator for interval-based scheduled jobs
|
|
172
|
+
*
|
|
173
|
+
* The decorated method should return the data to be published.
|
|
174
|
+
*
|
|
175
|
+
* @param milliseconds - Interval in milliseconds
|
|
176
|
+
* @param options - Interval options including the pattern to publish to
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* // Every minute
|
|
181
|
+
* \@Interval(60000, { pattern: 'health.check' })
|
|
182
|
+
* getHealthData(): HealthData {
|
|
183
|
+
* return { timestamp: Date.now() };
|
|
184
|
+
* }
|
|
185
|
+
*
|
|
186
|
+
* // Every 5 seconds
|
|
187
|
+
* \@Interval(5000, { pattern: 'metrics.collect' })
|
|
188
|
+
* getMetrics(): MetricsData {
|
|
189
|
+
* return { cpu: process.cpuUsage(), memory: process.memoryUsage() };
|
|
190
|
+
* }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
194
|
+
export function Interval(milliseconds: number, options: IntervalDecoratorOptions): MethodDecorator {
|
|
195
|
+
return (target, propertyKey, descriptor) => {
|
|
196
|
+
const intervals: IntervalMetadata[] =
|
|
197
|
+
getMetadata(QUEUE_METADATA.INTERVAL, target.constructor) || [];
|
|
198
|
+
|
|
199
|
+
intervals.push({
|
|
200
|
+
milliseconds,
|
|
201
|
+
options: {
|
|
202
|
+
...options,
|
|
203
|
+
name: options.name ?? String(propertyKey),
|
|
204
|
+
},
|
|
205
|
+
propertyKey,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
defineMetadata(QUEUE_METADATA.INTERVAL, intervals, target.constructor);
|
|
209
|
+
|
|
210
|
+
return descriptor;
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Timeout job metadata
|
|
216
|
+
*/
|
|
217
|
+
export interface TimeoutMetadata {
|
|
218
|
+
milliseconds: number;
|
|
219
|
+
options: TimeoutDecoratorOptions;
|
|
220
|
+
propertyKey: string | symbol;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Decorator for one-time delayed jobs
|
|
225
|
+
*
|
|
226
|
+
* The decorated method should return the data to be published.
|
|
227
|
+
*
|
|
228
|
+
* @param milliseconds - Delay in milliseconds after application start
|
|
229
|
+
* @param options - Timeout options including the pattern to publish to
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* // Publish init complete after 5 seconds
|
|
234
|
+
* \@Timeout(5000, { pattern: 'init.complete' })
|
|
235
|
+
* getInitData(): InitData {
|
|
236
|
+
* return { startedAt: this.startTime };
|
|
237
|
+
* }
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
241
|
+
export function Timeout(milliseconds: number, options: TimeoutDecoratorOptions): MethodDecorator {
|
|
242
|
+
return (target, propertyKey, descriptor) => {
|
|
243
|
+
const timeouts: TimeoutMetadata[] =
|
|
244
|
+
getMetadata(QUEUE_METADATA.TIMEOUT, target.constructor) || [];
|
|
245
|
+
|
|
246
|
+
timeouts.push({
|
|
247
|
+
milliseconds,
|
|
248
|
+
options: {
|
|
249
|
+
...options,
|
|
250
|
+
name: options.name ?? String(propertyKey),
|
|
251
|
+
},
|
|
252
|
+
propertyKey,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
defineMetadata(QUEUE_METADATA.TIMEOUT, timeouts, target.constructor);
|
|
256
|
+
|
|
257
|
+
return descriptor;
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Guard Decorator
|
|
263
|
+
// ============================================================================
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Decorator for applying guards to message handlers
|
|
267
|
+
*
|
|
268
|
+
* @param guards - Guards to apply (can be guard instances or constructors)
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* @UseMessageGuards(MessageAuthGuard)
|
|
273
|
+
* @Subscribe('orders.*')
|
|
274
|
+
* async handleOrder(message: Message<OrderData>) {
|
|
275
|
+
* // Only messages with authorization token will be processed
|
|
276
|
+
* }
|
|
277
|
+
*
|
|
278
|
+
* @UseMessageGuards(MessageAuthGuard, new MessageServiceGuard(['payment-service']))
|
|
279
|
+
* @Subscribe('payments.*')
|
|
280
|
+
* async handlePayment(message: Message<PaymentData>) {
|
|
281
|
+
* // Requires both auth and service check
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
export function UseMessageGuards(
|
|
286
|
+
...guards: Array<MessageGuard | MessageGuardConstructor>
|
|
287
|
+
): MethodDecorator {
|
|
288
|
+
return (target, propertyKey, descriptor) => {
|
|
289
|
+
defineMetadata(QUEUE_METADATA.GUARDS, guards, target.constructor, propertyKey);
|
|
290
|
+
|
|
291
|
+
return descriptor;
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ============================================================================
|
|
296
|
+
// Lifecycle Decorators
|
|
297
|
+
// ============================================================================
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Lifecycle handler metadata
|
|
301
|
+
*/
|
|
302
|
+
export interface LifecycleMetadata {
|
|
303
|
+
propertyKey: string | symbol;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Decorator for handling queue ready events
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* \@OnQueueReady()
|
|
312
|
+
* handleReady() {
|
|
313
|
+
* console.log('Queue connected and ready');
|
|
314
|
+
* }
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
318
|
+
export function OnQueueReady(): MethodDecorator {
|
|
319
|
+
return (target, propertyKey, descriptor) => {
|
|
320
|
+
const handlers: LifecycleMetadata[] =
|
|
321
|
+
getMetadata(QUEUE_METADATA.ON_READY, target.constructor) || [];
|
|
322
|
+
|
|
323
|
+
handlers.push({ propertyKey });
|
|
324
|
+
|
|
325
|
+
defineMetadata(QUEUE_METADATA.ON_READY, handlers, target.constructor);
|
|
326
|
+
|
|
327
|
+
return descriptor;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Decorator for handling queue error events
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* \@OnQueueError()
|
|
337
|
+
* handleError(error: Error) {
|
|
338
|
+
* console.error('Queue error:', error);
|
|
339
|
+
* }
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
343
|
+
export function OnQueueError(): MethodDecorator {
|
|
344
|
+
return (target, propertyKey, descriptor) => {
|
|
345
|
+
const handlers: LifecycleMetadata[] =
|
|
346
|
+
getMetadata(QUEUE_METADATA.ON_ERROR, target.constructor) || [];
|
|
347
|
+
|
|
348
|
+
handlers.push({ propertyKey });
|
|
349
|
+
|
|
350
|
+
defineMetadata(QUEUE_METADATA.ON_ERROR, handlers, target.constructor);
|
|
351
|
+
|
|
352
|
+
return descriptor;
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Decorator for handling message failure events
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
* ```typescript
|
|
361
|
+
* \@OnMessageFailed()
|
|
362
|
+
* handleFailed(message: Message, error: Error) {
|
|
363
|
+
* console.error(`Message ${message.id} failed:`, error);
|
|
364
|
+
* }
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
368
|
+
export function OnMessageFailed(): MethodDecorator {
|
|
369
|
+
return (target, propertyKey, descriptor) => {
|
|
370
|
+
const handlers: LifecycleMetadata[] =
|
|
371
|
+
getMetadata(QUEUE_METADATA.ON_MESSAGE_FAILED, target.constructor) || [];
|
|
372
|
+
|
|
373
|
+
handlers.push({ propertyKey });
|
|
374
|
+
|
|
375
|
+
defineMetadata(QUEUE_METADATA.ON_MESSAGE_FAILED, handlers, target.constructor);
|
|
376
|
+
|
|
377
|
+
return descriptor;
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Decorator for handling message received events
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```typescript
|
|
386
|
+
* \@OnMessageReceived()
|
|
387
|
+
* handleReceived(message: Message) {
|
|
388
|
+
* console.log(`Message received: ${message.id}`);
|
|
389
|
+
* }
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
393
|
+
export function OnMessageReceived(): MethodDecorator {
|
|
394
|
+
return (target, propertyKey, descriptor) => {
|
|
395
|
+
const handlers: LifecycleMetadata[] =
|
|
396
|
+
getMetadata(QUEUE_METADATA.ON_MESSAGE_RECEIVED, target.constructor) || [];
|
|
397
|
+
|
|
398
|
+
handlers.push({ propertyKey });
|
|
399
|
+
|
|
400
|
+
defineMetadata(QUEUE_METADATA.ON_MESSAGE_RECEIVED, handlers, target.constructor);
|
|
401
|
+
|
|
402
|
+
return descriptor;
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Decorator for handling message processed events
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```typescript
|
|
411
|
+
* \@OnMessageProcessed()
|
|
412
|
+
* handleProcessed(message: Message) {
|
|
413
|
+
* console.log(`Message processed: ${message.id}`);
|
|
414
|
+
* }
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
418
|
+
export function OnMessageProcessed(): MethodDecorator {
|
|
419
|
+
return (target, propertyKey, descriptor) => {
|
|
420
|
+
const handlers: LifecycleMetadata[] =
|
|
421
|
+
getMetadata(QUEUE_METADATA.ON_MESSAGE_PROCESSED, target.constructor) || [];
|
|
422
|
+
|
|
423
|
+
handlers.push({ propertyKey });
|
|
424
|
+
|
|
425
|
+
defineMetadata(QUEUE_METADATA.ON_MESSAGE_PROCESSED, handlers, target.constructor);
|
|
426
|
+
|
|
427
|
+
return descriptor;
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ============================================================================
|
|
432
|
+
// Metadata Helpers
|
|
433
|
+
// ============================================================================
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get all subscribe metadata for a class
|
|
437
|
+
*/
|
|
438
|
+
export function getSubscribeMetadata(target: object): SubscribeMetadata[] {
|
|
439
|
+
return getMetadata(QUEUE_METADATA.SUBSCRIBE, target) || [];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Get all cron metadata for a class
|
|
444
|
+
*/
|
|
445
|
+
export function getCronMetadata(target: object): CronMetadata[] {
|
|
446
|
+
return getMetadata(QUEUE_METADATA.CRON, target) || [];
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Get all interval metadata for a class
|
|
451
|
+
*/
|
|
452
|
+
export function getIntervalMetadata(target: object): IntervalMetadata[] {
|
|
453
|
+
return getMetadata(QUEUE_METADATA.INTERVAL, target) || [];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Get all timeout metadata for a class
|
|
458
|
+
*/
|
|
459
|
+
export function getTimeoutMetadata(target: object): TimeoutMetadata[] {
|
|
460
|
+
return getMetadata(QUEUE_METADATA.TIMEOUT, target) || [];
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Get guards for a method
|
|
465
|
+
*/
|
|
466
|
+
export function getMessageGuards(
|
|
467
|
+
target: object,
|
|
468
|
+
propertyKey: string | symbol,
|
|
469
|
+
): Array<MessageGuard | MessageGuardConstructor> {
|
|
470
|
+
return getMetadata(QUEUE_METADATA.GUARDS, target, propertyKey) || [];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get lifecycle handlers for a class
|
|
475
|
+
*/
|
|
476
|
+
export function getLifecycleHandlers(
|
|
477
|
+
target: object,
|
|
478
|
+
event: keyof typeof QUEUE_METADATA,
|
|
479
|
+
): LifecycleMetadata[] {
|
|
480
|
+
return getMetadata(QUEUE_METADATA[event], target) || [];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Check if a class has any queue decorators
|
|
485
|
+
*/
|
|
486
|
+
export function hasQueueDecorators(target: object): boolean {
|
|
487
|
+
return (
|
|
488
|
+
getSubscribeMetadata(target).length > 0 ||
|
|
489
|
+
getCronMetadata(target).length > 0 ||
|
|
490
|
+
getIntervalMetadata(target).length > 0 ||
|
|
491
|
+
getTimeoutMetadata(target).length > 0
|
|
492
|
+
);
|
|
493
|
+
}
|