@autofleet/rabbit 4.0.0-beta.0 → 4.0.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.
Files changed (55) hide show
  1. package/dist/index.d.ts +24 -17
  2. package/dist/index.js +303 -180
  3. package/dist/index.js.map +1 -0
  4. package/dist/lib/celery.js +1 -0
  5. package/dist/lib/celery.js.map +1 -0
  6. package/dist/lib/consts.d.ts +0 -2
  7. package/dist/lib/consts.js +2 -3
  8. package/dist/lib/consts.js.map +1 -0
  9. package/dist/lib/rabbitError.js +1 -0
  10. package/dist/lib/rabbitError.js.map +1 -0
  11. package/dist/lib/redis.js +1 -0
  12. package/dist/lib/redis.js.map +1 -0
  13. package/dist/lib/types.d.ts +8 -0
  14. package/dist/lib/types.js +1 -0
  15. package/dist/lib/types.js.map +1 -0
  16. package/dist/lib/utils.js +1 -0
  17. package/dist/lib/utils.js.map +1 -0
  18. package/dist/logger.js +1 -0
  19. package/dist/logger.js.map +1 -0
  20. package/dist/{mock.d.ts → mock/index.d.ts} +1 -1
  21. package/dist/{mock.js → mock/index.js} +2 -1
  22. package/dist/mock/index.js.map +1 -0
  23. package/dist/mock/vitest.d.ts +13 -0
  24. package/dist/mock/vitest.js +18 -0
  25. package/dist/mock/vitest.js.map +1 -0
  26. package/package.json +22 -16
  27. package/src/index.ts +360 -203
  28. package/src/lib/consts.ts +0 -2
  29. package/src/lib/types.ts +10 -0
  30. package/src/{mock.ts → mock/index.ts} +2 -2
  31. package/src/mock/vitest.ts +24 -0
  32. package/tsconfig.build.json +5 -0
  33. package/tsconfig.json +2 -2
  34. package/vitest.config.ts +17 -0
  35. package/coverage/clover.xml +0 -669
  36. package/coverage/coverage-final.json +0 -9
  37. package/coverage/lcov-report/base.css +0 -224
  38. package/coverage/lcov-report/block-navigation.js +0 -87
  39. package/coverage/lcov-report/favicon.png +0 -0
  40. package/coverage/lcov-report/index.html +0 -131
  41. package/coverage/lcov-report/prettify.css +0 -1
  42. package/coverage/lcov-report/prettify.js +0 -2
  43. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  44. package/coverage/lcov-report/sorter.js +0 -196
  45. package/coverage/lcov-report/src/index.html +0 -131
  46. package/coverage/lcov-report/src/index.ts.html +0 -3826
  47. package/coverage/lcov-report/src/lib/celery.ts.html +0 -352
  48. package/coverage/lcov-report/src/lib/consts.ts.html +0 -142
  49. package/coverage/lcov-report/src/lib/index.html +0 -191
  50. package/coverage/lcov-report/src/lib/rabbitError.ts.html +0 -103
  51. package/coverage/lcov-report/src/lib/redis.ts.html +0 -133
  52. package/coverage/lcov-report/src/lib/types.ts.html +0 -268
  53. package/coverage/lcov-report/src/lib/utils.ts.html +0 -142
  54. package/coverage/lcov-report/src/logger.ts.html +0 -100
  55. package/coverage/lcov.info +0 -1076
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
- /* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars */
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
6
5
  Object.defineProperty(exports, "__esModule", { value: true });
7
6
  exports.sendCeleryTaskViaHttp = void 0;
7
+ /* eslint-disable no-empty,consistent-return,no-async-promise-executor,@typescript-eslint/no-unused-vars,no-param-reassign */
8
8
  const events_1 = require("events");
9
9
  const util_1 = require("util");
10
10
  const moment_1 = __importDefault(require("moment"));
@@ -12,7 +12,6 @@ const redis_lock_1 = __importDefault(require("redis-lock"));
12
12
  const amqp_connection_manager_1 = require("amqp-connection-manager");
13
13
  const zehut_1 = require("@autofleet/zehut");
14
14
  const node_crypto_1 = require("node:crypto");
15
- const axios_1 = __importDefault(require("axios"));
16
15
  const logger_1 = __importDefault(require("./logger"));
17
16
  const rabbitError_1 = __importDefault(require("./lib/rabbitError"));
18
17
  const redis_1 = __importDefault(require("./lib/redis"));
@@ -22,6 +21,8 @@ const types_1 = require("./lib/types");
22
21
  // const debug = nodeDebug('af-rabbitmq')
23
22
  const debug = logger_1.default.debug.bind(logger_1.default);
24
23
  const PUBLISH_TIMEOUT = 1000 * 10;
24
+ // TODO: [QUORUM-PHASE-3] Delete this env var
25
+ const { DISABLE_QUORUM_QUEUES_CONSUME, DISABLE_QUORUM_QUEUES_PUBLISH, } = process.env;
25
26
  const HEARTBEAT = '60';
26
27
  class RabbitMq {
27
28
  static parseMsg(msg) {
@@ -61,48 +62,50 @@ class RabbitMq {
61
62
  this.DISCONNECT_MSG = 'rabbit: connection disconnect';
62
63
  this.RECONNECT_MSG = 'rabbit: connection disconnect - reconnecting';
63
64
  this.consumers = [];
64
- this.isVHostExist = false;
65
+ this.doesVHostExist = false;
66
+ this.vhost = 'quorum-vhost';
65
67
  this.oldConsumers = [];
66
68
  this.assertVHost = async () => {
67
- if (this.isVHostExist) {
69
+ if (this.doesVHostExist) {
68
70
  return;
69
71
  }
70
- if (!this.options?.vhost) {
71
- throw new Error('vhost is not defined');
72
- }
73
- const { vhost } = this.options;
74
- const auth = {
75
- auth: {
76
- username: process.env.RABBITMQ_USERNAME || 'guest',
77
- password: process.env.RABBITMQ_PASSWORD || 'guest',
78
- },
72
+ const username = process.env.RABBITMQ_USERNAME || 'guest';
73
+ const password = process.env.RABBITMQ_PASSWORD || 'guest';
74
+ const credentials = Buffer.from(`${username}:${password}`).toString('base64');
75
+ const headers = {
76
+ Authorization: `Basic ${credentials}`,
77
+ 'Content-Type': 'application/json',
79
78
  };
80
- const rabbitHost = `http://${(this.options.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
79
+ const rabbitHost = `http://${(this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost').split(':')[0]}:15672`;
80
+ const url = `${rabbitHost}/api/vhosts/${encodeURIComponent(this.vhost)}`;
81
81
  try {
82
- const response = await axios_1.default.get(`${rabbitHost}/api/vhosts/${encodeURIComponent(vhost)}`, auth);
83
- if (response.status !== 200) {
84
- throw new Error('Failed to check vhost');
82
+ const response = await fetch(url, {
83
+ method: 'GET',
84
+ headers,
85
+ });
86
+ if (response.status === 200) {
87
+ this.doesVHostExist = true;
88
+ logger_1.default.info('Vhost exists', { vhost: this.vhost });
89
+ return;
90
+ }
91
+ if (response.status !== 404) {
92
+ logger_1.default.error('Failed to check vhost', { response });
93
+ throw new rabbitError_1.default('Failed to check vhost');
94
+ }
95
+ const createResponse = await fetch(url, {
96
+ method: 'PUT',
97
+ headers,
98
+ body: JSON.stringify({ default_queue_type: 'quorum' }),
99
+ });
100
+ if (!createResponse.ok) {
101
+ logger_1.default.error('Failed to create vhost', { response: createResponse });
102
+ throw new rabbitError_1.default('Failed to create vhost');
85
103
  }
86
- this.isVHostExist = true;
87
- logger_1.default.info('Vhost exists', { vhost });
104
+ this.doesVHostExist = true;
105
+ logger_1.default.info('Vhost created', { vhost: this.vhost });
88
106
  }
89
107
  catch (error) {
90
- // If the vhost does not exist, create it
91
- if (error instanceof axios_1.default.AxiosError && error.response?.status === 404) {
92
- try {
93
- await axios_1.default.put(`${rabbitHost}/api/vhosts/${encodeURIComponent(vhost)}`, {
94
- default_queue_type: 'quorum',
95
- }, auth);
96
- this.isVHostExist = true;
97
- logger_1.default.info('Vhost created', { vhost: this.options?.vhost });
98
- return;
99
- }
100
- catch (createError) {
101
- logger_1.default.error('Failed to create vhost', { error: createError });
102
- throw createError;
103
- }
104
- }
105
- logger_1.default.error('Failed to check vhost', { error });
108
+ logger_1.default.error('Failed to check or create vhost', { error });
106
109
  throw error;
107
110
  }
108
111
  };
@@ -135,11 +138,11 @@ class RabbitMq {
135
138
  await this.unlockRedisIfNeeded(releaseLock);
136
139
  if (channel && msg) {
137
140
  if (!skipRetry
138
- && (!msg.properties.headers[consts_1.RETRY_HEADER]
141
+ && (!msg.properties.headers?.[consts_1.RETRY_HEADER]
139
142
  || parseInt(msg.properties.headers[consts_1.RETRY_HEADER], 10) < options.retries)) {
140
143
  await this.sendToQueue(queue, RabbitMq.parseMsg(msg).content, options, {
141
144
  ...msg.properties.headers,
142
- [consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
145
+ [consts_1.RETRY_HEADER]: msg.properties.headers?.[consts_1.RETRY_HEADER]
143
146
  ? msg.properties.headers[consts_1.RETRY_HEADER] + 1
144
147
  : 1,
145
148
  });
@@ -148,7 +151,7 @@ class RabbitMq {
148
151
  const deadQueue = `${queue}-dead`;
149
152
  await this.sendToQueue(deadQueue, RabbitMq.parseMsg(msg).content, deadQueueOptions, {
150
153
  ...msg.properties.headers,
151
- [consts_1.RETRY_HEADER]: msg.properties.headers[consts_1.RETRY_HEADER]
154
+ [consts_1.RETRY_HEADER]: msg.properties.headers?.[consts_1.RETRY_HEADER]
152
155
  ? msg.properties.headers[consts_1.RETRY_HEADER] + 1
153
156
  : 1,
154
157
  });
@@ -162,10 +165,34 @@ class RabbitMq {
162
165
  });
163
166
  }
164
167
  };
168
+ this.maskURL = (url) => {
169
+ try {
170
+ const urlObj = new URL(url);
171
+ urlObj.username = '***';
172
+ urlObj.password = '***';
173
+ return urlObj.toString();
174
+ }
175
+ catch {
176
+ return url;
177
+ }
178
+ };
165
179
  this.em = new events_1.EventEmitter();
166
- this.channel = null;
180
+ this.publishChannel = null;
167
181
  this.publishChannelSetupPromise = null;
168
- this.connection = null;
182
+ this.publishConnection = {
183
+ amqpConnection: null,
184
+ creatingConnection: false,
185
+ connectionCreatedEventName: 'publishConnectionCreated',
186
+ connectionFailedEventName: 'publishConnectionFailed',
187
+ blockReconnect: false,
188
+ };
189
+ this.consumeConnection = {
190
+ amqpConnection: null,
191
+ creatingConnection: false,
192
+ connectionCreatedEventName: 'consumeConnectionCreated',
193
+ connectionFailedEventName: 'consumeConnectionFailed',
194
+ blockReconnect: false,
195
+ };
169
196
  this.creatingConnection = false;
170
197
  this.exchanges = {};
171
198
  this.queues = {};
@@ -173,9 +200,6 @@ class RabbitMq {
173
200
  this.assertExchangePromises = {};
174
201
  this.consumers = [];
175
202
  this.options = options;
176
- if (!options?.vhost) {
177
- this.options.vhost = process.env.VHOST_NAME || 'quorum-vhost';
178
- }
179
203
  this.redisClient = redisConfig && (0, redis_1.default)(redisConfig);
180
204
  if (this.redisClient) {
181
205
  this.redisLock = (0, util_1.promisify)((0, redis_lock_1.default)(this.redisClient));
@@ -190,11 +214,24 @@ class RabbitMq {
190
214
  await this.gracefulShutdown('SIGINT');
191
215
  });
192
216
  }
193
- // TODO: DELETE OLD PROPERTIES
217
+ // TODO: [QUORUM-PHASE-3] Delete the old properties that we use for the old consumers and publishers
194
218
  this.oldEm = new events_1.EventEmitter();
195
- this.oldChannel = null;
219
+ this.oldPublishChannel = null;
196
220
  this.oldPublishChannelSetupPromise = null;
197
- this.oldConnection = null;
221
+ this.oldPublishConnection = {
222
+ amqpConnection: null,
223
+ creatingConnection: false,
224
+ connectionCreatedEventName: 'oldPublishConnectionCreated',
225
+ connectionFailedEventName: 'oldPublishConnectionFailed',
226
+ blockReconnect: false,
227
+ };
228
+ this.oldConsumeConnection = {
229
+ amqpConnection: null,
230
+ creatingConnection: false,
231
+ connectionCreatedEventName: 'oldConsumeConnectionCreated',
232
+ connectionFailedEventName: 'oldConsumeConnectionFailed',
233
+ blockReconnect: false,
234
+ };
198
235
  this.oldCreatingConnection = false;
199
236
  this.oldExchanges = {};
200
237
  this.oldQueues = {};
@@ -203,30 +240,31 @@ class RabbitMq {
203
240
  this.oldConsumers = [];
204
241
  this.oldConsumersTags = [];
205
242
  }
206
- async getConnection() {
243
+ async getConnection(connection) {
207
244
  return new Promise(async (resolve, reject) => {
208
- if (this.blockReconnect) {
245
+ const { amqpConnection: connectionLocal, creatingConnection, connectionCreatedEventName, connectionFailedEventName, blockReconnect, } = connection;
246
+ if (blockReconnect) {
209
247
  debug('rabbit: block reconnect');
210
248
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
211
249
  // @ts-ignore
212
250
  return resolve();
213
251
  }
214
- if (this.connection !== null) {
215
- if (this.options?.disableReconnect || this.connection?.isConnected()) {
252
+ if (connectionLocal !== null) {
253
+ if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
216
254
  debug('rabbit: connection - is connected');
217
255
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
218
256
  // @ts-ignore
219
- return resolve(this.connection);
257
+ return resolve(connectionLocal);
220
258
  }
221
259
  debug('rabbit: connection - reconnecting');
222
260
  }
223
- if (this.creatingConnection) {
261
+ if (creatingConnection) {
224
262
  debug('rabbit: creating connection emi');
225
- this.em.once(consts_1.CONNECTION_CREATED_CONST, resolve);
226
- this.em.once(consts_1.CONNECTION_FAILED_CONST, reject);
263
+ this.em.once(connectionCreatedEventName, resolve);
264
+ this.em.once(connectionFailedEventName, reject);
227
265
  return;
228
266
  }
229
- this.creatingConnection = true;
267
+ connection.creatingConnection = true;
230
268
  let isResolved = false;
231
269
  // It is import to use it as a function and not as a variable
232
270
  // because of k8s changes the env variables
@@ -236,61 +274,63 @@ class RabbitMq {
236
274
  const password = process.env.RABBITMQ_PASSWORD || 'guest';
237
275
  const host = this.options?.rabbitHost || process.env.RABBITMQ_SERVICE_HOST || 'localhost';
238
276
  debug('rabbit: creating connection', { host, userName, HEARTBEAT });
239
- return [`amqp://${userName}:${password}@${host}/${this.options?.vhost}?heartbeat=${HEARTBEAT}`];
277
+ return [`amqp://${userName}:${password}@${host}/${this.vhost}?heartbeat=${HEARTBEAT}`];
240
278
  };
241
279
  const defaultUrls = findServers();
242
- const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
280
+ const newConnection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
243
281
  findServers,
244
282
  });
245
- this.connection = connection;
246
- this.connection.on('error', (err) => {
283
+ connection.amqpConnection = newConnection;
284
+ newConnection.on('error', (err) => {
247
285
  logger_1.default.error('rabbit: connection error', { err });
248
286
  if (!isResolved) {
249
287
  isResolved = true;
250
288
  reject(err);
251
- this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
289
+ this.em.emit(connectionFailedEventName, err);
252
290
  }
253
291
  });
254
- this.connection.on('connectFailed', (err) => {
292
+ newConnection.on('connectFailed', (err) => {
255
293
  this.consumersTags = [];
256
- logger_1.default.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.options?.vhost });
294
+ if (typeof err.url === 'string') {
295
+ err.url = this.maskURL(err.url);
296
+ }
297
+ logger_1.default.error('rabbit: connection connectFailed', { err, advice: 'Check if the vhost exist', vhost: this.vhost });
257
298
  if (!isResolved) {
258
299
  isResolved = true;
259
300
  reject(err);
260
- this.em.emit(consts_1.CONNECTION_FAILED_CONST, err);
301
+ this.em.emit(connectionFailedEventName, err);
261
302
  }
262
303
  });
263
- this.connection.on('disconnect', ({ err }) => {
264
- // this.channel = null;
304
+ newConnection.on('disconnect', ({ err }) => {
265
305
  this.consumersTags = [];
266
306
  debug('rabbit: connection closed');
267
307
  if (this.options?.disableReconnect) {
268
308
  logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
269
- this.blockReconnect = true;
309
+ connection.blockReconnect = true;
270
310
  }
271
311
  else {
272
312
  logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
273
313
  }
274
314
  });
275
- this.connection.once('connect', async () => {
315
+ newConnection.once('connect', async () => {
276
316
  debug('rabbit: connection established');
277
- this.creatingConnection = false;
278
- this.em.emit(consts_1.CONNECTION_CREATED_CONST, connection);
317
+ connection.creatingConnection = false;
318
+ this.em.emit(connectionCreatedEventName, newConnection);
279
319
  isResolved = true;
280
- resolve(connection);
320
+ resolve(newConnection);
281
321
  });
282
322
  });
283
323
  }
284
- async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
285
- let connection;
324
+ async getNewChannel({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}, connection, }) {
325
+ let localConnection;
286
326
  try {
287
- connection = await this.getConnection();
327
+ localConnection = await this.getConnection(connection);
288
328
  }
289
329
  catch (e) {
290
330
  logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
291
331
  throw e;
292
332
  }
293
- const channel = connection.createChannel({ ...options });
333
+ const channel = localConnection?.createChannel({ ...options });
294
334
  (0, events_1.once)(channel, 'close').then((args) => {
295
335
  logger_1.default.error(`rabbit: channel ${name} closed`);
296
336
  onClose?.(args);
@@ -305,18 +345,20 @@ class RabbitMq {
305
345
  throw err;
306
346
  }
307
347
  }
308
- async assertChannel({ force = false } = {}) {
348
+ async assertChannel({ force = false, connection }) {
309
349
  if (!this.publishChannelSetupPromise) {
310
350
  this.publishChannelSetupPromise = new Promise(async (resolve, reject) => {
311
- if (this.channel && !force) {
312
- return resolve(this.channel);
351
+ if (this.publishChannel && !force) {
352
+ return resolve(this.publishChannel);
313
353
  }
314
354
  try {
315
- const channel = await this.getNewChannel({});
355
+ const channel = await this.getNewChannel({ connection });
316
356
  channel.on('error', (err) => {
317
357
  logger_1.default.error('rabbit: channel error', { err });
318
358
  });
319
- this.channel = channel;
359
+ if (this.publishConnection === connection) {
360
+ this.publishChannel = channel;
361
+ }
320
362
  resolve(channel);
321
363
  }
322
364
  catch (e) {
@@ -326,8 +368,8 @@ class RabbitMq {
326
368
  }
327
369
  return this.publishChannelSetupPromise;
328
370
  }
329
- async assertExchange(exchangeName, options) {
330
- const channel = await this.assertChannel();
371
+ async assertExchange(exchangeName, connection) {
372
+ const channel = await this.assertChannel({ connection });
331
373
  if (this.exchanges[exchangeName]) {
332
374
  delete this.assertExchangePromises[exchangeName];
333
375
  return this.exchanges[exchangeName];
@@ -339,32 +381,31 @@ class RabbitMq {
339
381
  this.exchanges[exchangeName] = await this.assertExchangePromises[exchangeName];
340
382
  return this.exchanges[exchangeName];
341
383
  }
342
- // TODO: Change the implementation to the new one
343
384
  async getQueueLength(queue) {
344
385
  RabbitMq.validateName('queue', queue);
345
- const { oldChannel: channel } = this;
386
+ const { publishChannel: channel } = this;
346
387
  if (!channel) {
347
- throw new Error('channel is not defined');
388
+ throw new rabbitError_1.default('channel is not defined');
348
389
  }
349
- debug('rabbit: getting queue length', { queue, connected: this.connection?.isConnected() });
390
+ debug('rabbit: getting queue length', { queue, connected: this.publishConnection.amqpConnection?.isConnected() });
350
391
  return channel?.checkQueue(queue);
351
392
  }
352
- async deleteQueue(queue) {
393
+ async deleteQueue(queue, connection) {
353
394
  RabbitMq.validateName('queue', queue);
354
- const channel = await this.assertChannel();
395
+ const channel = await this.assertChannel({ connection });
355
396
  logger_1.default.info('rabbit: deleting queue', { queue });
356
397
  const deleteQueueRes = await channel.deleteQueue(queue);
357
398
  debug('queue deleted', deleteQueueRes);
358
399
  return deleteQueueRes;
359
400
  }
360
- // TODO: Change the implementation to the new one
361
401
  async bindQueue(queue, exchange) {
362
- const channel = await this.assertChannelOld();
402
+ const channel = await this.assertChannel({ connection: this.publishConnection });
363
403
  await channel.addSetup((setupChannel) => setupChannel.bindQueue(queue, exchange, ''));
364
404
  return channel.bindQueue(queue, exchange, '');
365
405
  }
366
406
  async setupQueue(queueName, options) {
367
407
  let queue;
408
+ const connection = this.publishConnection;
368
409
  const localeOptions = {
369
410
  ...options,
370
411
  durable: true,
@@ -375,7 +416,7 @@ class RabbitMq {
375
416
  },
376
417
  };
377
418
  try {
378
- const channel = await this.assertChannel();
419
+ const channel = await this.assertChannel({ connection });
379
420
  debug('assertQueue->channel.addSetup', { queueName });
380
421
  await channel.addSetup(async (setupChannel) => {
381
422
  await setupChannel.assertQueue(queueName, localeOptions);
@@ -387,8 +428,8 @@ class RabbitMq {
387
428
  logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
388
429
  if (!this.options?.dontRetryAssert) {
389
430
  debug('retrying assertQueue', { queueName });
390
- const channel = await this.assertChannel({ force: true });
391
- await this.deleteQueue(queueName);
431
+ const channel = await this.assertChannel({ force: true, connection });
432
+ await this.deleteQueue(queueName, connection);
392
433
  debug('retrying assertQueue->channel.addSetup', { queueName });
393
434
  await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
394
435
  debug('retrying assertQueue->channel.assertQueue', { queueName });
@@ -401,7 +442,7 @@ class RabbitMq {
401
442
  this.queues[queueName] = queue;
402
443
  return queue;
403
444
  }
404
- // TODO: Can be deleted after deleting the old consumers
445
+ // TODO: [QUORUM-PHASE-3] Can be deleted after deleting the old consumers and publishers because all the queues are created us quorum queues
405
446
  static shouldUseQuorum(queueName) {
406
447
  const envQuorumQueuesWhitelist = process.env.QUORUM_QUEUES_WHITELIST;
407
448
  if (envQuorumQueuesWhitelist === '*') {
@@ -438,18 +479,18 @@ class RabbitMq {
438
479
  }
439
480
  // Used by the microservices to consume messages from the queue
440
481
  async consume(queue, callback, options) {
441
- // TODO: USE THE IMPLEMENTATION OF THE NEW CONSUME AND DELETE THE NEW AND OLD
442
- if (options?.isQuorumQueue !== false) {
482
+ // TODO: [QUORUM-PHASE-3] Use only the implementation of consumeNew and delete consumeNew and consumeOld
483
+ if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
443
484
  await this.assertVHost();
444
485
  await this.consumeNew(queue, callback, options);
445
486
  }
446
487
  await this.consumeOld(queue, callback, options);
447
488
  }
448
- // TODO: DELETE
489
+ // TODO: [QUORUM-PHASE-3] Delete consumeNew we do not use it anymore
449
490
  async consumeNew(queue, callback, options) {
450
491
  await this.consumeFromRabbit(queue, callback, options);
451
492
  }
452
- // TODO: DELETE
493
+ // TODO: [QUORUM-PHASE-3] Delete consumeOld we do not use it anymore
453
494
  async consumeOld(queue, callback, options) {
454
495
  await this.consumeFromRabbitOld(queue, callback, options);
455
496
  }
@@ -475,11 +516,11 @@ class RabbitMq {
475
516
  const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
476
517
  if (useConsumeWithLock) {
477
518
  if (!this.redisLock) {
478
- throw new Error('Usage of consumeWithLock requires RedisInstance');
519
+ throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
479
520
  }
480
521
  logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
481
522
  }
482
- const channel = await this.getNewChannel({});
523
+ const channel = await this.getNewChannel({ connection: this.consumeConnection });
483
524
  return channel.addSetup(async (confirmChannel) => {
484
525
  const q = await this.assertQueue(queue, optionsWithDefaults);
485
526
  await confirmChannel.prefetch(limit, false);
@@ -563,10 +604,14 @@ class RabbitMq {
563
604
  RabbitMq.validateName('exchange', exchange);
564
605
  RabbitMq.validateName('queue', queue);
565
606
  const { limit, deadMessageTtl } = optionsWithDefaults;
566
- if (options?.isQuorumQueue !== false) {
607
+ // TODO: [QUORUM-PHASE-3] Delete the if statement after all the queues are created as quorum queues
608
+ if (options?.isQuorumQueue !== false && DISABLE_QUORUM_QUEUES_CONSUME !== 'true') {
567
609
  await this.assertVHost();
568
610
  await this.saveConsumer(queue, callback, options);
569
- const channel = await this.getNewChannel({ name: `consume-exchange-${exchange}-queue-${queue}` });
611
+ const channel = await this.getNewChannel({
612
+ name: `consume-exchange-${exchange}-queue-${queue}`,
613
+ connection: this.consumeConnection,
614
+ });
570
615
  await channel.addSetup(async (c) => {
571
616
  const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
572
617
  await c.assertQueue(queue);
@@ -578,9 +623,12 @@ class RabbitMq {
578
623
  ]);
579
624
  });
580
625
  }
581
- // TODO: DELETE OLD
626
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation
582
627
  await this.saveConsumerOld(queue, callback, options);
583
- const channelOld = await this.getNewChannelOld({ name: `consume-exchange-${exchange}-queue-${queue}-old` });
628
+ const channelOld = await this.getNewChannelOld({
629
+ name: `consume-exchange-${exchange}-queue-${queue}-old`,
630
+ connection: this.oldConsumeConnection,
631
+ });
584
632
  await channelOld.addSetup(async (c) => {
585
633
  const assertExchange = await (0, utils_1.assertExchangeFanout)(c, exchange);
586
634
  await c.assertQueue(queue);
@@ -593,68 +641,109 @@ class RabbitMq {
593
641
  });
594
642
  }
595
643
  // Used by the microservices to publish messages to the exchange
596
- // TODO: Change the implementation to the new one
597
- async publish(exchange, content, customHeaders) {
644
+ // TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
645
+ async publish(exchange, content, customHeaders, isQuorumQueue = true) {
646
+ if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
647
+ return (0, utils_1.wrapSetImmediate)(async () => {
648
+ await this.assertVHost();
649
+ RabbitMq.validateName('exchange', exchange);
650
+ const channel = await this.assertChannel({ connection: this.publishConnection });
651
+ await this.assertExchange(exchange, this.publishConnection);
652
+ await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
653
+ });
654
+ }
655
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation
598
656
  return (0, utils_1.wrapSetImmediate)(async () => {
599
657
  RabbitMq.validateName('exchange', exchange);
600
- const channel = await this.assertChannelOld();
601
- await this.assertExchangeOld(exchange);
658
+ const channel = await this.assertChannelOld({ connection: this.oldPublishConnection });
659
+ await this.assertExchangeOld(exchange, this.oldPublishConnection);
602
660
  await channel.publish(exchange, '', Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
603
661
  });
604
662
  }
605
663
  // Used by the microservices to send messages to the queue
606
- // TODO: Change the implementation to the new one
607
- async sendToQueue(queue, content, options, customHeaders) {
608
- try {
609
- await this.assertChannelOld();
610
- }
611
- catch (e) {
612
- logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
613
- throw e;
614
- }
615
- try {
616
- RabbitMq.validateName('queue', queue);
617
- await this.assertQueueOld(queue, options);
618
- }
619
- catch (e) {
620
- logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
621
- throw e;
622
- }
623
- try {
624
- const res = await this.oldChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
625
- debug(`rabbit: sending to queue ${queue}`, { res });
626
- return res;
664
+ // TODO: [QUORUM-PHASE-3] isQuorumQueue flag is not needed anymore because all the queues are created as quorum queues
665
+ async sendToQueue(queue, content, options, customHeaders, isQuorumQueue = true) {
666
+ if (isQuorumQueue && DISABLE_QUORUM_QUEUES_PUBLISH !== 'true') {
667
+ try {
668
+ await this.assertVHost();
669
+ await this.assertChannel({ connection: this.publishConnection });
670
+ }
671
+ catch (e) {
672
+ logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
673
+ throw e;
674
+ }
675
+ try {
676
+ RabbitMq.validateName('queue', queue);
677
+ await this.assertQueue(queue, options);
678
+ }
679
+ catch (e) {
680
+ logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
681
+ throw e;
682
+ }
683
+ try {
684
+ const res = await this.publishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
685
+ debug(`rabbit: sending to queue ${queue}`, { res });
686
+ return res;
687
+ }
688
+ catch (e) {
689
+ const isConnected = await this.isConnected();
690
+ logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
691
+ throw e;
692
+ }
627
693
  }
628
- catch (e) {
629
- const isConnected = await this.isConnected();
630
- logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
631
- throw e;
694
+ else {
695
+ try {
696
+ await this.assertChannelOld({ connection: this.oldPublishConnection });
697
+ }
698
+ catch (e) {
699
+ logger_1.default.error(`rabbit sendToQueue: failed to send assert channel when sending to queue ${queue}`, { e });
700
+ throw e;
701
+ }
702
+ try {
703
+ RabbitMq.validateName('queue', queue);
704
+ await this.assertQueueOld(queue, options);
705
+ }
706
+ catch (e) {
707
+ logger_1.default.error(`rabbit sendToQueue: failed to assert queue ${queue}`, { e });
708
+ throw e;
709
+ }
710
+ try {
711
+ const res = await this.oldPublishChannel?.sendToQueue(queue, Buffer.from(JSON.stringify(content)), RabbitMq.getPublishOptions(customHeaders));
712
+ debug(`rabbit: sending to queue ${queue}`, { res });
713
+ return res;
714
+ }
715
+ catch (e) {
716
+ const isConnected = await this.isConnectedOld();
717
+ logger_1.default.error(`rabbit sendToQueue: failed to send to queue ${queue}, isConnected: ${isConnected}`, { e });
718
+ throw e;
719
+ }
632
720
  }
633
721
  }
634
- // TODO: After changing the publish to the new implementation change the from the old to the new
635
722
  async isConnected() {
636
- const connection = await this.getConnectionOld();
637
- const isConnected = connection.isConnected();
723
+ debug('rabbit: start old is connected');
724
+ const consumeConnection = await this.getConnection(this.consumeConnection);
725
+ const publishConnection = await this.getConnection(this.publishConnection);
726
+ const isConnected = consumeConnection.isConnected() && publishConnection.isConnected();
638
727
  if (!isConnected) {
639
- logger_1.default.error('rabbit: isConnected - false');
728
+ logger_1.default.error('rabbit: old isConnected - false');
640
729
  return false;
641
730
  }
642
- const channel = await this.assertChannelOld();
731
+ const channel = await this.assertChannel({ connection: this.publishConnection });
643
732
  try {
644
733
  await Promise.all([
645
734
  channel.waitForConnect(),
646
- ...this.oldConsumers.map((c) => channel.checkQueue(c.queue)),
735
+ ...this.consumers.map((c) => channel.checkQueue(c.queue)),
647
736
  ]);
648
737
  }
649
738
  catch (e) {
650
739
  logger_1.default.error('rabbit: isConnected - false');
651
740
  return false;
652
741
  }
653
- logger_1.default.info('rabbit: isConnected - true');
742
+ logger_1.default.debug('rabbit: isConnected - true');
654
743
  return true;
655
744
  }
656
745
  async gracefulShutdown(signal) {
657
- // TODO: DELETE OLD
746
+ // TODO: [QUORUM-PHASE-3] Delete the old implementation they are not needed anymore
658
747
  const tagsNumber = this.consumersTags.length + this.oldConsumersTags.length;
659
748
  logger_1.default.info(`rabbit: [gracefully-shutdown] received ${signal}! canceling #${tagsNumber} tags...`);
660
749
  const cancelTagPromises = this.consumersTags.map(([channel, tag]) => channel.cancel(tag));
@@ -679,11 +768,11 @@ class RabbitMq {
679
768
  const { limit, deadMessageTtl, useConsumeWithLock, lockTimeout, auditContext, enableRabbitTrace, } = optionsWithDefaults;
680
769
  if (useConsumeWithLock) {
681
770
  if (!this.redisLock) {
682
- throw new Error('Usage of consumeWithLock requires RedisInstance');
771
+ throw new rabbitError_1.default('Usage of consumeWithLock requires RedisInstance');
683
772
  }
684
773
  logger_1.default.info(`rabbit: Consuming with lock from queue ${queue} with lockTimeout: ${lockTimeout}ms`);
685
774
  }
686
- const channel = await this.getNewChannelOld({});
775
+ const channel = await this.getNewChannelOld({ connection: this.oldConsumeConnection });
687
776
  return channel.addSetup(async (confirmChannel) => {
688
777
  const q = await this.assertQueueOld(queue, optionsWithDefaults);
689
778
  await confirmChannel.prefetch(limit, false);
@@ -761,17 +850,20 @@ class RabbitMq {
761
850
  }
762
851
  });
763
852
  }
764
- // TODO: DELETE OLD PROPERTIES UNDER THIS LINE
765
- async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {} } = {}) {
766
- let connection;
853
+ // TODO: [QUORUM-PHASE-3] Delete all the function under this line.
854
+ async getNewChannelOld({ name = (0, utils_1.rand)().toString(), onClose = null, options = {}, connection, }) {
855
+ let localConnection;
767
856
  try {
768
- connection = await this.getConnectionOld();
857
+ localConnection = await this.getConnectionOld(connection);
769
858
  }
770
859
  catch (e) {
771
860
  logger_1.default.error(`rabbit: error on get connection for new channel ${name} `, { e });
772
861
  throw e;
773
862
  }
774
- const channel = connection.createChannel({ ...options });
863
+ if (!localConnection) {
864
+ throw new Error(`rabbit: couldnt get connection for new channel ${name}`);
865
+ }
866
+ const channel = localConnection?.createChannel({ ...options });
775
867
  (0, events_1.once)(channel, 'close').then((args) => {
776
868
  logger_1.default.error(`rabbit: channel ${name} closed`);
777
869
  onClose?.(args);
@@ -786,30 +878,31 @@ class RabbitMq {
786
878
  throw err;
787
879
  }
788
880
  }
789
- async getConnectionOld() {
881
+ async getConnectionOld(connection) {
790
882
  return new Promise(async (resolve, reject) => {
791
- if (this.oldBlockReconnect) {
883
+ const { amqpConnection: connectionLocal, creatingConnection, connectionCreatedEventName, connectionFailedEventName, blockReconnect, } = connection;
884
+ if (blockReconnect) {
792
885
  debug('rabbit: block reconnect');
793
886
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
794
887
  // @ts-ignore
795
888
  return resolve();
796
889
  }
797
- if (this.oldConnection !== null) {
798
- if (this.options?.disableReconnect || this.oldConnection?.isConnected()) {
890
+ if (connectionLocal !== null) {
891
+ if (this.options?.disableReconnect || connectionLocal?.isConnected()) {
799
892
  debug('rabbit: connection - is connected');
800
893
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
801
894
  // @ts-ignore
802
- return resolve(this.oldConnection);
895
+ return resolve(connectionLocal);
803
896
  }
804
897
  debug('rabbit: connection - reconnecting');
805
898
  }
806
- if (this.oldCreatingConnection) {
899
+ if (creatingConnection) {
807
900
  debug('rabbit: creating connection emi');
808
- this.oldEm.once(consts_1.CONNECTION_CREATED_CONST, resolve);
809
- this.oldEm.once(consts_1.CONNECTION_FAILED_CONST, reject);
901
+ this.oldEm.once(connectionCreatedEventName, resolve);
902
+ this.oldEm.once(connectionFailedEventName, reject);
810
903
  return;
811
904
  }
812
- this.oldCreatingConnection = true;
905
+ connection.creatingConnection = true;
813
906
  let isResolved = false;
814
907
  // It is import to use it as a function and not as a variable
815
908
  // because of k8s changes the env variables
@@ -822,44 +915,47 @@ class RabbitMq {
822
915
  return [`amqp://${userName}:${password}@${host}?heartbeat=${HEARTBEAT}`];
823
916
  };
824
917
  const defaultUrls = findServers();
825
- const connection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
918
+ const newConnection = await (0, amqp_connection_manager_1.connect)(defaultUrls, {
826
919
  findServers,
827
920
  });
828
- this.oldConnection = connection;
829
- this.oldConnection.on('error', (err) => {
921
+ connection.amqpConnection = newConnection;
922
+ newConnection.on('error', (err) => {
830
923
  logger_1.default.error('rabbit: connection error', { err });
831
924
  if (!isResolved) {
832
925
  isResolved = true;
833
926
  reject(err);
834
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
927
+ this.oldEm.emit(connectionFailedEventName, err);
835
928
  }
836
929
  });
837
- this.oldConnection.on('connectFailed', (err) => {
930
+ newConnection.on('connectFailed', (err) => {
838
931
  this.oldConsumersTags = [];
932
+ if (typeof err.url === 'string') {
933
+ err.url = this.maskURL(err.url);
934
+ }
839
935
  logger_1.default.error('rabbit: connection connectFailed', { err });
840
936
  if (!isResolved) {
841
937
  isResolved = true;
842
938
  reject(err);
843
- this.oldEm.emit(consts_1.CONNECTION_FAILED_CONST, err);
939
+ this.oldEm.emit(connectionFailedEventName, err);
844
940
  }
845
941
  });
846
- this.oldConnection.on('disconnect', ({ err }) => {
942
+ newConnection.on('disconnect', ({ err }) => {
847
943
  this.oldConsumersTags = [];
848
944
  debug('rabbit: connection closed');
849
945
  if (this.options?.disableReconnect) {
850
946
  logger_1.default.error(`${this.DISCONNECT_MSG}${err && ` - ${err}`}`);
851
- this.oldBlockReconnect = true;
947
+ connection.blockReconnect = true;
852
948
  }
853
949
  else {
854
950
  logger_1.default.error(`${this.RECONNECT_MSG}${err && ` - ${err}`}`);
855
951
  }
856
952
  });
857
- this.oldConnection.once('connect', async () => {
953
+ newConnection.once('connect', async () => {
858
954
  debug('rabbit: connection established');
859
- this.oldCreatingConnection = false;
860
- this.oldEm.emit(consts_1.CONNECTION_CREATED_CONST, connection);
955
+ connection.creatingConnection = false;
956
+ this.oldEm.emit(connectionCreatedEventName, newConnection);
861
957
  isResolved = true;
862
- resolve(connection);
958
+ resolve(newConnection);
863
959
  });
864
960
  });
865
961
  }
@@ -888,6 +984,7 @@ class RabbitMq {
888
984
  }
889
985
  async setupQueueOld(queueName, options) {
890
986
  let queue;
987
+ const connection = this.oldPublishConnection;
891
988
  const shouldUseQuorum = RabbitMq.shouldUseQuorum(queueName);
892
989
  const localeOptions = {
893
990
  ...options,
@@ -899,7 +996,7 @@ class RabbitMq {
899
996
  },
900
997
  };
901
998
  try {
902
- const channel = await this.assertChannelOld();
999
+ const channel = await this.assertChannelOld({ connection });
903
1000
  debug('assertQueue->channel.addSetup', { queueName });
904
1001
  await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
905
1002
  debug('assertQueue->channel.assertQueue', { queueName });
@@ -909,8 +1006,8 @@ class RabbitMq {
909
1006
  logger_1.default.error('rabbit: assertQueue error', { queueName, options, error: e });
910
1007
  if (!this.options?.dontRetryAssert) {
911
1008
  debug('retrying assertQueue', { queueName });
912
- const channel = await this.assertChannelOld({ force: true });
913
- await this.deleteQueueOld(queueName);
1009
+ const channel = await this.assertChannelOld({ force: true, connection });
1010
+ await this.deleteQueueOld(queueName, connection);
914
1011
  debug('retrying assertQueue->channel.addSetup', { queueName });
915
1012
  await channel.addSetup((setupChannel) => setupChannel.assertQueue(queueName, localeOptions));
916
1013
  debug('retrying assertQueue->channel.assertQueue', { queueName });
@@ -923,18 +1020,20 @@ class RabbitMq {
923
1020
  this.oldQueues[queueName] = queue;
924
1021
  return queue;
925
1022
  }
926
- async assertChannelOld({ force = false } = {}) {
1023
+ async assertChannelOld({ force = false, connection }) {
927
1024
  if (!this.oldPublishChannelSetupPromise) {
928
1025
  this.oldPublishChannelSetupPromise = new Promise(async (resolve, reject) => {
929
- if (this.oldChannel && !force) {
930
- return resolve(this.oldChannel);
1026
+ if (this.oldPublishChannel && !force) {
1027
+ return resolve(this.oldPublishChannel);
931
1028
  }
932
1029
  try {
933
- const channel = await this.getNewChannelOld({});
1030
+ const channel = await this.getNewChannelOld({ connection });
934
1031
  channel.on('error', (err) => {
935
1032
  logger_1.default.error('rabbit: channel error', { err });
936
1033
  });
937
- this.oldChannel = channel;
1034
+ if (this.oldPublishConnection === connection) {
1035
+ this.oldPublishChannel = channel;
1036
+ }
938
1037
  resolve(channel);
939
1038
  }
940
1039
  catch (e) {
@@ -944,16 +1043,16 @@ class RabbitMq {
944
1043
  }
945
1044
  return this.oldPublishChannelSetupPromise;
946
1045
  }
947
- async deleteQueueOld(queue) {
1046
+ async deleteQueueOld(queue, connection) {
948
1047
  RabbitMq.validateName('queue', queue);
949
- const channel = await this.assertChannelOld();
1048
+ const channel = await this.assertChannelOld({ connection });
950
1049
  logger_1.default.info('rabbit: deleting queue', { queue });
951
1050
  const deleteQueueRes = await channel.deleteQueue(queue);
952
1051
  debug('queue deleted', deleteQueueRes);
953
1052
  return deleteQueueRes;
954
1053
  }
955
- async assertExchangeOld(exchangeName, options) {
956
- const channel = await this.assertChannelOld();
1054
+ async assertExchangeOld(exchangeName, connection) {
1055
+ const channel = await this.assertChannelOld({ connection });
957
1056
  if (this.oldExchanges[exchangeName]) {
958
1057
  delete this.oldAssertExchangePromises[exchangeName];
959
1058
  return this.oldExchanges[exchangeName];
@@ -965,7 +1064,31 @@ class RabbitMq {
965
1064
  this.oldExchanges[exchangeName] = await this.oldAssertExchangePromises[exchangeName];
966
1065
  return this.oldExchanges[exchangeName];
967
1066
  }
1067
+ async isConnectedOld() {
1068
+ debug('rabbit: start old is connected');
1069
+ const oldConsumeConnection = await this.getConnectionOld(this.oldConsumeConnection);
1070
+ const oldPublishConnection = await this.getConnectionOld(this.oldPublishConnection);
1071
+ const oldIsConnected = oldConsumeConnection.isConnected() && oldPublishConnection.isConnected();
1072
+ if (!oldIsConnected) {
1073
+ logger_1.default.error('rabbit: old isConnected - false');
1074
+ return false;
1075
+ }
1076
+ const oldChannel = await this.assertChannelOld({ connection: this.oldPublishConnection });
1077
+ try {
1078
+ await Promise.all([
1079
+ oldChannel.waitForConnect(),
1080
+ ...this.oldConsumers.map((c) => oldChannel.checkQueue(c.queue)),
1081
+ ]);
1082
+ }
1083
+ catch (e) {
1084
+ logger_1.default.error('rabbit: old isConnected - false');
1085
+ return false;
1086
+ }
1087
+ logger_1.default.debug('rabbit: old isConnected - true');
1088
+ return true;
1089
+ }
968
1090
  }
969
1091
  exports.default = RabbitMq;
970
1092
  var celery_1 = require("./lib/celery");
971
1093
  Object.defineProperty(exports, "sendCeleryTaskViaHttp", { enumerable: true, get: function () { return celery_1.sendCeleryTaskViaHttp; } });
1094
+ //# sourceMappingURL=index.js.map