fastify-rabbitmq 3.4.0 → 3.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Fastify RabbitMQ
2
2
 
3
+ ## v3.4.1 - 2026-09-26
4
+
5
+ ### What Changed 👀
6
+
7
+ #### 🐛 Bug Fixes
8
+
9
+ - fix: close the RabbitMQ connection when the Fastify app closes @Bugs5382 (#166)
10
+ - fix(test): stop declaring transient non-exclusive queues so tests pass on RabbitMQ 4 @Bugs5382 (#165)
11
+ - fix(build): keep source maps out of the npm package @Bugs5382 (#163)
12
+
13
+ #### 📄 Documentation
14
+
15
+ - docs(readme): apply the lite emoji treatment @Bugs5382 (#158)
16
+
17
+ #### 🧩 Dependency Updates
18
+
19
+ - build(deps): bump the github-actions group with 9 updates @[dependabot[bot]](https://github.com/apps/dependabot) (#143)
20
+
21
+ ### Extra
22
+
23
+ **Full Changelog**: https://github.com/Bugs5382/fastify-rabbitmq/compare/v3.4.0...v3.4.1
24
+
3
25
  ## v3.4.0 - 2026-06-09
4
26
 
5
27
  ### What Changed 👀
@@ -60,8 +82,6 @@
60
82
 
61
83
  #### What Changed 👀
62
84
 
63
- - ci: update workflows @Bugs5382 (#103)
64
-
65
85
  #### 🧩 Dependency Updates
66
86
 
67
87
  - feat: updated packages @Bugs5382 (#105)
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
- # 🐰 Fastify RabbitMQ
1
+ # Fastify RabbitMQ 🐰
2
+
3
+ > 📨 A Fastify RabbitMQ plugin developed in pure TypeScript.
2
4
 
3
- A Fastify RabbitMQ plugin developed in pure TypeScript.
4
5
  It wraps the [`rabbitmq-client`](https://www.npmjs.com/package/rabbitmq-client) package so a Fastify
5
6
  app can publish, consume, and RPC over RabbitMQ (AMQP 0-9-1).
6
7
 
@@ -15,7 +16,7 @@ contribution from the outside.
15
16
 
16
17
  > 🟢 **Requires Node.js ≥ 20.15.**
17
18
 
18
- ## Table of Contents
19
+ ## 📑 Table of Contents
19
20
 
20
21
  1. [Install](#-install)
21
22
  2. [Basic Usage](#-basic-usage)
@@ -58,6 +59,16 @@ await app.register(fastifyRabbitMQ, {
58
59
  Registering decorates the Fastify instance with `app.rabbitmq` — a live `rabbitmq-client`
59
60
  `Connection`. Use it to create publishers, consumers, and RPC clients, or to declare topology.
60
61
 
62
+ The plugin owns the connection's lifecycle:
63
+
64
+ - **`app.close()` closes the connection** (each one, with namespaces), so the process can exit.
65
+ Close your own consumers and publishers in an `onClose` hook, as in
66
+ [recipe 6](#6-encapsulate-messaging-in-your-own-plugin).
67
+ - **Connection errors are logged, not thrown.** If the broker is down or drops the connection,
68
+ the error goes to `app.log.error` and `rabbitmq-client` keeps reconnecting in the background.
69
+ The app does not crash. Add your own `app.rabbitmq.on("error", ...)` listener if you need to
70
+ react to it.
71
+
61
72
  ## 🧩 Recipes
62
73
 
63
74
  ### 1. Publish a message
@@ -195,8 +206,9 @@ export default fp(
195
206
  },
196
207
  );
197
208
 
198
- // 5. Tear everything down with the app, so a restart or test closes
199
- // cleanly instead of leaking connections.
209
+ // 5. Close the consumer and publisher with the app. The plugin then
210
+ // closes the connection itself, after this hook has released the
211
+ // channels, so app.close() resolves and the process can exit.
200
212
  app.addHook("onClose", async () => {
201
213
  await consumer.close();
202
214
  await publisher.close();
@@ -228,9 +240,9 @@ Why this shape works well:
228
240
  shutdown live together; the rest of the app depends only on `app.events`.
229
241
  - **Startup declares, routes send.** Topology is declared once at boot, so the first
230
242
  request never races a missing exchange.
231
- - **Lifecycle is handled.** The `onClose` hook closes the consumer and publisher with
232
- the app — important for graceful shutdown and for tests that start and stop Fastify
233
- repeatedly.
243
+ - **Lifecycle is handled.** The `onClose` hook closes the consumer and publisher, and
244
+ the plugin closes the connection, all with `app.close()` — important for graceful
245
+ shutdown and for tests that start and stop Fastify repeatedly.
234
246
  - **Swappable.** Because routes only know `app.events`, you can change brokers, add a
235
247
  [namespace](#5-multiple-connections-with-namespaces), or stub the decorator in a test
236
248
  without touching route code.
@@ -253,8 +265,9 @@ methods you will use most:
253
265
  | `queueDeclare(params)` | Declare a queue. |
254
266
  | `queueBind(params)` | Bind a queue to an exchange. |
255
267
  | `acquire()` | Acquire a raw channel. |
256
- | `ready()` | Resolve once the connection is established. |
257
- | `close()` | Close the connection. |
268
+ | `onConnect(timeout?)` | Resolve once the connection is established. |
269
+ | `ready` | `true` while the connection is established and unblocked. |
270
+ | `close()` | Close the connection. `app.close()` already does this for you. |
258
271
 
259
272
  The full option shapes for each come from `rabbitmq-client` — see [External Libraries](#-external-libraries).
260
273
 
@@ -11,4 +11,3 @@ export interface FastifyRabbitMQOptions {
11
11
  */
12
12
  namespace?: string;
13
13
  }
14
- //# sourceMappingURL=decorate.d.ts.map
package/dist/errors.d.ts CHANGED
@@ -12,4 +12,3 @@ export declare const errors: {
12
12
  code: "FASTIFY_RABBIT_MQ_ERR_USAGE";
13
13
  }, [any?, any?, any?]>;
14
14
  };
15
- //# sourceMappingURL=errors.d.ts.map
package/dist/index.cjs CHANGED
@@ -19,7 +19,7 @@ var __copyProps = (to, from, except, desc) => {
19
19
  }
20
20
  return to;
21
21
  };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
23
23
  value: mod,
24
24
  enumerable: true
25
25
  }) : target, mod));
@@ -105,9 +105,47 @@ const decorateFastifyInstance = (fastify, options, connection) => {
105
105
  */
106
106
  const fastifyRabbit = (0, fastify_plugin.default)(async (fastify, opts) => {
107
107
  await validateOpts(opts);
108
- const { connection } = opts;
109
- decorateFastifyInstance(fastify, opts, new rabbitmq_client.Connection(connection));
108
+ const { connection, namespace = "" } = opts;
109
+ const label = namespace === "" ? "(default)" : namespace;
110
+ fastify.log.debug("[fastify-rabbitmq] Creating connection for namespace %s", label);
111
+ const c = new rabbitmq_client.Connection(connection);
112
+ watchConnection(fastify, c, label);
113
+ decorateFastifyInstance(fastify, opts, c);
114
+ fastify.addHook("onClose", async () => {
115
+ const started = Date.now();
116
+ fastify.log.debug("[fastify-rabbitmq] Closing connection for namespace %s", label);
117
+ try {
118
+ await c.close();
119
+ fastify.log.info("[fastify-rabbitmq] Connection for namespace %s closed in %dms", label, Date.now() - started);
120
+ } catch (error) {
121
+ fastify.log.error({ err: error }, "[fastify-rabbitmq] Failed to close connection for namespace %s", label);
122
+ }
123
+ });
110
124
  });
125
+ /**
126
+ * Log the connection's lifecycle events. The 'error' listener also keeps a
127
+ * refused or dropped connection from becoming an unhandled 'error' event,
128
+ * which would crash the process (#164). rabbitmq-client keeps retrying in the
129
+ * background, so an error here is reported, not fatal.
130
+ * @since 3.4.1
131
+ * @param fastify
132
+ * @param c
133
+ * @param label
134
+ */
135
+ const watchConnection = (fastify, c, label) => {
136
+ c.on("error", (err) => {
137
+ fastify.log.error({ err }, "[fastify-rabbitmq] RabbitMQ connection error for namespace %s", label);
138
+ });
139
+ c.on("connection", () => {
140
+ fastify.log.info("[fastify-rabbitmq] RabbitMQ connection established for namespace %s", label);
141
+ });
142
+ c.on("connection.blocked", (reason) => {
143
+ fastify.log.warn("[fastify-rabbitmq] RabbitMQ connection blocked for namespace %s: %s", label, reason);
144
+ });
145
+ c.on("connection.unblocked", () => {
146
+ fastify.log.info("[fastify-rabbitmq] RabbitMQ connection unblocked for namespace %s", label);
147
+ });
148
+ };
111
149
  //#endregion
112
150
  Object.defineProperty(exports, "AMQPChannelError", {
113
151
  enumerable: true,
@@ -135,5 +173,3 @@ Object.defineProperty(exports, "ConsumerStatus", {
135
173
  });
136
174
  exports.decorateFastifyInstance = decorateFastifyInstance;
137
175
  exports.default = fastifyRabbit;
138
-
139
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.ts CHANGED
@@ -33,4 +33,3 @@ export { decorateFastifyInstance };
33
33
  export * from "./types";
34
34
  export type { AsyncMessage, Channel, Connection, ConnectionOptions, Consumer, ConsumerHandler, ConsumerProps, Envelope, HeaderFields, MessageBody, Publisher, PublisherProps, ReturnedMessage, RPCClient, RPCProps, SyncMessage, } from "rabbitmq-client";
35
35
  export { AMQPChannelError, AMQPConnectionError, AMQPError, ConsumerStatus, } from "rabbitmq-client";
36
- //# sourceMappingURL=index.d.ts.map
package/dist/index.mjs CHANGED
@@ -77,10 +77,46 @@ const decorateFastifyInstance = (fastify, options, connection) => {
77
77
  */
78
78
  const fastifyRabbit = fp(async (fastify, opts) => {
79
79
  await validateOpts(opts);
80
- const { connection } = opts;
81
- decorateFastifyInstance(fastify, opts, new Connection(connection));
80
+ const { connection, namespace = "" } = opts;
81
+ const label = namespace === "" ? "(default)" : namespace;
82
+ fastify.log.debug("[fastify-rabbitmq] Creating connection for namespace %s", label);
83
+ const c = new Connection(connection);
84
+ watchConnection(fastify, c, label);
85
+ decorateFastifyInstance(fastify, opts, c);
86
+ fastify.addHook("onClose", async () => {
87
+ const started = Date.now();
88
+ fastify.log.debug("[fastify-rabbitmq] Closing connection for namespace %s", label);
89
+ try {
90
+ await c.close();
91
+ fastify.log.info("[fastify-rabbitmq] Connection for namespace %s closed in %dms", label, Date.now() - started);
92
+ } catch (error) {
93
+ fastify.log.error({ err: error }, "[fastify-rabbitmq] Failed to close connection for namespace %s", label);
94
+ }
95
+ });
82
96
  });
97
+ /**
98
+ * Log the connection's lifecycle events. The 'error' listener also keeps a
99
+ * refused or dropped connection from becoming an unhandled 'error' event,
100
+ * which would crash the process (#164). rabbitmq-client keeps retrying in the
101
+ * background, so an error here is reported, not fatal.
102
+ * @since 3.4.1
103
+ * @param fastify
104
+ * @param c
105
+ * @param label
106
+ */
107
+ const watchConnection = (fastify, c, label) => {
108
+ c.on("error", (err) => {
109
+ fastify.log.error({ err }, "[fastify-rabbitmq] RabbitMQ connection error for namespace %s", label);
110
+ });
111
+ c.on("connection", () => {
112
+ fastify.log.info("[fastify-rabbitmq] RabbitMQ connection established for namespace %s", label);
113
+ });
114
+ c.on("connection.blocked", (reason) => {
115
+ fastify.log.warn("[fastify-rabbitmq] RabbitMQ connection blocked for namespace %s: %s", label, reason);
116
+ });
117
+ c.on("connection.unblocked", () => {
118
+ fastify.log.info("[fastify-rabbitmq] RabbitMQ connection unblocked for namespace %s", label);
119
+ });
120
+ };
83
121
  //#endregion
84
122
  export { AMQPChannelError, AMQPConnectionError, AMQPError, ConsumerStatus, decorateFastifyInstance, fastifyRabbit as default };
85
-
86
- //# sourceMappingURL=index.mjs.map
package/dist/types.d.ts CHANGED
@@ -10,4 +10,3 @@ export declare namespace fastifyRabbitMQ {
10
10
  [namespace: string]: RabbitMQConnection;
11
11
  }
12
12
  }
13
- //# sourceMappingURL=types.d.ts.map
@@ -13,4 +13,3 @@ import { FastifyRabbitMQOptions } from "./decorate";
13
13
  * @param options
14
14
  */
15
15
  export declare const validateOpts: (options: FastifyRabbitMQOptions) => Promise<void>;
16
- //# sourceMappingURL=validation.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify-rabbitmq",
3
- "version": "3.4.0",
3
+ "version": "3.4.1",
4
4
  "description": "A Fastify RabbitMQ Plugin Developed in Pure TypeScript.",
5
5
  "keywords": [
6
6
  "rabbitmq-client",
@@ -42,6 +42,7 @@
42
42
  ],
43
43
  "scripts": {
44
44
  "build": "tsdown && tsc --emitDeclarationOnly",
45
+ "check:pack": "node scripts/checkPack.mjs",
45
46
  "clean": "rm -rf coverage docs dist temp",
46
47
  "lint": "eslint .",
47
48
  "lint:fix": "eslint . --fix",
@@ -1 +0,0 @@
1
- {"version":3,"file":"decorate.d.ts","sourceRoot":"","sources":["../src/decorate.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAAC;IACvC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,MAAM;IACjB,oEAAoE;;;;IAKpE,6DAA6D;;;;IAK7D,mEAAmE;;;;CAKpE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["RabbitMQConnection"],"sources":["../src/errors.ts","../src/validation.ts","../src/index.ts"],"sourcesContent":["/*\nMIT License\n\nCopyright (c) 2026 Shane Froebel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\nimport createError from \"@fastify/error\";\n\nexport const errors = {\n /** Error if there is an invalid option used during registration. */\n FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS: createError(\n \"FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS\",\n \"Invalid options: %s\",\n ),\n /** Error if there is an setup error of the plugin itself. */\n FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS: createError(\n \"FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS\",\n \"Setup error: %s\",\n ),\n /** If an invalid usage error was done, this error would pop up. */\n FASTIFY_RABBIT_MQ_ERR_USAGE: createError(\n \"FASTIFY_RABBIT_MQ_ERR_USAGE\",\n \"Usage error: %s\",\n ),\n};\n","/*\nMIT License\n\nCopyright (c) 2026 Shane Froebel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\nimport { FastifyRabbitMQOptions } from \"./decorate\";\nimport { errors } from \"./errors\";\n\n/**\n * Validate Options\n *\n * The plugin validates only the *shape* of `connection` -- that it is a\n * non-empty connection string or a `ConnectionOptions` object. Parsing the URL\n * and validating the broker options (hosts, TLS, reconnect, etc.) is delegated\n * to `rabbitmq-client`. The shape guard exists because `new Connection(...)`\n * accepts garbage (a number, an array, `null`, `{}`) without throwing and then\n * silently fails to connect at runtime; rejecting it here surfaces a clear\n * registration-time error instead.\n * @since 1.0.0\n * @param options\n */\nexport const validateOpts = async (\n options: FastifyRabbitMQOptions,\n): Promise<void> => {\n const { connection } = options;\n\n // Mandatory\n if (connection === undefined) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS(\n \"connection must be defined.\",\n );\n }\n\n if (typeof connection === \"string\") {\n if (connection.length === 0) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS(\n \"connection string must not be empty.\",\n );\n }\n return;\n }\n\n const isConnectionOptions =\n typeof connection === \"object\" &&\n connection !== null &&\n !Array.isArray(connection);\n\n if (!isConnectionOptions) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS(\n \"connection must be a connection string or a ConnectionOptions object.\",\n );\n }\n};\n","/*\nMIT License\n\nCopyright (c) 2026 Shane Froebel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\nimport { FastifyInstance } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { Connection as RabbitMQConnection } from \"rabbitmq-client\";\n\nimport { FastifyRabbitMQOptions } from \"./decorate\";\nimport { errors } from \"./errors\";\nimport { validateOpts } from \"./validation\";\nexport { type FastifyRabbitMQOptions } from \"./decorate\";\n\n/**\n * How we talk with Fastify\n * @since 1.0.0\n * @param fastify\n * @param options\n * @param connection\n */\nconst decorateFastifyInstance = (\n fastify: FastifyInstance,\n options: FastifyRabbitMQOptions,\n connection: any,\n): void => {\n const { namespace = \"\" } = options;\n\n if (namespace !== undefined && namespace !== \"\") {\n fastify.log.debug(\"[fastify-rabbitmq] Namespace Attempt: %s\", namespace);\n }\n if (namespace !== undefined && namespace !== \"\") {\n if (fastify.rabbitmq === undefined) {\n fastify.decorate(\"rabbitmq\", Object.create(null));\n }\n\n if (fastify.rabbitmq[namespace] !== undefined) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS(\n `Already registered with namespace: ${namespace}`,\n );\n }\n\n fastify.log.trace(\n `[fastify-rabbitmq] Decorate Fastify with Namespace: ${namespace}`,\n );\n fastify.rabbitmq[namespace] = connection;\n } else {\n if (fastify.rabbitmq !== undefined) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS(\n \"Already registered.\",\n );\n }\n }\n\n if (fastify.rabbitmq === undefined) {\n fastify.log.trace(\"[fastify-rabbitmq] Decorate Fastify\");\n fastify.decorate(\"rabbitmq\", connection);\n }\n};\n\n/**\n * Main Function\n * @since 1.0.0\n * @example\n * This is the basics on how to use this plugin:\n * ```js\n * app.register(fastifyRabbit, {\n * connection: 'amqp://guest:guest@localhost'\n * })\n * ```\n * This will allow you to read from your Fastify \"object\" and\n * use this plugin at the \"rabbitmq\" level. From there you can execute and maintain\n * the RabbitMQ Connection using the 'rabbitmq-client' package, which is wrapping around\n * this plugin to execute functions it provides.\n *\n * @see [https://cody-greene.github.io/node-rabbitmq-client/latest/index.html](https://cody-greene.github.io/node-rabbitmq-client/latest/index.html)\n *\n */\nconst fastifyRabbit = fp<FastifyRabbitMQOptions>(async (fastify, opts) => {\n await validateOpts(opts);\n\n const { connection } = opts;\n\n const c = new RabbitMQConnection(connection);\n\n decorateFastifyInstance(fastify, opts, c);\n});\n\nexport default fastifyRabbit;\n\nexport { decorateFastifyInstance };\n\nexport * from \"./types\";\n\n// Re-export the rabbitmq-client surface so consumers import from this package\n// instead of reaching for the wrapped client. These are the exact types the\n// app.rabbitmq decorator hands back, so they stay correct without owning a\n// parallel definition.\nexport type {\n AsyncMessage,\n Channel,\n Connection,\n ConnectionOptions,\n Consumer,\n ConsumerHandler,\n ConsumerProps,\n Envelope,\n HeaderFields,\n MessageBody,\n Publisher,\n PublisherProps,\n ReturnedMessage,\n RPCClient,\n RPCProps,\n SyncMessage,\n} from \"rabbitmq-client\";\nexport {\n AMQPChannelError,\n AMQPConnectionError,\n AMQPError,\n ConsumerStatus,\n} from \"rabbitmq-client\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,SAAS;;CAEpB,qCAAA,GAAA,eAAA,QAAA,CACE,sCACA,qBACF;;CAEA,qCAAA,GAAA,eAAA,QAAA,CACE,sCACA,iBACF;;CAEA,8BAAA,GAAA,eAAA,QAAA,CACE,+BACA,iBACF;AACF;;;;;;;;;;;;;;;;ACFA,MAAa,eAAe,OAC1B,YACkB;CAClB,MAAM,EAAE,eAAe;CAGvB,IAAI,eAAe,KAAA,GACjB,MAAM,IAAI,OAAO,mCACf,6BACF;CAGF,IAAI,OAAO,eAAe,UAAU;EAClC,IAAI,WAAW,WAAW,GACxB,MAAM,IAAI,OAAO,mCACf,sCACF;EAEF;CACF;CAOA,IAAI,EAJF,OAAO,eAAe,YACtB,eAAe,QACf,CAAC,MAAM,QAAQ,UAAU,IAGzB,MAAM,IAAI,OAAO,mCACf,uEACF;AAEJ;;;;;;;;;;AC/BA,MAAM,2BACJ,SACA,SACA,eACS;CACT,MAAM,EAAE,YAAY,OAAO;CAE3B,IAAI,cAAc,KAAA,KAAa,cAAc,IAC3C,QAAQ,IAAI,MAAM,4CAA4C,SAAS;CAEzE,IAAI,cAAc,KAAA,KAAa,cAAc,IAAI;EAC/C,IAAI,QAAQ,aAAa,KAAA,GACvB,QAAQ,SAAS,YAAY,OAAO,OAAO,IAAI,CAAC;EAGlD,IAAI,QAAQ,SAAS,eAAe,KAAA,GAClC,MAAM,IAAI,OAAO,mCACf,sCAAsC,WACxC;EAGF,QAAQ,IAAI,MACV,uDAAuD,WACzD;EACA,QAAQ,SAAS,aAAa;CAChC,OACE,IAAI,QAAQ,aAAa,KAAA,GACvB,MAAM,IAAI,OAAO,mCACf,qBACF;CAIJ,IAAI,QAAQ,aAAa,KAAA,GAAW;EAClC,QAAQ,IAAI,MAAM,qCAAqC;EACvD,QAAQ,SAAS,YAAY,UAAU;CACzC;AACF;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,iBAAA,GAAA,eAAA,QAAA,CAA2C,OAAO,SAAS,SAAS;CACxE,MAAM,aAAa,IAAI;CAEvB,MAAM,EAAE,eAAe;CAIvB,wBAAwB,SAAS,MAAM,IAFzBA,gBAAAA,WAAmB,UAEM,CAAC;AAC1C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGpD,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;GAMG;AACH,QAAA,MAAM,uBAAuB,GAC3B,SAAS,eAAe,EACxB,SAAS,sBAAsB,EAC/B,YAAY,GAAG,KACd,IAiCF,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,aAAa,wLAQjB,CAAC;AAEH,eAAe,aAAa,CAAC;AAE7B,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,cAAc,SAAS,CAAC;AAMxB,YAAY,EACV,YAAY,EACZ,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,SAAS,EACT,cAAc,EACd,eAAe,EACf,SAAS,EACT,QAAQ,EACR,WAAW,GACZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,EACT,cAAc,GACf,MAAM,iBAAiB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":["RabbitMQConnection"],"sources":["../src/errors.ts","../src/validation.ts","../src/index.ts"],"sourcesContent":["/*\nMIT License\n\nCopyright (c) 2026 Shane Froebel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\nimport createError from \"@fastify/error\";\n\nexport const errors = {\n /** Error if there is an invalid option used during registration. */\n FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS: createError(\n \"FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS\",\n \"Invalid options: %s\",\n ),\n /** Error if there is an setup error of the plugin itself. */\n FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS: createError(\n \"FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS\",\n \"Setup error: %s\",\n ),\n /** If an invalid usage error was done, this error would pop up. */\n FASTIFY_RABBIT_MQ_ERR_USAGE: createError(\n \"FASTIFY_RABBIT_MQ_ERR_USAGE\",\n \"Usage error: %s\",\n ),\n};\n","/*\nMIT License\n\nCopyright (c) 2026 Shane Froebel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\nimport { FastifyRabbitMQOptions } from \"./decorate\";\nimport { errors } from \"./errors\";\n\n/**\n * Validate Options\n *\n * The plugin validates only the *shape* of `connection` -- that it is a\n * non-empty connection string or a `ConnectionOptions` object. Parsing the URL\n * and validating the broker options (hosts, TLS, reconnect, etc.) is delegated\n * to `rabbitmq-client`. The shape guard exists because `new Connection(...)`\n * accepts garbage (a number, an array, `null`, `{}`) without throwing and then\n * silently fails to connect at runtime; rejecting it here surfaces a clear\n * registration-time error instead.\n * @since 1.0.0\n * @param options\n */\nexport const validateOpts = async (\n options: FastifyRabbitMQOptions,\n): Promise<void> => {\n const { connection } = options;\n\n // Mandatory\n if (connection === undefined) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS(\n \"connection must be defined.\",\n );\n }\n\n if (typeof connection === \"string\") {\n if (connection.length === 0) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS(\n \"connection string must not be empty.\",\n );\n }\n return;\n }\n\n const isConnectionOptions =\n typeof connection === \"object\" &&\n connection !== null &&\n !Array.isArray(connection);\n\n if (!isConnectionOptions) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS(\n \"connection must be a connection string or a ConnectionOptions object.\",\n );\n }\n};\n","/*\nMIT License\n\nCopyright (c) 2026 Shane Froebel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\nimport { FastifyInstance } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { Connection as RabbitMQConnection } from \"rabbitmq-client\";\n\nimport { FastifyRabbitMQOptions } from \"./decorate\";\nimport { errors } from \"./errors\";\nimport { validateOpts } from \"./validation\";\nexport { type FastifyRabbitMQOptions } from \"./decorate\";\n\n/**\n * How we talk with Fastify\n * @since 1.0.0\n * @param fastify\n * @param options\n * @param connection\n */\nconst decorateFastifyInstance = (\n fastify: FastifyInstance,\n options: FastifyRabbitMQOptions,\n connection: any,\n): void => {\n const { namespace = \"\" } = options;\n\n if (namespace !== undefined && namespace !== \"\") {\n fastify.log.debug(\"[fastify-rabbitmq] Namespace Attempt: %s\", namespace);\n }\n if (namespace !== undefined && namespace !== \"\") {\n if (fastify.rabbitmq === undefined) {\n fastify.decorate(\"rabbitmq\", Object.create(null));\n }\n\n if (fastify.rabbitmq[namespace] !== undefined) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS(\n `Already registered with namespace: ${namespace}`,\n );\n }\n\n fastify.log.trace(\n `[fastify-rabbitmq] Decorate Fastify with Namespace: ${namespace}`,\n );\n fastify.rabbitmq[namespace] = connection;\n } else {\n if (fastify.rabbitmq !== undefined) {\n throw new errors.FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS(\n \"Already registered.\",\n );\n }\n }\n\n if (fastify.rabbitmq === undefined) {\n fastify.log.trace(\"[fastify-rabbitmq] Decorate Fastify\");\n fastify.decorate(\"rabbitmq\", connection);\n }\n};\n\n/**\n * Main Function\n * @since 1.0.0\n * @example\n * This is the basics on how to use this plugin:\n * ```js\n * app.register(fastifyRabbit, {\n * connection: 'amqp://guest:guest@localhost'\n * })\n * ```\n * This will allow you to read from your Fastify \"object\" and\n * use this plugin at the \"rabbitmq\" level. From there you can execute and maintain\n * the RabbitMQ Connection using the 'rabbitmq-client' package, which is wrapping around\n * this plugin to execute functions it provides.\n *\n * @see [https://cody-greene.github.io/node-rabbitmq-client/latest/index.html](https://cody-greene.github.io/node-rabbitmq-client/latest/index.html)\n *\n */\nconst fastifyRabbit = fp<FastifyRabbitMQOptions>(async (fastify, opts) => {\n await validateOpts(opts);\n\n const { connection } = opts;\n\n const c = new RabbitMQConnection(connection);\n\n decorateFastifyInstance(fastify, opts, c);\n});\n\nexport default fastifyRabbit;\n\nexport { decorateFastifyInstance };\n\nexport * from \"./types\";\n\n// Re-export the rabbitmq-client surface so consumers import from this package\n// instead of reaching for the wrapped client. These are the exact types the\n// app.rabbitmq decorator hands back, so they stay correct without owning a\n// parallel definition.\nexport type {\n AsyncMessage,\n Channel,\n Connection,\n ConnectionOptions,\n Consumer,\n ConsumerHandler,\n ConsumerProps,\n Envelope,\n HeaderFields,\n MessageBody,\n Publisher,\n PublisherProps,\n ReturnedMessage,\n RPCClient,\n RPCProps,\n SyncMessage,\n} from \"rabbitmq-client\";\nexport {\n AMQPChannelError,\n AMQPConnectionError,\n AMQPError,\n ConsumerStatus,\n} from \"rabbitmq-client\";\n"],"mappings":";;;;AAwBA,MAAa,SAAS;;CAEpB,oCAAoC,YAClC,sCACA,qBACF;;CAEA,oCAAoC,YAClC,sCACA,iBACF;;CAEA,6BAA6B,YAC3B,+BACA,iBACF;AACF;;;;;;;;;;;;;;;;ACFA,MAAa,eAAe,OAC1B,YACkB;CAClB,MAAM,EAAE,eAAe;CAGvB,IAAI,eAAe,KAAA,GACjB,MAAM,IAAI,OAAO,mCACf,6BACF;CAGF,IAAI,OAAO,eAAe,UAAU;EAClC,IAAI,WAAW,WAAW,GACxB,MAAM,IAAI,OAAO,mCACf,sCACF;EAEF;CACF;CAOA,IAAI,EAJF,OAAO,eAAe,YACtB,eAAe,QACf,CAAC,MAAM,QAAQ,UAAU,IAGzB,MAAM,IAAI,OAAO,mCACf,uEACF;AAEJ;;;;;;;;;;AC/BA,MAAM,2BACJ,SACA,SACA,eACS;CACT,MAAM,EAAE,YAAY,OAAO;CAE3B,IAAI,cAAc,KAAA,KAAa,cAAc,IAC3C,QAAQ,IAAI,MAAM,4CAA4C,SAAS;CAEzE,IAAI,cAAc,KAAA,KAAa,cAAc,IAAI;EAC/C,IAAI,QAAQ,aAAa,KAAA,GACvB,QAAQ,SAAS,YAAY,OAAO,OAAO,IAAI,CAAC;EAGlD,IAAI,QAAQ,SAAS,eAAe,KAAA,GAClC,MAAM,IAAI,OAAO,mCACf,sCAAsC,WACxC;EAGF,QAAQ,IAAI,MACV,uDAAuD,WACzD;EACA,QAAQ,SAAS,aAAa;CAChC,OACE,IAAI,QAAQ,aAAa,KAAA,GACvB,MAAM,IAAI,OAAO,mCACf,qBACF;CAIJ,IAAI,QAAQ,aAAa,KAAA,GAAW;EAClC,QAAQ,IAAI,MAAM,qCAAqC;EACvD,QAAQ,SAAS,YAAY,UAAU;CACzC;AACF;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,gBAAgB,GAA2B,OAAO,SAAS,SAAS;CACxE,MAAM,aAAa,IAAI;CAEvB,MAAM,EAAE,eAAe;CAIvB,wBAAwB,SAAS,MAAM,IAFzBA,WAAmB,UAEM,CAAC;AAC1C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEnE,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAiB,eAAe;QAC9B,kCAAkC;QAClC,QAAQ,EAAE,eAAe,CAAC,iBAAiB,GAAG,kBAAkB,CAAC;KAClE;CACF;AAGD,MAAM,CAAC,OAAO,WAAW,eAAe,CAAC;IACvC,UAAiB,iBAAiB;QAChC,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAAC;KACzC;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGpD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GACvB,SAAS,sBAAsB,KAC9B,OAAO,CAAC,IAAI,CA6Bd,CAAC"}