@opra/rabbitmq 1.26.2 → 1.26.4

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/README.md CHANGED
@@ -1,3 +1,26 @@
1
- # @opra/core
1
+ # @opra/rabbitmq
2
2
 
3
- OPRA schema package.
3
+ [![NPM Version][npm-image]][npm-url]
4
+ [![NPM Downloads][downloads-image]][downloads-url]
5
+ [![CI Tests][ci-test-image]][ci-test-url]
6
+ [![Test Coverage][coveralls-image]][coveralls-url]
7
+
8
+
9
+ ## Support
10
+ You can report bugs and discuss features on the [GitHub issues](https://github.com/panates/opra/issues) page.
11
+
12
+ ## Node Compatibility
13
+ - node >= 20.x
14
+
15
+
16
+ ## License
17
+ Available under [MIT](LICENSE) license.
18
+
19
+ [npm-image]: https://img.shields.io/npm/v/@opra/rabbitmq
20
+ [npm-url]: https://npmjs.org/package/@opra/rabbitmq
21
+ [downloads-image]: https://img.shields.io/npm/dm/@opra/rabbitmq.svg
22
+ [downloads-url]: https://npmjs.org/package/@opra/rabbitmq
23
+ [ci-test-image]: https://github.com/panates/opra/actions/workflows/test.yml/badge.svg
24
+ [ci-test-url]: https://github.com/panates/opra/actions/workflows/test.yml
25
+ [coveralls-image]: https://coveralls.io/repos/github/panates/opra/badge.svg?branch=main
26
+ [coveralls-url]: https://coveralls.io/github/panates/opra?branch=main
@@ -1,7 +1,7 @@
1
1
  import '@opra/core';
2
2
  import { classes } from '@opra/common';
3
3
  import { RMQ_OPERATION_METADATA, RMQ_OPERATION_METADATA_RESOLVER, } from '../constants.js';
4
- /** Implementation **/
4
+ /* Implementation **/
5
5
  classes.MQOperationDecoratorFactory.augment((decorator, decoratorChain) => {
6
6
  decorator.RabbitMQ = (config) => {
7
7
  decoratorChain.push((_, target, propertyKey) => {
@@ -1,19 +1,40 @@
1
1
  import { ApiDocument, MQController, MQOperation } from '@opra/common';
2
2
  import type { RabbitmqAdapter } from './rabbitmq-adapter.js';
3
+ /**
4
+ * Helper class for building RabbitMQ adapter configuration and operation handlers.
5
+ */
3
6
  export declare class ConfigBuilder {
4
7
  readonly document: ApiDocument;
5
8
  readonly config: RabbitmqAdapter.Config;
6
9
  connectionOptions: RabbitmqAdapter.ConnectionOptions;
7
10
  controllerInstances: Map<MQController, any>;
8
11
  handlerArgs: ConfigBuilder.OperationArguments[];
12
+ /**
13
+ * Initializes a new instance of the ConfigBuilder.
14
+ *
15
+ * @param document - The API document.
16
+ * @param config - The adapter configuration.
17
+ */
9
18
  constructor(document: ApiDocument, config: RabbitmqAdapter.Config);
19
+ /**
20
+ * Builds the configuration, identifying controller instances and operation handlers.
21
+ *
22
+ * @returns A promise that resolves when the build is complete.
23
+ */
10
24
  build(): Promise<void>;
25
+ /**
26
+ * Prepares the RabbitMQ connection options from the provided configuration.
27
+ *
28
+ * @protected
29
+ */
11
30
  protected _prepareConnectionOptions(): void;
12
31
  /**
32
+ * Resolves the consumer configuration for a specific operation.
13
33
  *
14
- * @param controller
15
- * @param instance
16
- * @param operation
34
+ * @param controller - The MQ controller definition.
35
+ * @param instance - The controller instance.
36
+ * @param operation - The MQ operation definition.
37
+ * @returns A promise that resolves to the consumer configuration or undefined.
17
38
  * @protected
18
39
  */
19
40
  protected _getConsumerConfig(controller: MQController, instance: any, operation: MQOperation): Promise<RabbitmqAdapter.ConsumerConfig | undefined>;
package/config-builder.js CHANGED
@@ -1,18 +1,32 @@
1
1
  import { merge } from '@jsopen/objects';
2
2
  import { MQ_CONTROLLER_METADATA, } from '@opra/common';
3
3
  import { RMQ_OPERATION_METADATA, RMQ_OPERATION_METADATA_RESOLVER, } from './constants.js';
4
+ /**
5
+ * Helper class for building RabbitMQ adapter configuration and operation handlers.
6
+ */
4
7
  export class ConfigBuilder {
5
8
  document;
6
9
  config;
10
+ /**
11
+ * Initializes a new instance of the ConfigBuilder.
12
+ *
13
+ * @param document - The API document.
14
+ * @param config - The adapter configuration.
15
+ */
7
16
  constructor(document, config) {
8
17
  this.document = document;
9
18
  this.config = config;
10
19
  }
20
+ /**
21
+ * Builds the configuration, identifying controller instances and operation handlers.
22
+ *
23
+ * @returns A promise that resolves when the build is complete.
24
+ */
11
25
  async build() {
12
26
  this.controllerInstances = new Map();
13
27
  this.handlerArgs = [];
14
28
  this._prepareConnectionOptions();
15
- /** Initialize consumers */
29
+ /* Initialize consumers */
16
30
  for (const controller of this.document.getMqApi().controllers.values()) {
17
31
  let instance = controller.instance;
18
32
  if (!instance && controller.ctor)
@@ -20,7 +34,7 @@ export class ConfigBuilder {
20
34
  if (!instance)
21
35
  continue;
22
36
  this.controllerInstances.set(controller, instance);
23
- /** Build HandlerData array */
37
+ /* Build HandlerData array */
24
38
  for (const operation of controller.operations.values()) {
25
39
  const consumerConfig = await this._getConsumerConfig(controller, instance, operation);
26
40
  if (!consumerConfig)
@@ -40,6 +54,11 @@ export class ConfigBuilder {
40
54
  }
41
55
  }
42
56
  }
57
+ /**
58
+ * Prepares the RabbitMQ connection options from the provided configuration.
59
+ *
60
+ * @protected
61
+ */
43
62
  _prepareConnectionOptions() {
44
63
  this.connectionOptions = {};
45
64
  if (Array.isArray(this.config.connection))
@@ -53,10 +72,12 @@ export class ConfigBuilder {
53
72
  ];
54
73
  }
55
74
  /**
75
+ * Resolves the consumer configuration for a specific operation.
56
76
  *
57
- * @param controller
58
- * @param instance
59
- * @param operation
77
+ * @param controller - The MQ controller definition.
78
+ * @param instance - The controller instance.
79
+ * @param operation - The MQ operation definition.
80
+ * @returns A promise that resolves to the consumer configuration or undefined.
60
81
  * @protected
61
82
  */
62
83
  async _getConsumerConfig(controller, instance, operation) {
package/constants.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Default group name for RabbitMQ consumers.
3
+ */
1
4
  export declare const RMQ_DEFAULT_GROUP = "default";
5
+ /**
6
+ * Metadata key for RabbitMQ operation configuration.
7
+ */
2
8
  export declare const RMQ_OPERATION_METADATA = "RMQ_OPERATION_METADATA";
9
+ /**
10
+ * Metadata key for RabbitMQ operation configuration resolver.
11
+ */
3
12
  export declare const RMQ_OPERATION_METADATA_RESOLVER = "RMQ_OPERATION_METADATA_RESOLVER";
package/constants.js CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Default group name for RabbitMQ consumers.
3
+ */
1
4
  export const RMQ_DEFAULT_GROUP = 'default';
5
+ /**
6
+ * Metadata key for RabbitMQ operation configuration.
7
+ */
2
8
  export const RMQ_OPERATION_METADATA = 'RMQ_OPERATION_METADATA';
9
+ /**
10
+ * Metadata key for RabbitMQ operation configuration resolver.
11
+ */
3
12
  export const RMQ_OPERATION_METADATA_RESOLVER = 'RMQ_OPERATION_METADATA_RESOLVER';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/rabbitmq",
3
- "version": "1.26.2",
3
+ "version": "1.26.4",
4
4
  "description": "Opra RabbitMQ adapter",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -14,8 +14,8 @@
14
14
  "valgen": "^6.0.3"
15
15
  },
16
16
  "peerDependencies": {
17
- "@opra/common": "^1.26.2",
18
- "@opra/core": "^1.26.2",
17
+ "@opra/common": "^1.26.4",
18
+ "@opra/core": "^1.26.4",
19
19
  "rabbitmq-client": ">=5.0.0 <6"
20
20
  },
21
21
  "type": "module",
@@ -5,8 +5,10 @@ import type { Envelope, MessageBody } from 'rabbitmq-client/lib/codec.js';
5
5
  import { ConfigBuilder } from './config-builder.js';
6
6
  import { RabbitmqContext } from './rabbitmq-context.js';
7
7
  /**
8
+ * RabbitMQ platform adapter for Opra.
8
9
  *
9
- * @class RabbitmqAdapter
10
+ * This adapter handles communication with RabbitMQ, including connection management,
11
+ * queue subscription, message parsing, and operation execution.
10
12
  */
11
13
  export declare class RabbitmqAdapter extends PlatformAdapter<RabbitmqAdapter.Events> {
12
14
  static readonly PlatformName = "rabbitmq";
@@ -19,33 +21,80 @@ export declare class RabbitmqAdapter extends PlatformAdapter<RabbitmqAdapter.Eve
19
21
  readonly platform = "rabbitmq";
20
22
  readonly interceptors: (RabbitmqAdapter.InterceptorFunction | RabbitmqAdapter.IRabbitmqInterceptor)[];
21
23
  /**
24
+ * Initializes a new instance of the RabbitmqAdapter.
22
25
  *
23
- * @param document
24
- * @param config
25
- * @constructor
26
+ * @param document - The API document instance.
27
+ * @param config - Configuration options for the RabbitMQ adapter.
28
+ * @throws {@link TypeError} Throws if the document does not expose a RabbitMQ API.
26
29
  */
27
30
  constructor(document: ApiDocument, config: RabbitmqAdapter.Config);
31
+ /**
32
+ * Gets the MQ API instance associated with this adapter.
33
+ */
28
34
  get api(): MQApi;
35
+ /**
36
+ * Gets the active RabbitMQ connection, if any.
37
+ */
29
38
  get connection(): rabbit.Connection | undefined;
39
+ /**
40
+ * Gets the optional scope for this adapter.
41
+ */
30
42
  get scope(): string | undefined;
43
+ /**
44
+ * Gets the current status of the adapter.
45
+ */
31
46
  get status(): RabbitmqAdapter.Status;
32
47
  /**
33
- * Starts the service
48
+ * Starts the RabbitMQ service by establishing a connection and subscribing to queues.
49
+ *
50
+ * @returns A promise that resolves when the service has started.
51
+ * @throws {@link Error} Throws if the connection or subscription fails.
34
52
  */
35
53
  start(): Promise<void>;
36
54
  /**
37
- * Closes all connections and stops the service
55
+ * Closes all connections and stops the service.
56
+ *
57
+ * @returns A promise that resolves when all connections are closed.
38
58
  */
39
59
  close(): Promise<void>;
60
+ /**
61
+ * Retrieves the controller instance for a given path.
62
+ *
63
+ * @param controllerPath - The path of the controller.
64
+ * @returns The controller instance, or undefined if not found.
65
+ */
40
66
  getControllerInstance<T>(controllerPath: string): T | undefined;
41
67
  /**
68
+ * Creates a message handler for a specific operation.
42
69
  *
43
- * @param args
70
+ * @param args - Arguments required to create the handler.
71
+ * @returns A function that processes incoming RabbitMQ messages.
44
72
  * @protected
45
73
  */
46
74
  protected _createHandler(args: ConfigBuilder.OperationArguments): (consumer: rabbit.Consumer, queue: string, message: rabbit.AsyncMessage, _reply: RabbitmqAdapter.ReplyFunction) => Promise<void>;
75
+ /**
76
+ * Parses the content of a RabbitMQ message, handling encodings like gzip, deflate, and brotli.
77
+ *
78
+ * @param msg - The message to parse.
79
+ * @returns The parsed content, which may be a string, buffer, or object.
80
+ * @protected
81
+ */
47
82
  protected _parseContent(msg: rabbit.AsyncMessage): Promise<any>;
83
+ /**
84
+ * Emits an error event and logs the error.
85
+ *
86
+ * @param error - The error to emit.
87
+ * @param context - The RabbitMQ context associated with the error.
88
+ * @protected
89
+ */
48
90
  protected _emitError(error: any, context?: RabbitmqContext): void;
91
+ /**
92
+ * Wraps exceptions into OpraException instances.
93
+ *
94
+ * @param exceptions - An array of exceptions to wrap.
95
+ * @returns An array of OpraException instances.
96
+ * @protected
97
+ */
49
98
  protected _wrapExceptions(exceptions: any[]): OpraException[];
50
99
  }
51
100
  /**
@@ -18,8 +18,10 @@ const globalErrorTypes = ['unhandledRejection', 'uncaughtException'];
18
18
  const signalTraps = ['SIGTERM', 'SIGINT', 'SIGUSR2'];
19
19
  const noOp = () => undefined;
20
20
  /**
21
+ * RabbitMQ platform adapter for Opra.
21
22
  *
22
- * @class RabbitmqAdapter
23
+ * This adapter handles communication with RabbitMQ, including connection management,
24
+ * queue subscription, message parsing, and operation execution.
23
25
  */
24
26
  export class RabbitmqAdapter extends PlatformAdapter {
25
27
  static PlatformName = 'rabbitmq';
@@ -32,10 +34,11 @@ export class RabbitmqAdapter extends PlatformAdapter {
32
34
  platform = RabbitmqAdapter.PlatformName;
33
35
  interceptors;
34
36
  /**
37
+ * Initializes a new instance of the RabbitmqAdapter.
35
38
  *
36
- * @param document
37
- * @param config
38
- * @constructor
39
+ * @param document - The API document instance.
40
+ * @param config - Configuration options for the RabbitMQ adapter.
41
+ * @throws {@link TypeError} Throws if the document does not expose a RabbitMQ API.
39
42
  */
40
43
  constructor(document, config) {
41
44
  super(config);
@@ -56,20 +59,35 @@ export class RabbitmqAdapter extends PlatformAdapter {
56
59
  process.once(type, () => this.close());
57
60
  });
58
61
  }
62
+ /**
63
+ * Gets the MQ API instance associated with this adapter.
64
+ */
59
65
  get api() {
60
66
  return this.document.getMqApi();
61
67
  }
68
+ /**
69
+ * Gets the active RabbitMQ connection, if any.
70
+ */
62
71
  get connection() {
63
72
  return this._connection;
64
73
  }
74
+ /**
75
+ * Gets the optional scope for this adapter.
76
+ */
65
77
  get scope() {
66
78
  return this._config.scope;
67
79
  }
80
+ /**
81
+ * Gets the current status of the adapter.
82
+ */
68
83
  get status() {
69
84
  return this._status;
70
85
  }
71
86
  /**
72
- * Starts the service
87
+ * Starts the RabbitMQ service by establishing a connection and subscribing to queues.
88
+ *
89
+ * @returns A promise that resolves when the service has started.
90
+ * @throws {@link Error} Throws if the connection or subscription fails.
73
91
  */
74
92
  async start() {
75
93
  if (this.status !== 'idle')
@@ -80,13 +98,13 @@ export class RabbitmqAdapter extends PlatformAdapter {
80
98
  await configBuilder.build();
81
99
  this._connection = new rabbit.Connection(configBuilder.connectionOptions);
82
100
  try {
83
- /** Establish connection */
101
+ /* Establish connection */
84
102
  await this._connection.onConnect().catch(e => {
85
103
  updateErrorMessage(e, `RabbitMQ connection error. ${e.message}`);
86
104
  throw e;
87
105
  });
88
106
  this.logger?.info?.(`Connected RabbitMQ at ${configBuilder.connectionOptions.urls}`);
89
- /** Subscribe to queues */
107
+ /* Subscribe to queues */
90
108
  const promises = [];
91
109
  for (const args of configBuilder.handlerArgs) {
92
110
  for (const queue of args.topics) {
@@ -130,7 +148,9 @@ export class RabbitmqAdapter extends PlatformAdapter {
130
148
  }
131
149
  }
132
150
  /**
133
- * Closes all connections and stops the service
151
+ * Closes all connections and stops the service.
152
+ *
153
+ * @returns A promise that resolves when all connections are closed.
134
154
  */
135
155
  async close() {
136
156
  if (this._consumers.length)
@@ -141,18 +161,26 @@ export class RabbitmqAdapter extends PlatformAdapter {
141
161
  this._controllerInstances.clear();
142
162
  this._status = 'idle';
143
163
  }
164
+ /**
165
+ * Retrieves the controller instance for a given path.
166
+ *
167
+ * @param controllerPath - The path of the controller.
168
+ * @returns The controller instance, or undefined if not found.
169
+ */
144
170
  getControllerInstance(controllerPath) {
145
171
  const controller = this.api.findController(controllerPath);
146
172
  return controller && this._controllerInstances.get(controller);
147
173
  }
148
174
  /**
175
+ * Creates a message handler for a specific operation.
149
176
  *
150
- * @param args
177
+ * @param args - Arguments required to create the handler.
178
+ * @returns A function that processes incoming RabbitMQ messages.
151
179
  * @protected
152
180
  */
153
181
  _createHandler(args) {
154
182
  const { controller, instance, operation } = args;
155
- /** Prepare parsers */
183
+ /* Prepare parsers */
156
184
  const decodePayload = operation.generateCodec('decode', {
157
185
  scope: this.scope,
158
186
  ignoreReadonlyFields: true,
@@ -179,7 +207,7 @@ export class RabbitmqAdapter extends PlatformAdapter {
179
207
  return _reply(body, envelope);
180
208
  };
181
209
  const headers = {};
182
- /** Create context */
210
+ /* Create context */
183
211
  const context = new RabbitmqContext({
184
212
  __adapter: this,
185
213
  __contDef: controller,
@@ -194,7 +222,7 @@ export class RabbitmqAdapter extends PlatformAdapter {
194
222
  reply,
195
223
  });
196
224
  try {
197
- /** Parse and decode `payload` */
225
+ /* Parse and decode `payload` */
198
226
  let content = await this._parseContent(message);
199
227
  if (content && decodePayload) {
200
228
  if (Buffer.isBuffer(content))
@@ -202,7 +230,7 @@ export class RabbitmqAdapter extends PlatformAdapter {
202
230
  content = decodePayload(content);
203
231
  }
204
232
  // message.properties.
205
- /** Parse and decode `headers` */
233
+ /* Parse and decode `headers` */
206
234
  if (message.headers) {
207
235
  for (const [k, v] of Object.entries(message.headers)) {
208
236
  const header = operation.findHeader(k);
@@ -218,7 +246,7 @@ export class RabbitmqAdapter extends PlatformAdapter {
218
246
  }
219
247
  await this.emitAsync('execute', context).catch(noOp);
220
248
  try {
221
- /** Call operation handler */
249
+ /* Call operation handler */
222
250
  const result = await operationHandler.call(instance, context);
223
251
  if (result !== undefined)
224
252
  await reply(result);
@@ -229,6 +257,13 @@ export class RabbitmqAdapter extends PlatformAdapter {
229
257
  }
230
258
  };
231
259
  }
260
+ /**
261
+ * Parses the content of a RabbitMQ message, handling encodings like gzip, deflate, and brotli.
262
+ *
263
+ * @param msg - The message to parse.
264
+ * @returns The parsed content, which may be a string, buffer, or object.
265
+ * @protected
266
+ */
232
267
  async _parseContent(msg) {
233
268
  if (!Buffer.isBuffer(msg.body))
234
269
  return msg.body;
@@ -273,6 +308,13 @@ export class RabbitmqAdapter extends PlatformAdapter {
273
308
  }
274
309
  return content;
275
310
  }
311
+ /**
312
+ * Emits an error event and logs the error.
313
+ *
314
+ * @param error - The error to emit.
315
+ * @param context - The RabbitMQ context associated with the error.
316
+ * @protected
317
+ */
276
318
  _emitError(error, context) {
277
319
  Promise.resolve()
278
320
  .then(async () => {
@@ -297,6 +339,13 @@ export class RabbitmqAdapter extends PlatformAdapter {
297
339
  })
298
340
  .catch(noOp);
299
341
  }
342
+ /**
343
+ * Wraps exceptions into OpraException instances.
344
+ *
345
+ * @param exceptions - An array of exceptions to wrap.
346
+ * @returns An array of OpraException instances.
347
+ * @protected
348
+ */
300
349
  _wrapExceptions(exceptions) {
301
350
  const wrappedErrors = exceptions.map(e => e instanceof OpraException ? e : new OpraException(e));
302
351
  if (!wrappedErrors.length)
@@ -20,8 +20,9 @@ export declare class RabbitmqContext extends ExecutionContext implements AsyncEv
20
20
  readonly headers: Record<string, any>;
21
21
  readonly reply: RabbitmqAdapter.ReplyFunction;
22
22
  /**
23
- * Constructor
24
- * @param init the context options
23
+ * Initializes a new instance of the RabbitmqContext.
24
+ *
25
+ * @param init - The initialization options for the context.
25
26
  */
26
27
  constructor(init: RabbitmqContext.Initiator);
27
28
  }
@@ -11,8 +11,9 @@ export class RabbitmqContext extends ExecutionContext {
11
11
  headers;
12
12
  reply;
13
13
  /**
14
- * Constructor
15
- * @param init the context options
14
+ * Initializes a new instance of the RabbitmqContext.
15
+ *
16
+ * @param init - The initialization options for the context.
16
17
  */
17
18
  constructor(init) {
18
19
  super({