@relaybus/rabbitmq 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +236 -2
- package/dist/index.cjs +1113 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +281 -0
- package/dist/index.d.ts +281 -0
- package/dist/index.js +1105 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { NonRetryableError, RelayBusError, RetryPolicyOptions, Duration, RelayBusLogger, Transport, EventEnvelope, TransportMessageHandler } from '@relaybus/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The slice of amqplib this package relies on. Declaring it here keeps the
|
|
6
|
+
* public types independent of the amqplib version (peer range `>=0.10`) and
|
|
7
|
+
* lets tests substitute fakes. Real amqplib connections and channels satisfy it.
|
|
8
|
+
*/
|
|
9
|
+
/** Message properties as delivered by the broker. */
|
|
10
|
+
interface AmqpMessageProperties {
|
|
11
|
+
readonly messageId?: unknown;
|
|
12
|
+
readonly type?: unknown;
|
|
13
|
+
readonly appId?: unknown;
|
|
14
|
+
readonly correlationId?: unknown;
|
|
15
|
+
readonly timestamp?: unknown;
|
|
16
|
+
readonly contentType?: unknown;
|
|
17
|
+
readonly headers?: Readonly<Record<string, unknown>> | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** A message delivered to a consumer or returned by the broker. */
|
|
20
|
+
interface AmqpMessage {
|
|
21
|
+
readonly content: Buffer;
|
|
22
|
+
readonly fields: {
|
|
23
|
+
readonly routingKey: string;
|
|
24
|
+
};
|
|
25
|
+
readonly properties: AmqpMessageProperties;
|
|
26
|
+
}
|
|
27
|
+
/** Properties set on a published message. */
|
|
28
|
+
interface AmqpPublishOptions {
|
|
29
|
+
readonly contentType: string;
|
|
30
|
+
readonly persistent: boolean;
|
|
31
|
+
readonly mandatory?: boolean;
|
|
32
|
+
readonly messageId?: string;
|
|
33
|
+
readonly type?: string;
|
|
34
|
+
readonly appId?: string;
|
|
35
|
+
readonly timestamp?: number;
|
|
36
|
+
readonly correlationId?: string;
|
|
37
|
+
readonly headers: Readonly<Record<string, unknown>>;
|
|
38
|
+
}
|
|
39
|
+
/** Channel used for consuming. */
|
|
40
|
+
interface AmqpChannel extends EventEmitter {
|
|
41
|
+
assertExchange(exchange: string, type: string, options?: {
|
|
42
|
+
readonly durable?: boolean;
|
|
43
|
+
}): Promise<unknown>;
|
|
44
|
+
assertQueue(queue: string, options?: {
|
|
45
|
+
readonly durable?: boolean;
|
|
46
|
+
readonly arguments?: Record<string, unknown>;
|
|
47
|
+
}): Promise<unknown>;
|
|
48
|
+
bindQueue(queue: string, source: string, pattern: string): Promise<unknown>;
|
|
49
|
+
prefetch(count: number): Promise<unknown>;
|
|
50
|
+
consume(queue: string, onMessage: (message: AmqpMessage | null) => void, options?: {
|
|
51
|
+
readonly noAck?: boolean;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
readonly consumerTag: string;
|
|
54
|
+
}>;
|
|
55
|
+
cancel(consumerTag: string): Promise<unknown>;
|
|
56
|
+
ack(message: AmqpMessage): void;
|
|
57
|
+
nack(message: AmqpMessage, allUpTo?: boolean, requeue?: boolean): void;
|
|
58
|
+
close(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/** Channel with publisher confirms. */
|
|
61
|
+
interface AmqpConfirmChannel extends AmqpChannel {
|
|
62
|
+
publish(exchange: string, routingKey: string, content: Buffer, options: AmqpPublishOptions, callback: (error: Error | null | undefined) => void): boolean;
|
|
63
|
+
}
|
|
64
|
+
/** A broker connection. Emits `close` and `error`. */
|
|
65
|
+
interface AmqpConnection extends EventEmitter {
|
|
66
|
+
createChannel(): Promise<AmqpChannel>;
|
|
67
|
+
createConfirmChannel(): Promise<AmqpConfirmChannel>;
|
|
68
|
+
close(): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The broker cannot take or confirm a message right now: the transport is not
|
|
73
|
+
* connected, was closed, lost its channel, or the confirm did not arrive in time.
|
|
74
|
+
* Always retryable; the outbox keeps the delivery and tries again.
|
|
75
|
+
*/
|
|
76
|
+
declare class RabbitMqUnavailableError extends RelayBusError {
|
|
77
|
+
}
|
|
78
|
+
/** The broker negatively acknowledged a published message. Retryable. */
|
|
79
|
+
declare class RabbitMqPublishRejectedError extends RelayBusError {
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The broker accepted the message but no queue is bound to its routing key, so
|
|
83
|
+
* it would have been discarded. Retryable: it succeeds once a consumer binds.
|
|
84
|
+
*/
|
|
85
|
+
declare class UnroutableMessageError extends RelayBusError {
|
|
86
|
+
}
|
|
87
|
+
/** A received message is not a valid relaybus CloudEvent. It is dead-lettered. */
|
|
88
|
+
declare class MalformedMessageError extends RelayBusError {
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The payload of an event cannot be represented as JSON without losing or
|
|
92
|
+
* changing data (`undefined`, functions, symbols, BigInt, NaN, Infinity, Dates,
|
|
93
|
+
* Maps, class instances, cycles). Never retried: the payload will not change.
|
|
94
|
+
*/
|
|
95
|
+
declare class UnserializablePayloadError extends NonRetryableError {
|
|
96
|
+
name: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A value exceeds a protocol limit of AMQP 0-9-1, for example an event id or a
|
|
100
|
+
* routing key longer than the 255 bytes of a short string. Never retried.
|
|
101
|
+
*/
|
|
102
|
+
declare class AmqpLimitExceededError extends NonRetryableError {
|
|
103
|
+
name: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Connection settings accepted by `amqplib.connect`, given as an object instead of a URL. */
|
|
107
|
+
interface BrokerConnectionSettings {
|
|
108
|
+
readonly protocol?: string;
|
|
109
|
+
readonly hostname?: string;
|
|
110
|
+
readonly port?: number;
|
|
111
|
+
readonly username?: string;
|
|
112
|
+
readonly password?: string;
|
|
113
|
+
readonly vhost?: string;
|
|
114
|
+
/** Seconds. See "Operational notes" in the README for the heartbeat defaults of each amqplib version. */
|
|
115
|
+
readonly heartbeat?: number;
|
|
116
|
+
}
|
|
117
|
+
/** Backoff between reconnect attempts. Attempts are unlimited. */
|
|
118
|
+
type ReconnectOptions = Pick<RetryPolicyOptions, 'initialDelay' | 'factor' | 'maxDelay' | 'jitter'>;
|
|
119
|
+
/**
|
|
120
|
+
* Delayed redelivery of messages whose handler keeps failing. Each failed
|
|
121
|
+
* delivery goes to a retry queue and returns to the main queue after a growing
|
|
122
|
+
* delay, so an outage of the handler's dependency is waited out instead of
|
|
123
|
+
* burning through delivery attempts.
|
|
124
|
+
*/
|
|
125
|
+
type RedeliveryOptions = Pick<RetryPolicyOptions, 'initialDelay' | 'factor' | 'maxDelay' | 'jitter'> & {
|
|
126
|
+
/**
|
|
127
|
+
* How long a message may keep failing, counted from its first delayed
|
|
128
|
+
* redelivery, before it is dead-lettered. Default `'1h'`.
|
|
129
|
+
*/
|
|
130
|
+
readonly maxAge?: Duration;
|
|
131
|
+
};
|
|
132
|
+
interface RabbitMqTransportOptions {
|
|
133
|
+
/** Name referenced by routes and subscriptions. Default `'rabbitmq'`. */
|
|
134
|
+
readonly name?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Broker location, for example `amqp://user:pass@host:5672/vhost?heartbeat=30`.
|
|
137
|
+
* Give exactly one of `url` and `connect`.
|
|
138
|
+
*/
|
|
139
|
+
readonly url?: string | BrokerConnectionSettings;
|
|
140
|
+
/**
|
|
141
|
+
* Opens one connection. Called again after every connection loss. Use it for
|
|
142
|
+
* TLS options, custom credentials or an alternative amqplib instance.
|
|
143
|
+
*/
|
|
144
|
+
readonly connect?: () => Promise<AmqpConnection>;
|
|
145
|
+
/** Topic exchange events are published to. Durable, created when missing. Default `'relaybus'`. */
|
|
146
|
+
readonly exchange?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Unacknowledged messages the consumer holds, which is also its concurrency.
|
|
149
|
+
* Default 50, or 1 when `ordered`.
|
|
150
|
+
*/
|
|
151
|
+
readonly prefetch?: number;
|
|
152
|
+
/** Prefix of derived queue names. Default `'relaybus'`. */
|
|
153
|
+
readonly queuePrefix?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Consumer group: services sharing it share one queue and split the messages,
|
|
156
|
+
* services with different groups each receive every message. The queue is
|
|
157
|
+
* `<queuePrefix>.<consumerGroup>`. Required when subscribing, unless `queue` is set.
|
|
158
|
+
*/
|
|
159
|
+
readonly consumerGroup?: string;
|
|
160
|
+
/** Explicit queue name. Overrides `queuePrefix` and `consumerGroup`. */
|
|
161
|
+
readonly queue?: string;
|
|
162
|
+
/** Exchange poison messages are dead-lettered to. Default `'<exchange>.dead'`. */
|
|
163
|
+
readonly deadLetterExchange?: string;
|
|
164
|
+
/** Queue that keeps dead-lettered messages for inspection. Default `'<queue>.dead'`. */
|
|
165
|
+
readonly deadLetterQueue?: string;
|
|
166
|
+
/**
|
|
167
|
+
* Quorum queue `x-delivery-limit`: deliveries after which the broker itself
|
|
168
|
+
* dead-letters a message. Failing handlers do not consume it (they use
|
|
169
|
+
* `redelivery`); it only stops a message that crashes the consumer or its
|
|
170
|
+
* channel again and again. Default 10.
|
|
171
|
+
*/
|
|
172
|
+
readonly deliveryLimit?: number;
|
|
173
|
+
/**
|
|
174
|
+
* Handler attempts on the same delivery, with backoff, before the message is
|
|
175
|
+
* scheduled for delayed redelivery. Absorbs short blips without a broker round
|
|
176
|
+
* trip. Default: 3 attempts, 200 ms initial delay, factor 2, 5 s cap, equal jitter.
|
|
177
|
+
*/
|
|
178
|
+
readonly handlerRetry?: RetryPolicyOptions;
|
|
179
|
+
/**
|
|
180
|
+
* Delayed redelivery after `handlerRetry` is spent. Default: 2 s initial
|
|
181
|
+
* delay, factor 2, 5 min cap, equal jitter, dead-lettered after 1 h of
|
|
182
|
+
* failing (about 18 redeliveries). Delays are quantized to the retry queues,
|
|
183
|
+
* one per step of the exponential ladder (9 queues with the defaults).
|
|
184
|
+
* Ignored when `ordered`, where the same delays are waited in place.
|
|
185
|
+
*/
|
|
186
|
+
readonly redelivery?: RedeliveryOptions;
|
|
187
|
+
/**
|
|
188
|
+
* Consume the queue strictly in order: a single active consumer across all
|
|
189
|
+
* replicas, one message at a time, a failing message is retried in place
|
|
190
|
+
* (blocking the queue) instead of being delayed. Needed when
|
|
191
|
+
* `EventEnvelope.key` order matters; costs throughput, because one handler
|
|
192
|
+
* runs at a time. Default false: handlers run concurrently and a delayed
|
|
193
|
+
* redelivery overtakes later messages, so order is not preserved.
|
|
194
|
+
*/
|
|
195
|
+
readonly ordered?: boolean;
|
|
196
|
+
/** Reconnect backoff, or `false` to never reconnect. Default: 500 ms initial, factor 2, 30 s cap, equal jitter. */
|
|
197
|
+
readonly reconnect?: ReconnectOptions | false;
|
|
198
|
+
/**
|
|
199
|
+
* When true (default) `connect()` rejects if the broker is unreachable, which
|
|
200
|
+
* fails startup. When false it resolves and keeps trying in the background.
|
|
201
|
+
*/
|
|
202
|
+
readonly failOnConnectError?: boolean;
|
|
203
|
+
/**
|
|
204
|
+
* When false (default) a message that no queue is bound to makes `publish`
|
|
205
|
+
* reject. When true it resolves and the broker silently discards the message.
|
|
206
|
+
*/
|
|
207
|
+
readonly allowUnroutable?: boolean;
|
|
208
|
+
/** How long `publish` waits for the broker confirm. Default `'30s'`. */
|
|
209
|
+
readonly publishTimeout?: Duration;
|
|
210
|
+
/** How long `close` waits for running handlers. Default `'30s'`. */
|
|
211
|
+
readonly shutdownTimeout?: Duration;
|
|
212
|
+
/** Default: `console`. */
|
|
213
|
+
readonly logger?: RelayBusLogger;
|
|
214
|
+
/** Random source for jitter. Default `Math.random`. Intended for tests. */
|
|
215
|
+
readonly random?: () => number;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* RabbitMQ {@link Transport} built on amqplib.
|
|
220
|
+
*
|
|
221
|
+
* Publishing: each event goes to a durable topic exchange as a persistent,
|
|
222
|
+
* mandatory message with the destination as routing key. `publish` resolves
|
|
223
|
+
* only after the broker confirmed it was persisted and routed to a queue, and
|
|
224
|
+
* rejects when the transport is disconnected, the broker nacks, the message is
|
|
225
|
+
* unroutable or no confirm arrives in time. It never drops a message silently,
|
|
226
|
+
* so the outbox retries the delivery.
|
|
227
|
+
*
|
|
228
|
+
* Subscribing: one durable quorum queue per consumer group, bound to the
|
|
229
|
+
* destinations (routing-key patterns such as `orders.*`). A message is
|
|
230
|
+
* acknowledged only after the handler resolved. A failing handler is retried
|
|
231
|
+
* on the same delivery, then through retry queues with growing delays (see
|
|
232
|
+
* `redelivery`), and finally dead-lettered after the retry window; poison
|
|
233
|
+
* messages are dead-lettered at once. Nothing is lost on the way.
|
|
234
|
+
*
|
|
235
|
+
* Reconnection: after a connection or channel loss the transport reconnects
|
|
236
|
+
* with capped, jittered backoff and restores channels, topology and the
|
|
237
|
+
* consumer. Events published meanwhile are rejected, and therefore retried by
|
|
238
|
+
* the outbox, rather than buffered in memory.
|
|
239
|
+
*/
|
|
240
|
+
declare class RabbitMqTransport implements Transport {
|
|
241
|
+
#private;
|
|
242
|
+
readonly name: string;
|
|
243
|
+
constructor(options: RabbitMqTransportOptions);
|
|
244
|
+
/**
|
|
245
|
+
* True while the connection is open and publishing and consuming are set up.
|
|
246
|
+
* Use it for readiness probes.
|
|
247
|
+
*/
|
|
248
|
+
isConnected(): boolean;
|
|
249
|
+
/**
|
|
250
|
+
* True when the transport can publish and, once subscribed, is consuming: the
|
|
251
|
+
* connection is up, its channels are open and the consumer is registered. False while reconnecting and after a cancelled consumer.
|
|
252
|
+
*/
|
|
253
|
+
isReady(): boolean;
|
|
254
|
+
/** Connects to the broker. Rejects when it is unreachable unless `failOnConnectError` is false. */
|
|
255
|
+
connect(): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Publishes to the exchange with `destination` as routing key and resolves
|
|
258
|
+
* after the broker confirmed the message.
|
|
259
|
+
*
|
|
260
|
+
* @throws {UnserializablePayloadError} the payload is not representable as JSON (never retried)
|
|
261
|
+
* @throws {AmqpLimitExceededError} the event id, a header name or `destination` exceeds 255 bytes (never retried)
|
|
262
|
+
* @throws {RabbitMqUnavailableError} not connected, channel lost, or confirm timed out
|
|
263
|
+
* @throws {RabbitMqPublishRejectedError} the broker nacked the message
|
|
264
|
+
* @throws {UnroutableMessageError} no queue is bound to `destination` (unless `allowUnroutable`)
|
|
265
|
+
*/
|
|
266
|
+
publish(envelope: EventEnvelope, destination: string): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Binds one durable quorum queue to `destinations` and delivers its messages
|
|
269
|
+
* to `onMessage`. Call it once per transport; give each subscription its own
|
|
270
|
+
* transport instance, with its own `name` and `consumerGroup`.
|
|
271
|
+
*/
|
|
272
|
+
subscribe(destinations: readonly string[], onMessage: TransportMessageHandler): Promise<void>;
|
|
273
|
+
/**
|
|
274
|
+
* Stops consuming, waits up to `shutdownTimeout` for running handlers
|
|
275
|
+
* (messages still being retried go back to the queue), then closes the
|
|
276
|
+
* channels and the connection.
|
|
277
|
+
*/
|
|
278
|
+
close(): Promise<void>;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export { type AmqpChannel, type AmqpConfirmChannel, type AmqpConnection, AmqpLimitExceededError, type AmqpMessage, type AmqpMessageProperties, type AmqpPublishOptions, type BrokerConnectionSettings, MalformedMessageError, RabbitMqPublishRejectedError, RabbitMqTransport, type RabbitMqTransportOptions, RabbitMqUnavailableError, type ReconnectOptions, type RedeliveryOptions, UnroutableMessageError, UnserializablePayloadError };
|