@zdavison/matador 2.0.8 → 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 (77) hide show
  1. package/dist/index.d.cts +1 -1
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/package.json +6 -2
  5. package/examples/config.ts +0 -126
  6. package/examples/event.ts +0 -26
  7. package/examples/order-event.json +0 -19
  8. package/src/checkpoint/context.test.ts +0 -510
  9. package/src/checkpoint/context.ts +0 -213
  10. package/src/checkpoint/index.ts +0 -30
  11. package/src/checkpoint/stores/memory.ts +0 -47
  12. package/src/checkpoint/stores/noop.ts +0 -22
  13. package/src/checkpoint/stores/stores.test.ts +0 -177
  14. package/src/checkpoint/types.ts +0 -147
  15. package/src/codec/codec.ts +0 -42
  16. package/src/codec/header-aware-codec.ts +0 -41
  17. package/src/codec/index.ts +0 -11
  18. package/src/codec/json-codec.ts +0 -69
  19. package/src/codec/rabbitmq-codec.test.ts +0 -516
  20. package/src/codec/rabbitmq-codec.ts +0 -336
  21. package/src/core/fanout.test.ts +0 -1350
  22. package/src/core/fanout.ts +0 -184
  23. package/src/core/index.ts +0 -12
  24. package/src/core/matador.test.ts +0 -575
  25. package/src/core/matador.ts +0 -357
  26. package/src/core/shutdown.test.ts +0 -853
  27. package/src/core/shutdown.ts +0 -165
  28. package/src/errors/checkpoint-errors.ts +0 -62
  29. package/src/errors/has-description.ts +0 -25
  30. package/src/errors/index.ts +0 -58
  31. package/src/errors/matador-errors.ts +0 -477
  32. package/src/errors/retry-errors.test.ts +0 -175
  33. package/src/errors/retry-errors.ts +0 -188
  34. package/src/hooks/index.ts +0 -14
  35. package/src/hooks/safe-hooks.ts +0 -200
  36. package/src/hooks/types.ts +0 -226
  37. package/src/index.ts +0 -241
  38. package/src/pipeline/index.ts +0 -2
  39. package/src/pipeline/pipeline.test.ts +0 -1377
  40. package/src/pipeline/pipeline.ts +0 -393
  41. package/src/retry/index.ts +0 -4
  42. package/src/retry/policy.ts +0 -46
  43. package/src/retry/standard-policy.test.ts +0 -290
  44. package/src/retry/standard-policy.ts +0 -156
  45. package/src/schema/index.ts +0 -16
  46. package/src/schema/registry.test.ts +0 -339
  47. package/src/schema/registry.ts +0 -229
  48. package/src/schema/types.test.ts +0 -280
  49. package/src/schema/types.ts +0 -217
  50. package/src/topology/builder.test.ts +0 -451
  51. package/src/topology/builder.ts +0 -238
  52. package/src/topology/index.ts +0 -19
  53. package/src/topology/types.ts +0 -183
  54. package/src/transport/capabilities.ts +0 -88
  55. package/src/transport/connection-manager.ts +0 -218
  56. package/src/transport/index.ts +0 -42
  57. package/src/transport/local/local-transport.test.ts +0 -262
  58. package/src/transport/local/local-transport.ts +0 -330
  59. package/src/transport/multi/multi-transport.test.ts +0 -320
  60. package/src/transport/multi/multi-transport.ts +0 -294
  61. package/src/transport/rabbitmq/rabbitmq-transport.test.ts +0 -120
  62. package/src/transport/rabbitmq/rabbitmq-transport.ts +0 -782
  63. package/src/transport/transport.ts +0 -200
  64. package/src/types/common.ts +0 -53
  65. package/src/types/dispatcher.ts +0 -18
  66. package/src/types/envelope.ts +0 -244
  67. package/src/types/event.test.ts +0 -157
  68. package/src/types/event.ts +0 -112
  69. package/src/types/index.ts +0 -62
  70. package/src/types/subscriber.ts +0 -333
  71. package/test/e2e/multi-transport.e2e.test.ts +0 -237
  72. package/test/e2e/rabbitmq-transport.e2e.test.ts +0 -618
  73. package/test/e2e/transport-compliance.e2e.test.ts +0 -506
  74. package/test/integration/matador.integration.test.ts +0 -634
  75. package/tsconfig.json +0 -29
  76. package/tsconfig.tsbuildinfo +0 -1
  77. package/tsup.config.ts +0 -13
@@ -1,516 +0,0 @@
1
- import { describe, expect, it } from 'bun:test';
2
- import type { Importance } from '../types/common.js';
3
- import { RabbitMQCodec } from './rabbitmq-codec.js';
4
-
5
- /**
6
- * V1 message body format for test fixtures.
7
- */
8
- interface V1MessageBody {
9
- key: string;
10
- data: unknown;
11
- metadata?: unknown;
12
- universal?: {
13
- event_id?: string | null;
14
- user_id?: string | null;
15
- correlation_id?: string | null;
16
- [key: string]: unknown;
17
- };
18
- before?: unknown;
19
- options?: { delayMs?: number };
20
- targetSubscriber: string;
21
- }
22
-
23
- /**
24
- * A v1 message fixture with optional headers.
25
- */
26
- interface V1MessageFixture {
27
- name: string;
28
- body: V1MessageBody;
29
- headers?: Record<string, unknown>;
30
- expected: {
31
- id?: string;
32
- eventKey: string;
33
- targetSubscriber: string;
34
- data: unknown;
35
- metadata?: Record<string, unknown>;
36
- correlationId?: string;
37
- attempts?: number;
38
- importance?: Importance;
39
- };
40
- }
41
-
42
- /**
43
- * Add your v1 message examples here.
44
- * Each fixture describes:
45
- * - name: A descriptive name for the test case
46
- * - body: The v1 message body (what goes in the RabbitMQ message content)
47
- * - headers: Optional RabbitMQ headers that accompany the message
48
- * - expected: The expected v2 envelope fields after translation
49
- */
50
- const V1_MESSAGE_FIXTURES: V1MessageFixture[] = [
51
- // === BASIC EXAMPLES ===
52
- {
53
- name: 'minimal v1 message with only required fields',
54
- body: {
55
- key: 'user.created',
56
- data: { userId: '123' },
57
- targetSubscriber: 'email-service',
58
- },
59
- expected: {
60
- eventKey: 'user.created',
61
- targetSubscriber: 'email-service',
62
- data: { userId: '123' },
63
- attempts: 1,
64
- importance: 'should-investigate',
65
- },
66
- },
67
-
68
- {
69
- name: 'v1 message with metadata',
70
- body: {
71
- key: 'order.placed',
72
- data: { orderId: 'ORD-456', amount: 99.99 },
73
- metadata: { source: 'web', region: 'us-east' },
74
- targetSubscriber: 'fulfillment-service',
75
- },
76
- expected: {
77
- eventKey: 'order.placed',
78
- targetSubscriber: 'fulfillment-service',
79
- data: { orderId: 'ORD-456', amount: 99.99 },
80
- metadata: { source: 'web', region: 'us-east' },
81
- },
82
- },
83
-
84
- // === UNIVERSAL METADATA EXAMPLES ===
85
- {
86
- name: 'v1 message with universal.event_id',
87
- body: {
88
- key: 'payment.processed',
89
- data: { paymentId: 'PAY-789' },
90
- universal: {
91
- event_id: 'evt-abc-123',
92
- },
93
- targetSubscriber: 'notification-service',
94
- },
95
- expected: {
96
- id: 'evt-abc-123',
97
- eventKey: 'payment.processed',
98
- targetSubscriber: 'notification-service',
99
- data: { paymentId: 'PAY-789' },
100
- },
101
- },
102
-
103
- {
104
- name: 'v1 message with universal.user_id (merged into metadata)',
105
- body: {
106
- key: 'profile.updated',
107
- data: { field: 'email' },
108
- universal: {
109
- user_id: 'user-456',
110
- },
111
- targetSubscriber: 'audit-service',
112
- },
113
- expected: {
114
- eventKey: 'profile.updated',
115
- targetSubscriber: 'audit-service',
116
- data: { field: 'email' },
117
- metadata: { user_id: 'user-456' },
118
- },
119
- },
120
-
121
- {
122
- name: 'v1 message with universal.correlation_id',
123
- body: {
124
- key: 'request.received',
125
- data: { requestId: 'req-001' },
126
- universal: {
127
- correlation_id: 'corr-xyz-789',
128
- },
129
- targetSubscriber: 'logger-service',
130
- },
131
- expected: {
132
- eventKey: 'request.received',
133
- targetSubscriber: 'logger-service',
134
- data: { requestId: 'req-001' },
135
- correlationId: 'corr-xyz-789',
136
- },
137
- },
138
-
139
- {
140
- name: 'v1 message with all universal fields',
141
- body: {
142
- key: 'checkout.completed',
143
- data: { cartId: 'cart-999' },
144
- universal: {
145
- event_id: 'evt-full-123',
146
- user_id: 'user-777',
147
- correlation_id: 'corr-full-456',
148
- custom_field: 'custom_value',
149
- },
150
- targetSubscriber: 'analytics-service',
151
- },
152
- expected: {
153
- id: 'evt-full-123',
154
- eventKey: 'checkout.completed',
155
- targetSubscriber: 'analytics-service',
156
- data: { cartId: 'cart-999' },
157
- correlationId: 'corr-full-456',
158
- metadata: {
159
- user_id: 'user-777',
160
- custom_field: 'custom_value',
161
- },
162
- },
163
- },
164
-
165
- // === METADATA MERGING EXAMPLES ===
166
- {
167
- name: 'v1 message with both metadata and universal (merged)',
168
- body: {
169
- key: 'item.added',
170
- data: { itemId: 'item-123' },
171
- metadata: { category: 'electronics', priority: 'high' },
172
- universal: {
173
- user_id: 'user-888',
174
- tenant_id: 'tenant-001',
175
- },
176
- targetSubscriber: 'inventory-service',
177
- },
178
- expected: {
179
- eventKey: 'item.added',
180
- targetSubscriber: 'inventory-service',
181
- data: { itemId: 'item-123' },
182
- metadata: {
183
- category: 'electronics',
184
- priority: 'high',
185
- user_id: 'user-888',
186
- tenant_id: 'tenant-001',
187
- },
188
- },
189
- },
190
-
191
- // === HEADER-BASED EXAMPLES ===
192
- {
193
- name: 'v1 message with attempt count from header',
194
- body: {
195
- key: 'task.retry',
196
- data: { taskId: 'task-555' },
197
- targetSubscriber: 'worker-service',
198
- },
199
- headers: {
200
- 'x-matador-attempts': 3,
201
- },
202
- expected: {
203
- eventKey: 'task.retry',
204
- targetSubscriber: 'worker-service',
205
- data: { taskId: 'task-555' },
206
- attempts: 3,
207
- },
208
- },
209
-
210
- {
211
- name: 'v1 message with importance from header',
212
- body: {
213
- key: 'alert.triggered',
214
- data: { alertId: 'alert-111' },
215
- targetSubscriber: 'pager-service',
216
- },
217
- headers: {
218
- 'x-matador-importance': 'must-investigate',
219
- },
220
- expected: {
221
- eventKey: 'alert.triggered',
222
- targetSubscriber: 'pager-service',
223
- data: { alertId: 'alert-111' },
224
- importance: 'must-investigate',
225
- },
226
- },
227
-
228
- {
229
- name: 'v1 message with correlation_id from v1 header',
230
- body: {
231
- key: 'trace.event',
232
- data: { traceId: 'trace-222' },
233
- targetSubscriber: 'tracing-service',
234
- },
235
- headers: {
236
- 'x-correlation-id': 'header-corr-id',
237
- },
238
- expected: {
239
- eventKey: 'trace.event',
240
- targetSubscriber: 'tracing-service',
241
- data: { traceId: 'trace-222' },
242
- correlationId: 'header-corr-id',
243
- },
244
- },
245
-
246
- {
247
- name: 'v1 message with event_id from v1 header',
248
- body: {
249
- key: 'legacy.event',
250
- data: { legacyId: 'leg-333' },
251
- targetSubscriber: 'legacy-handler',
252
- },
253
- headers: {
254
- 'x-event-id': 'header-event-id-456',
255
- },
256
- expected: {
257
- id: 'header-event-id-456',
258
- eventKey: 'legacy.event',
259
- targetSubscriber: 'legacy-handler',
260
- data: { legacyId: 'leg-333' },
261
- },
262
- },
263
-
264
- // === EDGE CASES ===
265
- {
266
- name: 'v1 message with null universal fields (ignored)',
267
- body: {
268
- key: 'null.test',
269
- data: { test: true },
270
- universal: {
271
- event_id: null,
272
- user_id: null,
273
- correlation_id: null,
274
- },
275
- targetSubscriber: 'null-handler',
276
- },
277
- expected: {
278
- eventKey: 'null.test',
279
- targetSubscriber: 'null-handler',
280
- data: { test: true },
281
- },
282
- },
283
-
284
- {
285
- name: 'v1 message with empty metadata object',
286
- body: {
287
- key: 'empty.metadata',
288
- data: { value: 42 },
289
- metadata: {},
290
- targetSubscriber: 'empty-handler',
291
- },
292
- expected: {
293
- eventKey: 'empty.metadata',
294
- targetSubscriber: 'empty-handler',
295
- data: { value: 42 },
296
- },
297
- },
298
-
299
- {
300
- name: 'v1 message with complex nested data',
301
- body: {
302
- key: 'complex.event',
303
- data: {
304
- nested: {
305
- deeply: {
306
- value: [1, 2, { three: 'four' }],
307
- },
308
- },
309
- array: ['a', 'b', 'c'],
310
- },
311
- targetSubscriber: 'complex-handler',
312
- },
313
- expected: {
314
- eventKey: 'complex.event',
315
- targetSubscriber: 'complex-handler',
316
- data: {
317
- nested: {
318
- deeply: {
319
- value: [1, 2, { three: 'four' }],
320
- },
321
- },
322
- array: ['a', 'b', 'c'],
323
- },
324
- },
325
- },
326
-
327
- {
328
- name: 'v1 message with before field (ignored in v2)',
329
- body: {
330
- key: 'update.event',
331
- data: { newValue: 'after' },
332
- before: { oldValue: 'before' },
333
- targetSubscriber: 'update-handler',
334
- },
335
- expected: {
336
- eventKey: 'update.event',
337
- targetSubscriber: 'update-handler',
338
- data: { newValue: 'after' },
339
- },
340
- },
341
-
342
- // === ADD YOUR EXAMPLES BELOW ===
343
- // Copy this template and fill in your v1 message data:
344
- //
345
- // {
346
- // name: 'descriptive name for your test case',
347
- // body: {
348
- // key: 'your.event.key',
349
- // data: { /* your event data */ },
350
- // metadata: { /* optional metadata */ },
351
- // universal: {
352
- // event_id: 'optional-event-id',
353
- // user_id: 'optional-user-id',
354
- // correlation_id: 'optional-correlation-id',
355
- // // any other custom fields
356
- // },
357
- // before: { /* optional, will be ignored */ },
358
- // options: { delayMs: 1000 }, // optional
359
- // targetSubscriber: 'your-subscriber-name',
360
- // },
361
- // headers: {
362
- // // optional headers
363
- // 'x-matador-attempts': 1,
364
- // 'x-matador-importance': 'should-investigate',
365
- // 'x-event-id': 'header-event-id',
366
- // 'x-correlation-id': 'header-correlation-id',
367
- // },
368
- // expected: {
369
- // id: 'expected-id', // optional, will be generated if not in body/headers
370
- // eventKey: 'your.event.key',
371
- // targetSubscriber: 'your-subscriber-name',
372
- // data: { /* expected data */ },
373
- // metadata: { /* expected merged metadata */ },
374
- // correlationId: 'expected-correlation-id',
375
- // attempts: 1,
376
- // importance: 'should-investigate',
377
- // },
378
- // },
379
- ];
380
-
381
- describe('RabbitMQCodec', () => {
382
- const codec = new RabbitMQCodec();
383
-
384
- describe('v1 to v2 translation', () => {
385
- for (const fixture of V1_MESSAGE_FIXTURES) {
386
- it(`should translate: ${fixture.name}`, () => {
387
- const body = new TextEncoder().encode(JSON.stringify(fixture.body));
388
- const headers = fixture.headers ?? {};
389
-
390
- const envelope = codec.decode(body, headers);
391
-
392
- // Check required fields
393
- expect(envelope.docket.eventKey).toBe(fixture.expected.eventKey);
394
- expect(envelope.docket.targetSubscriber).toBe(
395
- fixture.expected.targetSubscriber,
396
- );
397
- expect(envelope.data).toEqual(fixture.expected.data);
398
-
399
- // Check optional ID (may be generated if not specified)
400
- if (fixture.expected.id !== undefined) {
401
- expect(envelope.id).toBe(fixture.expected.id);
402
- } else {
403
- expect(envelope.id).toMatch(
404
- /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
405
- );
406
- }
407
-
408
- // Check metadata
409
- if (fixture.expected.metadata !== undefined) {
410
- expect(envelope.docket.metadata).toEqual(fixture.expected.metadata);
411
- } else {
412
- expect(
413
- envelope.docket.metadata === undefined ||
414
- Object.keys(envelope.docket.metadata).length === 0,
415
- ).toBe(true);
416
- }
417
-
418
- // Check correlation ID
419
- if (fixture.expected.correlationId !== undefined) {
420
- expect(envelope.docket.correlationId).toBe(
421
- fixture.expected.correlationId,
422
- );
423
- }
424
-
425
- // Check attempts (defaults to 1)
426
- if (fixture.expected.attempts !== undefined) {
427
- expect(envelope.docket.attempts).toBe(fixture.expected.attempts);
428
- } else {
429
- expect(envelope.docket.attempts).toBe(1);
430
- }
431
-
432
- // Check importance (defaults to 'should-investigate')
433
- if (fixture.expected.importance !== undefined) {
434
- expect(envelope.docket.importance).toBe(fixture.expected.importance);
435
- } else {
436
- expect(envelope.docket.importance).toBe('should-investigate');
437
- }
438
-
439
- // Check createdAt is a valid ISO string
440
- expect(envelope.docket.createdAt).toMatch(
441
- /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/,
442
- );
443
- });
444
- }
445
- });
446
-
447
- describe('v1 edge cases', () => {
448
- it('should handle options.delayMs by setting scheduledFor', () => {
449
- const body: V1MessageBody = {
450
- key: 'delayed.event',
451
- data: { test: true },
452
- options: { delayMs: 5000 },
453
- targetSubscriber: 'delay-handler',
454
- };
455
-
456
- const encoded = new TextEncoder().encode(JSON.stringify(body));
457
- const before = Date.now();
458
- const envelope = codec.decode(encoded, {});
459
- const after = Date.now();
460
-
461
- expect(envelope.docket.scheduledFor).toBeDefined();
462
-
463
- const scheduledTime = new Date(envelope.docket.scheduledFor!).getTime();
464
- expect(scheduledTime).toBeGreaterThanOrEqual(before + 5000);
465
- expect(scheduledTime).toBeLessThanOrEqual(after + 5000);
466
- });
467
-
468
- it('should prefer header event_id over body universal.event_id', () => {
469
- const body: V1MessageBody = {
470
- key: 'priority.test',
471
- data: {},
472
- universal: { event_id: 'body-event-id' },
473
- targetSubscriber: 'test-handler',
474
- };
475
-
476
- const encoded = new TextEncoder().encode(JSON.stringify(body));
477
- const envelope = codec.decode(encoded, {
478
- 'x-event-id': 'header-event-id',
479
- });
480
-
481
- expect(envelope.id).toBe('header-event-id');
482
- });
483
-
484
- it('should prefer v2 correlation header over v1 header', () => {
485
- const body: V1MessageBody = {
486
- key: 'corr.priority',
487
- data: {},
488
- targetSubscriber: 'test-handler',
489
- };
490
-
491
- const encoded = new TextEncoder().encode(JSON.stringify(body));
492
- const envelope = codec.decode(encoded, {
493
- 'x-matador-correlation-id': 'v2-corr-id',
494
- 'x-correlation-id': 'v1-corr-id',
495
- });
496
-
497
- expect(envelope.docket.correlationId).toBe('v2-corr-id');
498
- });
499
-
500
- it('should prefer header correlation_id over body universal.correlation_id', () => {
501
- const body: V1MessageBody = {
502
- key: 'corr.priority',
503
- data: {},
504
- universal: { correlation_id: 'body-corr-id' },
505
- targetSubscriber: 'test-handler',
506
- };
507
-
508
- const encoded = new TextEncoder().encode(JSON.stringify(body));
509
- const envelope = codec.decode(encoded, {
510
- 'x-correlation-id': 'header-corr-id',
511
- });
512
-
513
- expect(envelope.docket.correlationId).toBe('header-corr-id');
514
- });
515
- });
516
- });