@zdavison/matador 2.0.9 → 2.0.11
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/checkpoint/context.d.ts +59 -0
- package/dist/checkpoint/context.d.ts.map +1 -0
- package/dist/checkpoint/context.js +140 -0
- package/dist/checkpoint/context.test.d.ts +2 -0
- package/dist/checkpoint/context.test.d.ts.map +1 -0
- package/dist/checkpoint/context.test.js +424 -0
- package/dist/checkpoint/index.d.ts +7 -0
- package/dist/checkpoint/index.d.ts.map +1 -0
- package/dist/checkpoint/index.js +6 -0
- package/dist/checkpoint/stores/memory.d.ts +29 -0
- package/dist/checkpoint/stores/memory.d.ts.map +1 -0
- package/dist/checkpoint/stores/memory.js +39 -0
- package/{src/checkpoint/stores/noop.ts → dist/checkpoint/stores/noop.d.ts} +5 -13
- package/dist/checkpoint/stores/noop.d.ts.map +1 -0
- package/dist/checkpoint/stores/noop.js +18 -0
- package/dist/checkpoint/stores/stores.test.d.ts +2 -0
- package/dist/checkpoint/stores/stores.test.d.ts.map +1 -0
- package/dist/checkpoint/stores/stores.test.js +146 -0
- package/dist/checkpoint/types.d.ts +119 -0
- package/dist/checkpoint/types.d.ts.map +1 -0
- package/dist/checkpoint/types.js +1 -0
- package/dist/codec/codec.d.ts +29 -0
- package/dist/codec/codec.d.ts.map +1 -0
- package/dist/codec/codec.js +15 -0
- package/dist/codec/header-aware-codec.d.ts +36 -0
- package/dist/codec/header-aware-codec.d.ts.map +1 -0
- package/dist/codec/header-aware-codec.js +1 -0
- package/{src/codec/index.ts → dist/codec/index.d.ts} +2 -7
- package/dist/codec/index.d.ts.map +1 -0
- package/dist/codec/index.js +3 -0
- package/dist/codec/json-codec.d.ts +13 -0
- package/dist/codec/json-codec.d.ts.map +1 -0
- package/dist/codec/json-codec.js +64 -0
- package/dist/codec/rabbitmq-codec.d.ts +28 -0
- package/dist/codec/rabbitmq-codec.d.ts.map +1 -0
- package/dist/codec/rabbitmq-codec.js +242 -0
- package/dist/codec/rabbitmq-codec.test.d.ts +2 -0
- package/dist/codec/rabbitmq-codec.test.d.ts.map +1 -0
- package/dist/codec/rabbitmq-codec.test.js +433 -0
- package/dist/core/fanout.d.ts +59 -0
- package/dist/core/fanout.d.ts.map +1 -0
- package/dist/core/fanout.js +121 -0
- package/dist/core/fanout.test.d.ts +2 -0
- package/dist/core/fanout.test.d.ts.map +1 -0
- package/dist/core/fanout.test.js +1054 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +2 -7
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/matador.d.ts +133 -0
- package/dist/core/matador.d.ts.map +1 -0
- package/dist/core/matador.js +228 -0
- package/dist/core/matador.test.d.ts +2 -0
- package/dist/core/matador.test.d.ts.map +1 -0
- package/dist/core/matador.test.js +446 -0
- package/dist/core/shutdown.d.ts +78 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +111 -0
- package/dist/core/shutdown.test.d.ts +2 -0
- package/dist/core/shutdown.test.d.ts.map +1 -0
- package/dist/core/shutdown.test.js +524 -0
- package/dist/errors/checkpoint-errors.d.ts +30 -0
- package/dist/errors/checkpoint-errors.d.ts.map +1 -0
- package/dist/errors/checkpoint-errors.js +49 -0
- package/dist/errors/has-description.d.ts +18 -0
- package/dist/errors/has-description.d.ts.map +1 -0
- package/dist/errors/has-description.js +9 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +22 -0
- package/dist/errors/matador-errors.d.ts +183 -0
- package/dist/errors/matador-errors.d.ts.map +1 -0
- package/dist/errors/matador-errors.js +376 -0
- package/dist/errors/retry-errors.d.ts +102 -0
- package/dist/errors/retry-errors.d.ts.map +1 -0
- package/dist/errors/retry-errors.js +155 -0
- package/dist/errors/retry-errors.test.d.ts +2 -0
- package/dist/errors/retry-errors.test.d.ts.map +1 -0
- package/dist/errors/retry-errors.test.js +136 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/safe-hooks.d.ts +32 -0
- package/dist/hooks/safe-hooks.d.ts.map +1 -0
- package/dist/hooks/safe-hooks.js +120 -0
- package/dist/hooks/types.d.ts +172 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +9 -0
- package/dist/index.cjs +3228 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/{src/pipeline/index.ts → dist/pipeline/index.d.ts} +1 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +1 -0
- package/dist/pipeline/pipeline.d.ts +63 -0
- package/dist/pipeline/pipeline.d.ts.map +1 -0
- package/dist/pipeline/pipeline.js +273 -0
- package/dist/pipeline/pipeline.test.d.ts +2 -0
- package/dist/pipeline/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline/pipeline.test.js +1112 -0
- package/{src/retry/index.ts → dist/retry/index.d.ts} +1 -1
- package/dist/retry/index.d.ts.map +1 -0
- package/dist/retry/index.js +1 -0
- package/dist/retry/policy.d.ts +43 -0
- package/dist/retry/policy.d.ts.map +1 -0
- package/dist/retry/policy.js +1 -0
- package/dist/retry/standard-policy.d.ts +44 -0
- package/dist/retry/standard-policy.d.ts.map +1 -0
- package/dist/retry/standard-policy.js +102 -0
- package/dist/retry/standard-policy.test.d.ts +2 -0
- package/dist/retry/standard-policy.test.d.ts.map +1 -0
- package/dist/retry/standard-policy.test.js +196 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/registry.d.ts +63 -0
- package/dist/schema/registry.d.ts.map +1 -0
- package/dist/schema/registry.js +174 -0
- package/dist/schema/registry.test.d.ts +2 -0
- package/dist/schema/registry.test.d.ts.map +1 -0
- package/dist/schema/registry.test.js +278 -0
- package/{src/schema/types.ts → dist/schema/types.d.ts} +29 -88
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +74 -0
- package/dist/schema/types.test.d.ts +2 -0
- package/dist/schema/types.test.d.ts.map +1 -0
- package/dist/schema/types.test.js +242 -0
- package/dist/topology/builder.d.ts +80 -0
- package/dist/topology/builder.d.ts.map +1 -0
- package/dist/topology/builder.js +165 -0
- package/dist/topology/builder.test.d.ts +2 -0
- package/dist/topology/builder.test.d.ts.map +1 -0
- package/dist/topology/builder.test.js +360 -0
- package/dist/topology/index.d.ts +5 -0
- package/dist/topology/index.d.ts.map +1 -0
- package/dist/topology/index.js +2 -0
- package/dist/topology/types.d.ts +128 -0
- package/dist/topology/types.d.ts.map +1 -0
- package/dist/topology/types.js +28 -0
- package/dist/transport/capabilities.d.ts +66 -0
- package/dist/transport/capabilities.d.ts.map +1 -0
- package/dist/transport/capabilities.js +18 -0
- package/dist/transport/connection-manager.d.ts +95 -0
- package/dist/transport/connection-manager.d.ts.map +1 -0
- package/dist/transport/connection-manager.js +144 -0
- package/dist/transport/index.d.ts +11 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +5 -0
- package/dist/transport/local/local-transport.d.ts +62 -0
- package/dist/transport/local/local-transport.d.ts.map +1 -0
- package/dist/transport/local/local-transport.js +241 -0
- package/dist/transport/local/local-transport.test.d.ts +2 -0
- package/dist/transport/local/local-transport.test.d.ts.map +1 -0
- package/dist/transport/local/local-transport.test.js +192 -0
- package/dist/transport/multi/multi-transport.d.ts +94 -0
- package/dist/transport/multi/multi-transport.d.ts.map +1 -0
- package/dist/transport/multi/multi-transport.js +184 -0
- package/dist/transport/multi/multi-transport.test.d.ts +2 -0
- package/dist/transport/multi/multi-transport.test.d.ts.map +1 -0
- package/dist/transport/multi/multi-transport.test.js +236 -0
- package/dist/transport/rabbitmq/rabbitmq-transport.d.ts +83 -0
- package/dist/transport/rabbitmq/rabbitmq-transport.d.ts.map +1 -0
- package/dist/transport/rabbitmq/rabbitmq-transport.js +541 -0
- package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts +2 -0
- package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts.map +1 -0
- package/dist/transport/rabbitmq/rabbitmq-transport.test.js +100 -0
- package/dist/transport/transport.d.ts +152 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/transport/transport.js +1 -0
- package/{src/types/common.ts → dist/types/common.d.ts} +8 -20
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +12 -0
- package/dist/types/dispatcher.d.ts +14 -0
- package/dist/types/dispatcher.d.ts.map +1 -0
- package/dist/types/dispatcher.js +1 -0
- package/dist/types/envelope.d.ts +131 -0
- package/dist/types/envelope.d.ts.map +1 -0
- package/dist/types/envelope.js +99 -0
- package/dist/types/event.d.ts +92 -0
- package/dist/types/event.d.ts.map +1 -0
- package/dist/types/event.js +26 -0
- package/dist/types/event.test.d.ts +2 -0
- package/dist/types/event.test.d.ts.map +1 -0
- package/dist/types/event.test.js +130 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/subscriber.d.ts +227 -0
- package/dist/types/subscriber.d.ts.map +1 -0
- package/dist/types/subscriber.js +97 -0
- package/package.json +6 -2
- package/examples/config.ts +0 -126
- package/examples/event.ts +0 -26
- package/examples/order-event.json +0 -19
- package/src/checkpoint/context.test.ts +0 -510
- package/src/checkpoint/context.ts +0 -213
- package/src/checkpoint/index.ts +0 -30
- package/src/checkpoint/stores/memory.ts +0 -47
- package/src/checkpoint/stores/stores.test.ts +0 -177
- package/src/checkpoint/types.ts +0 -147
- package/src/codec/codec.ts +0 -42
- package/src/codec/header-aware-codec.ts +0 -41
- package/src/codec/json-codec.ts +0 -69
- package/src/codec/rabbitmq-codec.test.ts +0 -516
- package/src/codec/rabbitmq-codec.ts +0 -336
- package/src/core/fanout.test.ts +0 -1350
- package/src/core/fanout.ts +0 -184
- package/src/core/matador.test.ts +0 -575
- package/src/core/matador.ts +0 -357
- package/src/core/shutdown.test.ts +0 -853
- package/src/core/shutdown.ts +0 -165
- package/src/errors/checkpoint-errors.ts +0 -62
- package/src/errors/has-description.ts +0 -25
- package/src/errors/index.ts +0 -58
- package/src/errors/matador-errors.ts +0 -477
- package/src/errors/retry-errors.test.ts +0 -175
- package/src/errors/retry-errors.ts +0 -188
- package/src/hooks/index.ts +0 -14
- package/src/hooks/safe-hooks.ts +0 -200
- package/src/hooks/types.ts +0 -226
- package/src/index.ts +0 -242
- package/src/pipeline/pipeline.test.ts +0 -1377
- package/src/pipeline/pipeline.ts +0 -393
- package/src/retry/policy.ts +0 -46
- package/src/retry/standard-policy.test.ts +0 -290
- package/src/retry/standard-policy.ts +0 -156
- package/src/schema/index.ts +0 -16
- package/src/schema/registry.test.ts +0 -339
- package/src/schema/registry.ts +0 -229
- package/src/schema/types.test.ts +0 -280
- package/src/topology/builder.test.ts +0 -451
- package/src/topology/builder.ts +0 -238
- package/src/topology/index.ts +0 -19
- package/src/topology/types.ts +0 -183
- package/src/transport/capabilities.ts +0 -88
- package/src/transport/connection-manager.ts +0 -218
- package/src/transport/index.ts +0 -42
- package/src/transport/local/local-transport.test.ts +0 -262
- package/src/transport/local/local-transport.ts +0 -330
- package/src/transport/multi/multi-transport.test.ts +0 -320
- package/src/transport/multi/multi-transport.ts +0 -294
- package/src/transport/rabbitmq/rabbitmq-transport.test.ts +0 -120
- package/src/transport/rabbitmq/rabbitmq-transport.ts +0 -782
- package/src/transport/transport.ts +0 -200
- package/src/types/dispatcher.ts +0 -18
- package/src/types/envelope.ts +0 -244
- package/src/types/event.test.ts +0 -157
- package/src/types/event.ts +0 -112
- package/src/types/index.ts +0 -62
- package/src/types/subscriber.ts +0 -333
- package/test/e2e/multi-transport.e2e.test.ts +0 -237
- package/test/e2e/rabbitmq-transport.e2e.test.ts +0 -618
- package/test/e2e/transport-compliance.e2e.test.ts +0 -506
- package/test/integration/matador.integration.test.ts +0 -634
- package/tsconfig.json +0 -29
- package/tsup.config.ts +0 -13
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from 'bun:test';
|
|
2
|
-
import { MatadorEvent, createSubscriber } from '../types/index.js';
|
|
3
|
-
import { SchemaError, SchemaRegistry } from './registry.js';
|
|
4
|
-
|
|
5
|
-
class TestEvent extends MatadorEvent {
|
|
6
|
-
static readonly key = 'test.event';
|
|
7
|
-
static readonly description = 'A test event';
|
|
8
|
-
|
|
9
|
-
constructor(public data: { id: string }) {
|
|
10
|
-
super();
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class AliasedEvent extends MatadorEvent {
|
|
15
|
-
static readonly key = 'user.created.v2';
|
|
16
|
-
static readonly description = 'User created event with aliases';
|
|
17
|
-
static readonly aliases = ['user.created', 'user.created.v1'];
|
|
18
|
-
|
|
19
|
-
constructor(public data: { name: string }) {
|
|
20
|
-
super();
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe('SchemaRegistry', () => {
|
|
25
|
-
let registry: SchemaRegistry;
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
registry = new SchemaRegistry();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('register', () => {
|
|
32
|
-
it('should register an event with subscribers', () => {
|
|
33
|
-
const subscriber = createSubscriber({
|
|
34
|
-
name: 'test-subscriber',
|
|
35
|
-
description: 'Test subscriber',
|
|
36
|
-
callback: async () => {},
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
registry.register(TestEvent, [subscriber]);
|
|
40
|
-
|
|
41
|
-
expect(registry.hasEvent('test.event')).toBe(true);
|
|
42
|
-
expect(registry.getSubscribers('test.event')).toHaveLength(1);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should throw when registering duplicate event without override', () => {
|
|
46
|
-
const subscriber = createSubscriber({
|
|
47
|
-
name: 'test-subscriber',
|
|
48
|
-
description: 'Test subscriber',
|
|
49
|
-
callback: async () => {},
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
registry.register(TestEvent, [subscriber]);
|
|
53
|
-
|
|
54
|
-
expect(() => registry.register(TestEvent, [subscriber])).toThrow(
|
|
55
|
-
SchemaError,
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should allow override when option is set', () => {
|
|
60
|
-
const subscriber1 = createSubscriber({
|
|
61
|
-
name: 'sub-1',
|
|
62
|
-
description: 'Subscriber 1',
|
|
63
|
-
callback: async () => {},
|
|
64
|
-
});
|
|
65
|
-
const subscriber2 = createSubscriber({
|
|
66
|
-
name: 'sub-2',
|
|
67
|
-
description: 'Subscriber 2',
|
|
68
|
-
callback: async () => {},
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
registry.register(TestEvent, [subscriber1]);
|
|
72
|
-
registry.register(TestEvent, [subscriber2], { override: true });
|
|
73
|
-
|
|
74
|
-
const subscribers = registry.getSubscribers('test.event');
|
|
75
|
-
expect(subscribers).toHaveLength(1);
|
|
76
|
-
expect(subscribers[0]?.name).toBe('sub-2');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should register aliases', () => {
|
|
80
|
-
const subscriber = createSubscriber({
|
|
81
|
-
name: 'test-subscriber',
|
|
82
|
-
description: 'Test subscriber',
|
|
83
|
-
callback: async () => {},
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
registry.register(AliasedEvent, [subscriber]);
|
|
87
|
-
|
|
88
|
-
expect(registry.hasEvent('user.created.v2')).toBe(true);
|
|
89
|
-
expect(registry.hasEvent('user.created')).toBe(true);
|
|
90
|
-
expect(registry.hasEvent('user.created.v1')).toBe(true);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should throw on duplicate aliases without override', () => {
|
|
94
|
-
class EventWithSameAlias extends MatadorEvent {
|
|
95
|
-
static readonly key = 'another.event';
|
|
96
|
-
static readonly description = 'Another event';
|
|
97
|
-
static readonly aliases = ['user.created']; // conflicts with AliasedEvent
|
|
98
|
-
|
|
99
|
-
constructor(public data: { x: number }) {
|
|
100
|
-
super();
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const sub1 = createSubscriber({
|
|
105
|
-
name: 'sub-1',
|
|
106
|
-
description: 'Subscriber 1',
|
|
107
|
-
callback: async () => {},
|
|
108
|
-
});
|
|
109
|
-
const sub2 = createSubscriber({
|
|
110
|
-
name: 'sub-2',
|
|
111
|
-
description: 'Subscriber 2',
|
|
112
|
-
callback: async () => {},
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
registry.register(AliasedEvent, [sub1]);
|
|
116
|
-
|
|
117
|
-
expect(() => registry.register(EventWithSameAlias, [sub2])).toThrow(
|
|
118
|
-
'Alias "user.created" is already registered',
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
describe('getEventClass', () => {
|
|
124
|
-
it('should return event class by key', () => {
|
|
125
|
-
const subscriber = createSubscriber({
|
|
126
|
-
name: 'test-subscriber',
|
|
127
|
-
description: 'Test subscriber',
|
|
128
|
-
callback: async () => {},
|
|
129
|
-
});
|
|
130
|
-
registry.register(TestEvent, [subscriber]);
|
|
131
|
-
|
|
132
|
-
const eventClass = registry.getEventClass('test.event');
|
|
133
|
-
expect(eventClass).toBeDefined();
|
|
134
|
-
expect(eventClass?.key).toBe('test.event');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should return event class by alias', () => {
|
|
138
|
-
const subscriber = createSubscriber({
|
|
139
|
-
name: 'test-subscriber',
|
|
140
|
-
description: 'Test subscriber',
|
|
141
|
-
callback: async () => {},
|
|
142
|
-
});
|
|
143
|
-
registry.register(AliasedEvent, [subscriber]);
|
|
144
|
-
|
|
145
|
-
const eventClass = registry.getEventClass('user.created');
|
|
146
|
-
expect(eventClass).toBeDefined();
|
|
147
|
-
expect(eventClass?.key).toBe('user.created.v2');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should return undefined for unknown key', () => {
|
|
151
|
-
expect(registry.getEventClass('unknown.event')).toBeUndefined();
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe('getSubscribers', () => {
|
|
156
|
-
it('should return all subscribers for an event', () => {
|
|
157
|
-
const sub1 = createSubscriber({
|
|
158
|
-
name: 'sub-1',
|
|
159
|
-
description: 'Subscriber 1',
|
|
160
|
-
callback: async () => {},
|
|
161
|
-
});
|
|
162
|
-
const sub2 = createSubscriber({
|
|
163
|
-
name: 'sub-2',
|
|
164
|
-
description: 'Subscriber 2',
|
|
165
|
-
callback: async () => {},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
registry.register(TestEvent, [sub1, sub2]);
|
|
169
|
-
|
|
170
|
-
const subscribers = registry.getSubscribers('test.event');
|
|
171
|
-
expect(subscribers).toHaveLength(2);
|
|
172
|
-
expect(subscribers[0]?.name).toBe('sub-1');
|
|
173
|
-
expect(subscribers[1]?.name).toBe('sub-2');
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('should return empty array for unknown event', () => {
|
|
177
|
-
expect(registry.getSubscribers('unknown.event')).toEqual([]);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe('getSubscriber', () => {
|
|
182
|
-
it('should return specific subscriber by name', () => {
|
|
183
|
-
const sub1 = createSubscriber({
|
|
184
|
-
name: 'sub-1',
|
|
185
|
-
description: 'Subscriber 1',
|
|
186
|
-
callback: async () => {},
|
|
187
|
-
});
|
|
188
|
-
const sub2 = createSubscriber({
|
|
189
|
-
name: 'sub-2',
|
|
190
|
-
description: 'Subscriber 2',
|
|
191
|
-
callback: async () => {},
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
registry.register(TestEvent, [sub1, sub2]);
|
|
195
|
-
|
|
196
|
-
const subscriber = registry.getSubscriber('test.event', 'sub-2');
|
|
197
|
-
expect(subscriber?.name).toBe('sub-2');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('should return undefined for unknown subscriber', () => {
|
|
201
|
-
const sub = createSubscriber({
|
|
202
|
-
name: 'sub-1',
|
|
203
|
-
description: 'Subscriber 1',
|
|
204
|
-
callback: async () => {},
|
|
205
|
-
});
|
|
206
|
-
registry.register(TestEvent, [sub]);
|
|
207
|
-
|
|
208
|
-
expect(registry.getSubscriber('test.event', 'unknown')).toBeUndefined();
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
describe('getSubscriberDefinition', () => {
|
|
213
|
-
it('should return subscriber definition for pipeline', () => {
|
|
214
|
-
const sub = createSubscriber({
|
|
215
|
-
name: 'sub-1',
|
|
216
|
-
description: 'Subscriber 1',
|
|
217
|
-
callback: async () => {},
|
|
218
|
-
idempotent: 'yes',
|
|
219
|
-
importance: 'must-investigate',
|
|
220
|
-
targetQueue: 'custom-queue',
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
registry.register(TestEvent, [sub]);
|
|
224
|
-
|
|
225
|
-
const definition = registry.getSubscriberDefinition(
|
|
226
|
-
'test.event',
|
|
227
|
-
'sub-1',
|
|
228
|
-
);
|
|
229
|
-
expect(definition).toEqual({
|
|
230
|
-
name: 'sub-1',
|
|
231
|
-
description: 'Subscriber 1',
|
|
232
|
-
idempotent: 'yes',
|
|
233
|
-
importance: 'must-investigate',
|
|
234
|
-
targetQueue: 'custom-queue',
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('should return undefined for unknown subscriber', () => {
|
|
239
|
-
expect(
|
|
240
|
-
registry.getSubscriberDefinition('unknown', 'unknown'),
|
|
241
|
-
).toBeUndefined();
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
describe('getExecutableSubscriber', () => {
|
|
246
|
-
it('should return subscriber with callback', () => {
|
|
247
|
-
const callback = async () => {};
|
|
248
|
-
const sub = createSubscriber({
|
|
249
|
-
name: 'sub-1',
|
|
250
|
-
description: 'Subscriber 1',
|
|
251
|
-
callback,
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
registry.register(TestEvent, [sub]);
|
|
255
|
-
|
|
256
|
-
const executable = registry.getExecutableSubscriber(
|
|
257
|
-
'test.event',
|
|
258
|
-
'sub-1',
|
|
259
|
-
);
|
|
260
|
-
expect(executable).toBeDefined();
|
|
261
|
-
expect(executable?.callback).toBe(callback);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
describe('getEventKeys', () => {
|
|
266
|
-
it('should return all registered event keys', () => {
|
|
267
|
-
const sub1 = createSubscriber({
|
|
268
|
-
name: 'sub-1',
|
|
269
|
-
description: 'Subscriber 1',
|
|
270
|
-
callback: async () => {},
|
|
271
|
-
});
|
|
272
|
-
const sub2 = createSubscriber({
|
|
273
|
-
name: 'sub-2',
|
|
274
|
-
description: 'Subscriber 2',
|
|
275
|
-
callback: async () => {},
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
registry.register(TestEvent, [sub1]);
|
|
279
|
-
registry.register(AliasedEvent, [sub2]);
|
|
280
|
-
|
|
281
|
-
const keys = registry.getEventKeys();
|
|
282
|
-
expect(keys).toContain('test.event');
|
|
283
|
-
expect(keys).toContain('user.created.v2');
|
|
284
|
-
expect(keys).not.toContain('user.created'); // aliases not included
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
describe('validate', () => {
|
|
289
|
-
it('should pass validation for valid schema', () => {
|
|
290
|
-
const sub = createSubscriber({
|
|
291
|
-
name: 'sub-1',
|
|
292
|
-
description: 'Subscriber 1',
|
|
293
|
-
callback: async () => {},
|
|
294
|
-
});
|
|
295
|
-
registry.register(TestEvent, [sub]);
|
|
296
|
-
|
|
297
|
-
const result = registry.validate();
|
|
298
|
-
expect(result.valid).toBe(true);
|
|
299
|
-
expect(result.issues).toHaveLength(0);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('should detect duplicate subscriber names', () => {
|
|
303
|
-
const sub1 = createSubscriber({
|
|
304
|
-
name: 'duplicate-name',
|
|
305
|
-
description: 'Duplicate subscriber',
|
|
306
|
-
callback: async () => {},
|
|
307
|
-
});
|
|
308
|
-
const sub2 = createSubscriber({
|
|
309
|
-
name: 'duplicate-name',
|
|
310
|
-
description: 'Duplicate subscriber',
|
|
311
|
-
callback: async () => {},
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
registry.register(TestEvent, [sub1, sub2]);
|
|
315
|
-
|
|
316
|
-
const result = registry.validate();
|
|
317
|
-
expect(result.valid).toBe(false);
|
|
318
|
-
expect(result.issues).toHaveLength(1);
|
|
319
|
-
expect(result.issues[0]?.severity).toBe('error');
|
|
320
|
-
expect(result.issues[0]?.message).toContain('Duplicate subscriber name');
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
describe('clear', () => {
|
|
325
|
-
it('should remove all entries', () => {
|
|
326
|
-
const sub = createSubscriber({
|
|
327
|
-
name: 'sub-1',
|
|
328
|
-
description: 'Subscriber 1',
|
|
329
|
-
callback: async () => {},
|
|
330
|
-
});
|
|
331
|
-
registry.register(TestEvent, [sub]);
|
|
332
|
-
|
|
333
|
-
registry.clear();
|
|
334
|
-
|
|
335
|
-
expect(registry.hasEvent('test.event')).toBe(false);
|
|
336
|
-
expect(registry.getEventKeys()).toHaveLength(0);
|
|
337
|
-
});
|
|
338
|
-
});
|
|
339
|
-
});
|
package/src/schema/registry.ts
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
import type { HasDescription } from '../errors/index.js';
|
|
2
|
-
import type {
|
|
3
|
-
AnySubscriber,
|
|
4
|
-
EventClass,
|
|
5
|
-
MatadorEvent,
|
|
6
|
-
Subscriber,
|
|
7
|
-
SubscriberDefinition,
|
|
8
|
-
} from '../types/index.js';
|
|
9
|
-
import { isSubscriber } from '../types/index.js';
|
|
10
|
-
import type {
|
|
11
|
-
RegisterOptions,
|
|
12
|
-
SchemaEntry,
|
|
13
|
-
SchemaIssue,
|
|
14
|
-
SchemaValidationResult,
|
|
15
|
-
} from './types.js';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Error thrown when schema operations fail.
|
|
19
|
-
*/
|
|
20
|
-
export class SchemaError extends Error implements HasDescription {
|
|
21
|
-
readonly description =
|
|
22
|
-
'A schema operation failed, such as registering a duplicate event or ' +
|
|
23
|
-
'conflicting alias. This is a configuration error that should be fixed ' +
|
|
24
|
-
'during development. Review the event and subscriber registrations to ' +
|
|
25
|
-
'resolve the conflict.';
|
|
26
|
-
|
|
27
|
-
constructor(message: string) {
|
|
28
|
-
super(message);
|
|
29
|
-
this.name = 'SchemaError';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Registry for managing event-subscriber relationships.
|
|
35
|
-
*/
|
|
36
|
-
export class SchemaRegistry {
|
|
37
|
-
private readonly entries = new Map<string, SchemaEntry>();
|
|
38
|
-
private readonly aliases = new Map<string, string>();
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Registers an event class with its subscribers.
|
|
42
|
-
*/
|
|
43
|
-
register<T>(
|
|
44
|
-
eventClass: EventClass<T>,
|
|
45
|
-
subscribers: readonly AnySubscriber[],
|
|
46
|
-
options: RegisterOptions = {},
|
|
47
|
-
): void {
|
|
48
|
-
const key = eventClass.key;
|
|
49
|
-
|
|
50
|
-
if (this.entries.has(key) && !options.override) {
|
|
51
|
-
throw new SchemaError(`Event "${key}" is already registered`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.entries.set(key, {
|
|
55
|
-
eventClass,
|
|
56
|
-
subscribers,
|
|
57
|
-
} as SchemaEntry);
|
|
58
|
-
|
|
59
|
-
// Register aliases
|
|
60
|
-
if (eventClass.aliases) {
|
|
61
|
-
for (const alias of eventClass.aliases) {
|
|
62
|
-
if (
|
|
63
|
-
this.aliases.has(alias) &&
|
|
64
|
-
this.aliases.get(alias) !== key &&
|
|
65
|
-
!options.override
|
|
66
|
-
) {
|
|
67
|
-
throw new SchemaError(
|
|
68
|
-
`Alias "${alias}" is already registered for event "${this.aliases.get(alias)}"`,
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
this.aliases.set(alias, key);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Gets the event class for a given key.
|
|
78
|
-
*/
|
|
79
|
-
getEventClass(key: string): EventClass | undefined {
|
|
80
|
-
const entry = this.entries.get(key);
|
|
81
|
-
if (entry) return entry.eventClass;
|
|
82
|
-
|
|
83
|
-
// Check aliases
|
|
84
|
-
const aliasKey = this.aliases.get(key);
|
|
85
|
-
if (aliasKey) {
|
|
86
|
-
return this.entries.get(aliasKey)?.eventClass;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Gets all subscribers for an event key.
|
|
94
|
-
*/
|
|
95
|
-
getSubscribers(eventKey: string): readonly AnySubscriber[] {
|
|
96
|
-
const entry = this.getEntry(eventKey);
|
|
97
|
-
return entry?.subscribers ?? [];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Gets a specific subscriber by event key and subscriber name.
|
|
102
|
-
*/
|
|
103
|
-
getSubscriber(
|
|
104
|
-
eventKey: string,
|
|
105
|
-
subscriberName: string,
|
|
106
|
-
): AnySubscriber | undefined {
|
|
107
|
-
const subscribers = this.getSubscribers(eventKey);
|
|
108
|
-
return subscribers.find((s) => s.name === subscriberName);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Gets a subscriber definition for the pipeline.
|
|
113
|
-
*/
|
|
114
|
-
getSubscriberDefinition(
|
|
115
|
-
eventKey: string,
|
|
116
|
-
subscriberName: string,
|
|
117
|
-
): SubscriberDefinition | undefined {
|
|
118
|
-
const subscriber = this.getSubscriber(eventKey, subscriberName);
|
|
119
|
-
if (!subscriber) return undefined;
|
|
120
|
-
|
|
121
|
-
const def: SubscriberDefinition = {
|
|
122
|
-
name: subscriber.name,
|
|
123
|
-
idempotent: subscriber.idempotent ?? 'unknown',
|
|
124
|
-
importance: subscriber.importance ?? 'should-investigate',
|
|
125
|
-
...('description' in subscriber &&
|
|
126
|
-
subscriber.description !== undefined && {
|
|
127
|
-
description: subscriber.description,
|
|
128
|
-
}),
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
if (subscriber.targetQueue !== undefined) {
|
|
132
|
-
(def as { targetQueue?: string }).targetQueue = subscriber.targetQueue;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return def;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Gets a subscriber with callback for execution.
|
|
140
|
-
*/
|
|
141
|
-
getExecutableSubscriber(
|
|
142
|
-
eventKey: string,
|
|
143
|
-
subscriberName: string,
|
|
144
|
-
): Subscriber<MatadorEvent<unknown>> | undefined {
|
|
145
|
-
const subscriber = this.getSubscriber(eventKey, subscriberName);
|
|
146
|
-
if (!subscriber || !isSubscriber(subscriber)) return undefined;
|
|
147
|
-
return subscriber;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Gets the event class by alias.
|
|
152
|
-
*/
|
|
153
|
-
getEventByAlias(alias: string): EventClass | undefined {
|
|
154
|
-
const key = this.aliases.get(alias);
|
|
155
|
-
if (!key) return undefined;
|
|
156
|
-
return this.entries.get(key)?.eventClass;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Checks if an event key is registered.
|
|
161
|
-
*/
|
|
162
|
-
hasEvent(key: string): boolean {
|
|
163
|
-
return this.entries.has(key) || this.aliases.has(key);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Gets all registered event keys.
|
|
168
|
-
*/
|
|
169
|
-
getEventKeys(): readonly string[] {
|
|
170
|
-
return [...this.entries.keys()];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Validates the schema for issues.
|
|
175
|
-
*/
|
|
176
|
-
validate(): SchemaValidationResult {
|
|
177
|
-
const issues: SchemaIssue[] = [];
|
|
178
|
-
|
|
179
|
-
for (const [key, entry] of this.entries) {
|
|
180
|
-
// Check for duplicate subscriber names
|
|
181
|
-
const names = new Set<string>();
|
|
182
|
-
for (const subscriber of entry.subscribers) {
|
|
183
|
-
if (names.has(subscriber.name)) {
|
|
184
|
-
issues.push({
|
|
185
|
-
severity: 'error',
|
|
186
|
-
eventKey: key,
|
|
187
|
-
message: `Duplicate subscriber name: "${subscriber.name}"`,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
names.add(subscriber.name);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Check for subscribers without callbacks (stubs in consuming instance)
|
|
194
|
-
const stubs = entry.subscribers.filter((s) => !isSubscriber(s));
|
|
195
|
-
if (stubs.length === entry.subscribers.length && stubs.length > 0) {
|
|
196
|
-
issues.push({
|
|
197
|
-
severity: 'warning',
|
|
198
|
-
eventKey: key,
|
|
199
|
-
message: 'All subscribers are stubs, no local handlers',
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
valid: issues.filter((i) => i.severity === 'error').length === 0,
|
|
206
|
-
issues,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Clears all registered entries.
|
|
212
|
-
*/
|
|
213
|
-
clear(): void {
|
|
214
|
-
this.entries.clear();
|
|
215
|
-
this.aliases.clear();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
private getEntry(eventKey: string): SchemaEntry | undefined {
|
|
219
|
-
const entry = this.entries.get(eventKey);
|
|
220
|
-
if (entry) return entry;
|
|
221
|
-
|
|
222
|
-
const aliasKey = this.aliases.get(eventKey);
|
|
223
|
-
if (aliasKey) {
|
|
224
|
-
return this.entries.get(aliasKey);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return undefined;
|
|
228
|
-
}
|
|
229
|
-
}
|