amqplib 1.1.1 → 2.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.
@@ -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
+ ## v2.0.0
4
+ - **BREAKING**: `heartbeat: 0` now disables heartbeats, overriding any value suggested by the server. Previously, `0` was treated as "no preference" and the server's suggested value was used. If you are passing `heartbeat: 0` and want to preserve the old behaviour, omit the option or pass `null` instead (fixes #467)
5
+
6
+ ## v1.2.0
7
+ - Add bundled TypeScript type definitions (fixes #843)
8
+
3
9
  ## v1.1.1
4
10
  - Forward `handler-error` events from the underlying connection to the recovery wrapper, so listeners attached to `RecoveringPromiseModel`/`RecoveringCallbackModel` receive handler errors
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
package/lib/connect.js CHANGED
@@ -59,7 +59,7 @@ function openFrames(vhost, query, credentials, extraClientProperties) {
59
59
  // tune-ok
60
60
  channelMax: intOrDefault(query.channelMax, 0),
61
61
  frameMax: intOrDefault(query.frameMax, 131072),
62
- heartbeat: intOrDefault(query.heartbeat, 0),
62
+ heartbeat: query.heartbeat != null ? intOrDefault(query.heartbeat, 0) : null,
63
63
 
64
64
  // open
65
65
  virtualHost: vhost,
package/lib/connection.js CHANGED
@@ -159,7 +159,13 @@ class Connection extends EventEmitter {
159
159
  const fields = reply.fields;
160
160
  tunedOptions.frameMax = negotiate(fields.frameMax, allFields.frameMax);
161
161
  tunedOptions.channelMax = negotiate(fields.channelMax, allFields.channelMax);
162
- tunedOptions.heartbeat = negotiate(fields.heartbeat, allFields.heartbeat);
162
+ if (allFields.heartbeat == null) {
163
+ tunedOptions.heartbeat = fields.heartbeat; // no preference, accept server value
164
+ } else if (allFields.heartbeat === 0) {
165
+ tunedOptions.heartbeat = 0; // explicitly disable heartbeats
166
+ } else {
167
+ tunedOptions.heartbeat = negotiate(fields.heartbeat, allFields.heartbeat);
168
+ }
163
169
  try {
164
170
  send(defs.ConnectionTuneOk);
165
171
  send(defs.ConnectionOpen);
@@ -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/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.1",
5
+ "version": "2.0.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",
@@ -696,6 +696,77 @@ describe('Connection', () => {
696
696
  .then(cb, cb);
697
697
  // conspicuously not sending anything ...
698
698
  }));
699
+
700
+ it('without a heartbeat option, server suggested value is used', connectionTest((c, cb) => {
701
+ // OPEN_OPTS.heartbeat is null — no preference set by client
702
+ c.once('error', (err) => {
703
+ assert.match(err.message, /Heartbeat timeout/);
704
+ cb();
705
+ });
706
+ c.open(OPEN_OPTS, (err) => {
707
+ assert.ifError(err);
708
+ assert.strictEqual(c.heartbeat, 1);
709
+ });
710
+ }, (send, wait, cb) => {
711
+ send(defs.ConnectionStart, {
712
+ versionMajor: 0, versionMinor: 9,
713
+ serverProperties: {},
714
+ mechanisms: Buffer.from('PLAIN'),
715
+ locales: Buffer.from('en_US'),
716
+ });
717
+ wait(defs.ConnectionStartOk)()
718
+ .then(() => send(defs.ConnectionTune, { channelMax: 0, heartbeat: 1, frameMax: 0 }))
719
+ .then(wait(defs.ConnectionTuneOk))
720
+ .then(wait(defs.ConnectionOpen))
721
+ .then(() => send(defs.ConnectionOpenOk, { knownHosts: '' }))
722
+ .then(cb, cb);
723
+ }));
724
+
725
+ it('heartbeat:0 means no heartbeater is started', connectionTest((c, cb) => {
726
+ const opts = Object.create(OPEN_OPTS);
727
+ opts.heartbeat = 0;
728
+ c.open(opts, (err) => {
729
+ assert.ifError(err);
730
+ assert.strictEqual(c.heartbeat, 0);
731
+ assert.strictEqual(c.heartbeater, null);
732
+ cb();
733
+ });
734
+ }, (send, wait, cb) => {
735
+ send(defs.ConnectionStart, {
736
+ versionMajor: 0, versionMinor: 9,
737
+ serverProperties: {},
738
+ mechanisms: Buffer.from('PLAIN'),
739
+ locales: Buffer.from('en_US'),
740
+ });
741
+ wait(defs.ConnectionStartOk)()
742
+ .then(() => send(defs.ConnectionTune, { channelMax: 0, heartbeat: 60, frameMax: 0 }))
743
+ .then(wait(defs.ConnectionTuneOk))
744
+ .then(wait(defs.ConnectionOpen))
745
+ .then(() => send(defs.ConnectionOpenOk, { knownHosts: '' }))
746
+ .then(cb, cb);
747
+ }));
748
+
749
+ it('heartbeat:0 disables heartbeats even if server suggests one', connectionTest((c, cb) => {
750
+ const opts = Object.create(OPEN_OPTS);
751
+ opts.heartbeat = 0;
752
+ c.open(opts, cb);
753
+ }, (send, wait, cb) => {
754
+ send(defs.ConnectionStart, {
755
+ versionMajor: 0, versionMinor: 9,
756
+ serverProperties: {},
757
+ mechanisms: Buffer.from('PLAIN'),
758
+ locales: Buffer.from('en_US'),
759
+ });
760
+ wait(defs.ConnectionStartOk)()
761
+ .then(() => send(defs.ConnectionTune, { channelMax: 0, heartbeat: 60, frameMax: 0 }))
762
+ .then(wait(defs.ConnectionTuneOk))
763
+ .then((tuneOk) => {
764
+ assert.strictEqual(tuneOk.fields.heartbeat, 0);
765
+ })
766
+ .then(wait(defs.ConnectionOpen))
767
+ .then(() => send(defs.ConnectionOpenOk, { knownHosts: '' }))
768
+ .then(cb, cb);
769
+ }));
699
770
  });
700
771
 
701
772
  });
package/test/lib/data.js CHANGED
@@ -214,7 +214,7 @@ const OPEN_OPTS = {
214
214
  // tune-ok
215
215
  channelMax: 0,
216
216
  frameMax: 0,
217
- heartbeat: 0,
217
+ heartbeat: null,
218
218
 
219
219
  // open
220
220
  virtualHost: '/',