{"id":17216888,"url":"https://github.com/markusjx/n-api-tools","last_synced_at":"2026-03-15T20:35:40.092Z","repository":{"id":42474080,"uuid":"281101451","full_name":"MarkusJx/n-api-tools","owner":"MarkusJx","description":"A toolbox for node-addon-api","archived":false,"fork":false,"pushed_at":"2024-01-10T01:11:16.000Z","size":194,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-08T12:42:22.497Z","etag":null,"topics":["javascript","n-api","nodejs","promise"],"latest_commit_sha":null,"homepage":"","language":"C++","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/MarkusJx.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-07-20T11:46:08.000Z","updated_at":"2023-04-18T02:53:11.000Z","dependencies_parsed_at":"2022-08-19T08:50:37.194Z","dependency_job_id":null,"html_url":"https://github.com/MarkusJx/n-api-tools","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fn-api-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fn-api-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fn-api-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fn-api-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarkusJx","download_url":"https://codeload.github.com/MarkusJx/n-api-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219845300,"owners_count":16556449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["javascript","n-api","nodejs","promise"],"created_at":"2024-10-15T03:42:38.396Z","updated_at":"2025-10-05T01:27:58.676Z","avatar_url":"https://github.com/MarkusJx.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# n-api-tools\nA toolbox containing C++ classes to be used with node-addon-api. \n\n## Installation\n```sh\nnpm install @markusjx/n-api-tools\n```\n\n## Usage\nFirst, include the file in your project. CMake example:\n```cmake\nexecute_process(COMMAND node -p \"require('@markusjx/n-api-tools').include\"\n                WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n                OUTPUT_VARIABLE N_API_TOOLS_DIR)\n\n# Include the directory\ninclude_directories(${N_API_TOOLS_DIR})\n```\n\nThis library is header-only, just include it:\n```c++\n#include \u003cnapi_tools.hpp\u003e\n```\n### Promises\n#### Void promises\n```c++\nNapi::Promise returnsPromise(const Napi::CallbackInfo \u0026info) {\n    // Return a promise\n    return napi_tools::promises::promise\u003cvoid\u003e(info.Env(), [] {\n        // Sleep to pretend we're actually doing work\n        std::this_thread::sleep_for(std::chrono::seconds(2));\n    });\n}\n```\n\n#### Non-void promises\nNon-void promises support most basic types as numbers, strings, vectors or booleans.\n```c++\nNapi::Promise returnsPromise(const Napi::CallbackInfo \u0026info) {\n    // Return a promise\n    return napi_tools::promises::promise\u003cstd::string\u003e(info.Env(), [] {\n        // Sleep to pretend we're actually doing work\n        std::this_thread::sleep_for(std::chrono::seconds(2));\n\n        // Return a string value\n        return \"some string\";\n    });\n}\n```\n\n### Callbacks\nCallbacks can be used to call javascript function even without supplying a ``Napi::Env``.\nThe ``napi_tools::callbacks::callback`` takes function-like template arguments,\ne.g. ``\u003cvoid()\u003e`` or ``\u003cint(std::string, float)\u003e``\n#### Void callbacks\nCreate a callback with no arguments:\n```c++\n// Create a void callback\nnapi_tools::callbacks::callback\u003cvoid()\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cvoid()\u003e(info);\n}\n\n// Call a callback function\nvoid callCallback() {\n    // Call the function async\n    callback();\n}\n```\n\nCreate a callback with arguments:\n```c++\n// Create a void callback with arguments\nnapi_tools::callbacks::callback\u003cvoid(std::string, int)\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cvoid(std::string, int)\u003e(info);\n}\n\n// Call a callback function\nvoid callCallback() {\n    // Call the function async and supply some arguments\n    callback(\"some string\", 42);\n}\n```\n\n### Non-void callbacks\nNon-void callbacks return a ``std::promise`` to get a ``std::future``\nfrom to get the result of the callback. **NOTE:** If you call ``std::future\u003cT\u003e::wait()``\nin the main thread, you will create a deadlock as the callback cannot be called since\nthe main thread is waiting for the callback to be called. To call a callback function\nfrom node.js use a ``napi_tools::promises::Promise\u003cT\u003e`` or some other technique to not\nblock the main thread. You can also supply a callback function to be called with the\nfunction return type.\n\nCreate a callback with no arguments:\n```c++\n// Create a callback returning a number\nnapi_tools::callbacks::callback\u003cint()\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cint()\u003e(info);\n}\n\n// Call a callback function.\nvoid callCallback() {\n    // Call the function async. It returns a std::promise\n    std::promise\u003cint\u003e promise = callback();\n\n    // Get the future\n    std::future\u003cint\u003e future = promise.get_future();\n\n    // Wait for the future to be resolved and get the result\n    future.wait();\n    int res = future.get();\n}\n```\n\nCreate a callback with no arguments and without ``std::future``:\n```c++\n// Create a callback returning a number\nnapi_tools::callbacks::callback\u003cint()\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cint()\u003e(info);\n}\n\n// Call a callback function.\nvoid callCallback() {\n    // Call the callback and supply a callback function\n    callback([] (int res) {\n        // The lambde will be called when the callback function finished.\n        // The result of the callback will be stored in res.\n    });\n}\n```\n\nCreate a callback with arguments:\n```c++\n// Create a callback returning a number\nnapi_tools::callbacks::callback\u003cint(std::string, int)\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cint(std::string, int)\u003e(info);\n}\n\n// Call a callback function.\nvoid callCallback() {\n    // Call the function async. It returns a std::promise\n    std::shared_ptr\u003cstd::promise\u003cint\u003e\u003e promise = callback(\"some string\", 42);\n\n    // Get the future\n    std::future\u003cint\u003e future = promise-\u003eget_future();\n\n    // Wait for the future to be resolved and get the result\n    future.wait();\n    int res = future.get();\n}\n```\n\nCreate a callback with arguments and without ``std::future``:\n```c++\n// Create a callback returning a number\nnapi_tools::callbacks::callback\u003cint(std::string, int)\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cint(std::string, int)\u003e(info);\n}\n\n// Call a callback function.\nvoid callCallback() {\n    // Call the function and supply a callback function\n    callback(\"some string\", 42, [] (int res) {\n        // The result will be stored in res\n    });\n}\n```\n\nCreate a callback and wait for the js function to finish:\n```c++\n// Create a callback returning a number\nnapi_tools::callbacks::callback\u003cint(std::string, int)\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] should be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    callback = callbacks::callback\u003cint(std::string, int)\u003e(info);\n}\n\n// Call a callback function.\nvoid callCallback() {\n    // Call the sync version of the function\n    int result = callback.callSync(\"some string\", 42);\n}\n```\n\nSupply a conversion function with the callback:\n```c++\n// Create a callback returning a number\nnapi_tools::callbacks::callback\u003cint(std::string, int)\u003e callback = nullptr;\n\n// Create a callback setter.\n// This function should be exported and called by javascript.\n// info[0] may be a Napi::Function.\nvoid setCallback(const Napi::CallbackInfo \u0026info) {\n    // Create a conversion function.\n    // The conversion function must return std::vector\u003cnapi_value\u003e\n    const auto converter = [] (std::string, int) -\u003e std::vector\u003cnapi_value\u003e {\n        // Convert the values\n    };\n\n    // Set the callback and set the environment and the function manually.\n    // Aditionally, supply the custom conversion function\n    callback = callbacks::callback\u003cint(std::string, int)\u003e(info.Env(),\n                                                          info[0].As\u003cNapi::Function(),\n                                                          converter);\n}\n```\n\n## Custom classes/structs as arguments/return types\nIn order to pass custom classes or structs to node.js or receive them, your class or struct\nmust implement the ``static Napi::Value toNapiValue(Napi::Env, T)`` function\nto pass the class as an argument and the ``static T fromNapiValue(Napi::Value)``\nfunction to get the class returned from the javascript process.\n\nA custom implementation may look like this:\n```c++\nclass custom_class {\npublic:\n    // Some attributes\n    std::string s1, s2;\n    int i;\n    std::vector\u003cint\u003e ints;\n\n    // The toNapiValue function\n    static Napi::Value toNapiValue(const Napi::Env \u0026env, const custom_class \u0026c) {\n        Napi::Object obj = Napi::Object::New(env);\n\n        // Convert the attributes using Napi::Value::From\n        obj.Set(\"s1\", Napi::Value::From(env, c.s1));\n        obj.Set(\"s2\", Napi::Value::From(env, c.s1));\n        obj.Set(\"i\",  Napi::Value::From(env, c.i));\n\n        // You may also use the included conversion functions.\n        // These can handle most basic types as strings, integers,\n        // but also std::vector and std::map, plus classes with\n        // the toNapiValue and/or fromNapiValue function(s)\n        obj.Set(\"ints\", napi_tools::util::conversions::cppValToValue(env, ints));\n        return obj;\n    }\n\n    // The fromNapiValue function\n    static custom_class fromNapiValue(const Napi::Env \u0026env, const Napi::Value \u0026val) {\n        // Assuming val is an object, you may test if it actually is\n        Napi::Object obj = val.ToObject();\n\n        // Set all values\n        custom_class c;\n        c.s1 = obj.Get(\"s1\").ToString();\n        c.s2 = obj.Get(\"s2\").ToString();\n        c.i = obj.Get(\"i\").ToNumber();\n\n        // napi_tools also has functions to convert from napi values:\n        c.ints = napi_tools::util::conversions::convertToCpp\u003cstd::vector\u003cint\u003e\u003e(obj.Get(\"ints\"));\n        return c;\n    }\n};\n```\n\n## Other tools\n### Catch all exceptions\nTo catch all exceptions possibly thrown by c++ to throw them in the javascript process,\nuse the ``TRY``/``CATCH_EXCEPTIONS`` macros:\n```c++\nvoid someFunction(const Napi::CallbackInfo \u0026info) {\n    TRY\n        // Some code that may throw an exception\n    CATCH_EXCEPTIONS\n}\n```\n\n### Check argument types\nTo check if the number of supplied arguments, and the argument types match,\nuse the ``CHECK_ARGS(...)`` macro. A ``Napi::Error`` will be thrown if\nthe arguments do not match. Supported type names are: ``string``, ``number``,\n``function``, ``object``, ``boolean``, ``array``, ``buffer``, ``undefined``, ``null``.\n\nExample:\n```c++\nvoid someFunction(const Napi::CallbackInfo \u0026info) {\n    using namespace napi_tools;\n    // Expect a function, a string, a number and a boolean\n    CHECK_ARGS(function, string, number, boolean);\n}\n```\n\nIt is also possible to allow multiple types as an input:\n```c++\nvoid someFunction(const Napi::CallbackInfo \u0026info) {\n    using namespace napi_tools;\n    // Expect a string, number, null or undefined\n    CHECK_ARGS(string | number | null | undefined);\n}\n```\n\n### Export functions\nTo make exporting functions in your ``ìnit`` method easier, n-api-tools provides the\n``EXPORT_FUNCTION(exports, env, fn)`` macro. This macro will \"export\" functions using\ntheir C++ function name to javascript.\n\nExample:\n```c++\nNapi::Object InitAll(Napi::Env env, Napi::Object exports) {\n    EXPORT_FUNCTION(exports, env, func1);\n    EXPORT_FUNCTION(exports, env, func2);\n    EXPORT_FUNCTION(exports, env, anotherFunc);\n\n    return exports;\n}\n\n// Initialize the module\nNODE_API_MODULE(some_module, InitAll)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusjx%2Fn-api-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkusjx%2Fn-api-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusjx%2Fn-api-tools/lists"}