diff --git a/packages/qified/README.md b/packages/qified/README.md index 000aa8f..b876ddd 100644 --- a/packages/qified/README.md +++ b/packages/qified/README.md @@ -28,6 +28,30 @@ Task and Message Queues with Multiple Providers * Customizable Compress / Decompress Handlers (Coming in v1.0.0) * Provider Fail Over Support +# Table of Contents +- [Installation](#installation) +- [Quick Start](#quick-start) +- [Constructor](#constructor) +- [Properties](#properties) +- [Methods](#methods) + - [subscribe](#subscribe) + - [publish](#publish) + - [unsubscribe](#unsubscribe) + - [disconnect](#disconnect) +- [Events](#events) + - [Available Events](#available-events) + - [Listening to Events](#listening-to-events) + - [Error Handling with Events](#error-handling-with-events) +- [Hooks](#hooks) + - [Available Hooks](#available-hooks) + - [Using Hooks](#using-hooks) + - [Modifying Data with Before Hooks](#modifying-data-with-before-hooks) + - [Modifying Topics with Before Hooks](#modifying-topics-with-before-hooks) + - [Multiple Hooks](#multiple-hooks) + - [Hooks vs Events](#hooks-vs-events) +- [Providers](#providers) +- [Development and Testing](#development-and-testing) +- [License](#license) # Installation @@ -326,7 +350,7 @@ The following hooks are available via the `QifiedHooks` enum: ## Using Hooks -Use the `onHook()` method to register a hook handler: +Use the `onHook()` method to register a hook handler. Hooks use the `IHook` object format from [Hookified](https://hookified.org): ```js import { Qified, MemoryMessageProvider, QifiedHooks } from 'qified'; @@ -335,15 +359,30 @@ const qified = new Qified({ messageProviders: new MemoryMessageProvider() }); -// Register a before hook -qified.onHook(QifiedHooks.beforePublish, async (context) => { - console.log('About to publish to:', context.topic); +// Register a before hook using IHook object +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + console.log('About to publish to:', context.topic); + } }); -// Register an after hook -qified.onHook(QifiedHooks.afterPublish, async (context) => { - console.log('Published message:', context.message.id); +// Register an after hook with an id for later removal +qified.onHook({ + id: 'publish-logger', + event: QifiedHooks.afterPublish, + handler: async (context) => { + console.log('Published message:', context.message.id); + } }); + +// Register with options to control position +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + console.log('This runs first'); + } +}, { position: 'Top' }); ``` ## Modifying Data with Before Hooks @@ -358,28 +397,34 @@ const qified = new Qified({ }); // Add timestamp and headers to all messages -qified.onHook(QifiedHooks.beforePublish, async (context) => { - // Add timestamp if not present - context.message.timestamp = context.message.timestamp ?? Date.now(); - - // Add custom headers - context.message.headers = { - ...context.message.headers, - 'x-processed-by': 'qified', - 'x-environment': process.env.NODE_ENV - }; +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + // Add timestamp if not present + context.message.timestamp = context.message.timestamp ?? Date.now(); + + // Add custom headers + context.message.headers = { + ...context.message.headers, + 'x-processed-by': 'qified', + 'x-environment': process.env.NODE_ENV + }; + } }); // Modify message data -qified.onHook(QifiedHooks.beforePublish, async (context) => { - // Add metadata to the message data - context.message.data = { - ...context.message.data, - _meta: { - version: '1.0', - source: 'api' - } - }; +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + // Add metadata to the message data + context.message.data = { + ...context.message.data, + _meta: { + version: '1.0', + source: 'api' + } + }; + } }); // Subscribe to receive messages @@ -406,8 +451,11 @@ You can also modify the topic in before hooks: ```js // Route all messages to a prefixed topic -qified.onHook(QifiedHooks.beforePublish, async (context) => { - context.topic = `production/${context.topic}`; +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + context.topic = `production/${context.topic}`; + } }); // Subscribe to the prefixed topic @@ -430,20 +478,37 @@ await qified.publish('events', { Multiple hooks for the same event execute in the order they were registered: ```js -// First hook - runs first -qified.onHook(QifiedHooks.beforePublish, async (context) => { - context.message.timestamp = Date.now(); +// First hook - runs first (default position is 'Bottom') +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + context.message.timestamp = Date.now(); + } }); // Second hook - runs second, can see changes from first hook -qified.onHook(QifiedHooks.beforePublish, async (context) => { - context.message.headers = { 'x-timestamp': String(context.message.timestamp) }; +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + context.message.headers = { 'x-timestamp': String(context.message.timestamp) }; + } }); // Third hook - runs third -qified.onHook(QifiedHooks.beforePublish, async (context) => { - console.log('Final message:', context.message); +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + console.log('Final message:', context.message); + } }); + +// Use position option to insert at the top +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + console.log('This runs before all other hooks'); + } +}, { position: 'Top' }); ``` ## Hooks vs Events @@ -458,8 +523,11 @@ Both hooks and events are available, but they serve different purposes: ```js // Hook - can modify the message before it's published -qified.onHook(QifiedHooks.beforePublish, async (context) => { - context.message.timestamp = Date.now(); +qified.onHook({ + event: QifiedHooks.beforePublish, + handler: async (context) => { + context.message.timestamp = Date.now(); + } }); // Event - notified after publish completes (cannot modify) diff --git a/packages/qified/package.json b/packages/qified/package.json index 2a6dc2c..049d1f9 100644 --- a/packages/qified/package.json +++ b/packages/qified/package.json @@ -46,6 +46,6 @@ "LICENSE" ], "dependencies": { - "hookified": "^1.15.1" + "hookified": "^2.1.0" } } \ No newline at end of file diff --git a/packages/rabbitmq/package.json b/packages/rabbitmq/package.json index 640628d..ddc5361 100644 --- a/packages/rabbitmq/package.json +++ b/packages/rabbitmq/package.json @@ -34,7 +34,7 @@ "license": "MIT", "dependencies": { "amqplib": "^0.10.9", - "hookified": "^1.15.1" + "hookified": "^2.1.0" }, "peerDependencies": { "qified": "workspace:^" diff --git a/packages/redis/package.json b/packages/redis/package.json index 21d6473..6a8c826 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -33,7 +33,7 @@ "author": "Jared Wray ", "license": "MIT", "dependencies": { - "hookified": "^1.15.1", + "hookified": "^2.1.0", "redis": "^5.10.0" }, "peerDependencies": { diff --git a/packages/redis/test/task.test.ts b/packages/redis/test/task.test.ts index 8ec12bc..ff00e41 100644 --- a/packages/redis/test/task.test.ts +++ b/packages/redis/test/task.test.ts @@ -109,6 +109,7 @@ describe("RedisTaskProvider", () => { beforeEach(async () => { provider = new RedisTaskProvider(); + provider.throwOnEmptyListeners = false; await provider.connect(); await provider.clearQueue(testQueue); }); @@ -468,6 +469,7 @@ describe("RedisTaskProvider", () => { retries: 3, pollInterval: 100, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -502,6 +504,7 @@ describe("RedisTaskProvider", () => { timeout: 100, pollInterval: 50, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -539,6 +542,7 @@ describe("RedisTaskProvider", () => { timeout: 200, pollInterval: 50, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -952,6 +956,7 @@ describe("RedisTaskProvider", () => { retries: 2, pollInterval: 30, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -985,6 +990,7 @@ describe("RedisTaskProvider", () => { timeout: 20, pollInterval: 30, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -1074,6 +1080,7 @@ describe("RedisTaskProvider", () => { timeout: 5000, pollInterval: 50, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -1111,6 +1118,7 @@ describe("RedisTaskProvider", () => { test("should handle processQueue when _active becomes false after getClient", async () => { // This test covers line 376 (early return after getClient when _active is false) const customProvider = new RedisTaskProvider({ pollInterval: 30 }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -1142,6 +1150,7 @@ describe("RedisTaskProvider", () => { retries: 1, pollInterval: 20, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -1211,6 +1220,7 @@ describe("RedisTaskProvider", () => { retries: 5, pollInterval: 20, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -1249,6 +1259,7 @@ describe("RedisTaskProvider", () => { retries: 1, // Only 1 retry allowed pollInterval: 15, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); @@ -1296,6 +1307,7 @@ describe("RedisTaskProvider", () => { retries: 5, pollInterval: 15, }); + customProvider.throwOnEmptyListeners = false; await customProvider.connect(); await customProvider.clearQueue(testQueue); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 868ef6b..bade1a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ importers: packages/qified: dependencies: hookified: - specifier: ^1.15.1 - version: 1.15.1 + specifier: ^2.1.0 + version: 2.1.0 packages/rabbitmq: dependencies: @@ -60,8 +60,8 @@ importers: specifier: ^0.10.9 version: 0.10.9 hookified: - specifier: ^1.15.1 - version: 1.15.1 + specifier: ^2.1.0 + version: 2.1.0 qified: specifier: workspace:^ version: link:../qified @@ -73,8 +73,8 @@ importers: packages/redis: dependencies: hookified: - specifier: ^1.15.1 - version: 1.15.1 + specifier: ^2.1.0 + version: 2.1.0 qified: specifier: workspace:^ version: link:../qified @@ -1488,6 +1488,9 @@ packages: hookified@1.15.1: resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + hookified@2.1.0: + resolution: {integrity: sha512-ootKng4eaxNxa7rx6FJv2YKef3DuhqbEj3l70oGXwddPQEEnISm50TEZQclqiLTAtilT2nu7TErtCO523hHkyg==} + html-dom-parser@5.1.8: resolution: {integrity: sha512-MCIUng//mF2qTtGHXJWr6OLfHWmg3Pm8ezpfiltF83tizPWY17JxT4dRLE8lykJ5bChJELoY3onQKPbufJHxYA==} @@ -3845,6 +3848,8 @@ snapshots: hookified@1.15.1: {} + hookified@2.1.0: {} + html-dom-parser@5.1.8: dependencies: domhandler: 5.0.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 61dea49..36ce617 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,6 +3,9 @@ packages: minimumReleaseAge: 2880 +minimumReleaseAgeExclude: + - hookified + onlyBuiltDependencies: - esbuild - unrs-resolver