From fc559e2f6c20f05bf3814d40471a7ae484271c8d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 19:37:59 +0000 Subject: [PATCH 1/4] Add a fixture registering via the deprecated napi_module_register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The host gained support for addons that register themselves by calling napi_module_register while their library loads (#445), but nothing in the repo exercises that path — every other addon here exports napi_register_module_v1, which the loader finds first. This addon exports no such symbol, so it only loads if the fallback works. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_013ugFE6vmMUVMTuoupvhMhX --- packages/node-addon-examples/src/index.ts | 2 + .../tests/module-register/CMakeLists.txt | 28 +++++++++++++ .../tests/module-register/addon.c | 42 +++++++++++++++++++ .../tests/module-register/addon.js | 6 +++ .../tests/module-register/binding.gyp | 8 ++++ .../tests/module-register/package.json | 14 +++++++ 6 files changed, 100 insertions(+) create mode 100644 packages/node-addon-examples/tests/module-register/CMakeLists.txt create mode 100644 packages/node-addon-examples/tests/module-register/addon.c create mode 100644 packages/node-addon-examples/tests/module-register/addon.js create mode 100644 packages/node-addon-examples/tests/module-register/binding.gyp create mode 100644 packages/node-addon-examples/tests/module-register/package.json diff --git a/packages/node-addon-examples/src/index.ts b/packages/node-addon-examples/src/index.ts index 68bac88a..09c27c88 100644 --- a/packages/node-addon-examples/src/index.ts +++ b/packages/node-addon-examples/src/index.ts @@ -86,6 +86,8 @@ export const suites: Record< require("../tests/buffers/addon.js"); }, async: () => require("../tests/async/addon.js") as () => Promise, + "module-register": () => + require("../tests/module-register/addon.js") as () => void, "threadsafe-function": () => require("../tests/threadsafe-function/addon.js") as () => Promise, }, diff --git a/packages/node-addon-examples/tests/module-register/CMakeLists.txt b/packages/node-addon-examples/tests/module-register/CMakeLists.txt new file mode 100644 index 00000000..fbaa096e --- /dev/null +++ b/packages/node-addon-examples/tests/module-register/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.15...3.31) +project(module-register-test) + +find_package(weak-node-api REQUIRED CONFIG) + +add_library(module-register-test-addon SHARED addon.c) + +option(BUILD_APPLE_FRAMEWORK "Wrap addon in an Apple framework" ON) + +if(APPLE AND BUILD_APPLE_FRAMEWORK) + set_target_properties(module-register-test-addon PROPERTIES + FRAMEWORK TRUE + MACOSX_FRAMEWORK_IDENTIFIER module-register-test.addon + MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.0 + MACOSX_FRAMEWORK_BUNDLE_VERSION 1.0 + XCODE_ATTRIBUTE_SKIP_INSTALL NO + OUTPUT_NAME addon + ) +else() + set_target_properties(module-register-test-addon PROPERTIES + PREFIX "" + SUFFIX .node + OUTPUT_NAME addon + ) +endif() + +target_link_libraries(module-register-test-addon PRIVATE weak-node-api) +target_compile_features(module-register-test-addon PRIVATE cxx_std_17) \ No newline at end of file diff --git a/packages/node-addon-examples/tests/module-register/addon.c b/packages/node-addon-examples/tests/module-register/addon.c new file mode 100644 index 00000000..83d3d503 --- /dev/null +++ b/packages/node-addon-examples/tests/module-register/addon.c @@ -0,0 +1,42 @@ +#include + +// This addon registers itself the deprecated way — a napi_module_register call +// made while the library loads — and deliberately exports no +// napi_register_module_v1 symbol, so a host that only looks for that symbol +// cannot load it. +// +// The constructor is hand-rolled because node_api.h no longer offers a macro +// that emits one: NAPI_MODULE_X is now an alias of the symbol-based +// NAPI_MODULE. + +static napi_value Registration(napi_env env, napi_callback_info info) { + (void)info; + napi_value result; + if (napi_create_string_utf8(env, "napi_module_register", NAPI_AUTO_LENGTH, + &result) != napi_ok) { + return NULL; + } + return result; +} + +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor properties[] = { + {"registration", NULL, Registration, NULL, NULL, NULL, napi_default, + NULL}, + }; + if (napi_define_properties(env, exports, + sizeof(properties) / sizeof(properties[0]), + properties) != napi_ok) { + return NULL; + } + return exports; +} + +static napi_module addon_module = { + NAPI_MODULE_VERSION, 0, __FILE__, Init, "module-register-test", + NULL, {0}, +}; + +__attribute__((constructor)) static void RegisterAddon(void) { + napi_module_register(&addon_module); +} diff --git a/packages/node-addon-examples/tests/module-register/addon.js b/packages/node-addon-examples/tests/module-register/addon.js new file mode 100644 index 00000000..b7f3758e --- /dev/null +++ b/packages/node-addon-examples/tests/module-register/addon.js @@ -0,0 +1,6 @@ +const assert = require("assert"); +const addon = require("bindings")("addon.node"); + +module.exports = () => { + assert.strictEqual(addon.registration(), "napi_module_register"); +}; diff --git a/packages/node-addon-examples/tests/module-register/binding.gyp b/packages/node-addon-examples/tests/module-register/binding.gyp new file mode 100644 index 00000000..80f9fa87 --- /dev/null +++ b/packages/node-addon-examples/tests/module-register/binding.gyp @@ -0,0 +1,8 @@ +{ + "targets": [ + { + "target_name": "addon", + "sources": [ "addon.c" ] + } + ] +} diff --git a/packages/node-addon-examples/tests/module-register/package.json b/packages/node-addon-examples/tests/module-register/package.json new file mode 100644 index 00000000..69dd980f --- /dev/null +++ b/packages/node-addon-examples/tests/module-register/package.json @@ -0,0 +1,14 @@ +{ + "name": "module-register-test", + "version": "0.0.0", + "description": "Tests of the deprecated napi_module_register registration", + "main": "addon.js", + "private": true, + "dependencies": { + "bindings": "~1.5.0" + }, + "scripts": { + "test": "node addon.js" + }, + "gypfile": true +} From 306a6ec5825555683e00a071a53b0b8d5bf94650 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 19:39:13 +0000 Subject: [PATCH 2/4] Trigger the label-gated CI jobs The check workflow only re-evaluates its label conditions on opened, synchronize and reopened events, so the labels added after opening this PR need a push to take effect. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_013ugFE6vmMUVMTuoupvhMhX From aec0ef8327a6204aaa64824201932713ae5a8dc4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 21:25:02 +0000 Subject: [PATCH 3/4] Drop the gyp file from the module-register fixture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing builds this from binding.gyp — cmake-rn drives the CMake project directly. The sibling fixtures keep theirs to stay close to upstream sources they were derived from, which does not apply to an addon written here. CMakeLists.txt is now hand-maintained rather than regenerated by gyp-to-cmake, which skips the directory now that there is no binding.gyp. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_013ugFE6vmMUVMTuoupvhMhX --- .../node-addon-examples/tests/module-register/binding.gyp | 8 -------- .../tests/module-register/package.json | 6 +----- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 packages/node-addon-examples/tests/module-register/binding.gyp diff --git a/packages/node-addon-examples/tests/module-register/binding.gyp b/packages/node-addon-examples/tests/module-register/binding.gyp deleted file mode 100644 index 80f9fa87..00000000 --- a/packages/node-addon-examples/tests/module-register/binding.gyp +++ /dev/null @@ -1,8 +0,0 @@ -{ - "targets": [ - { - "target_name": "addon", - "sources": [ "addon.c" ] - } - ] -} diff --git a/packages/node-addon-examples/tests/module-register/package.json b/packages/node-addon-examples/tests/module-register/package.json index 69dd980f..01ddec8d 100644 --- a/packages/node-addon-examples/tests/module-register/package.json +++ b/packages/node-addon-examples/tests/module-register/package.json @@ -6,9 +6,5 @@ "private": true, "dependencies": { "bindings": "~1.5.0" - }, - "scripts": { - "test": "node addon.js" - }, - "gypfile": true + } } From 561e84ad0245ea18dd452deb79cd903c20f28ac0 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 21:45:34 +0000 Subject: [PATCH 4/4] Require the addon directly instead of through bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bindings package earns its place when an addon has to be found across the several output directories node-gyp might have used. This addon is built by cmake-rn to one known location, so a plain require says the same thing with one less dependency — and it exercises the Babel plugin's ordinary require path rather than its bindings special case. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_013ugFE6vmMUVMTuoupvhMhX --- packages/node-addon-examples/tests/module-register/addon.js | 4 +++- .../node-addon-examples/tests/module-register/package.json | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/node-addon-examples/tests/module-register/addon.js b/packages/node-addon-examples/tests/module-register/addon.js index b7f3758e..c06fe88e 100644 --- a/packages/node-addon-examples/tests/module-register/addon.js +++ b/packages/node-addon-examples/tests/module-register/addon.js @@ -1,5 +1,7 @@ const assert = require("assert"); -const addon = require("bindings")("addon.node"); +// cmake-rn emits to {targetSourceDir}/build/{configuration}, and this package's +// build script pins the configuration. +const addon = require("./build/RelWithDebInfo/addon.node"); module.exports = () => { assert.strictEqual(addon.registration(), "napi_module_register"); diff --git a/packages/node-addon-examples/tests/module-register/package.json b/packages/node-addon-examples/tests/module-register/package.json index 01ddec8d..13a9c9f4 100644 --- a/packages/node-addon-examples/tests/module-register/package.json +++ b/packages/node-addon-examples/tests/module-register/package.json @@ -3,8 +3,5 @@ "version": "0.0.0", "description": "Tests of the deprecated napi_module_register registration", "main": "addon.js", - "private": true, - "dependencies": { - "bindings": "~1.5.0" - } + "private": true }