arnavmq 0.16.4 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +2 -2
- package/README.md +1 -1
- package/eslint.config.mjs +82 -0
- package/package.json +13 -13
- package/src/index.js +2 -2
- package/src/modules/consumer.js +11 -7
- package/src/modules/hooks/base_hooks.js +1 -1
- package/src/modules/message-parsers.js +6 -6
- package/src/modules/producer.js +1 -5
- package/src/modules/utils.js +2 -2
- package/types/modules/channels.d.ts +2 -2
- package/types/modules/connection.d.ts +4 -4
- package/types/modules/hooks/connection_hooks.d.ts +1 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
|
|
17
17
|
strategy:
|
|
18
18
|
matrix:
|
|
19
|
-
node-version: [
|
|
19
|
+
node-version: [20.x, 22.x, 24.x]
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v3
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
|
|
43
43
|
- uses: actions/setup-node@v3
|
|
44
44
|
with:
|
|
45
|
-
node-version:
|
|
45
|
+
node-version: 22.x
|
|
46
46
|
registry-url: https://registry.npmjs.org
|
|
47
47
|
|
|
48
48
|
- run: npm publish --access public
|
package/README.md
CHANGED
|
@@ -171,7 +171,7 @@ const arnavmq = require('arnavmq')({
|
|
|
171
171
|
consumerSuffix: '',
|
|
172
172
|
|
|
173
173
|
// generate a hostname so we can track this connection on the broker (rabbitmq management plugin)
|
|
174
|
-
hostname: process.env.HOSTNAME || process.env.USER ||
|
|
174
|
+
hostname: process.env.HOSTNAME || process.env.USER || crypto.randomUUID(),
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
177
|
* A logger object with a log function for each of the log levels ("debug", "info", "warn", or "error").
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import globals from 'globals';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import js from '@eslint/js';
|
|
5
|
+
import { FlatCompat } from '@eslint/eslintrc';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
const compat = new FlatCompat({
|
|
12
|
+
baseDirectory: __dirname,
|
|
13
|
+
recommendedConfig: js.configs.recommended,
|
|
14
|
+
allConfig: js.configs.all,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export default [
|
|
18
|
+
{
|
|
19
|
+
ignores: [
|
|
20
|
+
'bin/**/*',
|
|
21
|
+
'build/**/*',
|
|
22
|
+
'coverage/**/*',
|
|
23
|
+
'docs/**/*',
|
|
24
|
+
'jsdoc/**/*',
|
|
25
|
+
'templates/**/*',
|
|
26
|
+
'tests/bench/**/*',
|
|
27
|
+
'tests/fixtures/**/*',
|
|
28
|
+
'tests/performance/**/*',
|
|
29
|
+
'tmp/**/*',
|
|
30
|
+
'public/**/*',
|
|
31
|
+
'node_modules/**/*',
|
|
32
|
+
'lib-cov/**/*',
|
|
33
|
+
'.grunt/**/*',
|
|
34
|
+
'.sonar/**/*',
|
|
35
|
+
'logs/**/*',
|
|
36
|
+
'.idea/**/*',
|
|
37
|
+
'samples/**/*',
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
...compat.extends('eslint-config-prettier'),
|
|
41
|
+
{
|
|
42
|
+
languageOptions: {
|
|
43
|
+
globals: {
|
|
44
|
+
...globals.node,
|
|
45
|
+
...globals.mocha,
|
|
46
|
+
...globals.mongo,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
rules: {
|
|
51
|
+
'no-await-in-loop': 0,
|
|
52
|
+
'comma-dangle': 0,
|
|
53
|
+
'max-classes-per-file': 0,
|
|
54
|
+
|
|
55
|
+
'max-len': [
|
|
56
|
+
'error',
|
|
57
|
+
{
|
|
58
|
+
code: 190,
|
|
59
|
+
ignoreComments: true,
|
|
60
|
+
ignoreUrls: true,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
|
|
64
|
+
'no-underscore-dangle': [
|
|
65
|
+
1,
|
|
66
|
+
{
|
|
67
|
+
allow: ['_config', '_connection', '_maxListeners'],
|
|
68
|
+
allowAfterThis: true,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
|
|
72
|
+
'no-return-await': 'off',
|
|
73
|
+
'no-console': 'error',
|
|
74
|
+
'no-param-reassign': 'error',
|
|
75
|
+
'global-require': 'error',
|
|
76
|
+
'no-unused-expressions': 'error',
|
|
77
|
+
'no-sequences': 'error',
|
|
78
|
+
'prefer-rest-params': 'error',
|
|
79
|
+
'func-names': ['error', 'as-needed'],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arnavmq",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "ArnavMQ is a RabbitMQ wrapper",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rabbitmq",
|
|
@@ -34,26 +34,26 @@
|
|
|
34
34
|
},
|
|
35
35
|
"homepage": "https://github.com/bringg/node-arnavmq#readme",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@types/amqplib": "^0.10.
|
|
38
|
-
"amqplib": "^0.10.
|
|
37
|
+
"@types/amqplib": "^0.10.7",
|
|
38
|
+
"amqplib": "^0.10.9",
|
|
39
39
|
"p-defer": "^3.0.0",
|
|
40
|
-
"serialize-error": "^8.0.1"
|
|
41
|
-
"uuid": "^9.0.0"
|
|
40
|
+
"serialize-error": "^8.0.1"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
43
|
+
"@eslint/js": "^9.13.0",
|
|
44
44
|
"child-process-promise": "^2.2.1",
|
|
45
45
|
"dot-only-hunter": "^1.0.3",
|
|
46
|
-
"eslint": "^
|
|
47
|
-
"eslint-config-
|
|
48
|
-
"eslint-
|
|
49
|
-
"
|
|
50
|
-
"mocha": "^
|
|
51
|
-
"nyc": "^
|
|
46
|
+
"eslint": "^9.13.0",
|
|
47
|
+
"eslint-config-prettier": "^10.0.1",
|
|
48
|
+
"eslint-plugin-import": "^2.31.0",
|
|
49
|
+
"globals": "^17.0.0",
|
|
50
|
+
"mocha": "^11.0.1",
|
|
51
|
+
"nyc": "^17.0.0",
|
|
52
52
|
"prettier": "^3.0.0",
|
|
53
|
-
"sinon": "^
|
|
53
|
+
"sinon": "^21.0.1",
|
|
54
54
|
"typescript": "^5.3.3"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
|
-
"node": ">=
|
|
57
|
+
"node": ">=18"
|
|
58
58
|
}
|
|
59
59
|
}
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const crypto = require('crypto');
|
|
2
2
|
const connection = require('./modules/connection');
|
|
3
3
|
const { setLogger } = require('./modules/logger');
|
|
4
4
|
|
|
@@ -28,7 +28,7 @@ module.exports = (config) => {
|
|
|
28
28
|
consumerSuffix: '',
|
|
29
29
|
|
|
30
30
|
// generate a hostname so we can track this connection on the broker (rabbitmq management plugin)
|
|
31
|
-
hostname: process.env.HOSTNAME || process.env.USER ||
|
|
31
|
+
hostname: process.env.HOSTNAME || process.env.USER || crypto.randomUUID(),
|
|
32
32
|
|
|
33
33
|
...config,
|
|
34
34
|
};
|
package/src/modules/consumer.js
CHANGED
|
@@ -190,10 +190,10 @@ class Consumer {
|
|
|
190
190
|
params: { queue, message: messageString },
|
|
191
191
|
});
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
// receive message, parse it, execute callback, check if should answer, ack/reject message
|
|
195
|
-
const body = parsers.in(msg);
|
|
193
|
+
let body = {};
|
|
196
194
|
try {
|
|
195
|
+
body = parsers.in(msg);
|
|
196
|
+
|
|
197
197
|
const action = { message: msg, content: body, callback };
|
|
198
198
|
await this.hooks.trigger(this, ConsumerHooks.beforeProcessMessageEvent, {
|
|
199
199
|
queue,
|
|
@@ -203,13 +203,20 @@ class Consumer {
|
|
|
203
203
|
const res = await action.callback(body, msg.properties);
|
|
204
204
|
await this.checkRpc(msg.properties, queue, res);
|
|
205
205
|
} catch (error) {
|
|
206
|
-
// if something bad happened in the callback, reject the message so we can requeue it (or not)
|
|
207
206
|
logger.error({
|
|
208
207
|
message: `${loggerAlias} Failed processing message from queue ${queue}: ${error.message}`,
|
|
209
208
|
error,
|
|
210
209
|
params: { queue, message: messageString },
|
|
211
210
|
});
|
|
212
211
|
|
|
212
|
+
if (error instanceof SyntaxError) {
|
|
213
|
+
// For parsing errors, reject the message and don't requeue it.
|
|
214
|
+
await this._rejectMessageAfterProcess(channel, queue, msg, body, false, error);
|
|
215
|
+
// Backward compatibility: For parsing errors, throw to let client handle it
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// For callback errors, use default behavior with _rejectMessageAfterProcess
|
|
213
220
|
await this._rejectMessageAfterProcess(channel, queue, msg, body, this._connection.config.requeue, error);
|
|
214
221
|
return;
|
|
215
222
|
}
|
|
@@ -274,7 +281,4 @@ class Consumer {
|
|
|
274
281
|
}
|
|
275
282
|
}
|
|
276
283
|
|
|
277
|
-
/* eslint no-unused-expressions: "off" */
|
|
278
|
-
/* eslint no-sequences: "off" */
|
|
279
|
-
/* eslint arrow-body-style: "off" */
|
|
280
284
|
module.exports = Consumer;
|
|
@@ -103,7 +103,7 @@ module.exports = class BaseHooks {
|
|
|
103
103
|
|
|
104
104
|
const hookPromises = [];
|
|
105
105
|
// This rule intends to restrict it for arrays, but this is a Set which doesn't have a '.map' function to use instead.
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
for (const callback of callbacks) {
|
|
108
108
|
hookPromises.push(runHook(source, eventName, payload, callback));
|
|
109
109
|
}
|
|
@@ -33,19 +33,19 @@ module.exports.in = (msg) => {
|
|
|
33
33
|
* @param {object} options amqp.node message options object
|
|
34
34
|
* @return {Buffer} node.js Buffer object, sent by amqp.node
|
|
35
35
|
*/
|
|
36
|
-
/* eslint no-param-reassign: "off" */
|
|
37
36
|
module.exports.out = (content, options) => {
|
|
37
|
+
let parsedContent = content;
|
|
38
38
|
const falsie = [undefined, null];
|
|
39
39
|
if (!falsie.includes(content) && typeof content !== 'string') {
|
|
40
|
-
if (
|
|
41
|
-
|
|
40
|
+
if (parsedContent.error instanceof Error) {
|
|
41
|
+
parsedContent.error = serializeError(parsedContent.error);
|
|
42
42
|
}
|
|
43
43
|
// if content is not a string, we JSONify it (JSON.parse can handle numbers, etc. so we can skip all the checks)
|
|
44
|
-
|
|
44
|
+
parsedContent = JSON.stringify(parsedContent);
|
|
45
45
|
options.contentType = 'application/json';
|
|
46
|
-
} else if (falsie.includes(
|
|
46
|
+
} else if (falsie.includes(parsedContent)) {
|
|
47
47
|
return Buffer.from([]);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
return Buffer.from(
|
|
50
|
+
return Buffer.from(parsedContent, 'utf-8');
|
|
51
51
|
};
|
package/src/modules/producer.js
CHANGED
|
@@ -205,7 +205,6 @@ class Producer {
|
|
|
205
205
|
* @param {object} options message options (persistent, durable, rpc, etc.)
|
|
206
206
|
* @return {Promise} checkRpc response
|
|
207
207
|
*/
|
|
208
|
-
/* eslint prefer-rest-params: off */
|
|
209
208
|
produce(queue, msg, options) {
|
|
210
209
|
return this.publish(queue, msg, options);
|
|
211
210
|
}
|
|
@@ -217,7 +216,6 @@ class Producer {
|
|
|
217
216
|
* @param {object} options message options (persistent, durable, rpc, etc.)
|
|
218
217
|
* @return {Promise} checkRpc response
|
|
219
218
|
*/
|
|
220
|
-
/* eslint no-param-reassign: "off" */
|
|
221
219
|
async publish(queue, msg, options) {
|
|
222
220
|
// default options are persistent and durable because we do not want to miss any outgoing message
|
|
223
221
|
// unless user specify it
|
|
@@ -236,6 +234,7 @@ class Producer {
|
|
|
236
234
|
async _sendToQueue(queue, message, settings, currentRetryNumber) {
|
|
237
235
|
// undefined can't be serialized/buffered :p
|
|
238
236
|
if (!message) {
|
|
237
|
+
// eslint-disable-next-line no-param-reassign
|
|
239
238
|
message = null;
|
|
240
239
|
}
|
|
241
240
|
|
|
@@ -311,7 +310,4 @@ class Producer {
|
|
|
311
310
|
}
|
|
312
311
|
}
|
|
313
312
|
|
|
314
|
-
/* eslint no-unused-expressions: "off" */
|
|
315
|
-
/* eslint no-sequences: "off" */
|
|
316
|
-
/* eslint arrow-body-style: "off" */
|
|
317
313
|
module.exports = Producer;
|
package/src/modules/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const crypto = require('crypto');
|
|
2
2
|
|
|
3
3
|
function empty() {}
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ function getCorrelationId(options) {
|
|
|
19
19
|
if (options.correlationId) {
|
|
20
20
|
return options.correlationId;
|
|
21
21
|
}
|
|
22
|
-
return
|
|
22
|
+
return crypto.randomUUID();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
module.exports = {
|
|
@@ -5,8 +5,8 @@ interface ChannelConfig {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
declare class Channels {
|
|
8
|
-
constructor(connection: amqp.
|
|
9
|
-
private readonly _connection: amqp.
|
|
8
|
+
constructor(connection: amqp.ChannelModel, config: ChannelConfig);
|
|
9
|
+
private readonly _connection: amqp.ChannelModel;
|
|
10
10
|
private readonly _config: ChannelConfig;
|
|
11
11
|
private readonly _channels: Map<string, { chann: Promise<amqp.Channel>; config: ChannelConfig }>;
|
|
12
12
|
get(queue: string, config: ChannelConfig): Promise<amqp.Channel>;
|
|
@@ -57,14 +57,14 @@ interface ConnectionConfig {
|
|
|
57
57
|
declare class Connection {
|
|
58
58
|
constructor(config: ConnectionConfig);
|
|
59
59
|
|
|
60
|
-
private _connectionPromise: Promise<amqp.
|
|
60
|
+
private _connectionPromise: Promise<amqp.ChannelModel>;
|
|
61
61
|
private _config: ConnectionConfig;
|
|
62
62
|
public hooks: ConnectionHooks;
|
|
63
63
|
|
|
64
64
|
get config(): ConnectionConfig;
|
|
65
65
|
set config(value: ConnectionConfig);
|
|
66
66
|
|
|
67
|
-
getConnection(): Promise<amqp.
|
|
67
|
+
getConnection(): Promise<amqp.ChannelModel>;
|
|
68
68
|
getChannel(queue: string, config: channels.ChannelConfig): Promise<amqp.Channel>;
|
|
69
69
|
getDefaultChannel(): Promise<amqp.Channel>;
|
|
70
70
|
/**
|
|
@@ -74,14 +74,14 @@ declare class Connection {
|
|
|
74
74
|
*/
|
|
75
75
|
addListener(on: string, func: Function): Promise<void>;
|
|
76
76
|
|
|
77
|
-
private _connect(): Promise<amqp.
|
|
77
|
+
private _connect(): Promise<amqp.ChannelModel>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
declare function connection(config: ConnectionConfig): Connection;
|
|
81
81
|
|
|
82
82
|
declare namespace connection {
|
|
83
83
|
export interface Connection {
|
|
84
|
-
getConnection(): Promise<amqp.
|
|
84
|
+
getConnection(): Promise<amqp.ChannelModel>;
|
|
85
85
|
getChannel(queue: string, config: channels.ChannelConfig): Promise<amqp.Channel>;
|
|
86
86
|
getDefaultChannel(): Promise<amqp.Channel>;
|
|
87
87
|
/**
|