{"id":39839104,"url":"https://github.com/opbi/hooks","last_synced_at":"2026-01-18T13:25:19.608Z","repository":{"id":42889005,"uuid":"261447589","full_name":"opbi/hooks","owner":"opbi","description":"🎯 configurable decorators for automated observability and self-explanatory codebase","archived":false,"fork":false,"pushed_at":"2023-07-06T11:51:57.000Z","size":1731,"stargazers_count":11,"open_issues_count":12,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-29T17:32:47.219Z","etag":null,"topics":["consistency","decorators","maintainability","microservices","testability"],"latest_commit_sha":null,"homepage":"https://opbi.github.io/hooks/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/opbi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-05T11:39:55.000Z","updated_at":"2021-11-01T18:18:22.000Z","dependencies_parsed_at":"2022-09-03T15:02:53.704Z","dependency_job_id":null,"html_url":"https://github.com/opbi/hooks","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/opbi/hooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opbi%2Fhooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opbi%2Fhooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opbi%2Fhooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opbi%2Fhooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/opbi","download_url":"https://codeload.github.com/opbi/hooks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opbi%2Fhooks/sbom","scorecard":{"id":708189,"data":{"date":"2025-08-11","repo":{"name":"github.com/opbi/hooks","commit":"5ef35f9e3923bae8a90d26d456772a67058d62d3"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"70 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-h5c3-5r3r-rr8q","Warn: Project is vulnerable to: GHSA-rmvr-2pp2-xj38","Warn: Project is vulnerable to: GHSA-xx4v-prfh-6cgc","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-wg6g-ppvx-927h","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8mmm-9v2q-x3f9","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj","Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-8hfj-j24r-96c4","Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g","Warn: Project is vulnerable to: GHSA-qrpm-p2h7-hrv2","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-hj9c-8jmm-8c52","Warn: Project is vulnerable to: GHSA-3j8f-xvm3-ffx4","Warn: Project is vulnerable to: GHSA-4p35-cfcx-8653","Warn: Project is vulnerable to: GHSA-7f3x-x4pr-wqhj","Warn: Project is vulnerable to: GHSA-jpp7-7chh-cf67","Warn: Project is vulnerable to: GHSA-q6wq-5p59-983w","Warn: Project is vulnerable to: GHSA-j9fq-vwqv-2fm2","Warn: Project is vulnerable to: GHSA-pqw5-jmp5-px4v","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-x2pg-mjhr-2m5x","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4x5v-gmq8-25ch","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-38fc-wpqx-33j7","Warn: Project is vulnerable to: GHSA-g3ch-rx76-35fx","Warn: Project is vulnerable to: GHSA-g78m-2chm-r7qv","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T07:20:49.050Z","repository_id":42889005,"created_at":"2025-08-22T07:20:49.050Z","updated_at":"2025-08-22T07:20:49.050Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28536751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T13:04:05.990Z","status":"ssl_error","status_checked_at":"2026-01-18T13:01:44.092Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["consistency","decorators","maintainability","microservices","testability"],"created_at":"2026-01-18T13:25:19.074Z","updated_at":"2026-01-18T13:25:19.603Z","avatar_url":"https://github.com/opbi.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"hooks\" src=\"https://raw.githubusercontent.com/opbi/logo/master/hooks/hooks.svg\" width=\"160\"\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003ehooks\u003c/h3\u003e\n\u003cp align=\"center\" style=\"margin-bottom: 2em;\"\u003econfigurable decorators for automated observability and self-explanatory codebase\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@opbi/hooks\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/@opbi/hooks.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://circleci.com/gh/opbi/workflows/hooks\"\u003e\n    \u003cimg alt=\"CircleCI\" src=\"https://img.shields.io/circleci/project/github/opbi/hooks/master.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://coveralls.io/github/opbi/hooks?branch=master\"\u003e\n    \u003cimg alt=\"Coveralls\" src=\"https://img.shields.io/coveralls/github/opbi/hooks/master.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://inch-ci.org/github/opbi/hooks\"\u003e\n    \u003cimg alt=\"inch-ci\" src=\"http://inch-ci.org/github/opbi/hooks.svg?branch=master\u0026style=shields\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/semantic-release/semantic-release\"\u003e\n    \u003cimg alt=\"semantic-release\" src=\"https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://snyk.io/test/github/opbi/hooks\"\u003e\n    \u003cimg alt=\"Known Vulnerabilities\" src=\"https://snyk.io/test/github/opbi/hooks/badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://app.fossa.io/projects/git%2Bgithub.com%2Fopbi%2Fhooks?ref=badge_shield\"\u003e\n    \u003cimg alt=\"License Scan\" src=\"https://app.fossa.io/api/projects/git%2Bgithub.com%2Fopbi%2Fhooks.svg?type=shield\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://david-dm.org/opbi/hooks\"\u003e\n    \u003cimg alt=\"Dependencies\" src=\"https://img.shields.io/david/opbi/hooks.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://david-dm.org/opbi/hooks?type=dev\"\u003e\n    \u003cimg alt=\"devDependencies\" src=\"https://img.shields.io/david/dev/opbi/hooks.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://scrutinizer-ci.com/g/opbi/hooks/?branch=master\"\u003e\n    \u003cimg alt=\"Scrutinizer Code Quality\" src=\"https://img.shields.io/scrutinizer/g/opbi/hooks.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n- [Purpose](#purpose)\n  * [Automated Observability and Error Handling](#automated-observability-and-error-handling)\n  * [Self-Expanatory Business Logic](#self-expanatory-business-logic)\n  * [JavaScript Decorators At Its Best](#javascript-decorators-at-its-best)\n- [How to Use](#how-to-use)\n  * [Install](#install)\n  * [Config the Hooks](#config-the-hooks)\n  * [Chain the Hooks](#chain-the-hooks)\n  * [Ecosystem](#ecosystem)\n  * [Extension](#extension)\n  * [Opinionated Function Signature](#opinionated-function-signature)\n  * [Refactor](#refactor)\n- [Integration](#integration)\n  * [Integrate with Server Frameworks](#integrate-with-server-frameworks)\n  * [Integrate with Redux](#integrate-with-redux)\n- [Inspiration](#inspiration)\n- [License](#license)\n\n---\n\n### Purpose\n\n#### Automated Observability and Error Handling\n\nBy packing all standardisable patterns such as observarability, error handling, etc. as reusable decorators, it promotes and ensures consistency across micro-services and teams. This greatly improves the monitor clarity and debugging/maintainance experience.\n\n\n```js\n/* api.js - common behaviour can be declared by decorators */\nclass UserProfileAPI\n  //...\n  @eventLogger()\n  @eventTimer()\n  getSubscription({ userId }) {\n    //...\n  }\n\nclass SubscriptionAPI\n  //...\n  @eventLogger()\n  @eventTimer()\n  @errorRetry({ condition: e =\u003e e.type === 'TimeoutError' })\n  cancel({ subscriptionId }) {\n    //...\n  }\n```\n```js\n/* handler.js - an illustration of the business logic */\nimport { UserProfileAPI, SubscriptionAPI } from './api.js';\n\nclass Handler\n  //...\n  @eventLogger()\n  @eventTimer()\n  userCancelSubscription = ({ userId }, meta, context)\n    |\u003e UserProfileAPI.getSubscription\n    |\u003e SubscriptionAPI.cancel\n```\n\u003e Thanks to the [opionated function signature](#opinionated-function-signature), those decorators work out of box with minimum configuration to create a calling stack tree using the exact names of the decorated functions, producing structured log, metrics, tracing.\n\nThe structured log it produced below makes it a breeze to precisely pinpoint the error function with param to reproduce the case. This can be easily further integrated into an automated cross-team monitoring and alerting/debugging system.\n\n```shell\n[info] event: userCancelSubscription.getSubscription\n[error] event: userCancelSubscription.cancelSubscription, type: TimeoutError, Retry: 1, Param: { subscriptionId: '4672c33a-ff0a-4a8c-8632-80aea3a1c1c1' }\n```\n\nWe are calling those decorators **hooks(decorators at call-time beside definition-time)** to indicate that they can be used at any point of a business logic function lifecycle to extend highly flexible and precise control.\n\n```js\n/* handler.js - configure and attach hooks to business logic steps with hookEachPipe */\nimport { chain, eventLogger, eventTimer, errorRetry } from '@opbi/hooks';\nimport { UserProfileAPI, SubscriptionAPI } from './api.js';\n\nconst monitor = chain(eventLogger(), eventTimer());\n\nconst userCancelSubscription = ({ userId }, meta, context)\n  |\u003e monitor(UserProfileAPI.getSubscription)\n  |\u003e chain(\n    monitor, \n    errorRetry({ condition: e =\u003e e.type === 'TimeoutError' }), // step level control\n  )(SubscriptionAPI.cancel)\n\nexport default {\n  'userCancelSubscription': monitor(userCancelSubscription)\n};\n```\n\n#### Self-Expanatory Business Logic\n\nBy abstract out all common control mechanism and observability code into well-tested, composable decorators, this also helps to achieve codebase that is self-explanatory of its business logic and technical behaviour by the names of functions and decorators. This is great for testing and potentially rewrite the entire business logic functions as anything other than business logic is being packed into well-tested reusable decorators, which can be handily mocked during test.\n\n\u003e With the decorator and pipe operators being enabled, we can easily turn the codebase into an illustration of business logic and technical behaviour.\n\n#### JavaScript Decorators At Its Best\n\nIt is a very simple package and many companies probably have similar ones built in-house, while this package aims at providing the most maintainable, concise and universal solution to the common problems, utilising everything modern JavaScript is offering and taking care of all possible pitafalls. For example, standard decorators need to be enhaced so that the name of the decoratee function can be passed correctly through the decorator chain. All those small details hidden in the corner have been well polished for you.\n\n\u003e This high-quality suite draws the essence from its predecessor that has served a large-scale production system and is designed to empower your codebase with minimum effort. \n\n---\n### How to Use\n\n#### Install\n```shell\nyarn add @opbi/hooks\n```\n\n#### Config the Hooks\n\nAll the hooks come with default configuration.\n\n```js\nerrorRetry()(stepFunction)\n```\n\nDescriptive names of configured hooks help to make the behaviour self-explanatory.\n\n```js\nconst errorRetryOnTimeout = errorRetry({ condition: e =\u003e e.type === 'TimeoutError' })\n```\n\nPatterns composed of configured hooks can easily be reused.\n\n```js\nconst monitor = chain(eventLogger(), eventTimer(), eventTracer());\n```\n\n#### Chain the Hooks\n\n\u003e \"The order of the hooks in the chain matters.\"\n\n\u003ca href=\"https://innolitics.com/articles/javascript-decorators-for-promise-returning-functions/\"\u003e\n  \u003cimg alt=\"decorators\" width=\"640\" src=\"https://innolitics.com/img/javascript-decorators.png\"/\u003e\n\u003c/a\u003e\n\n#### Ecosystem\n\nCheck the [automated doc page](https://opbi.github.io/hooks/) for the available hooks in the current ecosystem.\n\n\u003e Hooks are named in a convention to reveal where and how it works `[hook point][what it is/does]`, e.g. *errorCounter, eventLogger*. Hook points are named `before, after, error` and `event` (multiple points).\n\n#### Extension\n\nYou can easily create more standardised hooks with [addHooks](https://github.com/opbi/hooks/blob/master/src/hooks/helpers/add-hooks.js) helper. Open source them aligning with the above standards via pull requests or individual packages are highly encouraged.\n\n---\n\n#### Opinionated Function Signature\n\nStandardisation of function signature is powerful that it creates predictable value flows throughout the functions and hooks chain, making functions more friendly to meta-programming. Moreover, it is also now a best-practice to use object destruct assign for key named parameters.\n\nVia exploration and the development of hooks, we set a function signature standard to define the order of different kinds of variables as expected and we call it `action function`:\n```js\n/**\n * The standard function signature.\n * @param  {object} param   - parameters input to the function\n * @param  {object} meta    - metadata tagged for function observability(logger, metrics), e.g. requestId\n * @param  {object} context - contextual callable instances or unrecorded metadata, e.g. logger, req\n */\nfunction (param, meta, context) {}\n```\n\n#### Refactor\nTo help adopting the hooks by testing them out with minimal refactor on non-standard signature functions, there's an unreleased [adaptor](https://github.com/opbi/toolchain/blob/adapator-non-standard/src/hooks/adaptors/nonstandard.js) to bridge the function signatures. It is not recommended to use this for anything but trying the hooks out, especially observability hooks are not utilised this way.\n\n---\n### Integration\n\n#### Integrate with Server Frameworks\n\nThose hook enhanced functions can be seemlessly plugged into server frameworks with the adaptor provided, e.g. Express.\n\n```js\n/* app.js - setup logger, metrics and adapt the express router to use hook signature */\nimport express from 'express';\nimport logger, metrics from '@opbi/toolchain';\nimport { adaptorExpress } from '@opbi/hooks';\n\nexport default adaptorExpress(express, { logger, metrics });\n\n/* router.js - use the handler with automated logger, metrics */\nimport app from './app.js';\nimport Handler from './handler.js';\n\napp.delete('/subscription/:userId', Handler.userCancelSubscription);\n```\n\n#### Integrate with Redux\nIntegration with Redux is TBC.\n\n---\n### Inspiration\n* [Financial-Times/n-express-monitor](https://github.com/Financial-Times/n-express-monitor)\n* [recompose](https://github.com/acdlite/recompose)\n* [ramda](https://github.com/ramda/ramda)\n* [funcy](https://github.com/suor/funcy/)\n---\n### License\n[MIT](License)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopbi%2Fhooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopbi%2Fhooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopbi%2Fhooks/lists"}