{"id":17798,"library":"mhook","title":"Node.js Middleware Hooks","description":"`mhook` is a small Node.js library that provides middleware-like hook functionality, particularly useful for structuring relations within entities in applications like ODMs or ORMs. It allows developers to define a set of named \"actions\" and then bind multiple hook functions to these actions. When an action is \"triggered,\" all associated hooks are executed sequentially. Hooks can be asynchronous, supporting both traditional Node.js error-first callbacks and Promises for indicating completion or failure. The current stable version is 1.0.1. Its key differentiators include a simple API for sequential hook execution and built-in support for both callback and promise-based asynchronous operations, making it flexible for various async patterns. It focuses purely on the hooking mechanism without dictating how the hooked objects should behave beyond providing `on` and `trigger` methods.","status":"maintenance","version":"1.0.1","language":"javascript","source_language":"en","source_url":"git://github.com/2do2go/mhook","tags":["javascript","hook","middlewre","trigger","event"],"install":[{"cmd":"npm install mhook","lang":"bash","label":"npm"},{"cmd":"yarn add mhook","lang":"bash","label":"yarn"},{"cmd":"pnpm add mhook","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"This package is CommonJS-only. Named exports like `Hook` are properties of the main module object accessed via `require()` and can be destructured.","wrong":"import { Hook } from 'mhook';","symbol":"Hook","correct":"const { Hook } = require('mhook');"},{"note":"The module does not have a default export. The `Hook` constructor is available as a property of the object exported by the module.","wrong":"import Hook from 'mhook';","symbol":"Hook","correct":"const mhook = require('mhook');\nconst Hook = mhook.Hook;"},{"note":"This imports the entire module object, from which `Hook` can be accessed as `mhook.Hook`.","symbol":"mhook module object","correct":"const mhook = require('mhook');"}],"quickstart":{"code":"const { Hook } = require('mhook'); // Correct CJS way to get Hook\n\n// 1. Define actions for the hook instance\nconst hook = new Hook(['beforeUpdate', 'afterUpdate', 'afterRemove']);\n\n// 2. Add a hook with a callback\nhook.on('beforeUpdate', function(done) {\n  console.log('Hook 1: beforeUpdate (callback style) started.');\n  // Simulate async work\n  setTimeout(() => {\n    console.log('Hook 1: beforeUpdate (callback style) finished.');\n    done(); // Signal completion\n  }, 100);\n});\n\n// 3. Add another hook with a promise\nhook.on('beforeUpdate', function(data) {\n  console.log('Hook 2: beforeUpdate (promise style) started with data:', data);\n  return new Promise((resolve) => {\n    // Simulate async work\n    setTimeout(() => {\n      console.log('Hook 2: beforeUpdate (promise style) finished.');\n      resolve(); // Signal completion\n    }, 50);\n  });\n});\n\n// 4. Trigger the 'beforeUpdate' action with arguments\nconsole.log('\\nTriggering beforeUpdate (callback-based)...');\nhook.trigger('beforeUpdate', [{ id: 1, name: 'oldName' }], function(err) {\n  if (err) {\n    console.error('Trigger failed (callback):', err);\n  } else {\n    console.log('All beforeUpdate hooks done (callback-based).');\n  }\n});\n\n// 5. Trigger the 'beforeUpdate' action again, using the promise return\nconsole.log('\\nTriggering beforeUpdate (promise-based)...');\nhook.trigger('beforeUpdate', [{ id: 2, name: 'anotherName' }])\n  .then(() => {\n    console.log('All beforeUpdate hooks successfully done (promise-based).');\n  })\n  .catch((err) => {\n    console.error('One of the beforeUpdate hooks failed (promise-based):', err);\n  });","lang":"javascript","description":"This example demonstrates how to define actions, bind both callback-based and promise-based hook functions to an action, and then trigger that action, showing how arguments are passed and results are handled."},"warnings":[{"fix":"Ensure all asynchronous `on` handler functions either return a `Promise` that resolves upon completion, or accept a `done` callback as their last argument and invoke `done()` (or `done(error)`) when their operation is finished.","message":"Asynchronous hook functions must explicitly signal completion by either returning a Promise or calling the `done` callback provided as the last argument. Failure to do so will cause the `trigger` operation to hang indefinitely, preventing subsequent hooks or the final callback from executing.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure that individual hook functions are efficient. For potentially long-running tasks, consider offloading them to worker threads or processing them asynchronously outside the main hook chain, if their completion isn't strictly necessary before subsequent hooks.","message":"`mhook` executes hooks sequentially. If a hook performs a long-running synchronous operation, or an asynchronous operation that takes a significant amount of time, it will block the execution of all subsequent hooks and the final `trigger` callback. This can lead to performance bottlenecks and unresponsiveness.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always define all possible action names in the array passed to the `Hook` constructor. Ensure consistency between declared actions and those used in `on()` and `trigger()` calls.","message":"The `Hook` constructor requires an array of predefined action strings (e.g., `['beforeUpdate', 'afterUpdate']`). Attempting to bind a hook using `hook.on()` or trigger an action using `hook.trigger()` with an action name not explicitly listed in the constructor will result in no operation or an error, as `mhook` does not dynamically register actions.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-23T00:00:00.000Z","next_check":"2026-07-22T00:00:00.000Z","problems":[{"fix":"Inspect all functions added via `hook.on()` for the affected action. Verify that asynchronous hooks either `return new Promise(...)` or accept `done` as the last argument and invoke `done()` when their work is complete.","cause":"An asynchronous hook function bound to the triggered action did not signal its completion (i.e., didn't return a Promise or call its `done` callback).","error":"My `hook.trigger()` call never finishes, and the callback or promise `then()` block is never executed."},{"fix":"Use CommonJS `require()` syntax: `const { Hook } = require('mhook');` for named exports or `const mhook = require('mhook');` and then `mhook.Hook`.","cause":"This package is CommonJS-only, and ES Module `import` syntax is not supported directly for its exports.","error":"TypeError: Cannot read properties of undefined (reading 'Hook') or 'Hook is not a constructor' when using `import { Hook } from 'mhook';`"},{"fix":"Ensure your hook function signature correctly accounts for the arguments you pass. If you pass `[obj]` and use a callback, the signature should be `function(obj, done)`. If you pass `[obj1, obj2]` and use a promise, it should be `function(obj1, obj2)`.","cause":"Hook functions declared with `function(done)` or `function()` are not correctly receiving the arguments passed in the `hookArgs` array of `trigger()`. The `done` callback (if used) is always the *last* argument.","error":"console output shows 'undefined' when passing arguments to hook functions using `hook.trigger('action', [obj])`."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}