amqplib 1.1.0 → 1.2.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.
@@ -47,5 +47,8 @@ jobs:
47
47
 
48
48
  - run: echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
49
49
 
50
+ # Check TypeScript types
51
+ - run: npm run typecheck
52
+
50
53
  # Run the tests
51
54
  - run: make test
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change log for amqplib
2
2
 
3
+ ## v1.2.0
4
+ - Add bundled TypeScript type definitions (fixes #843)
5
+
6
+ ## v1.1.1
7
+ - Forward `handler-error` events from the underlying connection to the recovery wrapper, so listeners attached to `RecoveringPromiseModel`/`RecoveringCallbackModel` receive handler errors
8
+
3
9
  ## v1.1.0
4
10
  - Add connection recovery via `connectWithRecoveryPromise` and `connectWithRecoveryCallback` — automatically reconnects on connection loss with configurable backoff delay, jitter, and retry limits (thanks [@ShiriNmi1520](https://github.com/ShiriNmi1520))
5
11
 
@@ -0,0 +1,209 @@
1
+ import events = require('events');
2
+ import {
3
+ ChannelOptions,
4
+ ConsumeMessage,
5
+ GetMessage,
6
+ Message,
7
+ Options,
8
+ Replies,
9
+ ServerProperties,
10
+ SocketOptions,
11
+ } from './lib/properties';
12
+ export * from './lib/properties';
13
+
14
+ export interface Connection extends events.EventEmitter {
15
+ close(callback?: (err: Error) => void): void;
16
+ createChannel(callback: (err: Error, channel: Channel) => void): Channel;
17
+ createChannel(options: ChannelOptions, callback: (err: Error, channel: Channel) => void): Channel;
18
+ createConfirmChannel(callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
19
+ createConfirmChannel(options: ChannelOptions, callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
20
+ readonly connection: {
21
+ readonly serverProperties: ServerProperties;
22
+ };
23
+ updateSecret(newSecret: Buffer, reason: string, callback?: (err: Error) => void): void;
24
+
25
+ on(event: 'close', listener: (err?: Error) => void): this;
26
+ on(event: 'error', listener: (err: Error) => void): this;
27
+ on(event: 'blocked', listener: (reason: string) => void): this;
28
+ on(event: 'unblocked', listener: () => void): this;
29
+ on(event: 'update-secret-ok', listener: () => void): this;
30
+ on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
31
+ on(event: string, listener: (...args: any[]) => void): this;
32
+ }
33
+
34
+ export interface Channel extends events.EventEmitter {
35
+ readonly connection: Connection;
36
+
37
+ on(event: 'close', listener: () => void): this;
38
+ on(event: 'error', listener: (err: Error) => void): this;
39
+ on(event: 'drain', listener: () => void): this;
40
+ on(event: 'ack', listener: (fields: { deliveryTag: number; multiple: boolean }) => void): this;
41
+ on(event: 'nack', listener: (fields: { deliveryTag: number; multiple: boolean; requeue: boolean }) => void): this;
42
+ on(event: 'cancel', listener: (fields: { consumerTag: string }) => void): this;
43
+ on(event: 'delivery', listener: (message: ConsumeMessage) => void): this;
44
+ on(event: 'return', listener: (message: Message) => void): this;
45
+ on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
46
+ on(event: string, listener: (...args: any[]) => void): this;
47
+
48
+ close(callback?: (err: Error) => void): void;
49
+
50
+ assertQueue(queue?: string, options?: Options.AssertQueue, callback?: (err: Error, ok: Replies.AssertQueue) => void): void;
51
+ checkQueue(queue: string, callback?: (err: Error, ok: Replies.AssertQueue) => void): void;
52
+
53
+ deleteQueue(queue: string, options?: Options.DeleteQueue, callback?: (err: Error, ok: Replies.DeleteQueue) => void): void;
54
+ purgeQueue(queue: string, callback?: (err: Error, ok: Replies.PurgeQueue) => void): void;
55
+
56
+ bindQueue(
57
+ queue: string,
58
+ source: string,
59
+ pattern: string,
60
+ args?: any,
61
+ callback?: (err: Error, ok: Replies.Empty) => void,
62
+ ): void;
63
+ unbindQueue(
64
+ queue: string,
65
+ source: string,
66
+ pattern: string,
67
+ args?: any,
68
+ callback?: (err: Error, ok: Replies.Empty) => void,
69
+ ): void;
70
+
71
+ assertExchange(
72
+ exchange: string,
73
+ type: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string,
74
+ options?: Options.AssertExchange,
75
+ callback?: (err: Error, ok: Replies.AssertExchange) => void,
76
+ ): void;
77
+ checkExchange(exchange: string, callback?: (err: Error, ok: Replies.Empty) => void): void;
78
+
79
+ deleteExchange(exchange: string, options?: Options.DeleteExchange, callback?: (err: Error, ok: Replies.Empty) => void): void;
80
+
81
+ bindExchange(
82
+ destination: string,
83
+ source: string,
84
+ pattern: string,
85
+ args?: any,
86
+ callback?: (err: Error, ok: Replies.Empty) => void,
87
+ ): void;
88
+ unbindExchange(
89
+ destination: string,
90
+ source: string,
91
+ pattern: string,
92
+ args?: any,
93
+ callback?: (err: Error, ok: Replies.Empty) => void,
94
+ ): void;
95
+
96
+ publish(exchange: string, routingKey: string, content: Buffer, options?: Options.Publish): boolean;
97
+ sendToQueue(queue: string, content: Buffer, options?: Options.Publish): boolean;
98
+
99
+ consume(
100
+ queue: string,
101
+ onMessage: (msg: ConsumeMessage | null) => void,
102
+ options?: Options.Consume,
103
+ callback?: (err: Error, ok: Replies.Consume) => void,
104
+ ): void;
105
+
106
+ cancel(consumerTag: string, callback?: (err: Error, ok: Replies.Empty) => void): void;
107
+ get(queue: string, options?: Options.Get, callback?: (err: Error, ok: GetMessage | false) => void): void;
108
+
109
+ ack(message: Message, allUpTo?: boolean): void;
110
+ ackAll(): void;
111
+
112
+ nack(message: Message, allUpTo?: boolean, requeue?: boolean): void;
113
+ nackAll(requeue?: boolean): void;
114
+ reject(message: Message, requeue?: boolean): void;
115
+
116
+ prefetch(count: number, global?: boolean, callback?: (err: Error, ok: Replies.Empty) => void): void;
117
+ recover(callback?: (err: Error, ok: Replies.Empty) => void): void;
118
+ }
119
+
120
+ export interface ConfirmChannel extends Channel {
121
+ publish(
122
+ exchange: string,
123
+ routingKey: string,
124
+ content: Buffer,
125
+ options?: Options.Publish,
126
+ callback?: (err: Error, ok: Replies.Empty) => void,
127
+ ): boolean;
128
+ sendToQueue(
129
+ queue: string,
130
+ content: Buffer,
131
+ options?: Options.Publish,
132
+ callback?: (err: Error, ok: Replies.Empty) => void,
133
+ ): boolean;
134
+
135
+ waitForConfirms(callback?: (err?: Error) => void): void;
136
+ }
137
+
138
+ export declare class IllegalOperationError extends Error {
139
+ name: 'IllegalOperationError';
140
+ stackAtStateChange: string | undefined;
141
+ constructor(msg: string, stack?: string);
142
+ }
143
+
144
+ export declare const credentials: {
145
+ plain(username: string, password: string): {
146
+ mechanism: string;
147
+ response(): Buffer;
148
+ username: string;
149
+ password: string;
150
+ };
151
+ amqplain(username: string, password: string): {
152
+ mechanism: string;
153
+ response(): Buffer;
154
+ username: string;
155
+ password: string;
156
+ };
157
+ external(): {
158
+ mechanism: string;
159
+ response(): Buffer;
160
+ };
161
+ };
162
+
163
+ export interface RecoveryOptions {
164
+ /** Initial reconnect delay in milliseconds. Default: 100 */
165
+ initialDelay?: number;
166
+ /** Maximum reconnect delay in milliseconds. Default: 30000 */
167
+ maxDelay?: number;
168
+ /** Backoff multiplier applied to delay on each attempt. Default: 2 */
169
+ factor?: number;
170
+ /** Jitter factor (0–1) applied to delay to avoid thundering herd. Default: 0.2 */
171
+ jitter?: number;
172
+ /** Maximum number of reconnect attempts. Default: Infinity */
173
+ maxRetries?: number;
174
+ /** Optional setup function called after each successful connection */
175
+ setup?: ((model: Connection) => Promise<void>) | ((model: Connection, done: (err?: Error) => void) => void);
176
+ }
177
+
178
+ export interface RecoveringConnection extends events.EventEmitter {
179
+ close(callback?: (err: Error) => void): void;
180
+ createChannel(callback: (err: Error, channel: Channel) => void): Channel;
181
+ createChannel(options: ChannelOptions, callback: (err: Error, channel: Channel) => void): Channel;
182
+ createConfirmChannel(callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
183
+ createConfirmChannel(options: ChannelOptions, callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
184
+ updateSecret(newSecret: Buffer, reason: string, callback?: (err: Error) => void): void;
185
+
186
+ on(event: 'connect', listener: (model: Connection) => void): this;
187
+ on(event: 'disconnect', listener: (err: Error) => void): this;
188
+ on(event: 'connect-failed', listener: (err: Error) => void): this;
189
+ on(event: 'reconnect-scheduled', listener: (info: { attempt: number; delay: number; error: Error }) => void): this;
190
+ on(event: 'reconnect-failed', listener: (err: Error) => void): this;
191
+ on(event: 'blocked', listener: (reason: string) => void): this;
192
+ on(event: 'unblocked', listener: () => void): this;
193
+ on(event: 'error', listener: (err: Error) => void): this;
194
+ on(event: 'update-secret-ok', listener: () => void): this;
195
+ on(event: string, listener: (...args: any[]) => void): this;
196
+ }
197
+
198
+ export declare function connect(callback: (err: Error, connection: Connection) => void): void;
199
+ export declare function connect(url: string | Options.Connect, callback: (err: Error, connection: Connection) => void): void;
200
+ export declare function connect(
201
+ url: string | Options.Connect,
202
+ socketOptions: SocketOptions,
203
+ callback: (err: Error, connection: Connection) => void,
204
+ ): void;
205
+ export declare function connect(
206
+ url: string | Options.Connect,
207
+ socketOptions: SocketOptions & { recovery: RecoveryOptions | true },
208
+ callback: (err: Error, connection: RecoveringConnection) => void,
209
+ ): RecoveringConnection;
package/index.d.ts ADDED
@@ -0,0 +1,171 @@
1
+ import events = require('events');
2
+ import {
3
+ ChannelOptions,
4
+ ConsumeMessage,
5
+ GetMessage,
6
+ Message,
7
+ Options,
8
+ Replies,
9
+ ServerProperties,
10
+ SocketOptions,
11
+ } from './lib/properties';
12
+ export * from './lib/properties';
13
+
14
+ export interface Connection {
15
+ readonly serverProperties: ServerProperties;
16
+ }
17
+
18
+ export interface ChannelModel extends events.EventEmitter {
19
+ close(): Promise<void>;
20
+ createChannel(options?: ChannelOptions): Promise<Channel>;
21
+ createConfirmChannel(options?: ChannelOptions): Promise<ConfirmChannel>;
22
+ readonly connection: Connection;
23
+ updateSecret(newSecret: Buffer, reason: string): Promise<void>;
24
+
25
+ on(event: 'close', listener: (err?: Error) => void): this;
26
+ on(event: 'error', listener: (err: Error) => void): this;
27
+ on(event: 'blocked', listener: (reason: string) => void): this;
28
+ on(event: 'unblocked', listener: () => void): this;
29
+ on(event: 'update-secret-ok', listener: () => void): this;
30
+ on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
31
+ on(event: string, listener: (...args: any[]) => void): this;
32
+ }
33
+
34
+ export interface Channel extends events.EventEmitter {
35
+ readonly connection: Connection;
36
+
37
+ on(event: 'close', listener: () => void): this;
38
+ on(event: 'error', listener: (err: Error) => void): this;
39
+ on(event: 'drain', listener: () => void): this;
40
+ on(event: 'ack', listener: (fields: { deliveryTag: number; multiple: boolean }) => void): this;
41
+ on(event: 'nack', listener: (fields: { deliveryTag: number; multiple: boolean; requeue: boolean }) => void): this;
42
+ on(event: 'cancel', listener: (fields: { consumerTag: string }) => void): this;
43
+ on(event: 'delivery', listener: (message: ConsumeMessage) => void): this;
44
+ on(event: 'return', listener: (message: Message) => void): this;
45
+ on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
46
+ on(event: string, listener: (...args: any[]) => void): this;
47
+
48
+ close(): Promise<void>;
49
+
50
+ assertQueue(queue?: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue>;
51
+ checkQueue(queue: string): Promise<Replies.AssertQueue>;
52
+
53
+ deleteQueue(queue: string, options?: Options.DeleteQueue): Promise<Replies.DeleteQueue>;
54
+ purgeQueue(queue: string): Promise<Replies.PurgeQueue>;
55
+
56
+ bindQueue(queue: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
57
+ unbindQueue(queue: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
58
+
59
+ assertExchange(
60
+ exchange: string,
61
+ type: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string,
62
+ options?: Options.AssertExchange,
63
+ ): Promise<Replies.AssertExchange>;
64
+ checkExchange(exchange: string): Promise<Replies.Empty>;
65
+
66
+ deleteExchange(exchange: string, options?: Options.DeleteExchange): Promise<Replies.Empty>;
67
+
68
+ bindExchange(destination: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
69
+ unbindExchange(destination: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
70
+
71
+ publish(exchange: string, routingKey: string, content: Buffer, options?: Options.Publish): boolean;
72
+ sendToQueue(queue: string, content: Buffer, options?: Options.Publish): boolean;
73
+
74
+ consume(
75
+ queue: string,
76
+ onMessage: (msg: ConsumeMessage | null) => void,
77
+ options?: Options.Consume,
78
+ ): Promise<Replies.Consume>;
79
+
80
+ cancel(consumerTag: string): Promise<Replies.Empty>;
81
+ get(queue: string, options?: Options.Get): Promise<GetMessage | false>;
82
+
83
+ ack(message: Message, allUpTo?: boolean): void;
84
+ ackAll(): void;
85
+
86
+ nack(message: Message, allUpTo?: boolean, requeue?: boolean): void;
87
+ nackAll(requeue?: boolean): void;
88
+ reject(message: Message, requeue?: boolean): void;
89
+
90
+ prefetch(count: number, global?: boolean): Promise<Replies.Empty>;
91
+ recover(): Promise<Replies.Empty>;
92
+ }
93
+
94
+ export interface ConfirmChannel extends Channel {
95
+ publish(
96
+ exchange: string,
97
+ routingKey: string,
98
+ content: Buffer,
99
+ options?: Options.Publish,
100
+ callback?: (err: any, ok: Replies.Empty) => void,
101
+ ): boolean;
102
+ sendToQueue(
103
+ queue: string,
104
+ content: Buffer,
105
+ options?: Options.Publish,
106
+ callback?: (err: any, ok: Replies.Empty) => void,
107
+ ): boolean;
108
+
109
+ waitForConfirms(): Promise<void>;
110
+ }
111
+
112
+ export declare class IllegalOperationError extends Error {
113
+ name: 'IllegalOperationError';
114
+ stackAtStateChange: string | undefined;
115
+ constructor(msg: string, stack?: string);
116
+ }
117
+
118
+ export declare const credentials: {
119
+ plain(username: string, password: string): {
120
+ mechanism: string;
121
+ response(): Buffer;
122
+ username: string;
123
+ password: string;
124
+ };
125
+ amqplain(username: string, password: string): {
126
+ mechanism: string;
127
+ response(): Buffer;
128
+ username: string;
129
+ password: string;
130
+ };
131
+ external(): {
132
+ mechanism: string;
133
+ response(): Buffer;
134
+ };
135
+ };
136
+
137
+ export interface RecoveryOptions {
138
+ /** Initial reconnect delay in milliseconds. Default: 100 */
139
+ initialDelay?: number;
140
+ /** Maximum reconnect delay in milliseconds. Default: 30000 */
141
+ maxDelay?: number;
142
+ /** Backoff multiplier applied to delay on each attempt. Default: 2 */
143
+ factor?: number;
144
+ /** Jitter factor (0–1) applied to delay to avoid thundering herd. Default: 0.2 */
145
+ jitter?: number;
146
+ /** Maximum number of reconnect attempts. Default: Infinity */
147
+ maxRetries?: number;
148
+ /** Optional setup function called after each successful connection */
149
+ setup?: ((model: ChannelModel) => Promise<void>) | ((model: ChannelModel, done: (err?: Error) => void) => void);
150
+ }
151
+
152
+ export interface RecoveringChannelModel extends events.EventEmitter {
153
+ close(): Promise<void>;
154
+ createChannel(options?: ChannelOptions): Promise<Channel>;
155
+ createConfirmChannel(options?: ChannelOptions): Promise<ConfirmChannel>;
156
+ updateSecret(newSecret: Buffer, reason: string): Promise<void>;
157
+
158
+ on(event: 'connect', listener: (model: ChannelModel) => void): this;
159
+ on(event: 'disconnect', listener: (err: Error) => void): this;
160
+ on(event: 'connect-failed', listener: (err: Error) => void): this;
161
+ on(event: 'reconnect-scheduled', listener: (info: { attempt: number; delay: number; error: Error }) => void): this;
162
+ on(event: 'reconnect-failed', listener: (err: Error) => void): this;
163
+ on(event: 'blocked', listener: (reason: string) => void): this;
164
+ on(event: 'unblocked', listener: () => void): this;
165
+ on(event: 'error', listener: (err: Error) => void): this;
166
+ on(event: 'update-secret-ok', listener: () => void): this;
167
+ on(event: string, listener: (...args: any[]) => void): this;
168
+ }
169
+
170
+ export declare function connect(url: string | Options.Connect, socketOptions: SocketOptions & { recovery: RecoveryOptions | true }): Promise<RecoveringChannelModel>;
171
+ export declare function connect(url: string | Options.Connect, socketOptions?: SocketOptions): Promise<ChannelModel>;
package/lefthook.yml CHANGED
@@ -10,5 +10,8 @@ pre-commit:
10
10
  glob: "**/*.js"
11
11
  run: npx biome lint {staged_files} --write
12
12
  stage_fixed: true
13
+ typecheck:
14
+ glob: "{**/*.d.ts,types/*.ts}"
15
+ run: npm run typecheck
13
16
  test:
14
17
  run: npm test
@@ -0,0 +1,208 @@
1
+ import * as tls from 'tls';
2
+
3
+ export namespace Replies {
4
+ interface Empty {}
5
+ interface AssertQueue {
6
+ queue: string;
7
+ messageCount: number;
8
+ consumerCount: number;
9
+ }
10
+ interface PurgeQueue {
11
+ messageCount: number;
12
+ }
13
+ interface DeleteQueue {
14
+ messageCount: number;
15
+ }
16
+ interface AssertExchange {
17
+ exchange: string;
18
+ }
19
+ interface Consume {
20
+ consumerTag: string;
21
+ }
22
+ }
23
+
24
+ export namespace Options {
25
+ interface Connect {
26
+ protocol?: string;
27
+ hostname?: string;
28
+ port?: number;
29
+ username?: string;
30
+ password?: string;
31
+ locale?: string;
32
+ frameMax?: number;
33
+ heartbeat?: number;
34
+ vhost?: string;
35
+ channelMax?: number;
36
+ credentials?: {
37
+ mechanism: string;
38
+ response(): Buffer;
39
+ username?: string;
40
+ password?: string;
41
+ };
42
+ }
43
+
44
+ interface AssertQueue {
45
+ exclusive?: boolean;
46
+ durable?: boolean;
47
+ autoDelete?: boolean;
48
+ arguments?: any;
49
+ messageTtl?: number;
50
+ expires?: number;
51
+ deadLetterExchange?: string;
52
+ deadLetterRoutingKey?: string;
53
+ maxLength?: number;
54
+ maxPriority?: number;
55
+ overflow?: string;
56
+ queueMode?: string;
57
+ }
58
+
59
+ interface DeleteQueue {
60
+ ifUnused?: boolean;
61
+ ifEmpty?: boolean;
62
+ }
63
+
64
+ interface AssertExchange {
65
+ durable?: boolean;
66
+ internal?: boolean;
67
+ autoDelete?: boolean;
68
+ alternateExchange?: string;
69
+ arguments?: any;
70
+ }
71
+
72
+ interface DeleteExchange {
73
+ ifUnused?: boolean;
74
+ }
75
+
76
+ interface Publish {
77
+ expiration?: string | number;
78
+ userId?: string;
79
+ CC?: string | string[];
80
+ mandatory?: boolean;
81
+ persistent?: boolean;
82
+ deliveryMode?: boolean | number;
83
+ BCC?: string | string[];
84
+ contentType?: string;
85
+ contentEncoding?: string;
86
+ headers?: any;
87
+ priority?: number;
88
+ correlationId?: string;
89
+ replyTo?: string;
90
+ messageId?: string;
91
+ timestamp?: number;
92
+ type?: string;
93
+ appId?: string;
94
+ }
95
+
96
+ interface Consume {
97
+ consumerTag?: string;
98
+ noLocal?: boolean;
99
+ noAck?: boolean;
100
+ exclusive?: boolean;
101
+ priority?: number;
102
+ arguments?: any;
103
+ }
104
+
105
+ interface Get {
106
+ noAck?: boolean;
107
+ }
108
+ }
109
+
110
+ export interface SocketOptions extends tls.ConnectionOptions {
111
+ noDelay?: boolean;
112
+ timeout?: number;
113
+ keepAlive?: boolean;
114
+ keepAliveDelay?: number;
115
+ clientProperties?: Record<string, unknown>;
116
+ credentials?: {
117
+ mechanism: string;
118
+ response(): Buffer;
119
+ username?: string;
120
+ password?: string;
121
+ };
122
+ }
123
+
124
+ export interface ChannelOptions {
125
+ highWaterMark?: number;
126
+ }
127
+
128
+ export interface Message {
129
+ content: Buffer;
130
+ fields: MessageFields;
131
+ properties: MessageProperties;
132
+ }
133
+
134
+ export interface GetMessage extends Message {
135
+ fields: GetMessageFields;
136
+ }
137
+
138
+ export interface ConsumeMessage extends Message {
139
+ fields: ConsumeMessageFields;
140
+ }
141
+
142
+ export interface CommonMessageFields {
143
+ deliveryTag: number;
144
+ redelivered: boolean;
145
+ exchange: string;
146
+ routingKey: string;
147
+ }
148
+
149
+ export interface MessageFields extends CommonMessageFields {
150
+ messageCount?: number;
151
+ consumerTag?: string;
152
+ }
153
+
154
+ export interface GetMessageFields extends CommonMessageFields {
155
+ messageCount: number;
156
+ }
157
+
158
+ export interface ConsumeMessageFields extends CommonMessageFields {
159
+ consumerTag: string;
160
+ }
161
+
162
+ export interface MessageProperties {
163
+ contentType: any | undefined;
164
+ contentEncoding: any | undefined;
165
+ headers: MessagePropertyHeaders | undefined;
166
+ deliveryMode: any | undefined;
167
+ priority: any | undefined;
168
+ correlationId: any | undefined;
169
+ replyTo: any | undefined;
170
+ expiration: any | undefined;
171
+ messageId: any | undefined;
172
+ timestamp: any | undefined;
173
+ type: any | undefined;
174
+ userId: any | undefined;
175
+ appId: any | undefined;
176
+ clusterId: any | undefined;
177
+ }
178
+
179
+ export interface MessagePropertyHeaders {
180
+ 'x-first-death-exchange'?: string;
181
+ 'x-first-death-queue'?: string;
182
+ 'x-first-death-reason'?: string;
183
+ 'x-death'?: XDeath[];
184
+ [key: string]: any;
185
+ }
186
+
187
+ export interface XDeath {
188
+ count: number;
189
+ reason: 'rejected' | 'expired' | 'maxlen';
190
+ queue: string;
191
+ time: {
192
+ '!': 'timestamp';
193
+ value: number;
194
+ };
195
+ exchange: string;
196
+ 'original-expiration'?: any;
197
+ 'routing-keys': string[];
198
+ }
199
+
200
+ export interface ServerProperties {
201
+ host: string;
202
+ product: string;
203
+ version: string;
204
+ platform: string;
205
+ copyright?: string;
206
+ information: string;
207
+ [key: string]: string | undefined;
208
+ }
package/lib/recovery.js CHANGED
@@ -220,12 +220,14 @@ class RecoveringCore extends EventEmitter {
220
220
  const onUnblocked = () => this.emit('unblocked');
221
221
  const onConnectionError = (err) => this.emit('error', err);
222
222
  const onUpdateSecretOk = () => this.emit('update-secret-ok');
223
+ const onHandlerError = (err, event) => this.emit('handler-error', err, event);
223
224
 
224
225
  model.on('close', onClose);
225
226
  model.on('blocked', onBlocked);
226
227
  model.on('unblocked', onUnblocked);
227
228
  model.on('error', onConnectionError);
228
229
  model.on('update-secret-ok', onUpdateSecretOk);
230
+ model.on('handler-error', onHandlerError);
229
231
 
230
232
  this._modelListeners = {
231
233
  model,
@@ -234,17 +236,19 @@ class RecoveringCore extends EventEmitter {
234
236
  onUnblocked,
235
237
  onConnectionError,
236
238
  onUpdateSecretOk,
239
+ onHandlerError,
237
240
  };
238
241
  }
239
242
 
240
243
  _unbindModel() {
241
244
  if (!this._modelListeners) return;
242
- const { model, onClose, onBlocked, onUnblocked, onConnectionError, onUpdateSecretOk } = this._modelListeners;
245
+ const { model, onClose, onBlocked, onUnblocked, onConnectionError, onUpdateSecretOk, onHandlerError } = this._modelListeners;
243
246
  model.removeListener('close', onClose);
244
247
  model.removeListener('blocked', onBlocked);
245
248
  model.removeListener('unblocked', onUnblocked);
246
249
  model.removeListener('error', onConnectionError);
247
250
  model.removeListener('update-secret-ok', onUpdateSecretOk);
251
+ model.removeListener('handler-error', onHandlerError);
248
252
  model.on('error', () => {});
249
253
  this._modelListeners = null;
250
254
  }
@@ -366,6 +370,7 @@ function wireCommonEvents(source, target) {
366
370
  'unblocked',
367
371
  'error',
368
372
  'update-secret-ok',
373
+ 'handler-error',
369
374
  ].forEach((eventName) => {
370
375
  source.on(eventName, (...args) => target.emit(eventName, ...args));
371
376
  });
package/package.json CHANGED
@@ -2,7 +2,18 @@
2
2
  "name": "amqplib",
3
3
  "homepage": "http://amqp-node.github.io/amqplib/",
4
4
  "main": "./channel_api.js",
5
- "version": "1.1.0",
5
+ "version": "1.2.0",
6
+ "types": "./index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./index.d.ts",
10
+ "default": "./channel_api.js"
11
+ },
12
+ "./callback_api": {
13
+ "types": "./callback_api.d.ts",
14
+ "default": "./callback_api.js"
15
+ }
16
+ },
6
17
  "description": "An AMQP 0-9-1 (e.g., RabbitMQ) library and client.",
7
18
  "repository": {
8
19
  "type": "git",
@@ -16,8 +27,10 @@
16
27
  },
17
28
  "devDependencies": {
18
29
  "@biomejs/biome": "^2.2.2",
30
+ "@types/node": "^25.6.0",
19
31
  "claire": "0.4.1",
20
32
  "lefthook": "^1.12.3",
33
+ "typescript": "^5.9.3",
21
34
  "uglify-js": "2.8.x"
22
35
  },
23
36
  "scripts": {
@@ -26,7 +39,8 @@
26
39
  "rabbitmq-3": "docker run -d --rm --name rabbitmq -p 5672:5672 rabbitmq:3.12-alpine",
27
40
  "rabbitmq-4": "docker run -d --rm --name rabbitmq -p 5672:5672 rabbitmq:4.2-alpine",
28
41
  "format": "biome format . --write",
29
- "lint": "biome lint --max-diagnostics=1000 ."
42
+ "lint": "biome lint --max-diagnostics=1000 .",
43
+ "typecheck": "tsc --noEmit -p tsconfig.types.json"
30
44
  },
31
45
  "keywords": [
32
46
  "AMQP",
@@ -167,6 +167,38 @@ describe('recovery', () => {
167
167
  assert(client);
168
168
  });
169
169
 
170
+ it('handler-error from underlying model is forwarded to recovery wrapper', async () => {
171
+ const models = [];
172
+ let opened = 0;
173
+
174
+ function openModel() {
175
+ const model = new FakePromiseModel(++opened);
176
+ models.push(model);
177
+ return Promise.resolve(model);
178
+ }
179
+
180
+ const client = await recovery.connectWithRecoveryPromise(openModel, {
181
+ initialDelay: 1,
182
+ maxDelay: 1,
183
+ jitter: 0,
184
+ });
185
+
186
+ const expectedErr = new Error('user close handler explodes');
187
+
188
+ await new Promise((resolve) => {
189
+ client.on('handler-error', (err, event) => {
190
+ assert.strictEqual(err, expectedErr);
191
+ assert.strictEqual(event, 'close');
192
+ resolve();
193
+ });
194
+
195
+ // Simulate a handler throwing in a 'close' listener on the underlying model
196
+ models[0].emit('handler-error', expectedErr, 'close');
197
+ });
198
+
199
+ await client.close();
200
+ });
201
+
170
202
  it('promise recovery fails after max retries', async () => {
171
203
  let attempts = 0;
172
204