fastify-rabbitmq
Version:
A Fastify RabbitMQ Plugin Developed in Pure TypeScript.
86 lines (85 loc) • 3.96 kB
JavaScript
import fp from "fastify-plugin";
import { AMQPChannelError, AMQPConnectionError, AMQPError, Connection, ConsumerStatus } from "rabbitmq-client";
import createError from "@fastify/error";
//#region src/errors.ts
const errors = {
/** Error if there is an invalid option used during registration. */
FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS: createError("FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS", "Invalid options: %s"),
/** Error if there is an setup error of the plugin itself. */
FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS: createError("FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS", "Setup error: %s"),
/** If an invalid usage error was done, this error would pop up. */
FASTIFY_RABBIT_MQ_ERR_USAGE: createError("FASTIFY_RABBIT_MQ_ERR_USAGE", "Usage error: %s")
};
//#endregion
//#region src/validation.ts
/**
* Validate Options
*
* The plugin validates only the *shape* of `connection` -- that it is a
* non-empty connection string or a `ConnectionOptions` object. Parsing the URL
* and validating the broker options (hosts, TLS, reconnect, etc.) is delegated
* to `rabbitmq-client`. The shape guard exists because `new Connection(...)`
* accepts garbage (a number, an array, `null`, `{}`) without throwing and then
* silently fails to connect at runtime; rejecting it here surfaces a clear
* registration-time error instead.
* @since 1.0.0
* @param options
*/
const validateOpts = async (options) => {
const { connection } = options;
if (connection === void 0) throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS("connection must be defined.");
if (typeof connection === "string") {
if (connection.length === 0) throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS("connection string must not be empty.");
return;
}
if (!(typeof connection === "object" && connection !== null && !Array.isArray(connection))) throw new errors.FASTIFY_RABBIT_MQ_ERR_INVALID_OPTS("connection must be a connection string or a ConnectionOptions object.");
};
//#endregion
//#region src/index.ts
/**
* How we talk with Fastify
* @since 1.0.0
* @param fastify
* @param options
* @param connection
*/
const decorateFastifyInstance = (fastify, options, connection) => {
const { namespace = "" } = options;
if (namespace !== void 0 && namespace !== "") fastify.log.debug("[fastify-rabbitmq] Namespace Attempt: %s", namespace);
if (namespace !== void 0 && namespace !== "") {
if (fastify.rabbitmq === void 0) fastify.decorate("rabbitmq", Object.create(null));
if (fastify.rabbitmq[namespace] !== void 0) throw new errors.FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS(`Already registered with namespace: ${namespace}`);
fastify.log.trace(`[fastify-rabbitmq] Decorate Fastify with Namespace: ${namespace}`);
fastify.rabbitmq[namespace] = connection;
} else if (fastify.rabbitmq !== void 0) throw new errors.FASTIFY_RABBIT_MQ_ERR_SETUP_ERRORS("Already registered.");
if (fastify.rabbitmq === void 0) {
fastify.log.trace("[fastify-rabbitmq] Decorate Fastify");
fastify.decorate("rabbitmq", connection);
}
};
/**
* Main Function
* @since 1.0.0
* @example
* This is the basics on how to use this plugin:
* ```js
* app.register(fastifyRabbit, {
* connection: 'amqp://guest:guest@localhost'
* })
* ```
* This will allow you to read from your Fastify "object" and
* use this plugin at the "rabbitmq" level. From there you can execute and maintain
* the RabbitMQ Connection using the 'rabbitmq-client' package, which is wrapping around
* this plugin to execute functions it provides.
*
* @see [https://cody-greene.github.io/node-rabbitmq-client/latest/index.html](https://cody-greene.github.io/node-rabbitmq-client/latest/index.html)
*
*/
const fastifyRabbit = fp(async (fastify, opts) => {
await validateOpts(opts);
const { connection } = opts;
decorateFastifyInstance(fastify, opts, new Connection(connection));
});
//#endregion
export { AMQPChannelError, AMQPConnectionError, AMQPError, ConsumerStatus, decorateFastifyInstance, fastifyRabbit as default };
//# sourceMappingURL=index.mjs.map