amqplib 2.1.0 → 2.2.1

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Change log for amqplib
2
2
 
3
+ ## v2.2.1
4
+ - Return the server acknowledgement from promise-based `channel.cancel`, matching the callback API (thanks [@edsonsims](https://github.com/edsonsims)).
5
+ - Type `cancel` replies as `Replies.Cancel` (`{ consumerTag }`) in both the promise and callback API declarations, which previously claimed `Replies.Empty`.
6
+ - 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)).
7
+ - `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.
8
+ - The callback API's `waitForConfirms` callback is now required in the TypeScript declarations, matching the docs. Calling it without one threw at runtime.
9
+ - 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))
10
+
11
+ ## v2.2.0
12
+ - 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))
13
+ - 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
14
+ - Channel operations attempted after recovery has given up (`reconnect-failed`) now reject with the failure instead of waiting forever
15
+ - Add `initialMaxRetries` recovery option to bound retries before the first successful connection separately from `maxRetries`, so startup can fail fast while steady-state recovery retries indefinitely (fixes #856)
16
+
3
17
  ## v2.1.0
4
18
  - Add `waitForConnect` recovery option. When `false`, `connect` returns the recovering connection immediately instead of waiting for the first successful connection, so listeners for `connect`, `connect-failed` and `reconnect-scheduled` can be attached before the initial attempt, and `close()` can cancel it. Expose `waitForConnect()` on recovering connections to await the first connection (fixes #858)
5
19
  - Fix `setup` being run when `close()` is called while the initial connection attempt is in flight
package/README.md CHANGED
@@ -210,6 +210,60 @@ callback is invoked immediately with the handle instead of after the first
210
210
  connection, and `waitForConnect(callback)` can be used to be notified once
211
211
  connected.
212
212
 
213
+ ### Custom delay strategy
214
+
215
+ By default, reconnect delays follow an exponential backoff with jitter,
216
+ controlled by `initialDelay`, `maxDelay`, `factor` and `jitter`. To use a
217
+ different strategy entirely (full jitter, decorrelated jitter, a fixed step
218
+ schedule, etc.), provide a `calculateDelay` function instead:
219
+
220
+ ```javascript
221
+ const connection = await amqplib.connect('amqp://localhost', {
222
+ recovery: {
223
+ maxRetries: Infinity,
224
+ // Called with the reconnect attempt number, starting at 1.
225
+ // Must return the delay in milliseconds.
226
+ calculateDelay(attempt) {
227
+ return Math.min(30000, 100 * 2 ** (attempt - 1));
228
+ },
229
+ },
230
+ });
231
+ ```
232
+
233
+ `maxDelay` only bounds the built-in strategy. Once you provide `calculateDelay`,
234
+ amqplib does not cap its return value - you're responsible for enforcing your
235
+ own maximum, as the example above does with `Math.min`.
236
+
237
+ When `calculateDelay` is absent, the built-in strategy is used. If it throws,
238
+ or returns something other than a finite, non-negative number, amqplib does
239
+ not fall back to the built-in strategy. Instead recovery gives up as if
240
+ `maxRetries` had been exhausted: the initial `connect` rejects (or the
241
+ callback receives the error), pending channel operations reject, and
242
+ `reconnect-failed` is emitted with the error. A broken `calculateDelay` is a
243
+ bug in caller-supplied code, so it is surfaced rather than papered over.
244
+
245
+ ### Separate retry budget for the initial connection
246
+
247
+ By default `maxRetries` bounds every phase of recovery, including the attempts
248
+ made before the first connection succeeds. To give the very first connection
249
+ its own budget, set `initialMaxRetries`; once connected, `maxRetries` applies.
250
+ A common production posture is to fail fast at startup, so a misconfigured or
251
+ unreachable broker fails the deployment, while never giving up on a service
252
+ that has already connected:
253
+
254
+ ```javascript
255
+ const connection = await amqplib.connect('amqp://localhost', {
256
+ recovery: {
257
+ initialMaxRetries: 5, // give up (and reject connect) after 5 failed retries at startup
258
+ maxRetries: Infinity, // but keep reconnecting forever once connected
259
+ },
260
+ });
261
+ ```
262
+
263
+ When the initial budget is exhausted `connect` rejects (or the callback receives
264
+ the error) and `reconnect-failed` is emitted. `initialMaxRetries` defaults to
265
+ `maxRetries`, so behaviour is unchanged unless it is set.
266
+
213
267
  ## Error handling in event handlers
214
268
 
215
269
  If a user-supplied event handler throws a synchronous error, the throw will
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.Empty) => void): void;
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?: (err?: Error) => void): void;
135
+ waitForConfirms(callback: (err?: Error) => void): void;
136
136
  }
137
137
 
138
138
  export declare class IllegalOperationError extends Error {
@@ -169,8 +169,15 @@ export interface RecoveryOptions {
169
169
  factor?: number;
170
170
  /** Jitter factor (0–1) applied to delay to avoid thundering herd. Default: 0.2 */
171
171
  jitter?: number;
172
- /** Maximum number of reconnect attempts. Default: Infinity */
172
+ /** Maximum number of reconnect attempts. Also bounds the initial connection unless `initialMaxRetries` is set. Default: Infinity */
173
173
  maxRetries?: number;
174
+ /**
175
+ * Maximum number of retries before the first successful connection. Once
176
+ * connected, `maxRetries` applies instead. Lets startup fail fast against an
177
+ * unreachable broker while steady-state recovery keeps retrying.
178
+ * Default: the value of `maxRetries`
179
+ */
180
+ initialMaxRetries?: number;
174
181
  /** Optional setup function called after each successful connection */
175
182
  setup?: ((model: Connection) => Promise<void>) | ((model: Connection, done: (err?: Error) => void) => void);
176
183
  /**
@@ -179,6 +186,15 @@ export interface RecoveryOptions {
179
186
  * Use `waitForConnect()` to be notified of the first connection. Default: true
180
187
  */
181
188
  waitForConnect?: boolean;
189
+ /**
190
+ * Optional custom delay strategy. Called with the reconnect attempt number
191
+ * (starting at 1) and must return the delay in milliseconds. Falls back to
192
+ * the built-in exponential-backoff-with-jitter strategy when absent. If it
193
+ * throws, or returns something other than a finite, non-negative number,
194
+ * recovery gives up as if `maxRetries` were exhausted: the initial connection
195
+ * fails with the error and `reconnect-failed` is emitted.
196
+ */
197
+ calculateDelay?: (attempt: number) => number;
182
198
  }
183
199
 
184
200
  export interface RecoveringConnection extends events.EventEmitter {
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.Empty>;
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;
@@ -143,8 +143,15 @@ export interface RecoveryOptions {
143
143
  factor?: number;
144
144
  /** Jitter factor (0–1) applied to delay to avoid thundering herd. Default: 0.2 */
145
145
  jitter?: number;
146
- /** Maximum number of reconnect attempts. Default: Infinity */
146
+ /** Maximum number of reconnect attempts. Also bounds the initial connection unless `initialMaxRetries` is set. Default: Infinity */
147
147
  maxRetries?: number;
148
+ /**
149
+ * Maximum number of retries before the first successful connection. Once
150
+ * connected, `maxRetries` applies instead. Lets startup fail fast against an
151
+ * unreachable broker while steady-state recovery keeps retrying.
152
+ * Default: the value of `maxRetries`
153
+ */
154
+ initialMaxRetries?: number;
148
155
  /** Optional setup function called after each successful connection */
149
156
  setup?: ((model: ChannelModel) => Promise<void>) | ((model: ChannelModel, done: (err?: Error) => void) => void);
150
157
  /**
@@ -154,6 +161,15 @@ export interface RecoveryOptions {
154
161
  * first connection. Default: true
155
162
  */
156
163
  waitForConnect?: boolean;
164
+ /**
165
+ * Optional custom delay strategy. Called with the reconnect attempt number
166
+ * (starting at 1) and must return the delay in milliseconds. Falls back to
167
+ * the built-in exponential-backoff-with-jitter strategy when absent. If it
168
+ * throws, or returns something other than a finite, non-negative number,
169
+ * recovery gives up as if `maxRetries` were exhausted: the initial connection
170
+ * fails with the error and `reconnect-failed` is emitted.
171
+ */
172
+ calculateDelay?: (attempt: number) => number;
157
173
  }
158
174
 
159
175
  export interface RecoveringChannelModel extends events.EventEmitter {
@@ -255,28 +255,9 @@ class ConfirmChannel extends Channel {
255
255
  }
256
256
 
257
257
  waitForConfirms(k) {
258
- const awaiting = [];
259
- const unconfirmed = this.unconfirmed;
260
- unconfirmed.forEach((val, index) => {
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
- this.unconfirmed = this.unconfirmed.filter((cb) => cb === false);
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
@@ -146,12 +146,9 @@ class Channel extends BaseChannel {
146
146
  }
147
147
 
148
148
  async cancel(consumerTag) {
149
- await promisify((cb) => {
150
- this._rpc(defs.BasicCancel, Args.cancel(consumerTag), defs.BasicCancelOk, cb);
151
- })().then((ok) => {
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
- const awaiting = [];
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
 
@@ -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 {
package/lib/recovery.js CHANGED
@@ -8,6 +8,7 @@ const DEFAULT_RECOVERY = {
8
8
  maxRetries: Infinity,
9
9
  setup: null,
10
10
  waitForConnect: true,
11
+ calculateDelay: null,
11
12
  };
12
13
 
13
14
  function splitConnectionOptions(connOptions) {
@@ -43,22 +44,32 @@ function toFiniteNumber(value, fallback) {
43
44
  return Number.isFinite(n) ? n : fallback;
44
45
  }
45
46
 
47
+ function toRetryCount(value, fallback) {
48
+ if (value == null) return fallback;
49
+ if (value === Infinity) return Infinity;
50
+ const n = toFiniteNumber(value, fallback);
51
+ return n < 0 ? 0 : n;
52
+ }
53
+
46
54
  function normaliseRecoveryOptions(recovery) {
47
55
  const source = recovery === true ? {} : recovery || {};
48
56
  const initialDelay = Math.max(0, toFiniteNumber(source.initialDelay, DEFAULT_RECOVERY.initialDelay));
49
57
  const maxDelay = Math.max(initialDelay, toFiniteNumber(source.maxDelay, DEFAULT_RECOVERY.maxDelay));
50
58
  const factor = Math.max(1, toFiniteNumber(source.factor, DEFAULT_RECOVERY.factor));
51
59
  const jitter = Math.min(1, Math.max(0, toFiniteNumber(source.jitter, DEFAULT_RECOVERY.jitter)));
52
- const parsedMaxRetries = source.maxRetries == null ? Infinity : toFiniteNumber(source.maxRetries, Infinity);
60
+ const maxRetries = toRetryCount(source.maxRetries, Infinity);
61
+ const initialMaxRetries = toRetryCount(source.initialMaxRetries, maxRetries);
53
62
 
54
63
  return {
55
64
  initialDelay,
56
65
  maxDelay,
57
66
  factor,
58
67
  jitter,
59
- maxRetries: parsedMaxRetries < 0 ? 0 : parsedMaxRetries,
68
+ maxRetries,
69
+ initialMaxRetries,
60
70
  setup: typeof source.setup === 'function' ? source.setup : null,
61
71
  waitForConnect: source.waitForConnect !== false,
72
+ calculateDelay: typeof source.calculateDelay === 'function' ? source.calculateDelay : null,
62
73
  };
63
74
  }
64
75
 
@@ -67,13 +78,39 @@ function toError(err, fallbackMessage) {
67
78
  return new Error(err ? String(err) : fallbackMessage);
68
79
  }
69
80
 
70
- function calculateDelay(recovery, attempt) {
71
- const base = Math.min(recovery.maxDelay, recovery.initialDelay * recovery.factor ** (attempt - 1));
81
+ function calculateBuiltinDelay(recovery, attempt) {
82
+ // Capping the base at maxDelay and then clamping base+offset to maxDelay
83
+ // would put a point mass on maxDelay itself: once base saturates, every
84
+ // positive jitter draw (half of them) collapses onto the same value,
85
+ // defeating the point of jitter. Capping the base at
86
+ // maxDelay / (1 + jitter) instead means the maximum possible offset
87
+ // lands exactly on maxDelay, so the result never exceeds it without
88
+ // needing a final clamp - the distribution stays smooth right up to the cap.
89
+ const cappedBase = recovery.maxDelay / (1 + recovery.jitter);
90
+ const base = Math.min(cappedBase, recovery.initialDelay * recovery.factor ** (attempt - 1));
72
91
  const jitterPart = base * recovery.jitter;
73
92
  const offset = jitterPart > 0 ? Math.random() * jitterPart * 2 - jitterPart : 0;
74
93
  return Math.max(0, Math.round(base + offset));
75
94
  }
76
95
 
96
+ // A custom `calculateDelay` that throws, or returns something other than a
97
+ // finite, non-negative number, is a bug in caller-supplied code. Rather than
98
+ // silently falling back to the built-in strategy, the error is treated as a
99
+ // terminal recovery failure by the caller (see _scheduleReconnect), so it
100
+ // surfaces immediately instead of manifesting as unexplained delay behavior.
101
+ function calculateDelay(recovery, attempt) {
102
+ if (!recovery.calculateDelay) {
103
+ return calculateBuiltinDelay(recovery, attempt);
104
+ }
105
+
106
+ const custom = recovery.calculateDelay(attempt);
107
+ if (typeof custom === 'number' && Number.isFinite(custom) && custom >= 0) {
108
+ return Math.round(custom);
109
+ }
110
+
111
+ throw new Error(`calculateDelay must return a finite, non-negative number of milliseconds (got ${String(custom)})`);
112
+ }
113
+
77
114
  function runSetup(setup, model) {
78
115
  if (!setup) return Promise.resolve();
79
116
 
@@ -118,6 +155,8 @@ class RecoveringCore extends EventEmitter {
118
155
  this._waiters = [];
119
156
  this._connecting = false;
120
157
  this._stopped = false;
158
+ this._failure = null;
159
+ this._connectedOnce = false;
121
160
  this._timer = null;
122
161
  this._attempt = 0;
123
162
 
@@ -205,7 +244,7 @@ class RecoveringCore extends EventEmitter {
205
244
 
206
245
  _waitForConnection() {
207
246
  if (this._model) return Promise.resolve(this._model);
208
- if (this._stopped) return Promise.reject(new Error('Connection closed'));
247
+ if (this._stopped) return Promise.reject(this._failure || new Error('Connection closed'));
209
248
 
210
249
  return new Promise((resolve, reject) => {
211
250
  this._waiters.push({ resolve, reject });
@@ -277,6 +316,7 @@ class RecoveringCore extends EventEmitter {
277
316
 
278
317
  this._model = model;
279
318
  this._attempt = 0;
319
+ this._connectedOnce = true;
280
320
  this._bindModel(model);
281
321
  this._resolveInitialConnection();
282
322
  this._resolvePendingWaiters(model);
@@ -296,15 +336,24 @@ class RecoveringCore extends EventEmitter {
296
336
 
297
337
  if (this._timer) return;
298
338
 
299
- if (this._attempt >= this._recovery.maxRetries) {
300
- this._rejectInitialConnection(err);
301
- this._rejectPendingWaiters(err);
302
- this.emit('reconnect-failed', err);
339
+ const maxRetries = this._connectedOnce ? this._recovery.maxRetries : this._recovery.initialMaxRetries;
340
+ if (this._attempt >= maxRetries) {
341
+ this._abandonRecovery(err);
303
342
  return;
304
343
  }
305
344
 
306
345
  const attempt = this._attempt + 1;
307
- const delay = calculateDelay(this._recovery, attempt);
346
+ let delay;
347
+ try {
348
+ delay = calculateDelay(this._recovery, attempt);
349
+ } catch (delayErr) {
350
+ // Both callers of _scheduleReconnect run from timers or socket events
351
+ // where a throw would either be an unhandled rejection or an uncaught
352
+ // exception. Give up recovery cleanly instead so the failure reaches the
353
+ // initial connect promise, pending channel waiters and 'reconnect-failed'.
354
+ this._abandonRecovery(toError(delayErr, 'calculateDelay failed'));
355
+ return;
356
+ }
308
357
  this._attempt = attempt;
309
358
 
310
359
  this.emit('reconnect-scheduled', { attempt, delay, error: err });
@@ -314,6 +363,18 @@ class RecoveringCore extends EventEmitter {
314
363
  }, delay);
315
364
  }
316
365
 
366
+ _abandonRecovery(err) {
367
+ // Recovery is over and cannot be restarted, so treat the connection as
368
+ // stopped. Remember why, so channel operations attempted afterwards
369
+ // reject with the underlying failure instead of waiting forever for a
370
+ // connection that will never arrive.
371
+ this._stopped = true;
372
+ this._failure = err;
373
+ this._rejectInitialConnection(err);
374
+ this._rejectPendingWaiters(err);
375
+ this.emit('reconnect-failed', err);
376
+ }
377
+
317
378
  _closeModelNoThrow(model) {
318
379
  return this._adapters.closeModel(model).catch(() => {});
319
380
  }
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.1.0",
5
+ "version": "2.2.1",
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,7 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(gh pr *)"
5
- ]
6
- }
7
- }
@@ -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,59 +0,0 @@
1
- name: Publish
2
-
3
- on:
4
- release:
5
- types: [created]
6
-
7
- jobs:
8
- build:
9
- runs-on: ubuntu-latest
10
- services:
11
- rabbitmq:
12
- image: rabbitmq:4.2-alpine
13
- ports:
14
- - 5672:5672
15
-
16
- strategy:
17
- matrix:
18
- node-version: [18.x, 20.x, 22.x, 24.x]
19
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
20
-
21
- steps:
22
- - uses: actions/checkout@v3
23
-
24
- - name: Use Node.js ${{ matrix.node-version }}
25
- uses: actions/setup-node@v3
26
- with:
27
- node-version: ${{ matrix.node-version }}
28
- cache: "npm"
29
-
30
- - run: npm ci
31
-
32
- - run: |
33
- n=0
34
- while :
35
- do
36
- sleep 5
37
- echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
38
- [[ $? = 0 ]] && break || ((n++))
39
- (( n >= 5 )) && break
40
- done
41
-
42
- - run: echo 'HELO\n\n\n\n' | nc localhost 5672 | grep AMQP
43
-
44
- - run: make test
45
-
46
- publish:
47
- needs: build
48
- runs-on: ubuntu-latest
49
- steps:
50
- - uses: actions/checkout@v3
51
- - uses: actions/setup-node@v4
52
- with:
53
- node-version: '20.x'
54
- cache: "npm"
55
- registry-url: https://registry.npmjs.org/
56
- - run: npm ci
57
- - run: npm publish --dry-run
58
- env:
59
- NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}