rascal 18.0.1 → 20.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Change Log
2
2
 
3
+ ## 20.0.0
4
+ - Replaced superagent with native node http client as per https://github.com/onebeyond/rascal/issues/234
5
+
6
+ ## 19.0.0
7
+ - I am not aware of any breaking changes in this release, but emitting error events asynchronously could have subtle side effects, hence the major release
8
+ - Deprecate session 'cancelled' event in favour of 'cancel' (both will work)
9
+ - Refactor reconnection and resubscription code
10
+ - Emit errors asynchronously to prevent them being caught by the amqplib main accept loop
11
+ - Fix bug which throw an exception in the error handler when a close event was emitted with no error argument
12
+
3
13
  ## 18.0.1
4
14
 
5
15
  - Removed console.log when the channel pool destroyed a channel
package/README.md CHANGED
@@ -130,7 +130,9 @@ The reason Rascal nacks the message is because the alternatives are to leave the
130
130
 
131
131
  ## Very Important Section About Event Handling
132
132
 
133
- [amqplib](https://www.npmjs.com/package/amqplib) emits error events when a connection or channel encounters a problem. Rascal will listen for these and provided you use the default configuration will attempt automatic recovery (reconnection etc), however these events can indicate errors in your code, so it's also important to bring them to your attention. Rascal does this by re-emitting the error event, which means if you don't handle them, they will bubble up to the uncaught error handler and crash your application. There are four places where you should do this
133
+ [amqplib](https://www.npmjs.com/package/amqplib) emits error events when a connection or channel encounters a problem. Rascal will listen for these and provided you use the default configuration will attempt automatic recovery (reconnection etc), however these events can indicate errors in your code, so it's also important to bring them to your attention. Rascal does this by re-emitting the error event, which means if you don't handle them, they will bubble up to the uncaught error handler and crash your application. It is insufficient to register a global uncaughtException handler - doing so without registering individual handlers will prevent your application from crashing, but also prevent Rascal from recovering.
134
+
135
+ There are four places where you need to register error handlers.
134
136
 
135
137
  1. Immediately after obtaining a broker instance
136
138
 
@@ -462,7 +464,7 @@ The AMQP protocol doesn't support assertion or checking of vhosts, so Rascal use
462
464
  }
463
465
  ```
464
466
 
465
- Rascal uses [superagent](https://github.com/visionmedia/superagent) under the hood. URL configuration is also supported.
467
+ Rascal uses [http.request](https://nodejs.org/api/http.html#httprequesturl-options-callback) under the hood. URL configuration is also supported.
466
468
 
467
469
  ```json
468
470
  {
@@ -487,11 +489,11 @@ Rascal uses [superagent](https://github.com/visionmedia/superagent) under the ho
487
489
  }
488
490
  ```
489
491
 
490
- You can also supply your own agent via the broker components. Use this when you need to set [TLS options](https://visionmedia.github.io/superagent/#tls-options).
492
+ You can also supply your own agent via the broker components. Use this when you need to set [TLS options](https://nodejs.org/api/https.html#httpsrequesturl-options-callback).
491
493
 
492
494
  ```js
493
- const superagent = require('superagent-defaults');
494
- const agent = superagent().on('request', (req) => console.log(req.url));
495
+ const https = require('https');
496
+ const agent = new https.Agent(options);
495
497
  const components = { agent };
496
498
  const broker = await Broker.create(config, components);
497
499
  ```
@@ -805,7 +807,7 @@ You also need to think about how you will [track the consumer offset](https://ww
805
807
  });
806
808
  ```
807
809
 
808
- However, if your application is offline for too long, and messages are still being published to the stream, it may not be able to resume from where you left off, since those messages may have been deleted. Furthremore, if your application consumes messages concurrently, you need to think about how you will recover should one fail. If you naively override the previouly saved offset, you may be replacing a higher/later offset with an lower/older one, causing in your application to restart from the wrong point. Finally, you also need to decide what to do if the message cannot be processed. You cannot simply replay the message since you are working with a stream, rather than a classic queue. You could cancel the subscription and resume from the current offset, but this will lead to duplicates if you have been consuming messages concurrently. Alternatively you could republish the failures to a dead letter queue and process them separately.
810
+ However, if your application is offline for too long, and messages are still being published to the stream, it may not be able to resume from where you left off, since those messages may have been deleted. Furthermore, if your application consumes messages concurrently, you need to think about how you will recover should one fail. If you naively override the previouly saved offset, you may be replacing a higher/later offset with an lower/older one, causing in your application to restart from the wrong point. Finally, you also need to decide what to do if the message cannot be processed. You cannot simply replay the message since you are working with a stream, rather than a queue. You could cancel the subscription and resume from the current offset, but this will lead to duplicates if you have been consuming messages concurrently. Alternatively you could republish the failures to a dead letter queue and process them separately.
809
811
 
810
812
  For the above reasons, we only recommend considering streams when you genuinely need the extra throughput.
811
813
 
@@ -1358,7 +1360,7 @@ If the message has not been auto-acknowledged you should ackOrNack it. **If you
1358
1360
 
1359
1361
  The RabbitMQ broker may [cancel](https://www.rabbitmq.com/consumer-cancel.html) the consumer if the queue is deleted or the node on which the queue is located fails. [amqplib](https://www.squaremobius.net/amqp.node/channel_api.html#channel_consume) handles this by delivering a `null` message. When Rascal receives the null message it will
1360
1362
 
1361
- 1. Emit a `cancelled` event from the subscription.
1363
+ 1. Emit a `cancel` event from the subscription.
1362
1364
  1. Emit an `error` event from the subscription if the `cancel` event was not handled
1363
1365
  1. Optionally attempt to resubscribe as per normal retry configuration. If the queue was deleted rather than being failed over, the queue will not automatically be re-created and retry attempts will fail indefinitely.
1364
1366
 
@@ -95,24 +95,27 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
95
95
  session._removePausedListener();
96
96
  if (err) return session.emit('error', err, messageId);
97
97
  if (session.isAborted()) return abortPublish(channel, messageId);
98
- const errorHandler = _.once(handleChannelError.bind(null, channel, messageId, session, config));
98
+
99
+ const disconnectionHandler = makeDisconnectionHandler(channel, messageId, session, config);
99
100
  const returnHandler = session.emit.bind(session, 'return');
100
- addListeners(channel, errorHandler, returnHandler);
101
+ addListeners(channel, disconnectionHandler, returnHandler);
102
+
101
103
  try {
102
104
  session._startPublish();
105
+
103
106
  publishFn(channel, buffer, publishConfig, (err, ok) => {
104
107
  session._endPublish();
105
108
  if (err) {
106
- destroyChannel(channel, errorHandler, returnHandler);
109
+ destroyChannel(channel, disconnectionHandler, returnHandler);
107
110
  return session.emit('error', err, messageId);
108
111
  }
109
112
 
110
- ok ? returnChannel(channel, errorHandler, returnHandler) : deferReturnChannel(channel, errorHandler, returnHandler);
113
+ ok ? returnChannel(channel, disconnectionHandler, returnHandler) : deferReturnChannel(channel, disconnectionHandler, returnHandler);
111
114
 
112
115
  session.emit('success', messageId);
113
116
  });
114
117
  } catch (err) {
115
- returnChannel(channel, errorHandler, returnHandler);
118
+ returnChannel(channel, disconnectionHandler, returnHandler);
116
119
  return session.emit('error', err, messageId);
117
120
  }
118
121
  });
@@ -125,19 +128,19 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
125
128
  returnChannelFn(channel);
126
129
  }
127
130
 
128
- function returnChannel(channel, errorHandler, returnHandler) {
129
- removeListeners(channel, errorHandler, returnHandler);
131
+ function returnChannel(channel, disconnectionHandler, returnHandler) {
132
+ removeListeners(channel, disconnectionHandler, returnHandler);
130
133
  returnChannelFn(channel);
131
134
  }
132
135
 
133
- function deferReturnChannel(channel, errorHandler, returnHandler) {
136
+ function deferReturnChannel(channel, disconnectionHandler, returnHandler) {
134
137
  channel.once('drain', () => {
135
- returnChannel(channel, errorHandler, returnHandler);
138
+ returnChannel(channel, disconnectionHandler, returnHandler);
136
139
  });
137
140
  }
138
141
 
139
- function destroyChannel(channel, errorHandler, returnHandler) {
140
- removeListeners(channel, errorHandler, returnHandler);
142
+ function destroyChannel(channel, disconnectionHandler, returnHandler) {
143
+ removeListeners(channel, disconnectionHandler, returnHandler);
141
144
  destroyChannelFn(channel);
142
145
  }
143
146
 
@@ -163,19 +166,29 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
163
166
  }
164
167
  }
165
168
 
166
- function addListeners(channel, errorHandler, returnHandler) {
167
- channel.on('error', errorHandler);
169
+ function makeDisconnectionHandler(channel, messageId, session, config) {
170
+ return _.once((err) => {
171
+ // Use setImmediate to avoid amqplib accept loop swallowing errors
172
+ setImmediate(() => (err
173
+ // Treat close events with errors as error events
174
+ ? handleChannelError(channel, messageId, session, config, err)
175
+ : handleChannelClose(channel, messageId, session, config)));
176
+ });
177
+ }
178
+
179
+ function addListeners(channel, disconnectionHandler, returnHandler) {
180
+ channel.on('error', disconnectionHandler);
168
181
  channel.on('return', returnHandler);
169
- channel.connection.once('error', errorHandler);
170
- channel.connection.once('close', errorHandler);
182
+ channel.connection.once('error', disconnectionHandler);
183
+ channel.connection.once('close', disconnectionHandler);
171
184
  }
172
185
 
173
- function removeListeners(channel, errorHandler, returnHandler) {
186
+ function removeListeners(channel, disconnectionHandler, returnHandler) {
174
187
  channel.removeAllListeners('drain');
175
- channel.removeListener('error', errorHandler);
188
+ channel.removeListener('error', disconnectionHandler);
176
189
  channel.removeListener('return', returnHandler);
177
- channel.connection.removeListener('error', errorHandler);
178
- channel.connection.removeListener('close', errorHandler);
190
+ channel.connection.removeListener('error', disconnectionHandler);
191
+ channel.connection.removeListener('close', disconnectionHandler);
179
192
  }
180
193
 
181
194
  function publishToExchange(channel, content, config, next) {
@@ -252,3 +265,8 @@ function handleChannelError(borked, messageId, emitter, config, err) {
252
265
  debug('Channel error: %s during publication of message: %s to %s using channel: %s', err.message, messageId, config.name, borked._rascal_id);
253
266
  emitter.emit('error', err, messageId);
254
267
  }
268
+
269
+ function handleChannelClose(borked, messageId, emitter, config) {
270
+ debug('Channel closed during publication of message: %s to %s using channel: %s', messageId, config.name, borked._rascal_id);
271
+ emitter.emit('close', messageId);
272
+ }
@@ -61,13 +61,13 @@ function Subscription(broker, vhost, subscriptionConfig, counter) {
61
61
  _configureQos(config, channel, (err) => {
62
62
  if (err) return done(err);
63
63
 
64
- const removeErrorHandlers = attachErrorHandlers(channel, session, config);
65
- const onMessage = _onMessage.bind(null, session, config, removeErrorHandlers);
64
+ const removeDisconnectionHandlers = attachDisconnectionHandlers(channel, session, config);
65
+ const onMessage = _onMessage.bind(null, session, config, removeDisconnectionHandlers);
66
66
 
67
67
  channel.consume(config.source, onMessage, config.options, (err, response) => {
68
68
  if (err) {
69
69
  debug('Error subscribing to %s using channel: %s. %s', config.source, channel._rascal_id, err.message);
70
- removeErrorHandlers();
70
+ removeDisconnectionHandlers();
71
71
  return done(err);
72
72
  }
73
73
  session._open(channel, response.consumerTag, (err) => {
@@ -88,8 +88,8 @@ function Subscription(broker, vhost, subscriptionConfig, counter) {
88
88
  async.series(qos, next);
89
89
  }
90
90
 
91
- function _onMessage(session, config, removeErrorHandlers, message) {
92
- if (!message) return handleConsumerCancel(session, config, removeErrorHandlers);
91
+ function _onMessage(session, config, removeDisconnectionHandlers, message) {
92
+ if (!message) return handleConsumerCancel(session, config, removeDisconnectionHandlers);
93
93
 
94
94
  debug('Received message: %s from queue: %s', message.properties.messageId, config.queue);
95
95
  session._incrementUnacknowledgeMessageCount(message.fields.consumerTag);
@@ -249,51 +249,66 @@ function Subscription(broker, vhost, subscriptionConfig, counter) {
249
249
  if (err) session.emit('error', err);
250
250
  }
251
251
 
252
- function attachErrorHandlers(channel, session, config) {
252
+ function attachDisconnectionHandlers(channel, session, config) {
253
253
  /* eslint-disable no-use-before-define */
254
254
  const connection = channel.connection;
255
- const removeErrorHandlers = _.once(() => {
256
- channel.removeListener('error', errorHandler);
255
+ const removeDisconnectionHandlers = _.once(() => {
256
+ channel.removeListener('error', disconnectionHandler);
257
257
  channel.on('error', (err) => {
258
258
  debug('Suppressing error on cancelled session: %s to prevent connection errors. %s', channel._rascal_id, err.message);
259
259
  });
260
- connection.removeListener('error', errorHandler);
261
- connection.removeListener('close', errorHandler);
260
+ connection.removeListener('error', disconnectionHandler);
261
+ connection.removeListener('close', disconnectionHandler);
262
+ });
263
+
264
+ const disconnectionHandler = makeDisconnectionHandler(session, config, removeDisconnectionHandlers);
265
+ channel.on('error', disconnectionHandler);
266
+ connection.once('error', disconnectionHandler);
267
+ connection.once('close', disconnectionHandler);
268
+ return removeDisconnectionHandlers;
269
+ }
270
+
271
+ function makeDisconnectionHandler(session, config, removeDisconnectionHandlers) {
272
+ return _.once((err) => {
273
+ // Use setImmediate to avoid amqplib accept loop swallowing errors
274
+ setImmediate(() => (err
275
+ // Treat close events with errors as error events
276
+ ? handleChannelError(session, config, removeDisconnectionHandlers, 0, err)
277
+ : handleChannelClose(session, config, removeDisconnectionHandlers, 0)));
262
278
  });
263
- const errorHandler = _.once(handleChannelError.bind(null, session, config, removeErrorHandlers, 0));
264
- channel.on('error', errorHandler);
265
- connection.once('error', errorHandler);
266
- connection.once('close', errorHandler);
267
- return removeErrorHandlers;
268
279
  }
269
280
 
270
- function handleChannelError(session, config, removeErrorHandlers, attempts, err) {
281
+ function handleChannelError(session, config, removeDisconnectionHandler, attempt, err) {
271
282
  debug('Handling channel error: %s from %s using channel: %s', err.message, config.name, session._getRascalChannelId());
272
- if (removeErrorHandlers) removeErrorHandlers();
283
+ if (removeDisconnectionHandler) removeDisconnectionHandler();
273
284
  session.emit('error', err);
274
- config.retry
275
- && subscribeNow(session, config, (err) => {
276
- if (!err) return;
277
- const delay = timer.next();
278
- debug('Will attempt resubscription(%d) to %s in %dms', attempts + 1, config.name, delay);
279
- session._schedule(handleChannelError.bind(null, session, config, null, attempts + 1, err), delay);
280
- });
285
+ retrySubscription(session, config, attempt + 1);
281
286
  }
282
287
 
283
- function handleConsumerCancel(session, config, removeErrorHandlers) {
288
+ function handleChannelClose(session, config, removeDisconnectionHandler, attempt) {
289
+ debug('Handling channel close from %s using channel: %s', config.name, session._getRascalChannelId());
290
+ removeDisconnectionHandler();
291
+ session.emit('close');
292
+ retrySubscription(session, config, attempt + 1);
293
+ }
294
+
295
+ function handleConsumerCancel(session, config, removeDisconnectionHandler) {
284
296
  debug('Received consumer cancel from %s using channel: %s', config.name, session._getRascalChannelId());
285
- removeErrorHandlers();
297
+ removeDisconnectionHandler();
298
+ const cancelErr = new Error(format('Subscription: %s was cancelled by the broker', config.name));
299
+ session.emit('cancelled', cancelErr) || session.emit('cancel', cancelErr) || session.emit('error', cancelErr);
286
300
  session._close((err) => {
287
301
  if (err) debug('Error cancelling subscription: %s', err.message);
288
- const cancelErr = new Error(format('Subscription: %s was cancelled by the broker', config.name));
289
- session.emit('cancelled', cancelErr) || session.emit('error', cancelErr);
290
- config.retry
291
- && subscribeNow(session, config, (err) => {
292
- if (!err) return;
293
- const delay = timer.next();
294
- debug('Will attempt resubscription(%d) to %s in %dms', 1, config.name, delay);
295
- session._schedule(handleChannelError.bind(null, session, config, null, 1, err), delay);
296
- });
302
+ retrySubscription(session, config, 1);
303
+ });
304
+ }
305
+
306
+ function retrySubscription(session, config, attempt) {
307
+ config.retry && subscribeNow(session, config, (err) => {
308
+ if (!err) return;
309
+ const delay = timer.next();
310
+ debug('Will attempt resubscription(%d) to %s in %dms', attempt, config.name, delay);
311
+ session._schedule(handleChannelError.bind(null, session, config, null, attempt, err), delay);
297
312
  });
298
313
  }
299
314
  }
package/lib/amqp/Vhost.js CHANGED
@@ -57,7 +57,7 @@ function Vhost(vhostConfig, components) {
57
57
  connectionConfig = ctx.connectionConfig;
58
58
  timer = backoff(ctx.connectionConfig.retry);
59
59
 
60
- attachErrorHandlers(config);
60
+ attachDisconnectionHandlers(config);
61
61
  forwardRabbitMQConnectionEvents();
62
62
  ensureChannelPools();
63
63
  resumeChannelAllocation();
@@ -471,11 +471,21 @@ function Vhost(vhostConfig, components) {
471
471
  );
472
472
  }
473
473
 
474
- function attachErrorHandlers(config) {
474
+ function attachDisconnectionHandlers(config) {
475
475
  connection.removeAllListeners('error');
476
- const errorHandler = _.once(handleConnectionError.bind(null, connection, config));
477
- connection.on('error', errorHandler);
478
- connection.on('close', errorHandler);
476
+ const disconectionHandler = makeDisconnectionHandler(config);
477
+ connection.on('error', disconectionHandler);
478
+ connection.on('close', disconectionHandler);
479
+ }
480
+
481
+ function makeDisconnectionHandler(config) {
482
+ return _.once((err) => {
483
+ // Use setImmediate to avoid amqplib accept loop swallowing errors
484
+ setImmediate(() => (err
485
+ // Treat close events with errors as error events
486
+ ? handleConnectionError(connection, config, err)
487
+ : handleConnectionClose(connection, config)));
488
+ });
479
489
  }
480
490
 
481
491
  function handleConnectionError(borked, config, err) {
@@ -484,12 +494,24 @@ function Vhost(vhostConfig, components) {
484
494
  connection = undefined;
485
495
  self.emit('disconnect');
486
496
  self.emit('error', err, self.getConnectionDetails());
487
- connectionConfig.retry
488
- && self.init((err) => {
489
- if (!err) return;
490
- const delay = timer.next();
491
- debug('Will attempt reconnection in in %dms', delay);
492
- reconnectTimeout = setTimeoutUnref(handleConnectionError.bind(null, borked, config, err), delay);
493
- });
497
+ retryConnection(borked, config);
498
+ }
499
+
500
+ function handleConnectionClose(borked, config) {
501
+ debug('Handling connection close initially from connection: %s, %s', borked._rascal_id, connectionConfig.loggableUrl);
502
+ pauseChannelAllocation();
503
+ connection = undefined;
504
+ self.emit('disconnect');
505
+ self.emit('close', self.getConnectionDetails());
506
+ retryConnection(borked, config);
507
+ }
508
+
509
+ function retryConnection(borked, config) {
510
+ connectionConfig.retry && self.init((err) => {
511
+ if (!err) return;
512
+ const delay = timer.next();
513
+ debug('Will attempt reconnection in in %dms', delay);
514
+ reconnectTimeout = setTimeoutUnref(handleConnectionError.bind(null, borked, config, err), delay);
515
+ });
494
516
  }
495
517
  }
@@ -1,13 +1,14 @@
1
1
  const debug = require('debug')('rascal:config:configure');
2
2
  const format = require('util').format;
3
3
  const url = require('url');
4
- const { URL } = require('node:url');
5
4
  const _ = require('lodash');
6
5
  const uuid = require('uuid').v4;
7
6
  const XRegExp = require('xregexp');
8
7
  const baseline = require('./baseline');
9
8
  const fqn = require('./fqn');
10
9
 
10
+ const { URL } = url;
11
+
11
12
  module.exports = _.curry((rascalConfig, next) => {
12
13
  rascalConfig = _.defaultsDeep(rascalConfig, baseline);
13
14
 
@@ -1,16 +1,14 @@
1
+ const http = require('http');
1
2
  const debug = require('debug')('rascal:management:client');
2
3
  const format = require('util').format;
3
- const _ = require('lodash');
4
- const defaultAgent = require('superagent');
5
4
 
6
- function Client(suppliedAgent) {
7
- const agent = suppliedAgent || defaultAgent;
5
+ function Client(agent) {
8
6
  const self = this;
9
7
 
10
8
  this.assertVhost = function (name, config, next) {
11
9
  debug('Asserting vhost: %s', name);
12
- const options = getVhostOptions(name, config);
13
- self._request('put', options.url, options.timeout, (err) => {
10
+ const url = getUrl(name, config);
11
+ self._request('PUT', url, config.options, (err) => {
14
12
  if (!err) return next();
15
13
  const _err = err.status ? new Error(format('Failed to assert vhost: %s. %s returned status %d', name, config.loggableUrl, err.status)) : err;
16
14
  return next(_err);
@@ -19,8 +17,8 @@ function Client(suppliedAgent) {
19
17
 
20
18
  this.checkVhost = function (name, config, next) {
21
19
  debug('Checking vhost: %s', name);
22
- const options = getVhostOptions(name, config);
23
- self._request('get', options.url, options.timeout, (err) => {
20
+ const url = getUrl(name, config);
21
+ self._request('GET', url, config.options, (err) => {
24
22
  if (!err) return next();
25
23
  const _err = err.status ? new Error(format('Failed to check vhost: %s. %s returned status %d', name, config.loggableUrl, err.status)) : err;
26
24
  return next(_err);
@@ -29,26 +27,29 @@ function Client(suppliedAgent) {
29
27
 
30
28
  this.deleteVhost = function (name, config, next) {
31
29
  debug('Deleting vhost: %s', name);
32
- const options = getVhostOptions(name, config);
33
- self._request('delete', options.url, options.timeout, (err) => {
30
+ const url = getUrl(name, config);
31
+ self._request('DELETE', url, config.options, (err) => {
34
32
  if (!err) return next();
35
33
  const _err = err.status ? new Error(format('Failed to delete vhost: %s. %s returned status %d', name, config.loggableUrl, err.status)) : err;
36
34
  return next(_err);
37
35
  });
38
36
  };
39
37
 
40
- this._request = function (method, url, timeout, next) {
41
- agent[method](url)
42
- .timeout({ deadline: timeout })
43
- .then(() => {
44
- next();
45
- })
46
- .catch(next);
38
+ this._request = function (method, url, options, next) {
39
+ const req = http.request(url, { ...options, method, agent }, (res) => {
40
+ if (res.statusCode >= 300) {
41
+ const err = Object.assign(new Error('HTTP Error'), { status: res.statusCode });
42
+ return next(err);
43
+ }
44
+ res.on('data', () => {});
45
+ res.on('end', () => next());
46
+ });
47
+ req.on('error', next);
48
+ req.end();
47
49
  };
48
50
 
49
- function getVhostOptions(name, config) {
50
- const url = format('%s/%s/%s', config.url, 'api/vhosts', name);
51
- return _.defaultsDeep({ url }, config.options);
51
+ function getUrl(name, config) {
52
+ return format('%s/%s/%s', config.url, 'api/vhosts', name);
52
53
  }
53
54
  }
54
55
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rascal",
3
- "version": "18.0.1",
3
+ "version": "20.0.0",
4
4
  "description": "A config driven wrapper for amqplib supporting multi-host connections, automatic error recovery, redelivery flood protection, transparent encryption / decryption, channel pooling and publication timeouts",
5
5
  "main": "index.js",
6
6
  "dependencies": {
@@ -12,7 +12,6 @@
12
12
  "lru-cache": "^7.10.1",
13
13
  "safe-json-parse": "^4.0.0",
14
14
  "stashback": "^2.0.1",
15
- "superagent": "^8.0.9",
16
15
  "uuid": "^8.3.2",
17
16
  "xregexp": "^5.1.0"
18
17
  },
@@ -27,7 +26,6 @@
27
26
  "lint-staged": "^11.2.4",
28
27
  "nyc": "^15.1.0",
29
28
  "random-readable": "^1.0.1",
30
- "superagent-defaults": "^0.1.14",
31
29
  "zunit": "^4.0.0"
32
30
  },
33
31
  "peerDependencies": {