amqplib 2.2.0 → 2.3.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/CHANGELOG.md +12 -0
- package/callback_api.d.ts +2 -2
- package/index.d.ts +1 -1
- package/lib/callback_model.js +3 -22
- package/lib/channel.js +27 -1
- package/lib/channel_model.js +4 -29
- package/lib/connect.js +8 -0
- package/lib/connection.js +25 -1
- package/lib/frame.js +5 -1
- package/lib/properties.d.ts +4 -0
- package/package.json +12 -2
- package/.claude/commands/lint-disable.md +0 -9
- package/.claude/commands/lint-enable.md +0 -12
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -41
- package/.github/workflows/publish.yml +0 -113
- package/.github/workflows/test.yml +0 -54
- package/CLAUDE.md +0 -12
- package/Makefile +0 -42
- package/bin/amqp-rabbitmq-0.9.1.json +0 -483
- package/bin/generate-defs.js +0 -734
- package/biome.json +0 -51
- package/lefthook.yml +0 -17
- package/test/bitset.test.js +0 -65
- package/test/callback_api.test.js +0 -439
- package/test/channel.test.js +0 -918
- package/test/channel_api.test.js +0 -599
- package/test/codec.test.js +0 -171
- package/test/connect.test.js +0 -155
- package/test/connection.test.js +0 -772
- package/test/data.test.js +0 -33
- package/test/frame.test.js +0 -180
- package/test/lib/data.js +0 -249
- package/test/lib/util.js +0 -223
- package/test/mux.test.js +0 -258
- package/test/recovery.test.js +0 -799
- package/test/uri_spec.test.js +0 -210
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Change log for amqplib
|
|
2
2
|
|
|
3
|
+
## v2.3.0
|
|
4
|
+
- Reject a `connection.tune` whose `frameMax` is below the protocol minimum of 4096 (the spec allows 0 or at least frame-min-size). Previously such a value was accepted, and the first publish whose encoded frames total 2048 bytes or more entered a loop in `sendContent` that never advanced, exhausting memory. `sendContent` now also throws if `frameMax` leaves no room for a body frame (GHSA-37f9-7m79-6866, reported by Rizwan Bedekar ([@r-bedekar](https://github.com/r-bedekar)); fix based in part on their patch and tests)
|
|
5
|
+
- Add a `maxFrameSize` connection option, also settable as a URL query parameter, bounding the payload size of frames accepted from the server. The default is 64 MiB, or the negotiated `frameMax` if that is larger, so raising `frameMax` needs no second option; `0` disables the limit. Incoming frame sizes were previously unchecked, so a frame header declaring up to 4 GiB made the client buffer, and repeatedly re-copy, that much data before looking at it. An oversized frame is now refused from its header alone and closes the connection with `Frame size N exceeds maxFrameSize M`. The limit is deliberately separate from the negotiated `frameMax`, since some brokers send larger frames without splitting them (see #784). **Upgrade note:** a broker that delivers an unsplit frame larger than the limit will now have that connection closed; pass `maxFrameSize: 0`, or a higher value, to restore the previous behaviour (GHSA-37f9-7m79-6866)
|
|
6
|
+
|
|
7
|
+
## v2.2.1
|
|
8
|
+
- Return the server acknowledgement from promise-based `channel.cancel`, matching the callback API (thanks [@edsonsims](https://github.com/edsonsims)).
|
|
9
|
+
- Type `cancel` replies as `Replies.Cancel` (`{ consumerTag }`) in both the promise and callback API declarations, which previously claimed `Replies.Empty`.
|
|
10
|
+
- Fix callback-based `waitForConfirms` never calling back when invoked after the confirm channel closed with unconfirmed messages; it now yields a `channel closed` error, matching the promise API (thanks [@youdie006](https://github.com/youdie006)).
|
|
11
|
+
- `waitForConfirms` (both APIs) now always fails with `channel closed` after the channel closes with unconfirmed messages. Previously it reported success if every outstanding message had its own callback, or on any call after the first.
|
|
12
|
+
- The callback API's `waitForConfirms` callback is now required in the TypeScript declarations, matching the docs. Calling it without one threw at runtime.
|
|
13
|
+
- Replace `.npmignore` with a `files` allowlist in `package.json` so the published package no longer includes tests, tooling config, dotfiles or the defs generator. Install size drops from 577 kB to 358 kB (fixes #859, thanks [@rubiesonthesky](https://github.com/rubiesonthesky))
|
|
14
|
+
|
|
3
15
|
## v2.2.0
|
|
4
16
|
- Add `calculateDelay` recovery option for supplying a custom reconnect delay strategy, e.g. full jitter, decorrelated jitter or a fixed schedule. When set, `maxDelay` is not applied to its return value; when it throws or returns an invalid value, recovery gives up as if `maxRetries` were exhausted (fixes #855, thanks [@GiHoon1123](https://github.com/GiHoon1123))
|
|
5
17
|
- The built-in reconnect delay no longer exceeds `maxDelay`. Previously the cap was applied before jitter, so delays could overshoot it by up to the jitter fraction. The exponential base is now capped at `maxDelay / (1 + jitter)` so the full jitter range fits under the cap; with default settings the steady-state delay is now spread over 20-30s rather than 24-36s
|
package/callback_api.d.ts
CHANGED
|
@@ -103,7 +103,7 @@ export interface Channel extends events.EventEmitter {
|
|
|
103
103
|
callback?: (err: Error, ok: Replies.Consume) => void,
|
|
104
104
|
): void;
|
|
105
105
|
|
|
106
|
-
cancel(consumerTag: string, callback?: (err: Error, ok: Replies.
|
|
106
|
+
cancel(consumerTag: string, callback?: (err: Error, ok: Replies.Cancel) => void): void;
|
|
107
107
|
get(queue: string, options?: Options.Get, callback?: (err: Error, ok: GetMessage | false) => void): void;
|
|
108
108
|
|
|
109
109
|
ack(message: Message, allUpTo?: boolean): void;
|
|
@@ -132,7 +132,7 @@ export interface ConfirmChannel extends Channel {
|
|
|
132
132
|
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
133
133
|
): boolean;
|
|
134
134
|
|
|
135
|
-
waitForConfirms(callback
|
|
135
|
+
waitForConfirms(callback: (err?: Error) => void): void;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
export declare class IllegalOperationError extends Error {
|
package/index.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export interface Channel extends events.EventEmitter {
|
|
|
77
77
|
options?: Options.Consume,
|
|
78
78
|
): Promise<Replies.Consume>;
|
|
79
79
|
|
|
80
|
-
cancel(consumerTag: string): Promise<Replies.
|
|
80
|
+
cancel(consumerTag: string): Promise<Replies.Cancel>;
|
|
81
81
|
get(queue: string, options?: Options.Get): Promise<GetMessage | false>;
|
|
82
82
|
|
|
83
83
|
ack(message: Message, allUpTo?: boolean): void;
|
package/lib/callback_model.js
CHANGED
|
@@ -255,28 +255,9 @@ class ConfirmChannel extends Channel {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
waitForConfirms(k) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (val === null); // already confirmed
|
|
262
|
-
else {
|
|
263
|
-
const confirmed = new Promise((resolve, reject) => {
|
|
264
|
-
unconfirmed[index] = (err) => {
|
|
265
|
-
if (val) val(err);
|
|
266
|
-
if (err === null) resolve();
|
|
267
|
-
else reject(err);
|
|
268
|
-
};
|
|
269
|
-
});
|
|
270
|
-
awaiting.push(confirmed);
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
return Promise.all(awaiting).then(
|
|
274
|
-
() => {
|
|
275
|
-
k();
|
|
276
|
-
},
|
|
277
|
-
(err) => {
|
|
278
|
-
k(err);
|
|
279
|
-
},
|
|
258
|
+
this._waitForConfirms().then(
|
|
259
|
+
() => k(),
|
|
260
|
+
(err) => k(err),
|
|
280
261
|
);
|
|
281
262
|
}
|
|
282
263
|
}
|
package/lib/channel.js
CHANGED
|
@@ -21,6 +21,7 @@ class Channel extends EventEmitter {
|
|
|
21
21
|
// for unconfirmed messages
|
|
22
22
|
this.lwm = 1; // the least, unconfirmed deliveryTag
|
|
23
23
|
this.unconfirmed = []; // rolling window of delivery callbacks
|
|
24
|
+
this.closedWithUnconfirmed = false;
|
|
24
25
|
this.on(
|
|
25
26
|
'ack',
|
|
26
27
|
this.handleConfirm.bind(this, (cb) => {
|
|
@@ -39,7 +40,10 @@ class Channel extends EventEmitter {
|
|
|
39
40
|
const cb = this.unconfirmed[i];
|
|
40
41
|
if (cb) cb(err);
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
+
// Remember that confirms were lost, so every later waitForConfirms
|
|
44
|
+
// fails, whether or not the messages had their own callbacks
|
|
45
|
+
this.closedWithUnconfirmed = this.unconfirmed.some((cb) => cb !== null);
|
|
46
|
+
this.unconfirmed = [];
|
|
43
47
|
});
|
|
44
48
|
// message frame state machine
|
|
45
49
|
this.handleMessage = acceptDeliveryOrReturn;
|
|
@@ -243,6 +247,28 @@ class Channel extends EventEmitter {
|
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
|
|
250
|
+
// Resolves once every outstanding message is confirmed, and rejects on
|
|
251
|
+
// the first nack, or if the channel closes before all are confirmed.
|
|
252
|
+
// Shared by the promise and callback ConfirmChannel#waitForConfirms.
|
|
253
|
+
_waitForConfirms() {
|
|
254
|
+
if (this.closedWithUnconfirmed) return Promise.reject(new Error('channel closed'));
|
|
255
|
+
const awaiting = [];
|
|
256
|
+
const unconfirmed = this.unconfirmed;
|
|
257
|
+
unconfirmed.forEach((cb, index) => {
|
|
258
|
+
if (cb !== null) {
|
|
259
|
+
const confirmed = new Promise((resolve, reject) => {
|
|
260
|
+
unconfirmed[index] = (err) => {
|
|
261
|
+
if (cb) cb(err);
|
|
262
|
+
if (err === null) resolve();
|
|
263
|
+
else reject(err);
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
awaiting.push(confirmed);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
return Promise.all(awaiting);
|
|
270
|
+
}
|
|
271
|
+
|
|
246
272
|
pushConfirmCallback(cb) {
|
|
247
273
|
// `null` is used specifically for marking already confirmed slots,
|
|
248
274
|
// so I coerce `undefined` and `null` to false; functions are never
|
package/lib/channel_model.js
CHANGED
|
@@ -146,12 +146,9 @@ class Channel extends BaseChannel {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
async cancel(consumerTag) {
|
|
149
|
-
await
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
this.unregisterConsumer(consumerTag);
|
|
153
|
-
return ok.fields;
|
|
154
|
-
});
|
|
149
|
+
const fields = await this.rpc(defs.BasicCancel, Args.cancel(consumerTag), defs.BasicCancelOk);
|
|
150
|
+
this.unregisterConsumer(consumerTag);
|
|
151
|
+
return fields;
|
|
155
152
|
}
|
|
156
153
|
|
|
157
154
|
get(queue, options) {
|
|
@@ -234,29 +231,7 @@ class ConfirmChannel extends Channel {
|
|
|
234
231
|
}
|
|
235
232
|
|
|
236
233
|
waitForConfirms() {
|
|
237
|
-
|
|
238
|
-
const unconfirmed = this.unconfirmed;
|
|
239
|
-
unconfirmed.forEach((cb, index) => {
|
|
240
|
-
if (cb !== null) {
|
|
241
|
-
const confirmed = new Promise((resolve, reject) => {
|
|
242
|
-
unconfirmed[index] = (err) => {
|
|
243
|
-
if (cb) cb(err);
|
|
244
|
-
if (err === null) resolve();
|
|
245
|
-
else reject(err);
|
|
246
|
-
};
|
|
247
|
-
});
|
|
248
|
-
awaiting.push(confirmed);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
// Channel closed
|
|
252
|
-
if (!this.pending) {
|
|
253
|
-
const err = new Error('channel closed');
|
|
254
|
-
while (unconfirmed.length > 0) {
|
|
255
|
-
const cb = unconfirmed.shift();
|
|
256
|
-
if (cb) cb(err);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return Promise.all(awaiting);
|
|
234
|
+
return this._waitForConfirms();
|
|
260
235
|
}
|
|
261
236
|
}
|
|
262
237
|
|
package/lib/connect.js
CHANGED
|
@@ -47,6 +47,11 @@ function openFrames(vhost, query, credentials, extraClientProperties) {
|
|
|
47
47
|
return val === undefined ? def : parseInt(val, 10);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function maxFrameSizeOrUndefined(val) {
|
|
51
|
+
if (val == null) return undefined;
|
|
52
|
+
return /^\d+$/.test(String(val)) ? Number(val) : NaN;
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
const clientProperties = Object.create(CLIENT_PROPERTIES);
|
|
51
56
|
|
|
52
57
|
return {
|
|
@@ -61,6 +66,8 @@ function openFrames(vhost, query, credentials, extraClientProperties) {
|
|
|
61
66
|
frameMax: intOrDefault(query.frameMax, 131072),
|
|
62
67
|
heartbeat: query.heartbeat != null ? intOrDefault(query.heartbeat, 0) : null,
|
|
63
68
|
|
|
69
|
+
maxFrameSize: maxFrameSizeOrUndefined(query.maxFrameSize),
|
|
70
|
+
|
|
64
71
|
// open
|
|
65
72
|
virtualHost: vhost,
|
|
66
73
|
capabilities: '',
|
|
@@ -120,6 +127,7 @@ function connect(url, socketOptions, openCallback) {
|
|
|
120
127
|
channelMax: url.channelMax,
|
|
121
128
|
frameMax: url.frameMax,
|
|
122
129
|
heartbeat: url.heartbeat,
|
|
130
|
+
maxFrameSize: url.maxFrameSize,
|
|
123
131
|
};
|
|
124
132
|
|
|
125
133
|
fields = openFrames(url.vhost, config, sockopts.credentials || credentials.plain(user, pass), extraClientProperties);
|
package/lib/connection.js
CHANGED
|
@@ -27,6 +27,7 @@ const DEFAULT_WRITE_HWM = 1024;
|
|
|
27
27
|
// at once. Note that this is less than the minimum frame size: if it
|
|
28
28
|
// was greater, we might have to fragment the content.
|
|
29
29
|
const SINGLE_CHUNK_THRESHOLD = 2048;
|
|
30
|
+
const DEFAULT_MAX_FRAME_SIZE = 64 * 1024 * 1024;
|
|
30
31
|
|
|
31
32
|
class Connection extends EventEmitter {
|
|
32
33
|
constructor(underlying) {
|
|
@@ -38,6 +39,7 @@ class Connection extends EventEmitter {
|
|
|
38
39
|
// frames
|
|
39
40
|
this.rest = Buffer.alloc(0);
|
|
40
41
|
this.frameMax = constants.FRAME_MIN_SIZE;
|
|
42
|
+
this.maxFrameSize = DEFAULT_MAX_FRAME_SIZE;
|
|
41
43
|
this.sentSinceLastCheck = false;
|
|
42
44
|
this.recvSinceLastCheck = false;
|
|
43
45
|
|
|
@@ -86,6 +88,17 @@ class Connection extends EventEmitter {
|
|
|
86
88
|
const self = this;
|
|
87
89
|
const openCallback = openCallback0 || (() => {});
|
|
88
90
|
|
|
91
|
+
const maxFrameSize = allFields.maxFrameSize;
|
|
92
|
+
const maxFrameSizeDefaulted = maxFrameSize === undefined || maxFrameSize === null;
|
|
93
|
+
if (maxFrameSizeDefaulted) {
|
|
94
|
+
self.maxFrameSize = DEFAULT_MAX_FRAME_SIZE;
|
|
95
|
+
} else if (!Number.isInteger(maxFrameSize) || (maxFrameSize !== 0 && maxFrameSize < constants.FRAME_MIN_SIZE)) {
|
|
96
|
+
bail(new TypeError(fmt('maxFrameSize must be 0 (no limit) or an integer of at least %d; got %s', constants.FRAME_MIN_SIZE, maxFrameSize)));
|
|
97
|
+
return;
|
|
98
|
+
} else {
|
|
99
|
+
self.maxFrameSize = maxFrameSize;
|
|
100
|
+
}
|
|
101
|
+
|
|
89
102
|
// This is where we'll put our negotiated values
|
|
90
103
|
const tunedOptions = Object.create(allFields);
|
|
91
104
|
|
|
@@ -157,6 +170,10 @@ class Connection extends EventEmitter {
|
|
|
157
170
|
break;
|
|
158
171
|
case defs.ConnectionTune: {
|
|
159
172
|
const fields = reply.fields;
|
|
173
|
+
if (fields.frameMax !== 0 && fields.frameMax < constants.FRAME_MIN_SIZE) {
|
|
174
|
+
bail(new Error(fmt('Server frameMax %d is below the protocol minimum %d', fields.frameMax, constants.FRAME_MIN_SIZE)));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
160
177
|
tunedOptions.frameMax = negotiate(fields.frameMax, allFields.frameMax);
|
|
161
178
|
tunedOptions.channelMax = negotiate(fields.channelMax, allFields.channelMax);
|
|
162
179
|
if (allFields.heartbeat == null) {
|
|
@@ -191,6 +208,9 @@ class Connection extends EventEmitter {
|
|
|
191
208
|
// value is zero, meaning "no, no limits"
|
|
192
209
|
self.channelMax = tunedOptions.channelMax || 0xffff;
|
|
193
210
|
self.frameMax = tunedOptions.frameMax || 0xffffffff;
|
|
211
|
+
if (maxFrameSizeDefaulted && tunedOptions.frameMax !== 0 && tunedOptions.frameMax > self.maxFrameSize) {
|
|
212
|
+
self.maxFrameSize = tunedOptions.frameMax;
|
|
213
|
+
}
|
|
194
214
|
// 0 means "no heartbeat", rather than "maximum period of
|
|
195
215
|
// heartbeating"
|
|
196
216
|
self.heartbeat = tunedOptions.heartbeat;
|
|
@@ -526,6 +546,9 @@ class Connection extends EventEmitter {
|
|
|
526
546
|
const buffer = this.channels[channel].buffer;
|
|
527
547
|
|
|
528
548
|
const maxBody = this.frameMax - FRAME_OVERHEAD;
|
|
549
|
+
if (!(maxBody > 0)) {
|
|
550
|
+
throw new Error(fmt('Cannot send content: frameMax %d leaves no room for a body frame', this.frameMax));
|
|
551
|
+
}
|
|
529
552
|
|
|
530
553
|
for (let offset = 0; offset < body.length; offset += maxBody) {
|
|
531
554
|
const end = offset + maxBody;
|
|
@@ -539,7 +562,7 @@ class Connection extends EventEmitter {
|
|
|
539
562
|
|
|
540
563
|
recvFrame() {
|
|
541
564
|
// %%% identifying invariants might help here?
|
|
542
|
-
const frame = parseFrame(this.rest);
|
|
565
|
+
const frame = parseFrame(this.rest, this.maxFrameSize);
|
|
543
566
|
|
|
544
567
|
if (!frame) {
|
|
545
568
|
const incoming = this.stream.read();
|
|
@@ -654,3 +677,4 @@ function isFatalError(error) {
|
|
|
654
677
|
|
|
655
678
|
module.exports.Connection = Connection;
|
|
656
679
|
module.exports.isFatalError = isFatalError;
|
|
680
|
+
module.exports.DEFAULT_MAX_FRAME_SIZE = DEFAULT_MAX_FRAME_SIZE;
|
package/lib/frame.js
CHANGED
|
@@ -78,7 +78,7 @@ module.exports.makeBodyFrame = (channel, payload) => {
|
|
|
78
78
|
* @arg { number } max
|
|
79
79
|
* @returns { FrameStructure | boolean }
|
|
80
80
|
*/
|
|
81
|
-
function parseFrame(bin) {
|
|
81
|
+
function parseFrame(bin, max) {
|
|
82
82
|
if (bin.length < FRAME_HEADER_BYTES) {
|
|
83
83
|
return false;
|
|
84
84
|
}
|
|
@@ -87,6 +87,10 @@ function parseFrame(bin) {
|
|
|
87
87
|
const channel = bin.readUInt16BE(1);
|
|
88
88
|
const size = bin.readUInt32BE(3);
|
|
89
89
|
|
|
90
|
+
if (max > 0 && size > max) {
|
|
91
|
+
throw new Error(`Frame size ${size} exceeds maxFrameSize ${max}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
90
94
|
const totalSize = FRAME_HEADER_BYTES + size + FRAME_END_BYTES;
|
|
91
95
|
|
|
92
96
|
if (bin.length < totalSize) {
|
package/lib/properties.d.ts
CHANGED
|
@@ -19,6 +19,9 @@ export namespace Replies {
|
|
|
19
19
|
interface Consume {
|
|
20
20
|
consumerTag: string;
|
|
21
21
|
}
|
|
22
|
+
interface Cancel {
|
|
23
|
+
consumerTag: string;
|
|
24
|
+
}
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export namespace Options {
|
|
@@ -30,6 +33,7 @@ export namespace Options {
|
|
|
30
33
|
password?: string;
|
|
31
34
|
locale?: string;
|
|
32
35
|
frameMax?: number;
|
|
36
|
+
maxFrameSize?: number;
|
|
33
37
|
heartbeat?: number;
|
|
34
38
|
vhost?: string;
|
|
35
39
|
channelMax?: number;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "amqplib",
|
|
3
3
|
"homepage": "http://amqp-node.github.io/amqplib/",
|
|
4
4
|
"main": "./channel_api.js",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.3.0",
|
|
6
6
|
"types": "./index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
@@ -46,5 +46,15 @@
|
|
|
46
46
|
"RabbitMQ"
|
|
47
47
|
],
|
|
48
48
|
"author": "Michael Bridgen <mikeb@squaremobius.net>",
|
|
49
|
-
"license": "MIT"
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"files": [
|
|
51
|
+
"lib",
|
|
52
|
+
"examples",
|
|
53
|
+
"channel_api.js",
|
|
54
|
+
"callback_api.js",
|
|
55
|
+
"index.d.ts",
|
|
56
|
+
"callback_api.d.ts",
|
|
57
|
+
"CHANGELOG.md",
|
|
58
|
+
"LICENSE-MIT"
|
|
59
|
+
]
|
|
50
60
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
Please follow the following process when I ask you to disable a lint rule using /lint-disable $rule
|
|
2
|
-
|
|
3
|
-
1. Create and change to a new branch. Ask for the branch name.
|
|
4
|
-
2. If the rule is off by default, delete it (See https://biomejs.dev/linter/javascript/rules/ for rule details)
|
|
5
|
-
3. If the rule is on by default, configure it to off in biome.json
|
|
6
|
-
4. Update the project changelog
|
|
7
|
-
5. Add the changes
|
|
8
|
-
6. Commit the changes
|
|
9
|
-
7. Push the changes
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Please follow the following process when I ask you to enable a lint rule using /lint-enable $rule
|
|
2
|
-
|
|
3
|
-
1. Create and change to a new branch. Ask for the branch name.
|
|
4
|
-
2. Configure the rule to error in biome.json
|
|
5
|
-
3. Run lint (npm run lint). If there are NO errors, goto step 8
|
|
6
|
-
4. Use biome to SAFELY auto fix (npm run lint -- --fix). If there are errors stop and ask for instruction.
|
|
7
|
-
5. Run the tests (npm test). If there are errors, stop and ask for instruction.
|
|
8
|
-
6. If the rule defaults to error, delete it (See https://biomejs.dev/linter/javascript/rules/ for rule details)
|
|
9
|
-
7. Update the project changelog
|
|
10
|
-
8. Add the changes
|
|
11
|
-
9. Commit the changes
|
|
12
|
-
10. Push the changes
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Bug report / Support request
|
|
3
|
-
about: Report a bug or ask for help
|
|
4
|
-
title: ''
|
|
5
|
-
labels: ''
|
|
6
|
-
assignees: ''
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
Before reporting a bug or requesting support please...
|
|
11
|
-
|
|
12
|
-
1. Read the troubleshooting guide
|
|
13
|
-
|
|
14
|
-
- https://amqp-node.github.io/amqplib/#troubleshooting
|
|
15
|
-
|
|
16
|
-
2. Search for existing open and closed issues
|
|
17
|
-
|
|
18
|
-
- https://github.com/amqp-node/amqplib/issues?q=is%3Aissue+TYPE+YOUR+KEYWORDS+HERE
|
|
19
|
-
|
|
20
|
-
3. Ensure you are familiar with the amqplib Channel API and RabbitMQ basics
|
|
21
|
-
|
|
22
|
-
- https://amqp-node.github.io/amqplib/channel_api.html
|
|
23
|
-
- https://www.cloudamqp.com/blog/part1-rabbitmq-for-beginners-what-is-rabbitmq.html
|
|
24
|
-
- https://www.rabbitmq.com/tutorials/amqp-concepts.html
|
|
25
|
-
|
|
26
|
-
If the above does not help, please provide as much of the following information as is relevant...
|
|
27
|
-
|
|
28
|
-
- A clear and concise description of the problem
|
|
29
|
-
- RabbitMQ version
|
|
30
|
-
- amqplib version
|
|
31
|
-
- Node.js version
|
|
32
|
-
- The simplest possible code snippet that demonstrates the problem
|
|
33
|
-
- A stack trace
|
|
34
|
-
|
|
35
|
-
Please format code snippets and/or stack traces using GitHub Markdown
|
|
36
|
-
|
|
37
|
-
- https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks).
|
|
38
|
-
|
|
39
|
-
Thank you
|
|
40
|
-
|
|
41
|
-
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# Runs when a GitHub release is published (draft releases do not trigger it).
|
|
2
|
-
#
|
|
3
|
-
# Tests the tagged commit on every supported Node.js version, then stages the
|
|
4
|
-
# package on npm with `npm stage publish` using OIDC trusted publishing, so no
|
|
5
|
-
# npm token is stored in this repository. Nothing goes live until a maintainer
|
|
6
|
-
# reviews the staged version and approves it with 2FA:
|
|
7
|
-
#
|
|
8
|
-
# npm stage list amqplib
|
|
9
|
-
# npm stage approve <stage-id>
|
|
10
|
-
#
|
|
11
|
-
# Prerequisites on npmjs.com: the package's trusted publisher must be set to
|
|
12
|
-
# this repository and this workflow file (publish.yml), with allowed actions
|
|
13
|
-
# restricted to `npm stage publish`.
|
|
14
|
-
|
|
15
|
-
name: Publish
|
|
16
|
-
|
|
17
|
-
on:
|
|
18
|
-
release:
|
|
19
|
-
types: [published]
|
|
20
|
-
|
|
21
|
-
permissions:
|
|
22
|
-
contents: read
|
|
23
|
-
|
|
24
|
-
jobs:
|
|
25
|
-
build:
|
|
26
|
-
runs-on: ubuntu-latest
|
|
27
|
-
services:
|
|
28
|
-
rabbitmq:
|
|
29
|
-
image: rabbitmq:4.2-alpine
|
|
30
|
-
ports:
|
|
31
|
-
- 5672:5672
|
|
32
|
-
|
|
33
|
-
strategy:
|
|
34
|
-
matrix:
|
|
35
|
-
node-version: [18.x, 20.x, 22.x, 24.x]
|
|
36
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
37
|
-
|
|
38
|
-
steps:
|
|
39
|
-
- uses: actions/checkout@v4
|
|
40
|
-
|
|
41
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
42
|
-
uses: actions/setup-node@v4
|
|
43
|
-
with:
|
|
44
|
-
node-version: ${{ matrix.node-version }}
|
|
45
|
-
cache: "npm"
|
|
46
|
-
|
|
47
|
-
- run: npm ci
|
|
48
|
-
|
|
49
|
-
- name: Wait for RabbitMQ
|
|
50
|
-
run: |
|
|
51
|
-
n=0
|
|
52
|
-
while :
|
|
53
|
-
do
|
|
54
|
-
sleep 5
|
|
55
|
-
echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
|
|
56
|
-
[[ $? = 0 ]] && break || ((n++))
|
|
57
|
-
(( n >= 5 )) && break
|
|
58
|
-
done
|
|
59
|
-
|
|
60
|
-
- run: echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
|
|
61
|
-
|
|
62
|
-
- run: make test
|
|
63
|
-
|
|
64
|
-
stage:
|
|
65
|
-
needs: build
|
|
66
|
-
runs-on: ubuntu-latest
|
|
67
|
-
permissions:
|
|
68
|
-
contents: read
|
|
69
|
-
id-token: write # required for OIDC trusted publishing
|
|
70
|
-
steps:
|
|
71
|
-
- uses: actions/checkout@v4
|
|
72
|
-
|
|
73
|
-
- uses: actions/setup-node@v4
|
|
74
|
-
with:
|
|
75
|
-
node-version: 24.x
|
|
76
|
-
cache: "npm"
|
|
77
|
-
registry-url: https://registry.npmjs.org/
|
|
78
|
-
|
|
79
|
-
# npm stage publish needs npm 11.15.0 or later
|
|
80
|
-
- run: npm install -g npm@^11.15.0
|
|
81
|
-
|
|
82
|
-
- run: npm ci
|
|
83
|
-
|
|
84
|
-
- name: Check release tag matches package.json version
|
|
85
|
-
id: version
|
|
86
|
-
env:
|
|
87
|
-
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
88
|
-
run: |
|
|
89
|
-
version="$(node -p "require('./package.json').version")"
|
|
90
|
-
if [[ "$RELEASE_TAG" != "v${version}" ]]; then
|
|
91
|
-
echo "Release tag ${RELEASE_TAG} does not match package.json version v${version}" >&2
|
|
92
|
-
exit 1
|
|
93
|
-
fi
|
|
94
|
-
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
|
95
|
-
|
|
96
|
-
# Pre-release versions (e.g. 2.2.0-rc.0) are staged under the `next`
|
|
97
|
-
# dist-tag; everything else under `latest`. The tag is fixed at staging
|
|
98
|
-
# time and cannot be changed on approval.
|
|
99
|
-
- name: Choose dist-tag
|
|
100
|
-
id: dist-tag
|
|
101
|
-
env:
|
|
102
|
-
VERSION: ${{ steps.version.outputs.version }}
|
|
103
|
-
run: |
|
|
104
|
-
if [[ "$VERSION" == *-* ]]; then
|
|
105
|
-
echo "tag=next" >> "$GITHUB_OUTPUT"
|
|
106
|
-
else
|
|
107
|
-
echo "tag=latest" >> "$GITHUB_OUTPUT"
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
- name: Stage publish
|
|
111
|
-
env:
|
|
112
|
-
DIST_TAG: ${{ steps.dist-tag.outputs.tag }}
|
|
113
|
-
run: npm stage publish --tag "$DIST_TAG" --provenance
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
3
|
-
|
|
4
|
-
name: Node.js CI
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
push:
|
|
8
|
-
branches: [main]
|
|
9
|
-
pull_request:
|
|
10
|
-
branches: [main]
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
build:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
services:
|
|
16
|
-
rabbitmq:
|
|
17
|
-
image: rabbitmq:4.2-alpine
|
|
18
|
-
ports:
|
|
19
|
-
- 5672:5672
|
|
20
|
-
|
|
21
|
-
strategy:
|
|
22
|
-
matrix:
|
|
23
|
-
node-version: [18.x, 20.x, 22.x, 24.x]
|
|
24
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
25
|
-
|
|
26
|
-
steps:
|
|
27
|
-
- uses: actions/checkout@v3
|
|
28
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
29
|
-
uses: actions/setup-node@v4
|
|
30
|
-
with:
|
|
31
|
-
node-version: ${{ matrix.node-version }}
|
|
32
|
-
cache: "npm"
|
|
33
|
-
|
|
34
|
-
# Install all prerequisites
|
|
35
|
-
- run: npm ci
|
|
36
|
-
|
|
37
|
-
# Ensure RabbitMQ is available before continuing
|
|
38
|
-
- run: |
|
|
39
|
-
n=0
|
|
40
|
-
while :
|
|
41
|
-
do
|
|
42
|
-
sleep 5
|
|
43
|
-
echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
|
|
44
|
-
[[ $? = 0 ]] && break || ((n++))
|
|
45
|
-
(( n >= 5 )) && break
|
|
46
|
-
done
|
|
47
|
-
|
|
48
|
-
- run: echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
|
|
49
|
-
|
|
50
|
-
# Check TypeScript types
|
|
51
|
-
- run: npm run typecheck
|
|
52
|
-
|
|
53
|
-
# Run the tests
|
|
54
|
-
- run: make test
|
package/CLAUDE.md
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Project-Specific Guidelines for amqplib
|
|
2
|
-
|
|
3
|
-
## Generated Files - DO NOT EDIT
|
|
4
|
-
- `lib/defs.js` - This file is generated code. NEVER modify it directly.
|
|
5
|
-
- Generated via `make lib/defs.js` from the AMQP specification
|
|
6
|
-
- If linting issues arise, exclude this file from linting rules rather than modifying it
|
|
7
|
-
|
|
8
|
-
## Commit Requirements
|
|
9
|
-
- NEVER commit when tests are failing
|
|
10
|
-
- NEVER commit when there are lint errors
|
|
11
|
-
- Always run `npm test` and `npm run lint` before committing
|
|
12
|
-
- If tests are failing, investigate and fix the issue before proceeding
|
package/Makefile
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
RABBITMQ_SRC_VERSION=v3.12.13
|
|
2
|
-
JSON=amqp-rabbitmq-0.9.1.json
|
|
3
|
-
AMQP_JSON=https://raw.githubusercontent.com/rabbitmq/rabbitmq-server/$(RABBITMQ_SRC_VERSION)/deps/rabbitmq_codegen/$(JSON)
|
|
4
|
-
|
|
5
|
-
NODEJS_VERSIONS='18.20.0' '20.10.0' '22.14.0' '24.7.0'
|
|
6
|
-
|
|
7
|
-
UGLIFY=./node_modules/.bin/uglifyjs
|
|
8
|
-
|
|
9
|
-
.PHONY: test test-all-nodejs coverage lib/defs.js
|
|
10
|
-
|
|
11
|
-
error:
|
|
12
|
-
@echo "Please choose one of the following targets: test, test-all-nodejs, coverage, lib/defs.js"
|
|
13
|
-
@exit 1
|
|
14
|
-
|
|
15
|
-
test:
|
|
16
|
-
node --test --test-reporter=spec
|
|
17
|
-
|
|
18
|
-
test-all-nodejs:
|
|
19
|
-
for v in $(NODEJS_VERSIONS); \
|
|
20
|
-
do echo "-- Node version $$v --"; \
|
|
21
|
-
nave use $$v node --test --test-reporter=spec; \
|
|
22
|
-
done
|
|
23
|
-
|
|
24
|
-
coverage:
|
|
25
|
-
node --test --test-coverage --test-reporter=spec
|
|
26
|
-
|
|
27
|
-
lib/defs.js: clean bin/generate-defs test
|
|
28
|
-
|
|
29
|
-
clean:
|
|
30
|
-
rm -f lib/defs.js bin/amqp-rabbitmq-0.9.1.json
|
|
31
|
-
|
|
32
|
-
bin/generate-defs: $(UGLIFY) bin/generate-defs.js bin/amqp-rabbitmq-0.9.1.json
|
|
33
|
-
(cd bin; node ./generate-defs.js > ../lib/defs.js)
|
|
34
|
-
$(UGLIFY) ./lib/defs.js -o ./lib/defs.js \
|
|
35
|
-
-c 'sequences=false' --comments \
|
|
36
|
-
-b 'indent-level=2' 2>&1 | (grep -v 'WARN' || true)
|
|
37
|
-
|
|
38
|
-
bin/amqp-rabbitmq-0.9.1.json:
|
|
39
|
-
curl -L $(AMQP_JSON) > $@
|
|
40
|
-
|
|
41
|
-
$(UGLIFY):
|
|
42
|
-
npm install
|