@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,634 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
2
- import {
3
- DoRetry,
4
- DontRetry,
5
- LocalTransport,
6
- Matador,
7
- MatadorEvent,
8
- type MatadorSchema,
9
- TopologyBuilder,
10
- createSubscriber,
11
- } from '../../src/index.js';
12
-
13
- class UserCreatedEvent extends MatadorEvent {
14
- static readonly key = 'user.created';
15
- static readonly description = 'Fired when a new user is created';
16
-
17
- constructor(public data: { userId: string; email: string }) {
18
- super();
19
- }
20
- }
21
-
22
- class OrderPlacedEvent extends MatadorEvent {
23
- static readonly key = 'order.placed';
24
- static readonly description = 'Fired when an order is placed';
25
-
26
- constructor(
27
- public data: {
28
- orderId: string;
29
- amount: number;
30
- userId: string;
31
- },
32
- ) {
33
- super();
34
- }
35
- }
36
-
37
- class PaymentProcessedEvent extends MatadorEvent {
38
- static readonly key = 'payment.processed';
39
- static readonly description = 'Fired when a payment is processed';
40
-
41
- constructor(
42
- public data: {
43
- paymentId: string;
44
- orderId: string;
45
- status: 'success' | 'failed';
46
- },
47
- ) {
48
- super();
49
- }
50
- }
51
-
52
- describe('Matador Integration Tests', () => {
53
- let transport: LocalTransport;
54
- let matador: Matador;
55
-
56
- beforeEach(() => {
57
- transport = new LocalTransport();
58
- });
59
-
60
- afterEach(async () => {
61
- if (matador) {
62
- await matador.shutdown();
63
- }
64
- });
65
-
66
- describe('full message flow', () => {
67
- it('should dispatch event and process successfully', async () => {
68
- const processedUsers: string[] = [];
69
-
70
- const topology = TopologyBuilder.create()
71
- .withNamespace('int-test')
72
- .addQueue('events')
73
- .build();
74
-
75
- const subscriber = createSubscriber({
76
- name: 'process-user',
77
- description: 'Processes user events',
78
- callback: async ({ data }) => {
79
- processedUsers.push(data.userId);
80
- },
81
- });
82
-
83
- const schema: MatadorSchema = {
84
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
85
- };
86
-
87
- matador = new Matador({
88
- transport,
89
- topology,
90
- schema,
91
- consumeFrom: ['events'],
92
- });
93
-
94
- await matador.start();
95
-
96
- const event = new UserCreatedEvent({
97
- userId: 'user-123',
98
- email: 'test@example.com',
99
- });
100
-
101
- const result = await matador.send(event);
102
-
103
- // Wait for processing
104
- await matador.waitForIdle(5000);
105
-
106
- expect(result.subscribersSent).toBe(1);
107
- expect(result.errors).toHaveLength(0);
108
- expect(processedUsers).toContain('user-123');
109
- });
110
-
111
- it('should fan out to multiple subscribers', async () => {
112
- const notifications: string[] = [];
113
- const analytics: string[] = [];
114
- const emails: string[] = [];
115
-
116
- const topology = TopologyBuilder.create()
117
- .withNamespace('int-fanout')
118
- .addQueue('events')
119
- .build();
120
-
121
- const notifySub = createSubscriber({
122
- name: 'send-notification',
123
- description: 'Sends notifications',
124
- callback: async ({ data }) => {
125
- notifications.push(data.userId);
126
- },
127
- });
128
-
129
- const analyticsSub = createSubscriber({
130
- name: 'track-analytics',
131
- description: 'Tracks analytics',
132
- callback: async ({ data }) => {
133
- analytics.push(data.userId);
134
- },
135
- });
136
-
137
- const emailSub = createSubscriber({
138
- name: 'send-welcome-email',
139
- description: 'Sends welcome email',
140
- callback: async ({ data }) => {
141
- emails.push(data.email);
142
- },
143
- });
144
-
145
- const schema: MatadorSchema = {
146
- [UserCreatedEvent.key]: [
147
- UserCreatedEvent,
148
- [notifySub, analyticsSub, emailSub],
149
- ],
150
- };
151
-
152
- matador = new Matador({
153
- transport,
154
- topology,
155
- schema,
156
- consumeFrom: ['events'],
157
- });
158
-
159
- await matador.start();
160
-
161
- const event = new UserCreatedEvent({
162
- userId: 'user-456',
163
- email: 'fan@out.com',
164
- });
165
-
166
- const result = await matador.send(event);
167
- await matador.waitForIdle(5000);
168
-
169
- expect(result.subscribersSent).toBe(3);
170
- expect(notifications).toContain('user-456');
171
- expect(analytics).toContain('user-456');
172
- expect(emails).toContain('fan@out.com');
173
- });
174
-
175
- it('should handle multiple event types', async () => {
176
- const users: string[] = [];
177
- const orders: string[] = [];
178
-
179
- const topology = TopologyBuilder.create()
180
- .withNamespace('int-multi-event')
181
- .addQueue('events')
182
- .build();
183
-
184
- const userSub = createSubscriber({
185
- name: 'process-user',
186
- description: 'Processes user events',
187
- callback: async ({ data }) => {
188
- users.push(data.userId);
189
- },
190
- });
191
-
192
- const orderSub = createSubscriber({
193
- name: 'process-order',
194
- description: 'Processes order events',
195
- callback: async ({ data }) => {
196
- orders.push(data.orderId);
197
- },
198
- });
199
-
200
- const schema: MatadorSchema = {
201
- [UserCreatedEvent.key]: [UserCreatedEvent, [userSub]],
202
- [OrderPlacedEvent.key]: [OrderPlacedEvent, [orderSub]],
203
- };
204
-
205
- matador = new Matador({
206
- transport,
207
- topology,
208
- schema,
209
- consumeFrom: ['events'],
210
- });
211
-
212
- await matador.start();
213
-
214
- await matador.send(
215
- new UserCreatedEvent({ userId: 'u1', email: 'u1@test.com' }),
216
- );
217
- await matador.send(
218
- new OrderPlacedEvent({ orderId: 'o1', amount: 100, userId: 'u1' }),
219
- );
220
- await matador.send(
221
- new UserCreatedEvent({ userId: 'u2', email: 'u2@test.com' }),
222
- );
223
-
224
- await matador.waitForIdle(5000);
225
-
226
- expect(users).toEqual(['u1', 'u2']);
227
- expect(orders).toEqual(['o1']);
228
- });
229
- });
230
-
231
- describe('retry behavior', () => {
232
- it('should retry failed subscribers', async () => {
233
- let attempts = 0;
234
- const maxAttempts = 3;
235
-
236
- const topology = TopologyBuilder.create()
237
- .withNamespace('int-retry')
238
- .addQueue('events')
239
- .withRetry({ enabled: true, defaultDelayMs: 10, maxDelayMs: 100 })
240
- .build();
241
-
242
- const subscriber = createSubscriber({
243
- name: 'flaky-subscriber',
244
- description: 'Flaky subscriber for retry testing',
245
- callback: async () => {
246
- attempts++;
247
- if (attempts < maxAttempts) {
248
- throw new DoRetry('Temporary failure');
249
- }
250
- },
251
- });
252
-
253
- const schema: MatadorSchema = {
254
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
255
- };
256
-
257
- matador = new Matador({
258
- transport,
259
- topology,
260
- schema,
261
- consumeFrom: ['events'],
262
- });
263
-
264
- await matador.start();
265
-
266
- await matador.send(
267
- new UserCreatedEvent({ userId: 'retry-user', email: 'retry@test.com' }),
268
- );
269
-
270
- // Wait for retries
271
- await waitFor(() => attempts >= maxAttempts, 5000);
272
-
273
- expect(attempts).toBe(maxAttempts);
274
- });
275
-
276
- it('should not retry when DontRetry is thrown', async () => {
277
- let attempts = 0;
278
-
279
- const topology = TopologyBuilder.create()
280
- .withNamespace('int-dont-retry')
281
- .addQueue('events')
282
- .build();
283
-
284
- const subscriber = createSubscriber({
285
- name: 'permanent-fail-subscriber',
286
- description: 'Permanent failure subscriber',
287
- callback: async () => {
288
- attempts++;
289
- throw new DontRetry('Permanent failure');
290
- },
291
- });
292
-
293
- const schema: MatadorSchema = {
294
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
295
- };
296
-
297
- matador = new Matador({
298
- transport,
299
- topology,
300
- schema,
301
- consumeFrom: ['events'],
302
- });
303
-
304
- await matador.start();
305
-
306
- await matador.send(
307
- new UserCreatedEvent({
308
- userId: 'no-retry-user',
309
- email: 'noretry@test.com',
310
- }),
311
- );
312
-
313
- await matador.waitForIdle(2000);
314
-
315
- // Should only try once
316
- expect(attempts).toBe(1);
317
- });
318
- });
319
-
320
- describe('correlation ID propagation', () => {
321
- it('should propagate correlation ID through event chain', async () => {
322
- const correlationIds: string[] = [];
323
-
324
- const topology = TopologyBuilder.create()
325
- .withNamespace('int-correlation')
326
- .addQueue('events')
327
- .build();
328
-
329
- const subscriber = createSubscriber({
330
- name: 'track-correlation',
331
- description: 'Tracks correlation IDs',
332
- callback: async ({ docket }) => {
333
- if (docket.correlationId) {
334
- correlationIds.push(docket.correlationId);
335
- }
336
- },
337
- });
338
-
339
- const schema: MatadorSchema = {
340
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
341
- };
342
-
343
- matador = new Matador({
344
- transport,
345
- topology,
346
- schema,
347
- consumeFrom: ['events'],
348
- });
349
-
350
- await matador.start();
351
-
352
- await matador.send(
353
- new UserCreatedEvent({ userId: 'corr-user', email: 'corr@test.com' }),
354
- { correlationId: 'request-abc-123' },
355
- );
356
-
357
- await matador.waitForIdle(2000);
358
-
359
- expect(correlationIds).toContain('request-abc-123');
360
- });
361
- });
362
-
363
- describe('metadata handling', () => {
364
- it('should include metadata in docket', async () => {
365
- const receivedMetadata: Record<string, unknown>[] = [];
366
-
367
- const topology = TopologyBuilder.create()
368
- .withNamespace('int-metadata')
369
- .addQueue('events')
370
- .build();
371
-
372
- const subscriber = createSubscriber({
373
- name: 'capture-metadata',
374
- description: 'Captures metadata',
375
- callback: async ({ docket }) => {
376
- if (docket.metadata) {
377
- receivedMetadata.push(docket.metadata);
378
- }
379
- },
380
- });
381
-
382
- const schema: MatadorSchema = {
383
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
384
- };
385
-
386
- matador = new Matador({
387
- transport,
388
- topology,
389
- schema,
390
- consumeFrom: ['events'],
391
- });
392
-
393
- await matador.start();
394
-
395
- await matador.send(
396
- new UserCreatedEvent({
397
- userId: 'meta-user',
398
- email: 'meta@test.com',
399
- }),
400
- {
401
- metadata: {
402
- source: 'api',
403
- requestId: 'req-123',
404
- userAgent: 'test-client',
405
- },
406
- },
407
- );
408
-
409
- await matador.waitForIdle(2000);
410
-
411
- expect(receivedMetadata.length).toBe(1);
412
- expect(receivedMetadata[0]).toMatchObject({
413
- source: 'api',
414
- requestId: 'req-123',
415
- });
416
- });
417
- });
418
-
419
- describe('graceful shutdown', () => {
420
- it('should complete in-flight processing during shutdown', async () => {
421
- const processed: string[] = [];
422
- let processingStarted = false;
423
-
424
- const topology = TopologyBuilder.create()
425
- .withNamespace('int-shutdown')
426
- .addQueue('events')
427
- .build();
428
-
429
- const subscriber = createSubscriber({
430
- name: 'slow-subscriber',
431
- description: 'Slow subscriber for shutdown testing',
432
- callback: async ({ data }) => {
433
- processingStarted = true;
434
- // Simulate slow processing
435
- await new Promise((resolve) => setTimeout(resolve, 500));
436
- processed.push(data.userId);
437
- },
438
- });
439
-
440
- const schema: MatadorSchema = {
441
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
442
- };
443
-
444
- matador = new Matador({
445
- transport,
446
- topology,
447
- schema,
448
- consumeFrom: ['events'],
449
- shutdownConfig: {
450
- gracefulTimeoutMs: 5000,
451
- pollIntervalMs: 50,
452
- },
453
- });
454
-
455
- await matador.start();
456
-
457
- // Dispatch event
458
- await matador.send(
459
- new UserCreatedEvent({
460
- userId: 'shutdown-user',
461
- email: 'shutdown@test.com',
462
- }),
463
- );
464
-
465
- // Wait for processing to start
466
- await waitFor(() => processingStarted, 1000);
467
-
468
- // Initiate shutdown while processing
469
- await matador.shutdown();
470
-
471
- // Processing should have completed
472
- expect(processed).toContain('shutdown-user');
473
- });
474
-
475
- it('should reject new dispatches during shutdown', async () => {
476
- const topology = TopologyBuilder.create()
477
- .withNamespace('int-shutdown-reject')
478
- .addQueue('events')
479
- .build();
480
-
481
- const subscriber = createSubscriber({
482
- name: 'test-subscriber',
483
- description: 'Test subscriber',
484
- callback: async () => {},
485
- });
486
-
487
- const schema: MatadorSchema = {
488
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
489
- };
490
-
491
- matador = new Matador({
492
- transport,
493
- topology,
494
- schema,
495
- consumeFrom: ['events'],
496
- });
497
-
498
- await matador.start();
499
-
500
- // Start shutdown
501
- const shutdownPromise = matador.shutdown();
502
-
503
- // Try to dispatch after shutdown started
504
- await shutdownPromise;
505
-
506
- await expect(
507
- matador.send(
508
- new UserCreatedEvent({ userId: 'late', email: 'late@test.com' }),
509
- ),
510
- ).rejects.toThrow();
511
- });
512
- });
513
-
514
- describe('subscriber filtering', () => {
515
- it('should filter subscribers based on enabled hook', async () => {
516
- const processed: string[] = [];
517
-
518
- const topology = TopologyBuilder.create()
519
- .withNamespace('int-filter')
520
- .addQueue('events')
521
- .build();
522
-
523
- const enabledSub = createSubscriber({
524
- name: 'enabled-subscriber',
525
- description: 'Enabled subscriber',
526
- callback: async ({ data }) => {
527
- processed.push(`enabled:${data.userId}`);
528
- },
529
- enabled: () => true,
530
- });
531
-
532
- const disabledSub = createSubscriber({
533
- name: 'disabled-subscriber',
534
- description: 'Disabled subscriber',
535
- callback: async ({ data }) => {
536
- processed.push(`disabled:${data.userId}`);
537
- },
538
- enabled: () => false,
539
- });
540
-
541
- const schema: MatadorSchema = {
542
- [UserCreatedEvent.key]: [UserCreatedEvent, [enabledSub, disabledSub]],
543
- };
544
-
545
- matador = new Matador({
546
- transport,
547
- topology,
548
- schema,
549
- consumeFrom: ['events'],
550
- });
551
-
552
- await matador.start();
553
-
554
- const result = await matador.send(
555
- new UserCreatedEvent({
556
- userId: 'filter-user',
557
- email: 'filter@test.com',
558
- }),
559
- );
560
-
561
- await matador.waitForIdle(2000);
562
-
563
- // Only enabled subscriber should be dispatched
564
- expect(result.subscribersSent).toBe(1);
565
- expect(processed).toContain('enabled:filter-user');
566
- expect(processed).not.toContain('disabled:filter-user');
567
- });
568
- });
569
-
570
- describe('handlers state', () => {
571
- it('should track handlers state during processing', async () => {
572
- let wasNotIdle = false;
573
-
574
- const topology = TopologyBuilder.create()
575
- .withNamespace('int-state')
576
- .addQueue('events')
577
- .build();
578
-
579
- const subscriber = createSubscriber({
580
- name: 'state-subscriber',
581
- description: 'State tracking subscriber',
582
- callback: async () => {
583
- // Check state while processing
584
- const state = matador.getHandlersState();
585
- if (state.eventsBeingProcessed > 0) {
586
- wasNotIdle = true;
587
- }
588
- await new Promise((resolve) => setTimeout(resolve, 100));
589
- },
590
- });
591
-
592
- const schema: MatadorSchema = {
593
- [UserCreatedEvent.key]: [UserCreatedEvent, [subscriber]],
594
- };
595
-
596
- matador = new Matador({
597
- transport,
598
- topology,
599
- schema,
600
- consumeFrom: ['events'],
601
- });
602
-
603
- await matador.start();
604
-
605
- expect(matador.isIdle()).toBe(true);
606
-
607
- await matador.send(
608
- new UserCreatedEvent({ userId: 'state-user', email: 'state@test.com' }),
609
- );
610
-
611
- await matador.waitForIdle(5000);
612
-
613
- expect(wasNotIdle).toBe(true);
614
- expect(matador.isIdle()).toBe(true);
615
- });
616
- });
617
- });
618
-
619
- /**
620
- * Waits for a condition to be true, with timeout.
621
- */
622
- async function waitFor(
623
- condition: () => boolean,
624
- timeoutMs: number,
625
- intervalMs = 50,
626
- ): Promise<void> {
627
- const startTime = Date.now();
628
- while (!condition()) {
629
- if (Date.now() - startTime > timeoutMs) {
630
- throw new Error(`Timeout waiting for condition after ${timeoutMs}ms`);
631
- }
632
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
633
- }
634
- }
package/tsconfig.json DELETED
@@ -1,29 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "composite": true,
4
- "target": "ES2022",
5
- "module": "NodeNext",
6
- "moduleResolution": "NodeNext",
7
- "lib": ["ES2022"],
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "declaration": true,
13
- "declarationMap": true,
14
- "outDir": "./dist",
15
- "rootDir": "./src",
16
- "noEmit": false,
17
- "noUnusedLocals": true,
18
- "noUnusedParameters": true,
19
- "noImplicitReturns": true,
20
- "noFallthroughCasesInSwitch": true,
21
- "exactOptionalPropertyTypes": true,
22
- "noUncheckedIndexedAccess": true,
23
- "resolveJsonModule": true,
24
- "isolatedModules": true,
25
- "verbatimModuleSyntax": true
26
- },
27
- "include": ["src/**/*"],
28
- "exclude": ["node_modules", "dist", "test"]
29
- }
package/tsup.config.ts DELETED
@@ -1,13 +0,0 @@
1
- import { defineConfig } from 'tsup';
2
-
3
- export default defineConfig({
4
- entry: ['src/index.ts'],
5
- format: ['cjs', 'esm'],
6
- dts: false,
7
- splitting: false,
8
- sourcemap: true,
9
- clean: false,
10
- outDir: 'dist',
11
- target: 'node18',
12
- treeshake: true,
13
- });