@zdavison/matador 2.0.9 → 2.0.10

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.
Files changed (259) hide show
  1. package/dist/checkpoint/context.d.ts +59 -0
  2. package/dist/checkpoint/context.d.ts.map +1 -0
  3. package/dist/checkpoint/context.js +140 -0
  4. package/dist/checkpoint/context.test.d.ts +2 -0
  5. package/dist/checkpoint/context.test.d.ts.map +1 -0
  6. package/dist/checkpoint/context.test.js +424 -0
  7. package/dist/checkpoint/index.d.ts +7 -0
  8. package/dist/checkpoint/index.d.ts.map +1 -0
  9. package/dist/checkpoint/index.js +6 -0
  10. package/dist/checkpoint/stores/memory.d.ts +29 -0
  11. package/dist/checkpoint/stores/memory.d.ts.map +1 -0
  12. package/dist/checkpoint/stores/memory.js +39 -0
  13. package/{src/checkpoint/stores/noop.ts → dist/checkpoint/stores/noop.d.ts} +5 -13
  14. package/dist/checkpoint/stores/noop.d.ts.map +1 -0
  15. package/dist/checkpoint/stores/noop.js +18 -0
  16. package/dist/checkpoint/stores/stores.test.d.ts +2 -0
  17. package/dist/checkpoint/stores/stores.test.d.ts.map +1 -0
  18. package/dist/checkpoint/stores/stores.test.js +146 -0
  19. package/dist/checkpoint/types.d.ts +119 -0
  20. package/dist/checkpoint/types.d.ts.map +1 -0
  21. package/dist/checkpoint/types.js +1 -0
  22. package/dist/codec/codec.d.ts +29 -0
  23. package/dist/codec/codec.d.ts.map +1 -0
  24. package/dist/codec/codec.js +15 -0
  25. package/dist/codec/header-aware-codec.d.ts +36 -0
  26. package/dist/codec/header-aware-codec.d.ts.map +1 -0
  27. package/dist/codec/header-aware-codec.js +1 -0
  28. package/{src/codec/index.ts → dist/codec/index.d.ts} +2 -7
  29. package/dist/codec/index.d.ts.map +1 -0
  30. package/dist/codec/index.js +3 -0
  31. package/dist/codec/json-codec.d.ts +13 -0
  32. package/dist/codec/json-codec.d.ts.map +1 -0
  33. package/dist/codec/json-codec.js +64 -0
  34. package/dist/codec/rabbitmq-codec.d.ts +28 -0
  35. package/dist/codec/rabbitmq-codec.d.ts.map +1 -0
  36. package/dist/codec/rabbitmq-codec.js +242 -0
  37. package/dist/codec/rabbitmq-codec.test.d.ts +2 -0
  38. package/dist/codec/rabbitmq-codec.test.d.ts.map +1 -0
  39. package/dist/codec/rabbitmq-codec.test.js +433 -0
  40. package/dist/core/fanout.d.ts +59 -0
  41. package/dist/core/fanout.d.ts.map +1 -0
  42. package/dist/core/fanout.js +121 -0
  43. package/dist/core/fanout.test.d.ts +2 -0
  44. package/dist/core/fanout.test.d.ts.map +1 -0
  45. package/dist/core/fanout.test.js +1054 -0
  46. package/{src/core/index.ts → dist/core/index.d.ts} +2 -7
  47. package/dist/core/index.d.ts.map +1 -0
  48. package/dist/core/index.js +3 -0
  49. package/dist/core/matador.d.ts +133 -0
  50. package/dist/core/matador.d.ts.map +1 -0
  51. package/dist/core/matador.js +228 -0
  52. package/dist/core/matador.test.d.ts +2 -0
  53. package/dist/core/matador.test.d.ts.map +1 -0
  54. package/dist/core/matador.test.js +446 -0
  55. package/dist/core/shutdown.d.ts +78 -0
  56. package/dist/core/shutdown.d.ts.map +1 -0
  57. package/dist/core/shutdown.js +111 -0
  58. package/dist/core/shutdown.test.d.ts +2 -0
  59. package/dist/core/shutdown.test.d.ts.map +1 -0
  60. package/dist/core/shutdown.test.js +524 -0
  61. package/dist/errors/checkpoint-errors.d.ts +30 -0
  62. package/dist/errors/checkpoint-errors.d.ts.map +1 -0
  63. package/dist/errors/checkpoint-errors.js +49 -0
  64. package/dist/errors/has-description.d.ts +18 -0
  65. package/dist/errors/has-description.d.ts.map +1 -0
  66. package/dist/errors/has-description.js +9 -0
  67. package/dist/errors/index.d.ts +6 -0
  68. package/dist/errors/index.d.ts.map +1 -0
  69. package/dist/errors/index.js +22 -0
  70. package/dist/errors/matador-errors.d.ts +183 -0
  71. package/dist/errors/matador-errors.d.ts.map +1 -0
  72. package/dist/errors/matador-errors.js +376 -0
  73. package/dist/errors/retry-errors.d.ts +102 -0
  74. package/dist/errors/retry-errors.d.ts.map +1 -0
  75. package/dist/errors/retry-errors.js +155 -0
  76. package/dist/errors/retry-errors.test.d.ts +2 -0
  77. package/dist/errors/retry-errors.test.d.ts.map +1 -0
  78. package/dist/errors/retry-errors.test.js +136 -0
  79. package/dist/hooks/index.d.ts +4 -0
  80. package/dist/hooks/index.d.ts.map +1 -0
  81. package/dist/hooks/index.js +2 -0
  82. package/dist/hooks/safe-hooks.d.ts +32 -0
  83. package/dist/hooks/safe-hooks.d.ts.map +1 -0
  84. package/dist/hooks/safe-hooks.js +120 -0
  85. package/dist/hooks/types.d.ts +172 -0
  86. package/dist/hooks/types.d.ts.map +1 -0
  87. package/dist/hooks/types.js +9 -0
  88. package/dist/index.cjs +3228 -0
  89. package/dist/index.cjs.map +1 -0
  90. package/dist/index.d.cts +23 -0
  91. package/dist/index.d.ts +23 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +31 -0
  94. package/dist/index.js.map +1 -0
  95. package/{src/pipeline/index.ts → dist/pipeline/index.d.ts} +1 -0
  96. package/dist/pipeline/index.d.ts.map +1 -0
  97. package/dist/pipeline/index.js +1 -0
  98. package/dist/pipeline/pipeline.d.ts +63 -0
  99. package/dist/pipeline/pipeline.d.ts.map +1 -0
  100. package/dist/pipeline/pipeline.js +273 -0
  101. package/dist/pipeline/pipeline.test.d.ts +2 -0
  102. package/dist/pipeline/pipeline.test.d.ts.map +1 -0
  103. package/dist/pipeline/pipeline.test.js +1112 -0
  104. package/{src/retry/index.ts → dist/retry/index.d.ts} +1 -1
  105. package/dist/retry/index.d.ts.map +1 -0
  106. package/dist/retry/index.js +1 -0
  107. package/dist/retry/policy.d.ts +43 -0
  108. package/dist/retry/policy.d.ts.map +1 -0
  109. package/dist/retry/policy.js +1 -0
  110. package/dist/retry/standard-policy.d.ts +44 -0
  111. package/dist/retry/standard-policy.d.ts.map +1 -0
  112. package/dist/retry/standard-policy.js +102 -0
  113. package/dist/retry/standard-policy.test.d.ts +2 -0
  114. package/dist/retry/standard-policy.test.d.ts.map +1 -0
  115. package/dist/retry/standard-policy.test.js +196 -0
  116. package/dist/schema/index.d.ts +4 -0
  117. package/dist/schema/index.d.ts.map +1 -0
  118. package/dist/schema/index.js +2 -0
  119. package/dist/schema/registry.d.ts +63 -0
  120. package/dist/schema/registry.d.ts.map +1 -0
  121. package/dist/schema/registry.js +174 -0
  122. package/dist/schema/registry.test.d.ts +2 -0
  123. package/dist/schema/registry.test.d.ts.map +1 -0
  124. package/dist/schema/registry.test.js +278 -0
  125. package/{src/schema/types.ts → dist/schema/types.d.ts} +29 -88
  126. package/dist/schema/types.d.ts.map +1 -0
  127. package/dist/schema/types.js +74 -0
  128. package/dist/schema/types.test.d.ts +2 -0
  129. package/dist/schema/types.test.d.ts.map +1 -0
  130. package/dist/schema/types.test.js +242 -0
  131. package/dist/topology/builder.d.ts +80 -0
  132. package/dist/topology/builder.d.ts.map +1 -0
  133. package/dist/topology/builder.js +165 -0
  134. package/dist/topology/builder.test.d.ts +2 -0
  135. package/dist/topology/builder.test.d.ts.map +1 -0
  136. package/dist/topology/builder.test.js +360 -0
  137. package/dist/topology/index.d.ts +5 -0
  138. package/dist/topology/index.d.ts.map +1 -0
  139. package/dist/topology/index.js +2 -0
  140. package/dist/topology/types.d.ts +128 -0
  141. package/dist/topology/types.d.ts.map +1 -0
  142. package/dist/topology/types.js +28 -0
  143. package/dist/transport/capabilities.d.ts +66 -0
  144. package/dist/transport/capabilities.d.ts.map +1 -0
  145. package/dist/transport/capabilities.js +18 -0
  146. package/dist/transport/connection-manager.d.ts +95 -0
  147. package/dist/transport/connection-manager.d.ts.map +1 -0
  148. package/dist/transport/connection-manager.js +144 -0
  149. package/dist/transport/index.d.ts +11 -0
  150. package/dist/transport/index.d.ts.map +1 -0
  151. package/dist/transport/index.js +5 -0
  152. package/dist/transport/local/local-transport.d.ts +62 -0
  153. package/dist/transport/local/local-transport.d.ts.map +1 -0
  154. package/dist/transport/local/local-transport.js +241 -0
  155. package/dist/transport/local/local-transport.test.d.ts +2 -0
  156. package/dist/transport/local/local-transport.test.d.ts.map +1 -0
  157. package/dist/transport/local/local-transport.test.js +192 -0
  158. package/dist/transport/multi/multi-transport.d.ts +94 -0
  159. package/dist/transport/multi/multi-transport.d.ts.map +1 -0
  160. package/dist/transport/multi/multi-transport.js +184 -0
  161. package/dist/transport/multi/multi-transport.test.d.ts +2 -0
  162. package/dist/transport/multi/multi-transport.test.d.ts.map +1 -0
  163. package/dist/transport/multi/multi-transport.test.js +236 -0
  164. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts +83 -0
  165. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts.map +1 -0
  166. package/dist/transport/rabbitmq/rabbitmq-transport.js +541 -0
  167. package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts +2 -0
  168. package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts.map +1 -0
  169. package/dist/transport/rabbitmq/rabbitmq-transport.test.js +100 -0
  170. package/dist/transport/transport.d.ts +152 -0
  171. package/dist/transport/transport.d.ts.map +1 -0
  172. package/dist/transport/transport.js +1 -0
  173. package/{src/types/common.ts → dist/types/common.d.ts} +8 -20
  174. package/dist/types/common.d.ts.map +1 -0
  175. package/dist/types/common.js +12 -0
  176. package/dist/types/dispatcher.d.ts +14 -0
  177. package/dist/types/dispatcher.d.ts.map +1 -0
  178. package/dist/types/dispatcher.js +1 -0
  179. package/dist/types/envelope.d.ts +131 -0
  180. package/dist/types/envelope.d.ts.map +1 -0
  181. package/dist/types/envelope.js +99 -0
  182. package/dist/types/event.d.ts +92 -0
  183. package/dist/types/event.d.ts.map +1 -0
  184. package/dist/types/event.js +26 -0
  185. package/dist/types/event.test.d.ts +2 -0
  186. package/dist/types/event.test.d.ts.map +1 -0
  187. package/dist/types/event.test.js +130 -0
  188. package/dist/types/index.d.ts +11 -0
  189. package/dist/types/index.d.ts.map +1 -0
  190. package/dist/types/index.js +4 -0
  191. package/dist/types/subscriber.d.ts +227 -0
  192. package/dist/types/subscriber.d.ts.map +1 -0
  193. package/dist/types/subscriber.js +97 -0
  194. package/package.json +6 -2
  195. package/examples/config.ts +0 -126
  196. package/examples/event.ts +0 -26
  197. package/examples/order-event.json +0 -19
  198. package/src/checkpoint/context.test.ts +0 -510
  199. package/src/checkpoint/context.ts +0 -213
  200. package/src/checkpoint/index.ts +0 -30
  201. package/src/checkpoint/stores/memory.ts +0 -47
  202. package/src/checkpoint/stores/stores.test.ts +0 -177
  203. package/src/checkpoint/types.ts +0 -147
  204. package/src/codec/codec.ts +0 -42
  205. package/src/codec/header-aware-codec.ts +0 -41
  206. package/src/codec/json-codec.ts +0 -69
  207. package/src/codec/rabbitmq-codec.test.ts +0 -516
  208. package/src/codec/rabbitmq-codec.ts +0 -336
  209. package/src/core/fanout.test.ts +0 -1350
  210. package/src/core/fanout.ts +0 -184
  211. package/src/core/matador.test.ts +0 -575
  212. package/src/core/matador.ts +0 -357
  213. package/src/core/shutdown.test.ts +0 -853
  214. package/src/core/shutdown.ts +0 -165
  215. package/src/errors/checkpoint-errors.ts +0 -62
  216. package/src/errors/has-description.ts +0 -25
  217. package/src/errors/index.ts +0 -58
  218. package/src/errors/matador-errors.ts +0 -477
  219. package/src/errors/retry-errors.test.ts +0 -175
  220. package/src/errors/retry-errors.ts +0 -188
  221. package/src/hooks/index.ts +0 -14
  222. package/src/hooks/safe-hooks.ts +0 -200
  223. package/src/hooks/types.ts +0 -226
  224. package/src/index.ts +0 -242
  225. package/src/pipeline/pipeline.test.ts +0 -1377
  226. package/src/pipeline/pipeline.ts +0 -393
  227. package/src/retry/policy.ts +0 -46
  228. package/src/retry/standard-policy.test.ts +0 -290
  229. package/src/retry/standard-policy.ts +0 -156
  230. package/src/schema/index.ts +0 -16
  231. package/src/schema/registry.test.ts +0 -339
  232. package/src/schema/registry.ts +0 -229
  233. package/src/schema/types.test.ts +0 -280
  234. package/src/topology/builder.test.ts +0 -451
  235. package/src/topology/builder.ts +0 -238
  236. package/src/topology/index.ts +0 -19
  237. package/src/topology/types.ts +0 -183
  238. package/src/transport/capabilities.ts +0 -88
  239. package/src/transport/connection-manager.ts +0 -218
  240. package/src/transport/index.ts +0 -42
  241. package/src/transport/local/local-transport.test.ts +0 -262
  242. package/src/transport/local/local-transport.ts +0 -330
  243. package/src/transport/multi/multi-transport.test.ts +0 -320
  244. package/src/transport/multi/multi-transport.ts +0 -294
  245. package/src/transport/rabbitmq/rabbitmq-transport.test.ts +0 -120
  246. package/src/transport/rabbitmq/rabbitmq-transport.ts +0 -782
  247. package/src/transport/transport.ts +0 -200
  248. package/src/types/dispatcher.ts +0 -18
  249. package/src/types/envelope.ts +0 -244
  250. package/src/types/event.test.ts +0 -157
  251. package/src/types/event.ts +0 -112
  252. package/src/types/index.ts +0 -62
  253. package/src/types/subscriber.ts +0 -333
  254. package/test/e2e/multi-transport.e2e.test.ts +0 -237
  255. package/test/e2e/rabbitmq-transport.e2e.test.ts +0 -618
  256. package/test/e2e/transport-compliance.e2e.test.ts +0 -506
  257. package/test/integration/matador.integration.test.ts +0 -634
  258. package/tsconfig.json +0 -29
  259. 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
- });
@@ -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
- }