@zdavison/matador 2.0.8 → 2.0.9

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 (196) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +1 -0
  3. package/dist/checkpoint/context.d.ts +0 -59
  4. package/dist/checkpoint/context.d.ts.map +0 -1
  5. package/dist/checkpoint/context.js +0 -140
  6. package/dist/checkpoint/context.test.d.ts +0 -2
  7. package/dist/checkpoint/context.test.d.ts.map +0 -1
  8. package/dist/checkpoint/context.test.js +0 -424
  9. package/dist/checkpoint/index.d.ts +0 -7
  10. package/dist/checkpoint/index.d.ts.map +0 -1
  11. package/dist/checkpoint/index.js +0 -6
  12. package/dist/checkpoint/stores/memory.d.ts +0 -29
  13. package/dist/checkpoint/stores/memory.d.ts.map +0 -1
  14. package/dist/checkpoint/stores/memory.js +0 -39
  15. package/dist/checkpoint/stores/noop.d.ts +0 -14
  16. package/dist/checkpoint/stores/noop.d.ts.map +0 -1
  17. package/dist/checkpoint/stores/noop.js +0 -18
  18. package/dist/checkpoint/stores/stores.test.d.ts +0 -2
  19. package/dist/checkpoint/stores/stores.test.d.ts.map +0 -1
  20. package/dist/checkpoint/stores/stores.test.js +0 -146
  21. package/dist/checkpoint/types.d.ts +0 -119
  22. package/dist/checkpoint/types.d.ts.map +0 -1
  23. package/dist/checkpoint/types.js +0 -1
  24. package/dist/codec/codec.d.ts +0 -29
  25. package/dist/codec/codec.d.ts.map +0 -1
  26. package/dist/codec/codec.js +0 -15
  27. package/dist/codec/header-aware-codec.d.ts +0 -36
  28. package/dist/codec/header-aware-codec.d.ts.map +0 -1
  29. package/dist/codec/header-aware-codec.js +0 -1
  30. package/dist/codec/index.d.ts +0 -6
  31. package/dist/codec/index.d.ts.map +0 -1
  32. package/dist/codec/index.js +0 -3
  33. package/dist/codec/json-codec.d.ts +0 -13
  34. package/dist/codec/json-codec.d.ts.map +0 -1
  35. package/dist/codec/json-codec.js +0 -64
  36. package/dist/codec/rabbitmq-codec.d.ts +0 -28
  37. package/dist/codec/rabbitmq-codec.d.ts.map +0 -1
  38. package/dist/codec/rabbitmq-codec.js +0 -242
  39. package/dist/codec/rabbitmq-codec.test.d.ts +0 -2
  40. package/dist/codec/rabbitmq-codec.test.d.ts.map +0 -1
  41. package/dist/codec/rabbitmq-codec.test.js +0 -433
  42. package/dist/core/fanout.d.ts +0 -59
  43. package/dist/core/fanout.d.ts.map +0 -1
  44. package/dist/core/fanout.js +0 -121
  45. package/dist/core/fanout.test.d.ts +0 -2
  46. package/dist/core/fanout.test.d.ts.map +0 -1
  47. package/dist/core/fanout.test.js +0 -1054
  48. package/dist/core/index.d.ts +0 -7
  49. package/dist/core/index.d.ts.map +0 -1
  50. package/dist/core/index.js +0 -3
  51. package/dist/core/matador.d.ts +0 -133
  52. package/dist/core/matador.d.ts.map +0 -1
  53. package/dist/core/matador.js +0 -228
  54. package/dist/core/matador.test.d.ts +0 -2
  55. package/dist/core/matador.test.d.ts.map +0 -1
  56. package/dist/core/matador.test.js +0 -446
  57. package/dist/core/shutdown.d.ts +0 -78
  58. package/dist/core/shutdown.d.ts.map +0 -1
  59. package/dist/core/shutdown.js +0 -111
  60. package/dist/core/shutdown.test.d.ts +0 -2
  61. package/dist/core/shutdown.test.d.ts.map +0 -1
  62. package/dist/core/shutdown.test.js +0 -524
  63. package/dist/errors/checkpoint-errors.d.ts +0 -30
  64. package/dist/errors/checkpoint-errors.d.ts.map +0 -1
  65. package/dist/errors/checkpoint-errors.js +0 -49
  66. package/dist/errors/has-description.d.ts +0 -18
  67. package/dist/errors/has-description.d.ts.map +0 -1
  68. package/dist/errors/has-description.js +0 -9
  69. package/dist/errors/index.d.ts +0 -6
  70. package/dist/errors/index.d.ts.map +0 -1
  71. package/dist/errors/index.js +0 -22
  72. package/dist/errors/matador-errors.d.ts +0 -183
  73. package/dist/errors/matador-errors.d.ts.map +0 -1
  74. package/dist/errors/matador-errors.js +0 -376
  75. package/dist/errors/retry-errors.d.ts +0 -102
  76. package/dist/errors/retry-errors.d.ts.map +0 -1
  77. package/dist/errors/retry-errors.js +0 -155
  78. package/dist/errors/retry-errors.test.d.ts +0 -2
  79. package/dist/errors/retry-errors.test.d.ts.map +0 -1
  80. package/dist/errors/retry-errors.test.js +0 -136
  81. package/dist/hooks/index.d.ts +0 -4
  82. package/dist/hooks/index.d.ts.map +0 -1
  83. package/dist/hooks/index.js +0 -2
  84. package/dist/hooks/safe-hooks.d.ts +0 -32
  85. package/dist/hooks/safe-hooks.d.ts.map +0 -1
  86. package/dist/hooks/safe-hooks.js +0 -120
  87. package/dist/hooks/types.d.ts +0 -172
  88. package/dist/hooks/types.d.ts.map +0 -1
  89. package/dist/hooks/types.js +0 -9
  90. package/dist/index.cjs +0 -3228
  91. package/dist/index.cjs.map +0 -1
  92. package/dist/index.d.cts +0 -23
  93. package/dist/index.d.ts +0 -23
  94. package/dist/index.d.ts.map +0 -1
  95. package/dist/index.js +0 -31
  96. package/dist/index.js.map +0 -1
  97. package/dist/pipeline/index.d.ts +0 -3
  98. package/dist/pipeline/index.d.ts.map +0 -1
  99. package/dist/pipeline/index.js +0 -1
  100. package/dist/pipeline/pipeline.d.ts +0 -63
  101. package/dist/pipeline/pipeline.d.ts.map +0 -1
  102. package/dist/pipeline/pipeline.js +0 -273
  103. package/dist/pipeline/pipeline.test.d.ts +0 -2
  104. package/dist/pipeline/pipeline.test.d.ts.map +0 -1
  105. package/dist/pipeline/pipeline.test.js +0 -1112
  106. package/dist/retry/index.d.ts +0 -4
  107. package/dist/retry/index.d.ts.map +0 -1
  108. package/dist/retry/index.js +0 -1
  109. package/dist/retry/policy.d.ts +0 -43
  110. package/dist/retry/policy.d.ts.map +0 -1
  111. package/dist/retry/policy.js +0 -1
  112. package/dist/retry/standard-policy.d.ts +0 -44
  113. package/dist/retry/standard-policy.d.ts.map +0 -1
  114. package/dist/retry/standard-policy.js +0 -102
  115. package/dist/retry/standard-policy.test.d.ts +0 -2
  116. package/dist/retry/standard-policy.test.d.ts.map +0 -1
  117. package/dist/retry/standard-policy.test.js +0 -196
  118. package/dist/schema/index.d.ts +0 -4
  119. package/dist/schema/index.d.ts.map +0 -1
  120. package/dist/schema/index.js +0 -2
  121. package/dist/schema/registry.d.ts +0 -63
  122. package/dist/schema/registry.d.ts.map +0 -1
  123. package/dist/schema/registry.js +0 -174
  124. package/dist/schema/registry.test.d.ts +0 -2
  125. package/dist/schema/registry.test.d.ts.map +0 -1
  126. package/dist/schema/registry.test.js +0 -278
  127. package/dist/schema/types.d.ts +0 -158
  128. package/dist/schema/types.d.ts.map +0 -1
  129. package/dist/schema/types.js +0 -74
  130. package/dist/schema/types.test.d.ts +0 -2
  131. package/dist/schema/types.test.d.ts.map +0 -1
  132. package/dist/schema/types.test.js +0 -242
  133. package/dist/topology/builder.d.ts +0 -80
  134. package/dist/topology/builder.d.ts.map +0 -1
  135. package/dist/topology/builder.js +0 -165
  136. package/dist/topology/builder.test.d.ts +0 -2
  137. package/dist/topology/builder.test.d.ts.map +0 -1
  138. package/dist/topology/builder.test.js +0 -360
  139. package/dist/topology/index.d.ts +0 -5
  140. package/dist/topology/index.d.ts.map +0 -1
  141. package/dist/topology/index.js +0 -2
  142. package/dist/topology/types.d.ts +0 -128
  143. package/dist/topology/types.d.ts.map +0 -1
  144. package/dist/topology/types.js +0 -28
  145. package/dist/transport/capabilities.d.ts +0 -66
  146. package/dist/transport/capabilities.d.ts.map +0 -1
  147. package/dist/transport/capabilities.js +0 -18
  148. package/dist/transport/connection-manager.d.ts +0 -95
  149. package/dist/transport/connection-manager.d.ts.map +0 -1
  150. package/dist/transport/connection-manager.js +0 -144
  151. package/dist/transport/index.d.ts +0 -11
  152. package/dist/transport/index.d.ts.map +0 -1
  153. package/dist/transport/index.js +0 -5
  154. package/dist/transport/local/local-transport.d.ts +0 -62
  155. package/dist/transport/local/local-transport.d.ts.map +0 -1
  156. package/dist/transport/local/local-transport.js +0 -241
  157. package/dist/transport/local/local-transport.test.d.ts +0 -2
  158. package/dist/transport/local/local-transport.test.d.ts.map +0 -1
  159. package/dist/transport/local/local-transport.test.js +0 -192
  160. package/dist/transport/multi/multi-transport.d.ts +0 -94
  161. package/dist/transport/multi/multi-transport.d.ts.map +0 -1
  162. package/dist/transport/multi/multi-transport.js +0 -184
  163. package/dist/transport/multi/multi-transport.test.d.ts +0 -2
  164. package/dist/transport/multi/multi-transport.test.d.ts.map +0 -1
  165. package/dist/transport/multi/multi-transport.test.js +0 -236
  166. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts +0 -83
  167. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts.map +0 -1
  168. package/dist/transport/rabbitmq/rabbitmq-transport.js +0 -541
  169. package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts +0 -2
  170. package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts.map +0 -1
  171. package/dist/transport/rabbitmq/rabbitmq-transport.test.js +0 -100
  172. package/dist/transport/transport.d.ts +0 -152
  173. package/dist/transport/transport.d.ts.map +0 -1
  174. package/dist/transport/transport.js +0 -1
  175. package/dist/types/common.d.ts +0 -41
  176. package/dist/types/common.d.ts.map +0 -1
  177. package/dist/types/common.js +0 -12
  178. package/dist/types/dispatcher.d.ts +0 -14
  179. package/dist/types/dispatcher.d.ts.map +0 -1
  180. package/dist/types/dispatcher.js +0 -1
  181. package/dist/types/envelope.d.ts +0 -131
  182. package/dist/types/envelope.d.ts.map +0 -1
  183. package/dist/types/envelope.js +0 -99
  184. package/dist/types/event.d.ts +0 -92
  185. package/dist/types/event.d.ts.map +0 -1
  186. package/dist/types/event.js +0 -26
  187. package/dist/types/event.test.d.ts +0 -2
  188. package/dist/types/event.test.d.ts.map +0 -1
  189. package/dist/types/event.test.js +0 -130
  190. package/dist/types/index.d.ts +0 -11
  191. package/dist/types/index.d.ts.map +0 -1
  192. package/dist/types/index.js +0 -4
  193. package/dist/types/subscriber.d.ts +0 -227
  194. package/dist/types/subscriber.d.ts.map +0 -1
  195. package/dist/types/subscriber.js +0 -97
  196. package/tsconfig.tsbuildinfo +0 -1
@@ -1,192 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'bun:test';
2
- import { createEnvelope } from '../../types/index.js';
3
- import { LocalTransport } from './local-transport.js';
4
- describe('LocalTransport', () => {
5
- let transport;
6
- beforeEach(() => {
7
- transport = new LocalTransport();
8
- });
9
- describe('connection', () => {
10
- it('should start disconnected', () => {
11
- expect(transport.isConnected()).toBe(false);
12
- });
13
- it('should connect successfully', async () => {
14
- await transport.connect();
15
- expect(transport.isConnected()).toBe(true);
16
- });
17
- it('should disconnect successfully', async () => {
18
- await transport.connect();
19
- await transport.disconnect();
20
- expect(transport.isConnected()).toBe(false);
21
- });
22
- });
23
- describe('capabilities', () => {
24
- it('should report correct capabilities', () => {
25
- expect(transport.name).toBe('local');
26
- expect(transport.capabilities.deliveryModes).toContain('at-least-once');
27
- expect(transport.capabilities.delayedMessages).toBe(true);
28
- expect(transport.capabilities.deadLetterRouting).toBe('manual');
29
- });
30
- });
31
- describe('send and receive', () => {
32
- beforeEach(async () => {
33
- await transport.connect();
34
- });
35
- it('should throw when sending while disconnected', async () => {
36
- await transport.disconnect();
37
- const envelope = createTestEnvelope();
38
- await expect(transport.send('test-queue', envelope)).rejects.toThrow('is not connected');
39
- });
40
- it('should send and receive a message', async () => {
41
- const envelope = createTestEnvelope();
42
- await transport.send('test-queue', envelope);
43
- const received = await transport.receiveOne('test-queue');
44
- expect(received).not.toBeNull();
45
- expect(received?.envelope.id).toBe(envelope.id);
46
- expect(received?.envelope.data).toEqual({ test: 'data' });
47
- });
48
- it('should track queue size correctly', async () => {
49
- expect(transport.getQueueSize('test-queue')).toBe(0);
50
- await transport.send('test-queue', createTestEnvelope());
51
- expect(transport.getQueueSize('test-queue')).toBe(1);
52
- await transport.send('test-queue', createTestEnvelope());
53
- expect(transport.getQueueSize('test-queue')).toBe(2);
54
- });
55
- it('should complete messages and remove from queue', async () => {
56
- const envelope = createTestEnvelope();
57
- await transport.send('test-queue', envelope);
58
- const received = await transport.receiveOne('test-queue');
59
- expect(received).not.toBeNull();
60
- await transport.complete(received.receipt);
61
- expect(transport.getQueueSize('test-queue')).toBe(0);
62
- expect(transport.getCompleted()).toHaveLength(1);
63
- });
64
- it('should return null when queue is empty', async () => {
65
- const received = await transport.receiveOne('empty-queue');
66
- expect(received).toBeNull();
67
- });
68
- });
69
- describe('subscriptions', () => {
70
- beforeEach(async () => {
71
- await transport.connect();
72
- });
73
- it('should throw when subscribing while disconnected', async () => {
74
- await transport.disconnect();
75
- await expect(transport.subscribe('test-queue', async () => { })).rejects.toThrow('is not connected');
76
- });
77
- it('should deliver messages to subscribers', async () => {
78
- const receivedMessages = [];
79
- await transport.subscribe('test-queue', async (envelope) => {
80
- receivedMessages.push(envelope);
81
- });
82
- const envelope = createTestEnvelope();
83
- await transport.send('test-queue', envelope);
84
- expect(receivedMessages).toHaveLength(1);
85
- expect(receivedMessages[0].id).toBe(envelope.id);
86
- });
87
- it('should deliver pending messages when subscribing', async () => {
88
- const envelope = createTestEnvelope();
89
- await transport.send('test-queue', envelope);
90
- const receivedMessages = [];
91
- await transport.subscribe('test-queue', async (env) => {
92
- receivedMessages.push(env);
93
- });
94
- expect(receivedMessages).toHaveLength(1);
95
- });
96
- it('should stop delivering after unsubscribe', async () => {
97
- const receivedMessages = [];
98
- const subscription = await transport.subscribe('test-queue', async (envelope) => {
99
- receivedMessages.push(envelope);
100
- });
101
- await transport.send('test-queue', createTestEnvelope());
102
- expect(receivedMessages).toHaveLength(1);
103
- await subscription.unsubscribe();
104
- expect(subscription.isActive).toBe(false);
105
- });
106
- });
107
- describe('dead letter queue', () => {
108
- beforeEach(async () => {
109
- await transport.connect();
110
- });
111
- it('should send messages to dead letter queue', async () => {
112
- const envelope = createTestEnvelope();
113
- await transport.send('test-queue', envelope);
114
- const received = await transport.receiveOne('test-queue');
115
- expect(received).not.toBeNull();
116
- await transport.sendToDeadLetter(received.receipt, 'dlq', envelope, 'test error');
117
- expect(transport.getQueueSize('test-queue')).toBe(0);
118
- expect(transport.getQueueSize('test-queue.dlq')).toBe(1);
119
- });
120
- });
121
- describe('topology', () => {
122
- it('should apply topology and create queues', async () => {
123
- const topology = {
124
- namespace: 'test',
125
- queues: [{ name: 'events' }, { name: 'notifications' }],
126
- deadLetter: {
127
- unhandled: { enabled: true },
128
- undeliverable: { enabled: true },
129
- },
130
- retry: {
131
- enabled: true,
132
- defaultDelayMs: 1000,
133
- maxDelayMs: 30000,
134
- },
135
- };
136
- await transport.connect();
137
- await transport.applyTopology(topology);
138
- // Queues should be created
139
- expect(transport.getQueueSize('test.events')).toBe(0);
140
- expect(transport.getQueueSize('test.notifications')).toBe(0);
141
- });
142
- });
143
- describe('clear', () => {
144
- it('should reset all state', async () => {
145
- await transport.connect();
146
- await transport.send('test-queue', createTestEnvelope());
147
- const received = await transport.receiveOne('test-queue');
148
- await transport.complete(received.receipt);
149
- transport.clear();
150
- expect(transport.getQueueSize('test-queue')).toBe(0);
151
- expect(transport.getCompleted()).toHaveLength(0);
152
- });
153
- });
154
- describe('delayed messages', () => {
155
- beforeEach(async () => {
156
- await transport.connect();
157
- });
158
- it('should return immediately and delay message delivery', async () => {
159
- const envelope = createTestEnvelope();
160
- // Send returns immediately (non-blocking)
161
- await transport.send('test-queue', envelope, {
162
- delay: 100,
163
- });
164
- // Message should not be in queue immediately
165
- expect(transport.getQueueSize('test-queue')).toBe(0);
166
- // Wait for the delay to pass
167
- await new Promise((resolve) => setTimeout(resolve, 150));
168
- // Message should now be in queue
169
- expect(transport.getQueueSize('test-queue')).toBe(1);
170
- });
171
- it('should cancel delayed messages on disconnect', async () => {
172
- const envelope = createTestEnvelope();
173
- await transport.send('test-queue', envelope, {
174
- delay: 100,
175
- });
176
- // Disconnect before delay expires
177
- await transport.disconnect();
178
- // Wait past the original delay
179
- await new Promise((resolve) => setTimeout(resolve, 150));
180
- // Message should never have been delivered
181
- expect(transport.getQueueSize('test-queue')).toBe(0);
182
- });
183
- });
184
- });
185
- function createTestEnvelope() {
186
- return createEnvelope({
187
- eventKey: 'test.event',
188
- targetSubscriber: 'test-subscriber',
189
- data: { test: 'data' },
190
- importance: 'should-investigate',
191
- });
192
- }
@@ -1,94 +0,0 @@
1
- import type { TransportFallbackContext } from '../../hooks/index.js';
2
- import type { Topology } from '../../topology/types.js';
3
- import type { Envelope } from '../../types/index.js';
4
- import type { TransportCapabilities } from '../capabilities.js';
5
- import type { MessageHandler, MessageReceipt, SendOptions, SubscribeOptions, Subscription, Transport } from '../transport.js';
6
- /**
7
- * Configuration for MultiTransport.
8
- */
9
- export interface MultiTransportConfig {
10
- /**
11
- * Ordered list of transports.
12
- * First transport is primary, rest are used as fallbacks when primary fails
13
- * (if fallback is enabled), or can be explicitly selected via the getDesiredBackend hook.
14
- */
15
- readonly transports: readonly Transport[];
16
- /**
17
- * Whether to automatically try fallback transports when the primary/selected fails.
18
- * When true (default), send() will try each transport in order until one succeeds.
19
- * When false, send() will only use the selected transport and throw immediately on failure.
20
- *
21
- * @default true
22
- */
23
- readonly fallbackEnabled?: boolean;
24
- }
25
- /**
26
- * Hooks for MultiTransport.
27
- */
28
- export interface MultiTransportHooks {
29
- /**
30
- * Hook to dynamically select which backend to use.
31
- * Return the transport name (e.g., 'local', 'rabbitmq') or undefined to use primary.
32
- *
33
- * @example
34
- * ```typescript
35
- * getDesiredBackend: async () => {
36
- * if (process.env.SANDBOX === 'true') return 'local';
37
- * const backend = await runtimeConfig.get('events.backend');
38
- * return backend || 'rabbitmq';
39
- * }
40
- * ```
41
- */
42
- readonly getDesiredBackend?: () => string | undefined | Promise<string | undefined>;
43
- /**
44
- * Called when a fallback transport is used successfully after the selected one fails.
45
- * Only called when fallbackEnabled is true.
46
- */
47
- readonly onEnqueueFallback?: (context: TransportFallbackContext) => void;
48
- }
49
- /**
50
- * A transport wrapper that manages multiple transports.
51
- *
52
- * Features:
53
- * - All transports are connected upfront
54
- * - send() tries transports in order until one succeeds (fallback behavior)
55
- * - Specific transport can be selected via getDesiredBackend hook
56
- * - Subscriptions are created on ALL transports
57
- *
58
- * @example
59
- * ```typescript
60
- * const transport = new MultiTransport(
61
- * { transports: [rabbitMQTransport, localTransport] },
62
- * { onEnqueueFallback: (ctx) => console.warn(`Fallback to ${ctx.nextTransport}`) },
63
- * );
64
- * ```
65
- */
66
- export declare class MultiTransport implements Transport {
67
- readonly name: string;
68
- readonly capabilities: TransportCapabilities;
69
- readonly primary: Transport;
70
- /** All available transports, in order of preference (primary first). */
71
- readonly transports: readonly Transport[];
72
- /** Whether fallback to secondary transports is enabled. */
73
- readonly fallbackEnabled: boolean;
74
- private readonly hooks;
75
- private connected;
76
- constructor(config: MultiTransportConfig, hooks?: MultiTransportHooks);
77
- connect(): Promise<void>;
78
- disconnect(): Promise<void>;
79
- isConnected(): boolean;
80
- applyTopology(topology: Topology): Promise<void>;
81
- send(queue: string, envelope: Envelope, options?: SendOptions): Promise<Transport['name']>;
82
- /**
83
- * Selects the transport to use based on the getDesiredBackend hook.
84
- */
85
- private selectTransport;
86
- /**
87
- * Returns transports in order, with the selected transport first.
88
- */
89
- private getTransportOrder;
90
- subscribe(queue: string, handler: MessageHandler, options?: SubscribeOptions): Promise<Subscription>;
91
- complete(receipt: MessageReceipt): Promise<void>;
92
- sendToDeadLetter(receipt: MessageReceipt, dlqName: string, envelope: Envelope, reason: string): Promise<void>;
93
- }
94
- //# sourceMappingURL=multi-transport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multi-transport.d.ts","sourceRoot":"","sources":["../../../src/transport/multi/multi-transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACV,MAAM,iBAAiB,CAAC;AAgBzB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAE1C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MACzB,MAAM,GACN,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEhC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;CAC1E;AAmBD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAE5B,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAE1C,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAElC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,oBAAoB,EAAE,KAAK,GAAE,mBAAwB;IAcnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,WAAW,IAAI,OAAO;IAKhB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,IAAI,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAyC7B;;OAEG;YACW,eAAe;IAwB7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASnB,SAAS,CACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC;IA0BlB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,gBAAgB,CACpB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;CAOjB"}
@@ -1,184 +0,0 @@
1
- import { AllTransportsFailedError } from '../../errors/index.js';
2
- /**
3
- * Symbol key used to store the source transport on wrapped receipts.
4
- */
5
- const SOURCE_TRANSPORT = Symbol('sourceTransport');
6
- /**
7
- * Extracts the source transport from a tagged receipt.
8
- */
9
- function getSourceTransport(receipt) {
10
- return receipt[SOURCE_TRANSPORT];
11
- }
12
- /**
13
- * Computes merged capabilities from multiple transports.
14
- * Uses the most restrictive/conservative interpretation.
15
- */
16
- function mergeCapabilities(transports) {
17
- const primary = transports[0];
18
- if (!primary) {
19
- throw new Error('At least one transport is required');
20
- }
21
- // For multi-transport scenarios, we use primary's capabilities since that's
22
- // what we'll use for subscriptions and most operations
23
- return primary.capabilities;
24
- }
25
- /**
26
- * A transport wrapper that manages multiple transports.
27
- *
28
- * Features:
29
- * - All transports are connected upfront
30
- * - send() tries transports in order until one succeeds (fallback behavior)
31
- * - Specific transport can be selected via getDesiredBackend hook
32
- * - Subscriptions are created on ALL transports
33
- *
34
- * @example
35
- * ```typescript
36
- * const transport = new MultiTransport(
37
- * { transports: [rabbitMQTransport, localTransport] },
38
- * { onEnqueueFallback: (ctx) => console.warn(`Fallback to ${ctx.nextTransport}`) },
39
- * );
40
- * ```
41
- */
42
- export class MultiTransport {
43
- name;
44
- capabilities;
45
- primary;
46
- /** All available transports, in order of preference (primary first). */
47
- transports;
48
- /** Whether fallback to secondary transports is enabled. */
49
- fallbackEnabled;
50
- hooks;
51
- connected = false;
52
- constructor(config, hooks = {}) {
53
- const primary = config.transports[0];
54
- if (!primary) {
55
- throw new Error('At least one transport is required');
56
- }
57
- this.primary = primary;
58
- this.transports = config.transports;
59
- this.fallbackEnabled = config.fallbackEnabled ?? true;
60
- this.hooks = hooks;
61
- this.name = `multi(${this.transports.map((t) => t.name).join(',')})`;
62
- this.capabilities = mergeCapabilities(this.transports);
63
- }
64
- async connect() {
65
- // Connect all transports in parallel
66
- await Promise.all(this.transports.map((t) => t.connect()));
67
- this.connected = true;
68
- }
69
- async disconnect() {
70
- // Disconnect all transports in parallel
71
- await Promise.all(this.transports.map((t) => t.disconnect()));
72
- this.connected = false;
73
- }
74
- isConnected() {
75
- // Consider connected if primary is connected
76
- return this.connected && this.primary.isConnected();
77
- }
78
- async applyTopology(topology) {
79
- // Apply topology to all transports so they're all ready
80
- await Promise.all(this.transports.map((t) => t.applyTopology(topology)));
81
- }
82
- async send(queue, envelope, options) {
83
- // Determine which transport to use
84
- const selectedTransport = await this.selectTransport();
85
- // If fallback is disabled, only use selected transport
86
- if (!this.fallbackEnabled) {
87
- return selectedTransport.send(queue, envelope, options);
88
- }
89
- // Build transport order: selected first, then others
90
- const transportOrder = this.getTransportOrder(selectedTransport);
91
- const errors = [];
92
- for (let i = 0; i < transportOrder.length; i++) {
93
- const transport = transportOrder[i];
94
- try {
95
- return await transport.send(queue, envelope, options);
96
- }
97
- catch (error) {
98
- const err = error instanceof Error ? error : new Error(String(error));
99
- errors.push(err);
100
- // Notify about fallback before trying next transport
101
- const nextTransport = transportOrder[i + 1];
102
- if (nextTransport && this.hooks.onEnqueueFallback) {
103
- this.hooks.onEnqueueFallback({
104
- envelope,
105
- queue,
106
- failedTransport: transport.name,
107
- nextTransport: nextTransport.name,
108
- error: err,
109
- });
110
- }
111
- // Continue to next transport
112
- }
113
- }
114
- // All transports failed
115
- throw new AllTransportsFailedError(queue, errors);
116
- }
117
- /**
118
- * Selects the transport to use based on the getDesiredBackend hook.
119
- */
120
- async selectTransport() {
121
- if (!this.hooks.getDesiredBackend) {
122
- return this.primary;
123
- }
124
- try {
125
- const desiredBackend = await this.hooks.getDesiredBackend();
126
- if (!desiredBackend) {
127
- return this.primary;
128
- }
129
- const selected = this.transports.find((t) => t.name === desiredBackend);
130
- if (selected) {
131
- return selected;
132
- }
133
- // Desired backend not found, use primary
134
- return this.primary;
135
- }
136
- catch {
137
- // Hook threw, use primary
138
- return this.primary;
139
- }
140
- }
141
- /**
142
- * Returns transports in order, with the selected transport first.
143
- */
144
- getTransportOrder(selected) {
145
- if (selected === this.primary) {
146
- return this.transports;
147
- }
148
- // Put selected first, then the rest (excluding selected)
149
- return [selected, ...this.transports.filter((t) => t !== selected)];
150
- }
151
- async subscribe(queue, handler, options) {
152
- // Subscribe on ALL transports so messages are processed regardless of
153
- // which transport they were enqueued to
154
- const subscriptions = await Promise.all(this.transports.map((transport) => {
155
- // Wrap handler to tag receipts with source transport
156
- const wrappedHandler = (envelope, receipt) => {
157
- const taggedReceipt = Object.assign(receipt, {
158
- [SOURCE_TRANSPORT]: transport,
159
- });
160
- return handler(envelope, taggedReceipt);
161
- };
162
- return transport.subscribe(queue, wrappedHandler, options);
163
- }));
164
- return {
165
- unsubscribe: async () => {
166
- await Promise.all(subscriptions.map((s) => s.unsubscribe()));
167
- },
168
- get isActive() {
169
- return subscriptions.some((s) => s.isActive);
170
- },
171
- };
172
- }
173
- async complete(receipt) {
174
- const transport = getSourceTransport(receipt) ?? this.primary;
175
- return transport.complete(receipt);
176
- }
177
- async sendToDeadLetter(receipt, dlqName, envelope, reason) {
178
- const transport = getSourceTransport(receipt) ?? this.primary;
179
- if (transport.sendToDeadLetter) {
180
- return transport.sendToDeadLetter(receipt, dlqName, envelope, reason);
181
- }
182
- throw new Error('Transport does not support dead letter routing');
183
- }
184
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=multi-transport.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multi-transport.test.d.ts","sourceRoot":"","sources":["../../../src/transport/multi/multi-transport.test.ts"],"names":[],"mappings":""}