{"id":51985856,"url":"https://github.com/node-3d/addon-tools","last_synced_at":"2026-07-30T19:01:35.604Z","repository":{"id":32332196,"uuid":"115880637","full_name":"node-3d/addon-tools","owner":"node-3d","description":"Helpers for Node.js addons and dependency packages","archived":false,"fork":false,"pushed_at":"2026-07-25T12:28:41.000Z","size":2306,"stargazers_count":2,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-07-25T14:08:09.243Z","etag":null,"topics":["addon","addons","cross-platform","fs","gyp","header","header-files","helpers","hpp","logger","macros","napi","node","node-3d","node-addon","node-addon-api","node-js","nodejs","ts","utils"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/node-3d.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-12-31T18:59:35.000Z","updated_at":"2026-07-25T12:28:47.000Z","dependencies_parsed_at":"2024-05-30T18:11:34.327Z","dependency_job_id":"a1e95dea-4f55-4149-bdd7-00aa644ce900","html_url":"https://github.com/node-3d/addon-tools","commit_stats":{"total_commits":267,"total_committers":4,"mean_commits":66.75,"dds":"0.42322097378277157","last_synced_commit":"105964614f00b939bb8af8f239e78fabc136c2d8"},"previous_names":["raub/node-addon-tools","node-3d/addon-tools"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/node-3d/addon-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-3d%2Faddon-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-3d%2Faddon-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-3d%2Faddon-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-3d%2Faddon-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/node-3d","download_url":"https://codeload.github.com/node-3d/addon-tools/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-3d%2Faddon-tools/sbom","scorecard":{"id":691770,"data":{"date":"2025-08-11","repo":{"name":"github.com/node-3d/addon-tools-raub","commit":"641fe140fbaa9892b6190c04055c643e88cebbc7"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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/30 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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/cpplint.yml:1","Warn: no topLevel permission defined: .github/workflows/eslint.yml:1","Warn: no topLevel permission defined: .github/workflows/publish.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"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":"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":"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":"Pinned-Dependencies","score":4,"reason":"dependency not pinned by hash detected -- score normalized to 4","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/cpplint.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/cpplint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/cpplint.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/cpplint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/eslint.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/eslint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/eslint.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/eslint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/publish.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/node-3d/addon-tools-raub/test.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/cpplint.yml:37","Info:   0 out of   8 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   3 out of   3 npmCommand dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"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":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"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":"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":"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":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-xffm-g5w8-qvg7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw"],"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-22T02:28:23.031Z","repository_id":32332196,"created_at":"2025-08-22T02:28:23.031Z","updated_at":"2025-08-22T02:28:23.031Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36088336,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-30T02:00:05.956Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["addon","addons","cross-platform","fs","gyp","header","header-files","helpers","hpp","logger","macros","napi","node","node-3d","node-addon","node-addon-api","node-js","nodejs","ts","utils"],"created_at":"2026-07-30T19:01:34.500Z","updated_at":"2026-07-30T19:01:35.465Z","avatar_url":"https://github.com/node-3d.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Addon Tools\n\nThis is a part of [Node3D](https://github.com/node-3d) project.\n\n[![NPM](https://badge.fury.io/js/@node-3d%2Faddon-tools.svg)](https://badge.fury.io/js/@node-3d%2Faddon-tools)\n[![Lint](https://github.com/node-3d/addon-tools/actions/workflows/lint.yml/badge.svg)](https://github.com/node-3d/addon-tools/actions/workflows/lint.yml)\n[![Test](https://github.com/node-3d/addon-tools/actions/workflows/test.yml/badge.svg)](https://github.com/node-3d/addon-tools/actions/workflows/test.yml)\n[![Cpplint](https://github.com/node-3d/addon-tools/actions/workflows/cpplint.yml/badge.svg)](https://github.com/node-3d/addon-tools/actions/workflows/cpplint.yml)\n\n```bash\nnpm install @node-3d/addon-tools\n```\n\nAddon Tools provide build-time and run-time helpers for Node.js C++ addons.\n- C++ shortcuts to replace repetitive code in method/class\ndeclaration and commonly used calls (such as `console.log`).\n- JS helpers to deliver the precompiled addons to end-users during npm install.\n- Common Logger for both C++ and JS sides with additional control,\ncompared to native (`printf/cout`) and console logging.\n\n## include/addon-tools.hpp\n\nMacros and helpers for C++ addons using **NAPI**.\nSee more detailed [docs here](doc).\n\nExample of a C++ method definition using Addon Tools:\n\n```c++\n// hpp:\n#include \u003caddon-tools.hpp\u003e\nDBG_EXPORT JS_METHOD(doSomething);\n// cpp:\nDBG_EXPORT JS_METHOD(doSomething) { NAPI_ENV;\n\tLET_INT32_ARG(0, param0);\n\tNapi::Value args[2] = { JS_STR(\"param0:\"), JS_NUM(param0) };\n\tconsoleLog(env, 2, \u0026args[0]);\n\tRET_UNDEFINED;\n}\n```\n\nAlso, ES5 class helpers allow exporting a JS class directly from C++:\ngenerated wrappers validate the JS receiver before dispatching to the native\ninstance, while exposing `unwrap()` for lower-level manual probing.\n\n```cpp\n// hpp:\n#include \u003caddon-tools.hpp\u003e\nclass MyClass {\nDECLARE_ES5_CLASS(MyClass, MyClass);\npublic:\n\tstatic void init(Napi::Env env, Napi::Object exports);\n\texplicit MyClass(const Napi::CallbackInfo\u0026 info);\n\t~MyClass();\nprivate:\n\tJS_DECLARE_GETTER(MyClass, a);\n\tJS_DECLARE_GETTER(MyClass, b);\n\tJS_DECLARE_METHOD(MyClass, test);\n};\n\n// cpp:\nIMPLEMENT_ES5_CLASS(MyClass);\n\nvoid MyClass::init(Napi::Env env, Napi::Object exports) {\n\tNapi::Function ctor = wrap(env);\n\tJS_ASSIGN_GETTER(a);\n\tJS_ASSIGN_GETTER(b);\n\tJS_ASSIGN_METHOD(test);\n\texports.Set(\"MyClass\", ctor);\n}\n\nMyClass::MyClass(const Napi::CallbackInfo \u0026info) {\n\tsuper(info);\n}\n\nMyClass::~MyClass() {}\n\nJS_IMPLEMENT_GETTER(MyClass, a) { NAPI_ENV;\n\tRET_NUM(10);\n}\n\nJS_IMPLEMENT_GETTER(MyClass, b) { NAPI_ENV;\n\tRET_NUM(20);\n}\n\nJS_IMPLEMENT_METHOD(MyClass, test) { NAPI_ENV;\n\tconsoleLog(\"test\");\n\tRET_STR(\"test\");\n}\n\nNapi::Object init(Napi::Env env, Napi::Object exports) {\n\tMyClass::init(env, exports);\n\treturn exports;\n}\n\nNODE_API_MODULE(myaddon, init)\n```\n\n## JS Addon Helpers\n\n### Example for an ADDON's **index.js**:\n\nGet the platform-specific directory name to import the `ADDON.node` file.\n\n```js\n\timport { createRequire } from 'node:module';\n\timport { getBin } from '@node-3d/addon-tools';\n\n\tconst require = createRequire(import.meta.url);\n\tconst core = require(`./${getBin()}/ADDON`);\n```\n\n\n### Example for **binding.gyp**:\n\nUsing the include directories for both Addon Tools header\nand Addon API header:\n\n```gyp\n\t'include_dirs': [\n\t\t'\u003c!@(node -e \"import(\\'@node-3d/addon-tools\\').then((m) =\u003e m.printInclude())\")',\n\t],\n```\n\n\u003e NOTE: the optional `node-addon-api` dependency is used by the `getInclude()`\nhelper. If not found,\n\tthe **napi.h** include path won't be a part of the returned string.\n\nUsing helpers for paths to dependency libs and own binaries:\n\n```gyp\n\t'variables': {\n\t\t'bin': '\u003c!(node -e \"import(\\'@node-3d/addon-tools\\').then((m) =\u003e m.printBin())\")',\n\t\t'gl_include': '\u003c!(node -p \"require(\\'@node-3d/deps-opengl\\').include\")',\n\t\t'gl_bin': '\u003c!(node -p \"require(\\'@node-3d/deps-opengl\\').bin\")',\n\t},\n```\n\n\n### Example of `cpbin` in **package.json :: scripts**:\n\nCopy the addon file, for example, from `./src/build/Release/glfw.node`\nto `./bin-windows/glfw.node`, but each platform uses a different folder.\n\n```json\n\"build\": \"cd src \u0026\u0026 node-gyp rebuild -j max --silent \u0026\u0026 node -e \\\"import('@node-3d/addon-tools').then((m) =\u003e m.cpbin('glfw'))\\\"\",\n\"build-only\": \"cd src \u0026\u0026 node-gyp build -j max --silent \u0026\u0026 node -e \\\"import('@node-3d/addon-tools').then((m) =\u003e m.cpbin('glfw'))\\\"\",\n```\n\n### Example of `cpcpplint` in **cpplint.yml**:\n\nSince all my addons use the same codestyle, I don't keep\ncopies of the [CPPLINT config](utils/CPPLINT.cfg) in\nevery addon. If that same config fits for you,\nhere's how it can be used:\n\n```yml\n- name: Run Cpplint\n  run: |\n    node -e \"import('@node-3d/addon-tools').then((m) =\u003e m.cpcpplint())\"\n    cpplint --recursive ./src/cpp\n```\n\n### Example of `cpclangformat` in **package.json :: scripts**:\n\nSince all my addons use the same C++ formatting style, I don't keep\ncopies of the [.clang-format config](utils/.clang-format) in every addon.\nIf that same config fits for you, here's how it can be used:\n\n```json\n\"format:src\": \"node -e \\\"import('@node-3d/addon-tools').then((m) =\u003e m.cpclangformat())\\\" \u0026\u0026 clang-format -i \\\"src/cpp/**/*.{cpp,hpp}\\\"\",\n\"format:src:ci\": \"node -e \\\"import('@node-3d/addon-tools').then((m) =\u003e m.cpclangformat())\\\" \u0026\u0026 clang-format --dry-run --Werror \\\"src/cpp/**/*.{cpp,hpp}\\\"\"\n```\n\n### Example of `install` in **install.js**:\n\nDownloads the addon (for example, from GitHub releases) and places\nit into a platform-specific folder.\n\n```js\nimport { install } from '@node-3d/addon-tools';\n\nconst prefix = 'https://github.com/node-3d/glfw/releases/download';\nconst tag = '5.5.0';\ninstall(`${prefix}/${tag}`);\n```\n\n## JS Utils\n\nJavaScript helpers for Node.js addon development. The short list of helpers:\n\n```js\n\t'getBin', 'getPlatform', 'getInclude', 'getPaths',\n\t'install', 'cpbin', 'download', 'copy', 'exists',\n\t'ensuredir', 'subdirs', 'subfiles', 'traverse',\n\t'rmdir', 'rm', 'actionPack', 'checkGypi',\n\t'createLogger', 'setLevel', 'getLevel', 'getLoggers',\n```\n\nThe public JS helpers are:\n\n* `getPaths(dir)` - return `{ bin, include }` for a dependency package and prepend `bin`\n  to `PATH` on Windows.\n* `getBin()`, `printBin()` - current platform binary directory, such as `bin-windows`.\n* `getPlatform()`, `printPlatform()` - current platform key.\n* `getInclude()`, `printInclude()` - include flags for addon-tools and optional\n  `node-addon-api`.\n* `cpbin(name)` - copy `src/build/Release/\u003cname\u003e.node` into the platform `bin-*` directory.\n* `cpcpplint()` - copy the shared `CPPLINT.cfg` into the current directory.\n* `cpclangformat()` - copy the shared `.clang-format` into the current directory.\n* `checkGypi(path?)` - verify a local `common.gypi` matches the shared one.\n* `install(folderUrl)` - download and unpack `\u003cplatform\u003e.gz` into the current platform bin dir.\n* `download(url)` - fetch a URL into a `Buffer`.\n* `copy`, `exists`, `ensuredir`, `subdirs`, `subfiles`, `traverse`, `rmdir`, `rm`.\n* `actionPack()` - pack the current platform bin directory as `\u003cplatform\u003e.gz`.\n\n### Logger:\n\nThis helper provides simple logging interface, for both JS and C++, that may be used\nlocally or globally.\n\n```js\n\t// to `console` by default\n\tconst logger = utils.createLogger({ name: 'my-logger' });\n```\n\nNow the following JS calls are equal:\n\n```js\n\tlogger.warn(1, 2, '3');\n\tglobal.AddonTools.log('my-logger', 'warn', 1, 2, '3');\n\tconst { getLogger } = await import('@node-3d/addon-tools');\n\tgetLogger('my-logger').warn(1, 2, '3');\n```\n\nAnd the C++ calls are:\n\n```cpp\n\tglobalLog(env, \"my-logger\", \"warn\", \"string log message\");\n\t// or\n\tNapi::Value args[3] = { JS_NUM(1), JS_NUM(2), JS_STR(\"3\") };\n\tglobalLog(env, \"cpp\", \"warn\", 3, \u0026args[0]);\n```\n\nLogger helpers:\n\n* `createLogger({ name, ...methods })` - create or update a named logger.\n* `getLogger(name)` - get an existing logger or create one with console methods.\n* `setLevel(level | null)` and `getLevel()` - control global log filtering.\n* `getLoggers()` - return the logger registry snapshot.\n\n`global.AddonTools.log(name, level, ...args)` is installed for C++ helpers that need to\nroute log messages back into JavaScript.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnode-3d%2Faddon-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnode-3d%2Faddon-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnode-3d%2Faddon-tools/lists"}