@signaltree/events 7.4.1 → 7.5.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/dist/nestjs/event-bus.module.cjs +67 -1
- package/dist/nestjs/event-bus.module.js +66 -2
- package/dist/nestjs/event-bus.service.cjs +75 -0
- package/dist/nestjs/event-bus.service.js +75 -0
- package/dist/nestjs/index.cjs +1 -0
- package/dist/nestjs/index.js +1 -1
- package/dist/testing/mock-event-bus.cjs +64 -0
- package/dist/testing/mock-event-bus.js +65 -1
- package/package.json +1 -1
- package/src/nestjs/event-bus.module.d.ts +36 -1
- package/src/nestjs/event-bus.service.d.ts +66 -1
- package/src/nestjs/index.d.ts +3 -3
- package/src/testing/index.d.ts +1 -1
- package/src/testing/mock-event-bus.d.ts +66 -1
|
@@ -10,6 +10,55 @@ var idempotency = require('../core/idempotency.cjs');
|
|
|
10
10
|
var errorClassification = require('../core/error-classification.cjs');
|
|
11
11
|
|
|
12
12
|
var EventBusModule_1;
|
|
13
|
+
/**
|
|
14
|
+
* Preset definitions
|
|
15
|
+
*/
|
|
16
|
+
const QUEUE_PRESETS = {
|
|
17
|
+
/**
|
|
18
|
+
* Full priority-based queues (default) - separate queues per priority
|
|
19
|
+
*/
|
|
20
|
+
'priority-based': [{
|
|
21
|
+
name: 'events-critical',
|
|
22
|
+
priorities: ['critical'],
|
|
23
|
+
concurrency: 10
|
|
24
|
+
}, {
|
|
25
|
+
name: 'events-high',
|
|
26
|
+
priorities: ['high'],
|
|
27
|
+
concurrency: 8
|
|
28
|
+
}, {
|
|
29
|
+
name: 'events-normal',
|
|
30
|
+
priorities: ['normal'],
|
|
31
|
+
concurrency: 5
|
|
32
|
+
}, {
|
|
33
|
+
name: 'events-low',
|
|
34
|
+
priorities: ['low'],
|
|
35
|
+
concurrency: 3
|
|
36
|
+
}, {
|
|
37
|
+
name: 'events-bulk',
|
|
38
|
+
priorities: ['bulk'],
|
|
39
|
+
concurrency: 2,
|
|
40
|
+
rateLimit: {
|
|
41
|
+
max: 100,
|
|
42
|
+
duration: 1000
|
|
43
|
+
}
|
|
44
|
+
}],
|
|
45
|
+
/**
|
|
46
|
+
* Single queue for all priorities - simpler setup, uses BullMQ priority numbers
|
|
47
|
+
*/
|
|
48
|
+
'single-queue': [{
|
|
49
|
+
name: 'events',
|
|
50
|
+
priorities: ['critical', 'high', 'normal', 'low', 'bulk'],
|
|
51
|
+
concurrency: 10
|
|
52
|
+
}],
|
|
53
|
+
/**
|
|
54
|
+
* Minimal setup - one queue, low concurrency, good for development
|
|
55
|
+
*/
|
|
56
|
+
'minimal': [{
|
|
57
|
+
name: 'events',
|
|
58
|
+
priorities: ['critical', 'high', 'normal', 'low', 'bulk'],
|
|
59
|
+
concurrency: 3
|
|
60
|
+
}]
|
|
61
|
+
};
|
|
13
62
|
/**
|
|
14
63
|
* Default queue configuration based on priorities
|
|
15
64
|
*/
|
|
@@ -124,8 +173,23 @@ exports.EventBusModule = EventBusModule_1 = class EventBusModule {
|
|
|
124
173
|
exports: [eventBus_service.EventBusService, dlq_service.DlqService, tokens.EVENT_BUS_CONFIG, tokens.EVENT_REGISTRY, tokens.IDEMPOTENCY_STORE, tokens.ERROR_CLASSIFIER]
|
|
125
174
|
};
|
|
126
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Resolve queue configuration from preset or explicit config
|
|
178
|
+
*/
|
|
179
|
+
static resolveQueues(config) {
|
|
180
|
+
// Explicit queues take precedence
|
|
181
|
+
if (config.queues && config.queues.length > 0) {
|
|
182
|
+
return config.queues;
|
|
183
|
+
}
|
|
184
|
+
// Use preset if specified
|
|
185
|
+
if (config.preset) {
|
|
186
|
+
return QUEUE_PRESETS[config.preset];
|
|
187
|
+
}
|
|
188
|
+
// Default to priority-based
|
|
189
|
+
return DEFAULT_QUEUES;
|
|
190
|
+
}
|
|
127
191
|
static createProviders(config) {
|
|
128
|
-
const queues = config
|
|
192
|
+
const queues = EventBusModule_1.resolveQueues(config);
|
|
129
193
|
const fullConfig = {
|
|
130
194
|
...config,
|
|
131
195
|
queues,
|
|
@@ -150,3 +214,5 @@ exports.EventBusModule = EventBusModule_1 = class EventBusModule {
|
|
|
150
214
|
}
|
|
151
215
|
};
|
|
152
216
|
exports.EventBusModule = EventBusModule_1 = tslib.__decorate([common.Module({})], exports.EventBusModule);
|
|
217
|
+
|
|
218
|
+
exports.QUEUE_PRESETS = QUEUE_PRESETS;
|
|
@@ -8,6 +8,55 @@ import { createInMemoryIdempotencyStore } from '../core/idempotency.js';
|
|
|
8
8
|
import { createErrorClassifier } from '../core/error-classification.js';
|
|
9
9
|
|
|
10
10
|
var EventBusModule_1;
|
|
11
|
+
/**
|
|
12
|
+
* Preset definitions
|
|
13
|
+
*/
|
|
14
|
+
const QUEUE_PRESETS = {
|
|
15
|
+
/**
|
|
16
|
+
* Full priority-based queues (default) - separate queues per priority
|
|
17
|
+
*/
|
|
18
|
+
'priority-based': [{
|
|
19
|
+
name: 'events-critical',
|
|
20
|
+
priorities: ['critical'],
|
|
21
|
+
concurrency: 10
|
|
22
|
+
}, {
|
|
23
|
+
name: 'events-high',
|
|
24
|
+
priorities: ['high'],
|
|
25
|
+
concurrency: 8
|
|
26
|
+
}, {
|
|
27
|
+
name: 'events-normal',
|
|
28
|
+
priorities: ['normal'],
|
|
29
|
+
concurrency: 5
|
|
30
|
+
}, {
|
|
31
|
+
name: 'events-low',
|
|
32
|
+
priorities: ['low'],
|
|
33
|
+
concurrency: 3
|
|
34
|
+
}, {
|
|
35
|
+
name: 'events-bulk',
|
|
36
|
+
priorities: ['bulk'],
|
|
37
|
+
concurrency: 2,
|
|
38
|
+
rateLimit: {
|
|
39
|
+
max: 100,
|
|
40
|
+
duration: 1000
|
|
41
|
+
}
|
|
42
|
+
}],
|
|
43
|
+
/**
|
|
44
|
+
* Single queue for all priorities - simpler setup, uses BullMQ priority numbers
|
|
45
|
+
*/
|
|
46
|
+
'single-queue': [{
|
|
47
|
+
name: 'events',
|
|
48
|
+
priorities: ['critical', 'high', 'normal', 'low', 'bulk'],
|
|
49
|
+
concurrency: 10
|
|
50
|
+
}],
|
|
51
|
+
/**
|
|
52
|
+
* Minimal setup - one queue, low concurrency, good for development
|
|
53
|
+
*/
|
|
54
|
+
'minimal': [{
|
|
55
|
+
name: 'events',
|
|
56
|
+
priorities: ['critical', 'high', 'normal', 'low', 'bulk'],
|
|
57
|
+
concurrency: 3
|
|
58
|
+
}]
|
|
59
|
+
};
|
|
11
60
|
/**
|
|
12
61
|
* Default queue configuration based on priorities
|
|
13
62
|
*/
|
|
@@ -122,8 +171,23 @@ let EventBusModule = EventBusModule_1 = class EventBusModule {
|
|
|
122
171
|
exports: [EventBusService, DlqService, EVENT_BUS_CONFIG, EVENT_REGISTRY, IDEMPOTENCY_STORE, ERROR_CLASSIFIER]
|
|
123
172
|
};
|
|
124
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Resolve queue configuration from preset or explicit config
|
|
176
|
+
*/
|
|
177
|
+
static resolveQueues(config) {
|
|
178
|
+
// Explicit queues take precedence
|
|
179
|
+
if (config.queues && config.queues.length > 0) {
|
|
180
|
+
return config.queues;
|
|
181
|
+
}
|
|
182
|
+
// Use preset if specified
|
|
183
|
+
if (config.preset) {
|
|
184
|
+
return QUEUE_PRESETS[config.preset];
|
|
185
|
+
}
|
|
186
|
+
// Default to priority-based
|
|
187
|
+
return DEFAULT_QUEUES;
|
|
188
|
+
}
|
|
125
189
|
static createProviders(config) {
|
|
126
|
-
const queues = config
|
|
190
|
+
const queues = EventBusModule_1.resolveQueues(config);
|
|
127
191
|
const fullConfig = {
|
|
128
192
|
...config,
|
|
129
193
|
queues,
|
|
@@ -149,4 +213,4 @@ let EventBusModule = EventBusModule_1 = class EventBusModule {
|
|
|
149
213
|
};
|
|
150
214
|
EventBusModule = EventBusModule_1 = __decorate([Module({})], EventBusModule);
|
|
151
215
|
|
|
152
|
-
export { EventBusModule };
|
|
216
|
+
export { EventBusModule, QUEUE_PRESETS };
|
|
@@ -5,6 +5,7 @@ var common = require('@nestjs/common');
|
|
|
5
5
|
var bullmq = require('bullmq');
|
|
6
6
|
var factory = require('../core/factory.cjs');
|
|
7
7
|
var registry = require('../core/registry.cjs');
|
|
8
|
+
var types = require('../core/types.cjs');
|
|
8
9
|
var tokens = require('./tokens.cjs');
|
|
9
10
|
|
|
10
11
|
var EventBusService_1;
|
|
@@ -139,6 +140,80 @@ exports.EventBusService = EventBusService_1 = class EventBusService {
|
|
|
139
140
|
correlationId
|
|
140
141
|
};
|
|
141
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Create an event with defaults from module configuration
|
|
145
|
+
*
|
|
146
|
+
* This is a convenience method that auto-fills id, timestamp, version,
|
|
147
|
+
* correlationId, and metadata.source from the module config.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* // Instead of constructing the full event manually:
|
|
152
|
+
* const event = this.eventBus.createEvent('TradeProposalCreated', {
|
|
153
|
+
* tradeId: '123',
|
|
154
|
+
* initiatorId: 'user-1',
|
|
155
|
+
* recipientId: 'user-2',
|
|
156
|
+
* }, {
|
|
157
|
+
* actor: { id: userId, type: 'user' },
|
|
158
|
+
* priority: 'high',
|
|
159
|
+
* });
|
|
160
|
+
*
|
|
161
|
+
* await this.eventBus.publish(event);
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
createEvent(type, data, options = {}) {
|
|
165
|
+
const id = options.id ?? factory.generateEventId();
|
|
166
|
+
const correlationId = options.correlationId ?? factory.generateCorrelationId();
|
|
167
|
+
const timestamp = options.timestamp ?? new Date().toISOString();
|
|
168
|
+
const actor = options.actor ?? {
|
|
169
|
+
id: 'system',
|
|
170
|
+
type: 'system'
|
|
171
|
+
};
|
|
172
|
+
const metadata = {
|
|
173
|
+
source: this.config.source ?? 'signaltree',
|
|
174
|
+
environment: this.config.environment ?? process.env['NODE_ENV'] ?? 'development',
|
|
175
|
+
...options.metadata
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
id,
|
|
179
|
+
type,
|
|
180
|
+
version: options.version ?? types.DEFAULT_EVENT_VERSION,
|
|
181
|
+
timestamp,
|
|
182
|
+
correlationId,
|
|
183
|
+
causationId: options.causationId,
|
|
184
|
+
actor,
|
|
185
|
+
metadata,
|
|
186
|
+
data,
|
|
187
|
+
priority: options.priority,
|
|
188
|
+
aggregate: options.aggregate
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Convenience method to create and publish an event in one call
|
|
193
|
+
*
|
|
194
|
+
* Combines createEvent() and publish() for the common case.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* await this.eventBus.publishEvent('TradeProposalCreated', {
|
|
199
|
+
* tradeId: '123',
|
|
200
|
+
* initiatorId: 'user-1',
|
|
201
|
+
* }, {
|
|
202
|
+
* actor: { id: userId, type: 'user' },
|
|
203
|
+
* priority: 'high',
|
|
204
|
+
* });
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
async publishEvent(type, data, options = {}) {
|
|
208
|
+
const event = this.createEvent(type, data, options);
|
|
209
|
+
return this.publish(event, {
|
|
210
|
+
delay: options.delay,
|
|
211
|
+
queue: options.queue,
|
|
212
|
+
jobId: options.jobId,
|
|
213
|
+
jobOptions: options.jobOptions,
|
|
214
|
+
priority: options.priority
|
|
215
|
+
});
|
|
216
|
+
}
|
|
142
217
|
/**
|
|
143
218
|
* Publish multiple events in a batch
|
|
144
219
|
*/
|
|
@@ -3,6 +3,7 @@ import { Injectable, Inject, Logger } from '@nestjs/common';
|
|
|
3
3
|
import { Queue, QueueEvents } from 'bullmq';
|
|
4
4
|
import { generateEventId, generateCorrelationId } from '../core/factory.js';
|
|
5
5
|
import { EventRegistry } from '../core/registry.js';
|
|
6
|
+
import { DEFAULT_EVENT_VERSION } from '../core/types.js';
|
|
6
7
|
import { EVENT_BUS_CONFIG, EVENT_REGISTRY } from './tokens.js';
|
|
7
8
|
|
|
8
9
|
var EventBusService_1;
|
|
@@ -137,6 +138,80 @@ let EventBusService = EventBusService_1 = class EventBusService {
|
|
|
137
138
|
correlationId
|
|
138
139
|
};
|
|
139
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Create an event with defaults from module configuration
|
|
143
|
+
*
|
|
144
|
+
* This is a convenience method that auto-fills id, timestamp, version,
|
|
145
|
+
* correlationId, and metadata.source from the module config.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // Instead of constructing the full event manually:
|
|
150
|
+
* const event = this.eventBus.createEvent('TradeProposalCreated', {
|
|
151
|
+
* tradeId: '123',
|
|
152
|
+
* initiatorId: 'user-1',
|
|
153
|
+
* recipientId: 'user-2',
|
|
154
|
+
* }, {
|
|
155
|
+
* actor: { id: userId, type: 'user' },
|
|
156
|
+
* priority: 'high',
|
|
157
|
+
* });
|
|
158
|
+
*
|
|
159
|
+
* await this.eventBus.publish(event);
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
createEvent(type, data, options = {}) {
|
|
163
|
+
const id = options.id ?? generateEventId();
|
|
164
|
+
const correlationId = options.correlationId ?? generateCorrelationId();
|
|
165
|
+
const timestamp = options.timestamp ?? new Date().toISOString();
|
|
166
|
+
const actor = options.actor ?? {
|
|
167
|
+
id: 'system',
|
|
168
|
+
type: 'system'
|
|
169
|
+
};
|
|
170
|
+
const metadata = {
|
|
171
|
+
source: this.config.source ?? 'signaltree',
|
|
172
|
+
environment: this.config.environment ?? process.env['NODE_ENV'] ?? 'development',
|
|
173
|
+
...options.metadata
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
id,
|
|
177
|
+
type,
|
|
178
|
+
version: options.version ?? DEFAULT_EVENT_VERSION,
|
|
179
|
+
timestamp,
|
|
180
|
+
correlationId,
|
|
181
|
+
causationId: options.causationId,
|
|
182
|
+
actor,
|
|
183
|
+
metadata,
|
|
184
|
+
data,
|
|
185
|
+
priority: options.priority,
|
|
186
|
+
aggregate: options.aggregate
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Convenience method to create and publish an event in one call
|
|
191
|
+
*
|
|
192
|
+
* Combines createEvent() and publish() for the common case.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* await this.eventBus.publishEvent('TradeProposalCreated', {
|
|
197
|
+
* tradeId: '123',
|
|
198
|
+
* initiatorId: 'user-1',
|
|
199
|
+
* }, {
|
|
200
|
+
* actor: { id: userId, type: 'user' },
|
|
201
|
+
* priority: 'high',
|
|
202
|
+
* });
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
async publishEvent(type, data, options = {}) {
|
|
206
|
+
const event = this.createEvent(type, data, options);
|
|
207
|
+
return this.publish(event, {
|
|
208
|
+
delay: options.delay,
|
|
209
|
+
queue: options.queue,
|
|
210
|
+
jobId: options.jobId,
|
|
211
|
+
jobOptions: options.jobOptions,
|
|
212
|
+
priority: options.priority
|
|
213
|
+
});
|
|
214
|
+
}
|
|
140
215
|
/**
|
|
141
216
|
* Publish multiple events in a batch
|
|
142
217
|
*/
|
package/dist/nestjs/index.cjs
CHANGED
|
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "EventBusModule", {
|
|
|
13
13
|
enumerable: true,
|
|
14
14
|
get: function () { return eventBus_module.EventBusModule; }
|
|
15
15
|
});
|
|
16
|
+
exports.QUEUE_PRESETS = eventBus_module.QUEUE_PRESETS;
|
|
16
17
|
Object.defineProperty(exports, "EventBusService", {
|
|
17
18
|
enumerable: true,
|
|
18
19
|
get: function () { return eventBus_service.EventBusService; }
|
package/dist/nestjs/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { EventBusModule } from './event-bus.module.js';
|
|
1
|
+
export { EventBusModule, QUEUE_PRESETS } from './event-bus.module.js';
|
|
2
2
|
export { EventBusService } from './event-bus.service.js';
|
|
3
3
|
export { BaseSubscriber } from './base.subscriber.js';
|
|
4
4
|
export { DlqService } from './dlq.service.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var factory = require('../core/factory.cjs');
|
|
4
|
+
var types = require('../core/types.cjs');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Mock Event Bus for testing
|
|
@@ -37,9 +38,72 @@ class MockEventBus {
|
|
|
37
38
|
asyncDelayMs: 10,
|
|
38
39
|
autoGenerateIds: true,
|
|
39
40
|
throwOnError: false,
|
|
41
|
+
source: 'mock-event-bus',
|
|
42
|
+
environment: 'test',
|
|
40
43
|
...options
|
|
41
44
|
};
|
|
42
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Create an event with defaults (matches EventBusService.createEvent API)
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const event = mockBus.createEvent('TradeAccepted', {
|
|
52
|
+
* tradeId: '123',
|
|
53
|
+
* acceptedById: 'user-1',
|
|
54
|
+
* }, {
|
|
55
|
+
* actor: { id: 'user-1', type: 'user' },
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
createEvent(type, data, options = {}) {
|
|
60
|
+
const id = options.id ?? (this.options.autoGenerateIds ? factory.generateEventId() : 'test-event-id');
|
|
61
|
+
const correlationId = options.correlationId ?? factory.generateCorrelationId();
|
|
62
|
+
const timestamp = options.timestamp ?? new Date().toISOString();
|
|
63
|
+
const actor = options.actor ?? {
|
|
64
|
+
id: 'test-user',
|
|
65
|
+
type: 'user'
|
|
66
|
+
};
|
|
67
|
+
const metadata = {
|
|
68
|
+
source: this.options.source ?? 'mock-event-bus',
|
|
69
|
+
environment: this.options.environment ?? 'test',
|
|
70
|
+
...options.metadata
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
type,
|
|
75
|
+
version: options.version ?? types.DEFAULT_EVENT_VERSION,
|
|
76
|
+
timestamp,
|
|
77
|
+
correlationId,
|
|
78
|
+
causationId: options.causationId,
|
|
79
|
+
actor,
|
|
80
|
+
metadata,
|
|
81
|
+
data,
|
|
82
|
+
priority: options.priority,
|
|
83
|
+
aggregate: options.aggregate
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Convenience method to create and publish an event in one call
|
|
88
|
+
* (matches EventBusService.publishEvent API)
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* await mockBus.publishEvent('TradeAccepted', {
|
|
93
|
+
* tradeId: '123',
|
|
94
|
+
* acceptedById: 'user-1',
|
|
95
|
+
* }, {
|
|
96
|
+
* actor: { id: 'user-1', type: 'user' },
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
async publishEvent(type, data, options = {}) {
|
|
101
|
+
const event = this.createEvent(type, data, options);
|
|
102
|
+
return this.publish(event, {
|
|
103
|
+
queue: options.queue,
|
|
104
|
+
delay: options.delay
|
|
105
|
+
});
|
|
106
|
+
}
|
|
43
107
|
/**
|
|
44
108
|
* Publish an event
|
|
45
109
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { generateEventId, generateCorrelationId } from '../core/factory.js';
|
|
2
|
+
import { DEFAULT_EVENT_VERSION } from '../core/types.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Mock Event Bus for testing
|
|
@@ -35,9 +36,72 @@ class MockEventBus {
|
|
|
35
36
|
asyncDelayMs: 10,
|
|
36
37
|
autoGenerateIds: true,
|
|
37
38
|
throwOnError: false,
|
|
39
|
+
source: 'mock-event-bus',
|
|
40
|
+
environment: 'test',
|
|
38
41
|
...options
|
|
39
42
|
};
|
|
40
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Create an event with defaults (matches EventBusService.createEvent API)
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const event = mockBus.createEvent('TradeAccepted', {
|
|
50
|
+
* tradeId: '123',
|
|
51
|
+
* acceptedById: 'user-1',
|
|
52
|
+
* }, {
|
|
53
|
+
* actor: { id: 'user-1', type: 'user' },
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
createEvent(type, data, options = {}) {
|
|
58
|
+
const id = options.id ?? (this.options.autoGenerateIds ? generateEventId() : 'test-event-id');
|
|
59
|
+
const correlationId = options.correlationId ?? generateCorrelationId();
|
|
60
|
+
const timestamp = options.timestamp ?? new Date().toISOString();
|
|
61
|
+
const actor = options.actor ?? {
|
|
62
|
+
id: 'test-user',
|
|
63
|
+
type: 'user'
|
|
64
|
+
};
|
|
65
|
+
const metadata = {
|
|
66
|
+
source: this.options.source ?? 'mock-event-bus',
|
|
67
|
+
environment: this.options.environment ?? 'test',
|
|
68
|
+
...options.metadata
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
id,
|
|
72
|
+
type,
|
|
73
|
+
version: options.version ?? DEFAULT_EVENT_VERSION,
|
|
74
|
+
timestamp,
|
|
75
|
+
correlationId,
|
|
76
|
+
causationId: options.causationId,
|
|
77
|
+
actor,
|
|
78
|
+
metadata,
|
|
79
|
+
data,
|
|
80
|
+
priority: options.priority,
|
|
81
|
+
aggregate: options.aggregate
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convenience method to create and publish an event in one call
|
|
86
|
+
* (matches EventBusService.publishEvent API)
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* await mockBus.publishEvent('TradeAccepted', {
|
|
91
|
+
* tradeId: '123',
|
|
92
|
+
* acceptedById: 'user-1',
|
|
93
|
+
* }, {
|
|
94
|
+
* actor: { id: 'user-1', type: 'user' },
|
|
95
|
+
* });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
async publishEvent(type, data, options = {}) {
|
|
99
|
+
const event = this.createEvent(type, data, options);
|
|
100
|
+
return this.publish(event, {
|
|
101
|
+
queue: options.queue,
|
|
102
|
+
delay: options.delay
|
|
103
|
+
});
|
|
104
|
+
}
|
|
41
105
|
/**
|
|
42
106
|
* Publish an event
|
|
43
107
|
*/
|
package/package.json
CHANGED
|
@@ -36,14 +36,45 @@ export interface QueueConfig {
|
|
|
36
36
|
duration: number;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Preset queue configurations for common use cases
|
|
41
|
+
*/
|
|
42
|
+
export type QueuePreset = 'priority-based' | 'single-queue' | 'minimal';
|
|
43
|
+
/**
|
|
44
|
+
* Preset definitions
|
|
45
|
+
*/
|
|
46
|
+
export declare const QUEUE_PRESETS: Record<QueuePreset, QueueConfig[]>;
|
|
39
47
|
/**
|
|
40
48
|
* EventBus module configuration
|
|
41
49
|
*/
|
|
42
50
|
export interface EventBusModuleConfig {
|
|
43
51
|
/** Redis connection config */
|
|
44
52
|
redis: RedisConfig;
|
|
45
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Queue preset for quick configuration.
|
|
55
|
+
* Use this OR `queues`, not both.
|
|
56
|
+
*
|
|
57
|
+
* - 'priority-based': Separate queues per priority (recommended for production)
|
|
58
|
+
* - 'single-queue': One queue with priority numbers (simpler setup)
|
|
59
|
+
* - 'minimal': Development-friendly, low concurrency
|
|
60
|
+
*
|
|
61
|
+
* @default 'priority-based'
|
|
62
|
+
*/
|
|
63
|
+
preset?: QueuePreset;
|
|
64
|
+
/** Queue configuration (defaults to priority-based queues if no preset specified) */
|
|
46
65
|
queues?: QueueConfig[];
|
|
66
|
+
/**
|
|
67
|
+
* Service/module name for event metadata.source
|
|
68
|
+
* Used by createEvent() and publishEvent() convenience methods.
|
|
69
|
+
* @default 'signaltree'
|
|
70
|
+
*/
|
|
71
|
+
source?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Environment name for event metadata.environment
|
|
74
|
+
* Used by createEvent() and publishEvent() convenience methods.
|
|
75
|
+
* @default process.env.NODE_ENV || 'development'
|
|
76
|
+
*/
|
|
77
|
+
environment?: string;
|
|
47
78
|
/** Event registry configuration */
|
|
48
79
|
registry?: EventRegistryConfig;
|
|
49
80
|
/** Custom idempotency store (defaults to in-memory) */
|
|
@@ -113,5 +144,9 @@ export declare class EventBusModule {
|
|
|
113
144
|
* ```
|
|
114
145
|
*/
|
|
115
146
|
static forRootAsync(asyncConfig: EventBusModuleAsyncConfig): DynamicModule;
|
|
147
|
+
/**
|
|
148
|
+
* Resolve queue configuration from preset or explicit config
|
|
149
|
+
*/
|
|
150
|
+
private static resolveQueues;
|
|
116
151
|
private static createProviders;
|
|
117
152
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { Queue } from 'bullmq';
|
|
3
3
|
import { EventRegistry } from '../core/registry';
|
|
4
|
-
import { BaseEvent, EventPriority } from '../core/types';
|
|
4
|
+
import { BaseEvent, EventActor, EventMetadata, EventPriority, EventVersion } from '../core/types';
|
|
5
5
|
import { EventBusModuleConfig } from './event-bus.module';
|
|
6
6
|
/**
|
|
7
7
|
* EventBus Service - Publish events to BullMQ queues
|
|
@@ -46,6 +46,32 @@ export interface PublishResult {
|
|
|
46
46
|
/** Correlation ID */
|
|
47
47
|
correlationId: string;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Options for creating an event via EventBusService.createEvent()
|
|
51
|
+
*/
|
|
52
|
+
export interface CreateEventServiceOptions {
|
|
53
|
+
/** Override event ID */
|
|
54
|
+
id?: string;
|
|
55
|
+
/** Correlation ID for request tracing */
|
|
56
|
+
correlationId?: string;
|
|
57
|
+
/** Causation ID (parent event) */
|
|
58
|
+
causationId?: string;
|
|
59
|
+
/** Actor who triggered the event */
|
|
60
|
+
actor?: EventActor;
|
|
61
|
+
/** Additional metadata */
|
|
62
|
+
metadata?: Partial<EventMetadata>;
|
|
63
|
+
/** Event priority */
|
|
64
|
+
priority?: EventPriority;
|
|
65
|
+
/** Schema version override */
|
|
66
|
+
version?: EventVersion;
|
|
67
|
+
/** Aggregate info */
|
|
68
|
+
aggregate?: {
|
|
69
|
+
type: string;
|
|
70
|
+
id: string;
|
|
71
|
+
};
|
|
72
|
+
/** Timestamp override (for testing/replay) */
|
|
73
|
+
timestamp?: string;
|
|
74
|
+
}
|
|
49
75
|
export declare class EventBusService implements OnModuleInit, OnModuleDestroy {
|
|
50
76
|
private readonly config;
|
|
51
77
|
private readonly registry;
|
|
@@ -73,6 +99,45 @@ export declare class EventBusService implements OnModuleInit, OnModuleDestroy {
|
|
|
73
99
|
* ```
|
|
74
100
|
*/
|
|
75
101
|
publish<T extends BaseEvent>(event: Omit<T, 'id' | 'timestamp'> & Partial<Pick<T, 'id' | 'timestamp'>>, options?: PublishOptions): Promise<PublishResult>;
|
|
102
|
+
/**
|
|
103
|
+
* Create an event with defaults from module configuration
|
|
104
|
+
*
|
|
105
|
+
* This is a convenience method that auto-fills id, timestamp, version,
|
|
106
|
+
* correlationId, and metadata.source from the module config.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // Instead of constructing the full event manually:
|
|
111
|
+
* const event = this.eventBus.createEvent('TradeProposalCreated', {
|
|
112
|
+
* tradeId: '123',
|
|
113
|
+
* initiatorId: 'user-1',
|
|
114
|
+
* recipientId: 'user-2',
|
|
115
|
+
* }, {
|
|
116
|
+
* actor: { id: userId, type: 'user' },
|
|
117
|
+
* priority: 'high',
|
|
118
|
+
* });
|
|
119
|
+
*
|
|
120
|
+
* await this.eventBus.publish(event);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
createEvent<TType extends string, TData>(type: TType, data: TData, options?: CreateEventServiceOptions): BaseEvent<TType, TData>;
|
|
124
|
+
/**
|
|
125
|
+
* Convenience method to create and publish an event in one call
|
|
126
|
+
*
|
|
127
|
+
* Combines createEvent() and publish() for the common case.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* await this.eventBus.publishEvent('TradeProposalCreated', {
|
|
132
|
+
* tradeId: '123',
|
|
133
|
+
* initiatorId: 'user-1',
|
|
134
|
+
* }, {
|
|
135
|
+
* actor: { id: userId, type: 'user' },
|
|
136
|
+
* priority: 'high',
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
publishEvent<TType extends string, TData>(type: TType, data: TData, options?: CreateEventServiceOptions & Pick<PublishOptions, 'delay' | 'queue' | 'jobId' | 'jobOptions'>): Promise<PublishResult>;
|
|
76
141
|
/**
|
|
77
142
|
* Publish multiple events in a batch
|
|
78
143
|
*/
|
package/src/nestjs/index.d.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* NestJS integration for event-driven architecture.
|
|
5
5
|
* Provides EventBusModule, BaseSubscriber, and DLQ handling.
|
|
6
6
|
*/
|
|
7
|
-
export { EventBusModule } from './event-bus.module';
|
|
8
|
-
export type { EventBusModuleConfig, EventBusModuleAsyncConfig, } from './event-bus.module';
|
|
7
|
+
export { EventBusModule, QUEUE_PRESETS } from './event-bus.module';
|
|
8
|
+
export type { EventBusModuleConfig, EventBusModuleAsyncConfig, QueueConfig, QueuePreset, RedisConfig, } from './event-bus.module';
|
|
9
9
|
export { EventBusService } from './event-bus.service';
|
|
10
|
-
export type { PublishOptions, PublishResult } from './event-bus.service';
|
|
10
|
+
export type { PublishOptions, PublishResult, CreateEventServiceOptions } from './event-bus.service';
|
|
11
11
|
export { BaseSubscriber } from './base.subscriber';
|
|
12
12
|
export type { SubscriberConfig, ProcessingResult, SubscriberMetrics, } from './base.subscriber';
|
|
13
13
|
export { DlqService } from './dlq.service';
|
package/src/testing/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides mocks, factories, and helpers for unit testing.
|
|
6
6
|
*/
|
|
7
7
|
export { MockEventBus, createMockEventBus } from './mock-event-bus';
|
|
8
|
-
export type { MockEventBusOptions, PublishedEvent } from './mock-event-bus';
|
|
8
|
+
export type { MockEventBusOptions, PublishedEvent, MockCreateEventOptions } from './mock-event-bus';
|
|
9
9
|
export { createTestEvent, createTestEventFactory } from './factories';
|
|
10
10
|
export type { TestEventFactory, TestEventOptions } from './factories';
|
|
11
11
|
export { EventAssertions, createEventAssertions } from './assertions';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseEvent } from '../core/types';
|
|
1
|
+
import { BaseEvent, EventActor, EventMetadata, EventPriority, EventVersion } from '../core/types';
|
|
2
2
|
/**
|
|
3
3
|
* Mock Event Bus - In-memory event bus for testing
|
|
4
4
|
*
|
|
@@ -32,6 +32,36 @@ export interface MockEventBusOptions {
|
|
|
32
32
|
autoGenerateIds?: boolean;
|
|
33
33
|
/** Throw on publish errors */
|
|
34
34
|
throwOnError?: boolean;
|
|
35
|
+
/** Source for event metadata (used by createEvent) */
|
|
36
|
+
source?: string;
|
|
37
|
+
/** Environment for event metadata (used by createEvent) */
|
|
38
|
+
environment?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Options for creating an event via MockEventBus.createEvent()
|
|
42
|
+
*/
|
|
43
|
+
export interface MockCreateEventOptions {
|
|
44
|
+
/** Override event ID */
|
|
45
|
+
id?: string;
|
|
46
|
+
/** Correlation ID for request tracing */
|
|
47
|
+
correlationId?: string;
|
|
48
|
+
/** Causation ID (parent event) */
|
|
49
|
+
causationId?: string;
|
|
50
|
+
/** Actor who triggered the event */
|
|
51
|
+
actor?: EventActor;
|
|
52
|
+
/** Additional metadata */
|
|
53
|
+
metadata?: Partial<EventMetadata>;
|
|
54
|
+
/** Event priority */
|
|
55
|
+
priority?: EventPriority;
|
|
56
|
+
/** Schema version override */
|
|
57
|
+
version?: EventVersion;
|
|
58
|
+
/** Aggregate info */
|
|
59
|
+
aggregate?: {
|
|
60
|
+
type: string;
|
|
61
|
+
id: string;
|
|
62
|
+
};
|
|
63
|
+
/** Timestamp override (for testing/replay) */
|
|
64
|
+
timestamp?: string;
|
|
35
65
|
}
|
|
36
66
|
/**
|
|
37
67
|
* Mock Event Bus for testing
|
|
@@ -62,6 +92,41 @@ export declare class MockEventBus {
|
|
|
62
92
|
private subscriptions;
|
|
63
93
|
private allSubscriptions;
|
|
64
94
|
constructor(options?: MockEventBusOptions);
|
|
95
|
+
/**
|
|
96
|
+
* Create an event with defaults (matches EventBusService.createEvent API)
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const event = mockBus.createEvent('TradeAccepted', {
|
|
101
|
+
* tradeId: '123',
|
|
102
|
+
* acceptedById: 'user-1',
|
|
103
|
+
* }, {
|
|
104
|
+
* actor: { id: 'user-1', type: 'user' },
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
createEvent<TType extends string, TData>(type: TType, data: TData, options?: MockCreateEventOptions): BaseEvent<TType, TData>;
|
|
109
|
+
/**
|
|
110
|
+
* Convenience method to create and publish an event in one call
|
|
111
|
+
* (matches EventBusService.publishEvent API)
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* await mockBus.publishEvent('TradeAccepted', {
|
|
116
|
+
* tradeId: '123',
|
|
117
|
+
* acceptedById: 'user-1',
|
|
118
|
+
* }, {
|
|
119
|
+
* actor: { id: 'user-1', type: 'user' },
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
publishEvent<TType extends string, TData>(type: TType, data: TData, options?: MockCreateEventOptions & {
|
|
124
|
+
queue?: string;
|
|
125
|
+
delay?: number;
|
|
126
|
+
}): Promise<{
|
|
127
|
+
eventId: string;
|
|
128
|
+
queue: string;
|
|
129
|
+
}>;
|
|
65
130
|
/**
|
|
66
131
|
* Publish an event
|
|
67
132
|
*/
|