@onify/fake-amqplib 2.0.0 → 3.1.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.
Files changed (5) hide show
  1. package/README.md +10 -10
  2. package/index.d.ts +8 -12
  3. package/index.js +309 -117
  4. package/main.cjs +309 -117
  5. package/package.json +9 -7
package/main.cjs CHANGED
@@ -6,8 +6,26 @@ var url = require('url');
6
6
 
7
7
  const kSmqp = Symbol.for('smqp');
8
8
  const kClosed = Symbol.for('closed');
9
- const kEmitter = Symbol.for('event emitter');
9
+ const kDeliveryTag = Symbol.for('channel delivery tag');
10
10
  const kPrefetch = Symbol.for('prefetch');
11
+ const kChannelPrefetch = Symbol.for('channel prefetch');
12
+
13
+ class AmqplibBroker extends smqp.Broker {
14
+ constructor(...args) {
15
+ super(...args);
16
+ this[kDeliveryTag] = 0;
17
+ }
18
+ _getNextDeliveryTag() {
19
+ return ++this[kDeliveryTag];
20
+ }
21
+ _getMessageByDeliveryTag(queue, deliveryTag) {
22
+ const q = this.getQueue(queue);
23
+ return q.messages.find((m) => m.fields.deliveryTag === deliveryTag);
24
+ }
25
+ _getChannelConsumers(channelName) {
26
+ return this.getConsumers().filter((f) => f.options.channelName === channelName);
27
+ }
28
+ }
11
29
 
12
30
  class FakeAmqpError extends Error {
13
31
  constructor(message, code, killChannel, killConnection) {
@@ -20,27 +38,55 @@ class FakeAmqpError extends Error {
20
38
 
21
39
  class FakeAmqpNotFoundError extends FakeAmqpError {
22
40
  constructor(type, name, vhost, killConnection = false) {
23
- super(`Channel closed by server: 404 (NOT-FOUND) with message "NOT_FOUND - no ${type} '${name}' in vhost '${vhost || '/'}'`, 404, true, killConnection);
41
+ super(
42
+ `Channel closed by server: 404 (NOT-FOUND) with message "NOT_FOUND - no ${type} '${name}' in vhost '${vhost || '/'}'`,
43
+ 404,
44
+ true,
45
+ killConnection,
46
+ );
24
47
  }
25
48
  }
26
49
 
27
- class FakeAmqplibChannel {
50
+ class FakeAmqpUnknownDeliveryTag extends FakeAmqpError {
51
+ constructor(deliveryTag) {
52
+ super(
53
+ `Channel closed by server: 406 (PRECONDITION-FAILED) with message "PRECONDITION_FAILED - unknown delivery tag ${deliveryTag}`,
54
+ 406,
55
+ true,
56
+ false,
57
+ );
58
+ }
59
+ get _emit() {
60
+ return true;
61
+ }
62
+ }
63
+
64
+ function Message(smqpMessage, deliveryTag) {
65
+ this[kSmqp] = smqpMessage;
66
+ this.fields = { ...smqpMessage.fields, deliveryTag };
67
+ this.content = Buffer.from(smqpMessage.content);
68
+ this.properties = { ...smqpMessage.properties };
69
+ }
70
+
71
+ class FakeAmqplibChannel extends events.EventEmitter {
28
72
  constructor(broker, connection) {
73
+ super();
29
74
  this.connection = connection;
30
75
 
31
76
  this[kPrefetch] = 10000;
77
+ this[kChannelPrefetch] = Infinity;
32
78
  this[kClosed] = false;
33
- this[kEmitter] = new events.EventEmitter();
34
- this._channelName = `channel-${generateId()}`;
79
+ const channelName = (this._channelName = `channel-${generateId()}`);
35
80
  this._version = connection._version;
36
81
  this._broker = broker;
37
82
 
83
+ this._channelQueue = broker.assertQueue(`#${channelName}`);
38
84
  this._emitReturn = this._emitReturn.bind(this);
39
85
 
40
86
  broker.on('return', this._emitReturn);
41
- }
42
- get _emitter() {
43
- return this[kEmitter];
87
+
88
+ this._createChannelMessage = this._createChannelMessage.bind(this);
89
+ this._calculateChannelCapacity = this._calculateChannelCapacity.bind(this);
44
90
  }
45
91
  get _closed() {
46
92
  return this[kClosed];
@@ -70,12 +116,12 @@ class FakeAmqplibChannel {
70
116
  }
71
117
  bindExchange(destination, source, ...args) {
72
118
  const broker = this._broker;
73
- return Promise.all([ this.checkExchange(source), this.checkExchange(destination) ]).then(() => {
119
+ return Promise.all([this.checkExchange(source), this.checkExchange(destination)]).then(() => {
74
120
  return this._callBroker(broker.bindExchange, source, destination, ...args);
75
121
  });
76
122
  }
77
123
  bindQueue(queue, source, ...args) {
78
- return Promise.all([ this.checkQueue(queue), this.checkExchange(source) ]).then(() => {
124
+ return Promise.all([this.checkQueue(queue), this.checkExchange(source)]).then(() => {
79
125
  return this._callBroker(this._broker.bindQueue, queue, source, ...args);
80
126
  });
81
127
  }
@@ -106,14 +152,16 @@ class FakeAmqplibChannel {
106
152
  }
107
153
  get(queue, ...args) {
108
154
  const connPath = this.connection._url.pathname;
155
+ const createMessage = this._createChannelMessage;
109
156
  return this._callBroker(getMessage, ...args);
110
157
 
111
158
  function getMessage(...getargs) {
112
159
  const q = this.getQueue(queue);
113
- if (!q) throw new FakeAmqpNotFoundError('queue', queue, connPath._url.pathname);
160
+ if (!q) throw new FakeAmqpNotFoundError('queue', queue, connPath);
114
161
  const msg = q.get(...getargs) || false;
115
162
  if (!msg) return msg;
116
- return new Message(msg);
163
+
164
+ return createMessage(msg, args[0]?.noAck);
117
165
  }
118
166
  }
119
167
  deleteExchange(exchange, ...args) {
@@ -140,15 +188,17 @@ class FakeAmqplibChannel {
140
188
  if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
141
189
  if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
142
190
 
143
- const args = [ this._broker.publish, exchange, routingKey, content ];
191
+ const args = [this._broker.publish, exchange, routingKey, content];
144
192
 
145
193
  args.push(options, callback);
146
194
 
147
- this.checkExchange(exchange).then(() => {
148
- return this._callBroker(...args);
149
- }).catch((err) => {
150
- this[kEmitter].emit('error', err);
151
- });
195
+ this.checkExchange(exchange)
196
+ .then(() => {
197
+ return this._callBroker(...args);
198
+ })
199
+ .catch((err) => {
200
+ this.emit('error', err);
201
+ });
152
202
 
153
203
  return true;
154
204
  }
@@ -165,15 +215,17 @@ class FakeAmqplibChannel {
165
215
  sendToQueue(queue, content, options, callback) {
166
216
  if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
167
217
 
168
- const args = [ this._broker.sendToQueue, queue, content ];
218
+ const args = [this._broker.sendToQueue, queue, content];
169
219
 
170
220
  args.push(options, callback);
171
221
 
172
- this.checkQueue(queue).then(() => {
173
- return this._callBroker(...args);
174
- }).catch((err) => {
175
- this[kEmitter].emit('error', err);
176
- });
222
+ this.checkQueue(queue)
223
+ .then(() => {
224
+ return this._callBroker(...args);
225
+ })
226
+ .catch((err) => {
227
+ this.emit('error', err);
228
+ });
177
229
 
178
230
  return true;
179
231
  }
@@ -216,31 +268,47 @@ class FakeAmqplibChannel {
216
268
  }
217
269
  consume(queue, onMessage, options = {}, callback) {
218
270
  const { _id: connId, _url: connUrl } = this.connection;
271
+ const createMessage = this._createChannelMessage;
272
+ const calculateCapacity = this._calculateChannelCapacity;
219
273
  const channelName = this._channelName;
220
274
  const prefetch = this[kPrefetch];
221
275
 
222
- return this._callBroker(check, callback);
276
+ return this._callBroker(consume, callback);
223
277
 
224
- function check() {
278
+ function consume() {
225
279
  const q = queue && this.getQueue(queue);
226
280
  if (!q) {
227
281
  throw new FakeAmqpNotFoundError('queue', queue, connUrl.pathname);
228
282
  }
229
283
 
230
284
  if (q.exclusive || (q.options.exclusive && q.options._connectionId !== connId)) {
231
- throw new FakeAmqpError(`Channel closed by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - queue '${queue}' in vhost '${connUrl.pathname}' in exclusive use"`, 403, true, true);
285
+ throw new FakeAmqpError(
286
+ `Channel closed by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - queue '${queue}' in vhost '${connUrl.pathname}' in exclusive use"`,
287
+ 403,
288
+ true,
289
+ true,
290
+ );
232
291
  }
233
292
 
234
- const { consumerTag } = this.consume(queue, onMessage && handler, {
293
+ const consumer = this.consume(queue, onMessage && handler, {
235
294
  ...options,
236
295
  channelName,
237
- prefetch,
296
+ prefetch: calculateCapacity(prefetch),
297
+ _consumerPrefetch: prefetch,
298
+ });
299
+
300
+ const capacityProp = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(consumer), 'capacity');
301
+ Object.defineProperty(consumer, 'capacity', {
302
+ get() {
303
+ return calculateCapacity(capacityProp.get.call(this));
304
+ },
238
305
  });
239
- return { consumerTag };
306
+
307
+ return { consumerTag: consumer.consumerTag };
240
308
  }
241
309
 
242
310
  function handler(_, msg) {
243
- onMessage(new Message(msg));
311
+ onMessage(createMessage(msg, options.noAck));
244
312
  }
245
313
  }
246
314
  cancel(consumerTag, ...args) {
@@ -248,51 +316,137 @@ class FakeAmqplibChannel {
248
316
  }
249
317
  close(callback) {
250
318
  if (this[kClosed]) return;
251
- const channelName = this._channelName;
252
- const broker = this._broker;
253
-
254
- broker.off('return', this._emitReturn);
255
- const channelConsumers = broker.getConsumers().filter((f) => f.options.channelName === channelName);
256
- channelConsumers.forEach((c) => broker.cancel(c.consumerTag));
257
- this[kClosed] = true;
258
- this[kEmitter].emit('close');
319
+ this._teardown();
320
+ this.emit('close');
259
321
  return resolveOrCallback(callback);
260
322
  }
261
- ack(message, ...args) {
262
- this._broker.ack(message[kSmqp], ...args);
323
+ ack(message, allUpTo) {
324
+ const deliveryTag = message.fields.deliveryTag;
325
+ const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
326
+ const channelQ = this._channelQueue;
327
+
328
+ if (!allUpTo) this._callBroker(ackMessage);
329
+ else this._callBroker(ackAllUpToMessage);
330
+
331
+ function ackMessage() {
332
+ const msg = message[kSmqp];
333
+ if (!channelMessage || !msg.pending) {
334
+ throw new FakeAmqpUnknownDeliveryTag(message.fields.deliveryTag);
335
+ }
336
+
337
+ channelQ.ack(channelMessage, false);
338
+ this.ack(msg, false);
339
+ }
340
+
341
+ function ackAllUpToMessage() {
342
+ const msg = message[kSmqp];
343
+ if (!channelMessage || !msg.pending) {
344
+ throw new FakeAmqpUnknownDeliveryTag(message.fields.deliveryTag);
345
+ }
346
+
347
+ const brokerMessages = allUpToDeliveryTag(channelQ, deliveryTag, 'ack', false);
348
+ for (const brokerMessage of brokerMessages) {
349
+ brokerMessage.ack(false);
350
+ }
351
+
352
+ channelQ.ack(channelMessage, false);
353
+ this.ack(msg, false);
354
+ }
263
355
  }
264
356
  ackAll() {
265
- const broker = this._broker;
266
- const channelName = this._channelName;
357
+ const channelQ = this._channelQueue;
358
+ let msg;
359
+ const brokerMessages = [];
360
+ while ((msg = channelQ.get())) {
361
+ brokerMessages.push(msg.content[kSmqp]);
362
+ msg.ack();
363
+ }
267
364
 
268
- const consumers = broker.getConsumers().filter(({ options }) => options.channelName === channelName);
269
- consumers.forEach((c) => broker.getConsumer(c.consumerTag).ackAll());
270
- }
271
- nack(message, ...args) {
272
- if (this.connection._version >= 2.3) throw new Error(`Nack is not implemented in versions before 2.3 (${this.connection._version})`);
273
- return this._broker.nack(message[kSmqp], ...args);
274
- }
275
- reject(message, ...args) {
276
- this._broker.reject(message[kSmqp], ...args);
365
+ for (const brokerMessage of brokerMessages) {
366
+ brokerMessage.ack();
367
+ }
277
368
  }
278
- nackAll(requeue = false) {
279
- const broker = this._broker;
280
- const channelName = this._channelName;
369
+ reject(message, requeue = false) {
370
+ const deliveryTag = message.fields.deliveryTag;
371
+ const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
372
+ const channelQ = this._channelQueue;
373
+
374
+ this._callBroker(rejectMessage);
281
375
 
282
- const consumers = broker.getConsumers().filter(({ options }) => options.channelName === channelName);
283
- consumers.forEach((c) => broker.getConsumer(c.consumerTag).nackAll(requeue));
376
+ function rejectMessage() {
377
+ const msg = message[kSmqp];
378
+ if (!channelMessage || !msg.pending) {
379
+ throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
380
+ }
381
+
382
+ channelQ.reject(channelMessage, false);
383
+ this.reject(msg, requeue);
384
+ }
284
385
  }
285
- prefetch(val) {
286
- this[kPrefetch] = val;
386
+ nack(message, allUpTo = false, requeue = false) {
387
+ if (this.connection._version < 2.3) throw new Error(`Nack is not implemented in versions before 2.3 (${this.connection._version})`);
388
+
389
+ const deliveryTag = message.fields.deliveryTag;
390
+ const channelMessage = this._broker._getMessageByDeliveryTag(this._channelQueue.name, deliveryTag);
391
+ const channelQ = this._channelQueue;
392
+
393
+ if (!allUpTo) this._callBroker(nackMessage);
394
+ else this._callBroker(nackAllUpToMessage);
395
+
396
+ function nackMessage() {
397
+ const msg = message[kSmqp];
398
+ if (!channelMessage || !msg.pending) {
399
+ throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
400
+ }
401
+
402
+ channelQ.nack(channelMessage, false, false);
403
+ this.nack(msg, false, requeue);
404
+ }
405
+
406
+ function nackAllUpToMessage() {
407
+ const msg = message[kSmqp];
408
+ if (!channelMessage || !msg.pending) {
409
+ throw new FakeAmqpUnknownDeliveryTag(deliveryTag);
410
+ }
411
+
412
+ const brokerMessages = allUpToDeliveryTag(channelQ, deliveryTag, 'nack', false, false);
413
+ for (const brokerMessage of brokerMessages) {
414
+ brokerMessage.nack(false, requeue);
415
+ }
416
+
417
+ channelMessage.nack(false, false);
418
+ this.nack(msg, false, requeue);
419
+ }
287
420
  }
288
- on(...args) {
289
- return this[kEmitter].on(...args);
421
+ nackAll(requeue = true) {
422
+ const channelQ = this._channelQueue;
423
+ let msg;
424
+ const brokerMessages = [];
425
+ while ((msg = channelQ.get())) {
426
+ brokerMessages.push(msg.content[kSmqp]);
427
+ msg.reject(false);
428
+ }
429
+
430
+ for (const brokerMessage of brokerMessages) {
431
+ brokerMessage.reject(requeue);
432
+ }
290
433
  }
291
- once(...args) {
292
- return this[kEmitter].once(...args);
434
+ prefetch(val, isChannelPrefetch) {
435
+ if (this.connection._version < 3.3) {
436
+ if (isChannelPrefetch !== undefined) {
437
+ return this.connection.close();
438
+ }
439
+ this[kChannelPrefetch] = val;
440
+ } else {
441
+ if (isChannelPrefetch) {
442
+ this[kChannelPrefetch] = val;
443
+ } else {
444
+ this[kPrefetch] = val;
445
+ }
446
+ }
293
447
  }
294
448
  _callBroker(fn, ...args) {
295
- let [ poppedCb ] = args.slice(-1);
449
+ let [poppedCb] = args.slice(-1);
296
450
  if (typeof poppedCb === 'function') args.splice(-1);
297
451
  else poppedCb = null;
298
452
 
@@ -306,7 +460,8 @@ class FakeAmqplibChannel {
306
460
  return resolve(result);
307
461
  } catch (err) {
308
462
  if (err._killConnection) this.connection.close();
309
- else if (err._killChannel) this[kClosed] = true;
463
+ else if (err._killChannel) this._teardown();
464
+ if (err._emit) this.emit('error', err);
310
465
  if (!poppedCb) return reject(err);
311
466
  poppedCb(err);
312
467
  return resolve();
@@ -315,9 +470,44 @@ class FakeAmqplibChannel {
315
470
  }
316
471
  _emitReturn({ fields, content, properties }) {
317
472
  process.nextTick(() => {
318
- this[kEmitter].emit('return', { fields, content, properties });
473
+ this.emit('return', { fields, content, properties });
319
474
  });
320
475
  }
476
+ _createChannelMessage(smqpMessage, noAck) {
477
+ const deliveryTag = this._broker._getNextDeliveryTag();
478
+ const consumeMessage = new Message(smqpMessage, deliveryTag);
479
+ if (!noAck) {
480
+ const channelQ = this._channelQueue;
481
+ channelQ.queueMessage(consumeMessage.fields, consumeMessage);
482
+ }
483
+ return consumeMessage;
484
+ }
485
+ _teardown() {
486
+ this[kClosed] = true;
487
+ const channelName = this._channelName;
488
+ const broker = this._broker;
489
+ const channelConsumers = broker._getChannelConsumers(channelName);
490
+ channelConsumers.forEach((c) => broker.cancel(c.consumerTag));
491
+
492
+ let msg;
493
+ while ((msg = this._channelQueue.get())) {
494
+ msg.content[kSmqp].reject(true);
495
+ msg.reject(false);
496
+ }
497
+
498
+ broker.off('return', this._emitReturn);
499
+ }
500
+ _calculateChannelCapacity(consumerCapacity) {
501
+ const channelPrefetch = this[kChannelPrefetch];
502
+ if (channelPrefetch === Infinity) return consumerCapacity;
503
+
504
+ const channelCapacity = channelPrefetch - this._channelQueue.messageCount;
505
+
506
+ let capacity = consumerCapacity;
507
+ if (channelCapacity <= 0) capacity = 0;
508
+ else if (channelCapacity < capacity) capacity = channelCapacity;
509
+ return capacity;
510
+ }
321
511
  }
322
512
 
323
513
  class FakeAmqplibConfirmChannel extends FakeAmqplibChannel {
@@ -325,38 +515,42 @@ class FakeAmqplibConfirmChannel extends FakeAmqplibChannel {
325
515
  if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
326
516
  if (exchange === '') return this.sendToQueue(routingKey, content, options, callback);
327
517
 
328
- const args = [ this._broker.publish, exchange, routingKey, content ];
518
+ const args = [this._broker.publish, exchange, routingKey, content];
329
519
 
330
520
  args.push(...addConfirmCallback(this._broker, options, callback));
331
521
 
332
- this.checkExchange(exchange).then(() => {
333
- return this._callBroker(...args);
334
- }).catch((err) => {
335
- this[kEmitter].emit('error', err);
336
- });
522
+ this.checkExchange(exchange)
523
+ .then(() => {
524
+ return this._callBroker(...args);
525
+ })
526
+ .catch((err) => {
527
+ this.emit('error', err);
528
+ });
337
529
 
338
530
  return true;
339
531
  }
340
532
  sendToQueue(queue, content, options, callback) {
341
533
  if (!Buffer.isBuffer(content)) throw new TypeError('content is not a buffer');
342
534
 
343
- const args = [ this._broker.sendToQueue, queue, content ];
535
+ const args = [this._broker.sendToQueue, queue, content];
344
536
 
345
537
  args.push(...addConfirmCallback(this._broker, options, callback));
346
538
 
347
- this.checkQueue(queue).then(() => {
348
- return this._callBroker(...args);
349
- }).catch((err) => {
350
- this[kEmitter].emit('error', err);
351
- });
539
+ this.checkQueue(queue)
540
+ .then(() => {
541
+ return this._callBroker(...args);
542
+ })
543
+ .catch((err) => {
544
+ this.emit('error', err);
545
+ });
352
546
 
353
547
  return true;
354
548
  }
355
549
  }
356
550
 
357
- class FakeAmqplibConnection {
551
+ class FakeAmqplibConnection extends events.EventEmitter {
358
552
  constructor(broker, version, amqpUrl) {
359
- this[kEmitter] = new events.EventEmitter();
553
+ super();
360
554
  this[kClosed] = false;
361
555
  this._channels = [];
362
556
  this._url = normalizeAmqpUrl(amqpUrl);
@@ -367,9 +561,6 @@ class FakeAmqplibConnection {
367
561
  get _closed() {
368
562
  return this[kClosed];
369
563
  }
370
- get _emitter() {
371
- return this[kEmitter];
372
- }
373
564
  get connection() {
374
565
  return {
375
566
  serverProperties: {
@@ -403,16 +594,10 @@ class FakeAmqplibConnection {
403
594
 
404
595
  this._channels.splice(0).forEach((channel) => channel.close());
405
596
 
406
- this[kEmitter].emit('close');
597
+ this.emit('close');
407
598
 
408
599
  return resolveOrCallback(args.slice(-1)[0]);
409
600
  }
410
- on(...args) {
411
- return this[kEmitter].on(...args);
412
- }
413
- once(...args) {
414
- return this[kEmitter].once(...args);
415
- }
416
601
  }
417
602
 
418
603
  function FakeAmqplib(minorVersion = '3.5') {
@@ -436,14 +621,14 @@ FakeAmqplib.prototype.connect = function fakeConnect(amqpUrl, ...args) {
436
621
 
437
622
  FakeAmqplib.prototype.connectSync = function fakeConnectSync(amqpUrl, ...args) {
438
623
  const { _broker } = this.connections.find((conn) => compareConnectionString(conn._url, amqpUrl)) || {};
439
- const broker = _broker || new smqp.Broker(this);
624
+ const broker = _broker || new AmqplibBroker(this);
440
625
  const connection = new FakeAmqplibConnection(broker, this.version, amqpUrl, ...args);
441
626
 
442
627
  const connections = this.connections;
443
628
 
444
629
  connections.push(connection);
445
630
 
446
- connection._emitter.once('close', () => {
631
+ connection.once('close', () => {
447
632
  const idx = connections.indexOf(connection);
448
633
  if (idx > -1) connections.splice(idx, 1);
449
634
  });
@@ -479,39 +664,26 @@ function compareConnectionString(url1, url2) {
479
664
  return parsedUrl1.host === parsedUrl2.host && parsedUrl1.pathname === parsedUrl2.pathname;
480
665
  }
481
666
 
482
- function Message(smqpMessage) {
483
- this[kSmqp] = smqpMessage;
484
- this.content = smqpMessage.content;
485
- this.fields = smqpMessage.fields;
486
- this.properties = smqpMessage.properties;
487
- }
488
-
489
667
  function normalizeAmqpUrl(url$1) {
490
668
  if (!url$1) return new URL('amqp://localhost:5672/');
491
669
  if (typeof url$1 === 'string') url$1 = new URL(url$1);
492
670
 
493
671
  if (!(url$1 instanceof URL)) {
494
- const {
495
- protocol = 'amqp',
496
- hostname = 'localhost',
497
- port = 5672,
498
- vhost = '/',
499
- username,
500
- password,
501
- ...rest
502
- } = url$1;
672
+ const { protocol = 'amqp', hostname = 'localhost', port = 5672, vhost = '/', username, password, ...rest } = url$1;
503
673
  let auth = username;
504
674
  if (auth && password) {
505
675
  auth += `:${password}`;
506
676
  }
507
- url$1 = new URL(url.format({
508
- protocol,
509
- hostname,
510
- port,
511
- pathname: vhost,
512
- slashes: true,
513
- auth,
514
- }));
677
+ url$1 = new URL(
678
+ url.format({
679
+ protocol,
680
+ hostname,
681
+ port,
682
+ pathname: vhost,
683
+ slashes: true,
684
+ auth,
685
+ }),
686
+ );
515
687
 
516
688
  for (const k in rest) {
517
689
  switch (k) {
@@ -558,7 +730,27 @@ function addConfirmCallback(broker, options, callback) {
558
730
  }
559
731
  }
560
732
 
561
- return [ options, confirmCallback ];
733
+ return [options, confirmCallback];
734
+ }
735
+
736
+ function allUpToDeliveryTag(q, deliveryTag, op, ...args) {
737
+ const brokerMessages = [];
738
+
739
+ const consumer = q.consume(
740
+ (_, cmsg) => {
741
+ const msgDeliveryTag = cmsg.fields.deliveryTag;
742
+ if (msgDeliveryTag >= deliveryTag) {
743
+ return q.cancel(cmsg.fields.consumerTag);
744
+ }
745
+ brokerMessages.push(cmsg.content[kSmqp]);
746
+ cmsg[op](...args);
747
+ },
748
+ { prefetch: Infinity },
749
+ );
750
+
751
+ consumer.cancel();
752
+
753
+ return brokerMessages;
562
754
  }
563
755
 
564
756
  const defaultFake = new FakeAmqplib('3.5');
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@onify/fake-amqplib",
3
- "version": "2.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Fake amqplib",
5
5
  "type": "module",
6
6
  "exports": {
7
+ "types": "./index.d.ts",
7
8
  "require": "./main.cjs",
8
9
  "import": "./index.js"
9
10
  },
@@ -13,7 +14,7 @@
13
14
  "scripts": {
14
15
  "test": "mocha",
15
16
  "posttest": "npm run lint && npm run dist",
16
- "lint": "eslint . --cache",
17
+ "lint": "eslint . --cache && prettier . -c --cache",
17
18
  "dist": "rollup -c",
18
19
  "prepack": "npm run dist",
19
20
  "cov:html": "c8 -r html -r text mocha",
@@ -32,16 +33,17 @@
32
33
  },
33
34
  "license": "MIT",
34
35
  "dependencies": {
35
- "smqp": "^8.2.0"
36
+ "smqp": "^8.2.4"
36
37
  },
37
38
  "devDependencies": {
38
- "@bonniernews/eslint-config": "^1.0.1",
39
39
  "@rollup/plugin-commonjs": "^25.0.5",
40
40
  "@types/amqplib": "^0.10.2",
41
- "c8": "^8.0.1",
42
- "chai": "^4.3.10",
43
- "eslint": "^8.51.0",
41
+ "c8": "^9.1.0",
42
+ "chai": "^5.1.0",
43
+ "eslint": "^9.0.0",
44
+ "globals": "^15.0.0",
44
45
  "mocha": "^10.2.0",
46
+ "prettier": "^3.2.5",
45
47
  "rollup": "^4.0.2"
46
48
  },
47
49
  "keywords": [