Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Node-API in bun.js (napi) #158

Open
Jarred-Sumner opened this issue May 5, 2022 · 44 comments
Open

Implement Node-API in bun.js (napi) #158

Jarred-Sumner opened this issue May 5, 2022 · 44 comments
Assignees
Labels
tracking An umbrella issue for tracking big features

Comments

@Jarred-Sumner
Copy link
Collaborator

Jarred-Sumner commented May 5, 2022

Node-API is Node.js' native addon API. The goal of this project is for many Node-API addons in bun.js to just work, without asking maintainers of node modules to make changes or rebuild their code specifically for Bun.

The first version will be scoped specifically to the napi_* functions. It will not include support for uv_* functions or the V8 C++ functions. A good initial target is napi.rs support.

  • async_hooks resource tracking will not be supported, it will just ignore them.
  • async cleanup will be stubbed

Internal changes

  • Support resolving .node files
  • process.dlopen support for native modules
  • require support for native modules

API implementation

  • napi_acquire_threadsafe_function
  • napi_add_async_cleanup_hook
  • napi_add_env_cleanup_hook
  • napi_add_finalizer
  • napi_adjust_external_memory (JSC doesn't have an exact version of this. it won't go down)
  • napi_async_destroy
  • napi_async_init
  • napi_call_function
  • napi_call_threadsafe_function
  • napi_cancel_async_work
  • napi_check_object_type_tag
  • napi_close_callback_scope
  • napi_close_escapable_handle_scope
  • napi_close_handle_scope
  • napi_coerce_to_bool
  • napi_coerce_to_number
  • napi_coerce_to_object
  • napi_coerce_to_string
  • napi_create_array
  • napi_create_array_with_length
  • napi_create_arraybuffer
  • napi_create_async_work
  • napi_create_bigint_int64
  • napi_create_bigint_uint64
  • napi_create_bigint_words
  • napi_create_buffer
  • napi_create_buffer_copy
  • napi_create_dataview
  • napi_create_date
  • napi_create_double
  • napi_create_error
  • napi_create_external
  • napi_create_external_arraybuffer
  • napi_create_external_buffer
  • napi_create_function
  • napi_create_int32
  • napi_create_int64
  • napi_create_object
  • napi_create_promise
  • napi_create_range_error
  • napi_create_reference
  • napi_create_string_latin1
  • napi_create_string_utf16
  • napi_create_string_utf8
  • napi_create_symbol
  • napi_create_threadsafe_function
  • napi_create_type_error
  • napi_create_typedarray
  • napi_create_uint32
  • napi_define_class
  • napi_define_properties
  • napi_delete_async_work
  • napi_delete_element
  • napi_delete_property
  • napi_delete_reference
  • napi_detach_arraybuffer
  • napi_escape_handle
  • napi_fatal_error (works but message formatting is low quality)
  • napi_fatal_exception (works but message formatting is low quality)
  • napi_get_all_property_names
  • napi_get_and_clear_last_exception (this uses JSC::VM::lastException())
  • napi_get_array_length
  • napi_get_arraybuffer_info
  • napi_get_boolean
  • napi_get_buffer_info
  • napi_get_cb_info
  • napi_get_dataview_info
  • napi_get_date_value
  • napi_get_element
  • napi_get_global
  • napi_get_instance_data
  • napi_get_last_error_info (stubbed, but with an error message)
  • napi_get_named_property
  • napi_get_new_target
  • napi_get_node_version
  • napi_get_null
  • napi_get_property
  • napi_get_property_names
  • napi_get_prototype
  • napi_get_reference_value
  • napi_get_threadsafe_function_context
  • napi_get_typedarray_info
  • napi_get_undefined
  • napi_get_uv_event_loop
  • napi_get_value_bigint_int64
  • napi_get_value_bigint_uint64
  • napi_get_value_bigint_words
  • napi_get_value_bool
  • napi_get_value_double
  • napi_get_value_external
  • napi_get_value_int32
  • napi_get_value_int64
  • napi_get_value_string_latin1
  • napi_get_value_string_utf16
  • napi_get_value_string_utf8
  • napi_get_value_uint32
  • napi_get_version
  • napi_has_element
  • napi_has_named_property
  • napi_has_own_property
  • napi_has_property
  • napi_instanceof
  • napi_is_array
  • napi_is_arraybuffer
  • napi_is_buffer
  • napi_is_dataview
  • napi_is_date
  • napi_is_detached_arraybuffer
  • napi_is_error
  • napi_is_exception_pending
  • napi_is_promise
  • napi_is_typedarray
  • napi_make_callback
  • napi_module_register
  • napi_new_instance
  • napi_object_freeze
  • napi_object_seal
  • napi_open_callback_scope
  • napi_open_escapable_handle_scope
  • napi_open_handle_scope
  • napi_queue_async_work
  • napi_ref_threadsafe_function
  • napi_reference_ref
  • napi_reference_unref
  • napi_reject_deferred
  • napi_release_threadsafe_function
  • napi_remove_async_cleanup_hook
  • napi_remove_env_cleanup_hook
  • napi_remove_wrap
  • napi_resolve_deferred
  • napi_run_script
  • napi_set_element
  • napi_set_instance_data
  • napi_set_named_property
  • napi_set_property
  • napi_strict_equals
  • napi_throw
  • napi_throw_error
  • napi_throw_range_error
  • napi_throw_type_error
  • napi_type_tag_object
  • napi_typeof
  • napi_unref_threadsafe_function
  • napi_unwrap
  • napi_wrap

Test coverage

The tentative plan is to rely on napi.rs tests, but haven't checked yet if that's possible.

  • napi_acquire_threadsafe_function
  • napi_add_async_cleanup_hook
  • napi_add_env_cleanup_hook
  • napi_add_finalizer
  • napi_adjust_external_memory
  • napi_async_destroy
  • napi_async_init
  • napi_call_function
  • napi_call_threadsafe_function
  • napi_cancel_async_work
  • napi_check_object_type_tag
  • napi_close_callback_scope
  • napi_close_escapable_handle_scope
  • napi_close_handle_scope
  • napi_coerce_to_bool
  • napi_coerce_to_number
  • napi_coerce_to_object
  • napi_coerce_to_string
  • napi_create_array
  • napi_create_array_with_length
  • napi_create_arraybuffer
  • napi_create_async_work
  • napi_create_bigint_int64
  • napi_create_bigint_uint64
  • napi_create_bigint_words
  • napi_create_buffer
  • napi_create_buffer_copy
  • napi_create_dataview
  • napi_create_date
  • napi_create_double
  • napi_create_error
  • napi_create_external
  • napi_create_external_arraybuffer
  • napi_create_external_buffer
  • napi_create_function
  • napi_create_int32
  • napi_create_int64
  • napi_create_object
  • napi_create_promise
  • napi_create_range_error
  • napi_create_reference
  • napi_create_string_latin1
  • napi_create_string_utf16
  • napi_create_string_utf8
  • napi_create_symbol
  • napi_create_threadsafe_function
  • napi_create_type_error
  • napi_create_typedarray
  • napi_create_uint32
  • napi_define_class
  • napi_define_properties
  • napi_delete_async_work
  • napi_delete_element
  • napi_delete_property
  • napi_delete_reference
  • napi_detach_arraybuffer
  • napi_escape_handle
  • napi_fatal_error
  • napi_fatal_exception
  • napi_get_all_property_names
  • napi_get_and_clear_last_exception
  • napi_get_array_length
  • napi_get_arraybuffer_info
  • napi_get_boolean
  • napi_get_buffer_info
  • napi_get_cb_info
  • napi_get_dataview_info
  • napi_get_date_value
  • napi_get_element
  • napi_get_global
  • napi_get_instance_data
  • napi_get_last_error_info
  • napi_get_named_property
  • napi_get_new_target
  • napi_get_node_version
  • napi_get_null
  • napi_get_property
  • napi_get_property_names
  • napi_get_prototype
  • napi_get_reference_value
  • napi_get_threadsafe_function_context
  • napi_get_typedarray_info
  • napi_get_undefined
  • napi_get_uv_event_loop
  • napi_get_value_bigint_int64
  • napi_get_value_bigint_uint64
  • napi_get_value_bigint_words
  • napi_get_value_bool
  • napi_get_value_double
  • napi_get_value_external
  • napi_get_value_int32
  • napi_get_value_int64
  • napi_get_value_string_latin1
  • napi_get_value_string_utf16
  • napi_get_value_string_utf8
  • napi_get_value_uint32
  • napi_get_version
  • napi_has_element
  • napi_has_named_property
  • napi_has_own_property
  • napi_has_property
  • napi_instanceof
  • napi_is_array
  • napi_is_arraybuffer
  • napi_is_buffer
  • napi_is_dataview
  • napi_is_date
  • napi_is_detached_arraybuffer
  • napi_is_error
  • napi_is_exception_pending
  • napi_is_promise
  • napi_is_typedarray
  • napi_make_callback
  • napi_module_register
  • napi_new_instance
  • napi_object_freeze
  • napi_object_seal
  • napi_open_callback_scope
  • napi_open_escapable_handle_scope
  • napi_open_handle_scope
  • napi_queue_async_work
  • napi_ref_threadsafe_function
  • napi_reference_ref
  • napi_reference_unref
  • napi_reject_deferred
  • napi_release_threadsafe_function
  • napi_remove_async_cleanup_hook
  • napi_remove_env_cleanup_hook
  • napi_remove_wrap
  • napi_resolve_deferred
  • napi_run_script
  • napi_set_element
  • napi_set_instance_data
  • napi_set_named_property
  • napi_set_property
  • napi_strict_equals
  • napi_throw
  • napi_throw_error
  • napi_throw_range_error
  • napi_throw_type_error
  • napi_type_tag_object
  • napi_typeof
  • napi_unref_threadsafe_function
  • napi_unwrap
  • napi_wrap
@Jarred-Sumner Jarred-Sumner added the tracking An umbrella issue for tracking big features label May 5, 2022
@kriszyp
Copy link

kriszyp commented May 14, 2022

I made a test repo that exercises a number of things that are currently having problems with the bun napi interface:
https://github.com/kriszyp/bun-test-apw
Clone that, npm install it, and then you can compare node index.js to bun index.js:

  • Occasional segfaults in calls through napi_call_threadsafe_function
  • napi_release_threadsafe_function not triggering thread_finalize_cb
  • NAPI_MODULE macro fails with symbol 'napi_register_module_v1' not found in native module (easy workaround, since NAPI_MODULE_INIT works fine)
  • If you get through those, I think the Callback().Call() ends up triggering escapable scopes, but that's not that important.

You will have uncomment NAPI_MODULE from apw.cpp (and comment NODE_MODULE_INIT) when you want to test that, figured the other things were more important.

Hope that helps, thanks for the great work!

@kriszyp
Copy link

kriszyp commented May 15, 2022

I also wanted to check to see if this is roughly the right approach loading a module for napi + ffi usage. I think the hybrid strategy is good: use napi for general purpose stuff like building objects, async work, and use ffi for "hot" functions that need to be fast. Here is an example from my code where I am loading the platform's binary with the napi loading package, and then, if running in bun, loading it through the FFI loader. But, I think this raises a couple points:

Anyway, here is my loading sequence right now:

import { dirname, join, default as pathModule } from 'path';
import { fileURLToPath } from 'url';
import loadNAPI from 'node-gyp-build'; // loads the correct napi binary, using the current OS/arch

let dirName = (typeof __dirname == 'string' ? __dirname : // for bun, which doesn't have fileURLToPath
	dirname(fileURLToPath(import.meta.url))).replace(/dist$/, ''); // for node, which doesn't have __dirname in ESM

export let nativeAddon = loadNAPI(dirName);
if (process.isBun) {
	const { dlopen, FFIType } = require('bun:ffi');
	// load the same napi module as above, but use bun's ffi
	// ideally we should use require.resolve to find a package, but here just hoping it is a sibling package in node_modules
	let libPath = join(dirName, '..', 'lmdb-linux-' + process.arch, 'node.napi.node');
	let lmdbLib = dlopen(libPath, {
		getByBinary: { args: [FFIType.f64, FFIType.u32], returns: FFIType.u32},
		iterate: { args: [FFIType.f64], returns: FFIType.i32},
		position: { args: [FFIType.f64, FFIType.u32, FFIType.u32, FFIType.u32, FFIType.f64], returns: FFIType.i32},
		write: { args: [FFIType.f64, FFIType.f64], returns: FFIType.i32},
		resetTxn: { args: [FFIType.f64], returns: FFIType.u8},
	});
	Object.assign(nativeAddon, lmdbLib.symbols);
}

@Jarred-Sumner
Copy link
Collaborator Author

Jarred-Sumner commented May 15, 2022

let dirName = (typeof __dirname == 'string' ? __dirname : // for bun, which doesn't have fileURLToPath

For bun you can also do import.meta.dir and/or import.meta.path, which at least saves you from the typeof check

I assume calling dlopen twice (once through the napi loader, once through the ffi loader) is cached at some level of the OS and doesn't result in duplicate binary footprints in memory

This is a good point. I don't know either, but worth checking.

require.resolve doesn't seem to exist in bun, and this seems challenging for loading a platform-specific package with a binary, which is direction that we are going with node-gyp-build: https://github.com/prebuild/node-gyp-build/pull/45/files#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346R50

This is an oversight – require.resolve should exist but does not currently. There are at least 5 other ways you can resolve without loading modules though:

  • Bun.resolve(path, fromPath) (async)
  • Bun.resolveSync(path, fromPath)
  • import.meta.resolve(path) (async)
  • import.meta.resolveSync(path) (sync)
  • Loader.resolveSync (lower-level, uses JSC builtin ModuleLoader and may be disabled at some point)

@kriszyp
Copy link

kriszyp commented May 15, 2022

assume calling dlopen twice (once through the napi loader

My evidence is that when I set the value of a static C variable from a NAPI call, that value was accessible/correct from an FFI call, so I think working correctly, but I am not claiming this as absolute proof.

This is an oversight – require.resolve should exist but does not currently

Ok, so you plan on adding require.resolve? I think in node-gyp-build it would either need to go through createRequire(libraryPath), or use the two arg version (require.resolve(id, { path: [ libraryPath ] }). node-gyp-build is CJS module, so unfortunately import.meta.resolve can't be used there (and can't even be mentioned, if (false) import.meta.resolve('test') will even fail in Node in CJS mode).

Anyway, thanks for the progress here, I know these are probably annoying details of the napi/node machinery, but I think node-gyp-build is pretty commonly used.

@Jarred-Sumner
Copy link
Collaborator Author

Jarred-Sumner commented May 17, 2022

Ok, so you plan on adding require.resolve? I think in node-gyp-build it would either need to go through createRequire(libraryPath), or use the two arg version (require.resolve(id, { path: [ libraryPath ] }). node-gyp-build is CJS module, so unfortunately import.meta.resolve can't be used there (and can't even be mentioned, if (false) import.meta.resolve('test') will even fail in Node in CJS mode).

Support for both of these was added in Bun v0.0.83 (released today)

@devongovett
Copy link

FYI, I tried to run parcel-css with Bun, but got the following error (logging with DYLD_PRINT_APIS). Not sure if this is useful. I tried to debug with lldb but wasn't able to due to macOS code signing. I guess I'd have to compile bun myself to debug further.

dyld[50777]: dlopen("/Users/devongovett/dev/parcel-css/parcel-css.darwin-arm64.node", 0x00000001)
dyld[50777]:       dlopen(parcel-css.darwin-arm64.node) => 0x2089957e0
dyld[50777]: dlsym(0x2089957e0, "napi_register_module_v1")
dyld[50777]:      dlsym("napi_register_module_v1") => 0x110ab41b0
dyld[50777]: dlsym(0xfffffffffffffffe, "getentropy")
dyld[50777]:      dlsym("getentropy") => 0x183fd8f5c

Example:

const parcelCss  = require('./parcel-css.darwin-arm64.node');
parcelCss.transform({
  filename: 'test.css',
  code: Buffer.from('.foo { color: red }'),
  minify: true
});

@kjvalencik
Copy link
Contributor

kjvalencik commented Jul 7, 2022

If I attempt to load a native module that uses Node-API, I get a crash on missing symbols. Additionally, I don't see any of the Node-API symbols in the bun binary (0.1.1, macOS x86_64).

Is there something additional that needs to be done to load these symbols or was this possibly optimized out in the latest release?

$ symbols $(which bun) | grep napi

Edit: It appears to be only the macOS release where they are missing. The symbols are present in linux.

@Pruxis
Copy link
Contributor

Pruxis commented Jul 10, 2022

What do you mean by async_hooks resource tracking will not be supported, it will just ignore them.

As bluebird uses async_hooks and requires it explicitly like this for example:

var AsyncResource = util.isNode && util.nodeSupportsAsyncResource ?
    require("async_hooks").AsyncResource : null;

Which then results into:

Could not resolve: "async_hooks". Maybe you need to "bun install"?

@Jarred-Sumner
Copy link
Collaborator Author

Jarred-Sumner commented Jul 10, 2022 via email

@droukd
Copy link

droukd commented Jul 24, 2022

Also in bun at least, you should try to avoid Bluebird. It’s a many X slowdown

What would you say is recommended to use (instead)? Par example,

(async () => { for (let i=0; i<800000; i++) { await functionCall(i); } })();

...would work, but only one execution at a time.
(And without limitation program will produce errors.)
(Promise.map([...Array(800000).keys()], functionCall, {concurrency: 8});)

P. S. http://bluebirdjs.com/docs/benchmarks.html claims to be faster (in node) than async-await.
P. S. If I am not mistaken, another problem rises with big arrays: bun took 7 GB (and counting) of RAM for 800 000 keys. Speaking of slowdowns.

@artokun
Copy link

artokun commented Jul 27, 2022

PrismaJS also requires async_hook

@harryrabin
Copy link

Hey folks! Is there any progress on napi_create_external?

@Jarred-Sumner
Copy link
Collaborator Author

Hey folks! Is there any progress on napi_create_external?

Added in dddbce8

@dariocravero
Copy link

When running @parcel/watcher, even just trying to import it with import watcher from '@parcel/watcher' bun fails with Segmentation fault: 11 (that's all it outputs). Since that module is written in C++ I figured it might be NAPI-related, might be related to this issue?

@Jarred-Sumner
Copy link
Collaborator Author

Jarred-Sumner commented Jan 23, 2023

When running @parcel/watcher, even just trying to import it with import watcher from '@parcel/watcher' bun fails with Segmentation fault: 11 (that's all it outputs). Since that module is written in C++ I figured it might be NAPI-related, might be related to this issue?

Yes, there are at least three issues blocking @parcel/watcher from working, of which I just fixed two:

  • napi_create_symbol wasn't handling a missing description string - aa45680
  • napi_define_property didn't support symbol properties - 4570ff7
  • napi_type_tag_object is not implemented yet

@cztomsik
Copy link

Looks like napi_set_instance_data() might be supported (I have seen some cpp impl in the repo) but it's probably not exported. I get this on my macos. Here's repro if anyone wants to have a look.

https://github.com/cztomsik/zig-napigen/tree/main/example

image

@Jarred-Sumner
Copy link
Collaborator Author

@cztomsik Yep, that was a mistake. Please try again once the canary build finishes (bun upgrade --canary)

229f5f7

@cztomsik
Copy link

@Jarred-Sumner Either I did something wrong or did not help :-/

image

@Jarred-Sumner
Copy link
Collaborator Author

Sorry, please try again after 4be3548

This time it should work
image

@fdaciuk
Copy link
Contributor

fdaciuk commented Nov 1, 2023

Hey guys! Any plans to support napi_env and napi_callback_info? I'm trying to use @elgato-stream-deck/node, but I'm receiving a segfault.

gdb output
  (gdb) run run src/index.ts
Starting program: /home/fernando/.bun/bin/bun run src/index.ts
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
[New Thread 0x7fffefc6a6c0 (LWP 144824)]
[New Thread 0x7fffa93e66c0 (LWP 144825)]
[New Thread 0x7fffa8be56c0 (LWP 144826)]
[New Thread 0x7fffa83e46c0 (LWP 144827)]
[New Thread 0x7fffa7be36c0 (LWP 144828)]
[New Thread 0x7fffa73e26c0 (LWP 144829)]
[New Thread 0x7fffa6be16c0 (LWP 144830)]
[New Thread 0x7fffa63e06c0 (LWP 144831)]
[New Thread 0x7fffa5bdf6c0 (LWP 144832)]
[New Thread 0x7fff9ffff6c0 (LWP 144833)]
[New Thread 0x7fff9effe6c0 (LWP 144834)]
[New Thread 0x7fffa4bde6c0 (LWP 144835)]
[New Thread 0x7fff9dffd6c0 (LWP 144836)]
[New Thread 0x7fff9d7fc6c0 (LWP 144837)]

(process:144821): VIPS-WARNING **: 06:26:08.031: unable to load "/usr/lib/vips-modules-8.14/vips-openslide.so" -- libopenslide.so.0: cannot open shared object file: No such file or directory
[New Thread 0x7fff87fff6c0 (LWP 144877)]
[New Thread 0x7fff86ffe6c0 (LWP 144879)]
[New Thread 0x7fff85ffd6c0 (LWP 144880)]
[Detaching after vfork from child process 144882]
[New Thread 0x7fff8cbff6c0 (LWP 144883)]
[New Thread 0x7fff84ffc6c0 (LWP 144884)]
[New Thread 0x7fff77fff6c0 (LWP 144885)]
[New Thread 0x7fff76ffe6c0 (LWP 144886)]
[New Thread 0x7fff75ffd6c0 (LWP 144887)]
[New Thread 0x7fff63fff6c0 (LWP 144889)]
[New Thread 0x7fff62ffe6c0 (LWP 144891)]
[New Thread 0x7fff61ffd6c0 (LWP 144893)]
[New Thread 0x7fff4ffff6c0 (LWP 144895)]
[New Thread 0x7fff4effe6c0 (LWP 144899)]
[New Thread 0x7fff4dffd6c0 (LWP 144905)]
[New Thread 0x7fff3ffff6c0 (LWP 144908)]
[New Thread 0x7fff74ffc6c0 (LWP 144909)]
[New Thread 0x7fff60ffc6c0 (LWP 144911)]
[New Thread 0x7fff4cffc6c0 (LWP 144912)]
[New Thread 0x7fff3effe6c0 (LWP 144913)]
[New Thread 0x7fff3e7fd6c0 (LWP 144914)]
[New Thread 0x7fff3dffc6c0 (LWP 144915)]
[New Thread 0x7fff3d7fb6c0 (LWP 144916)]
[New Thread 0x7fff3cffa6c0 (LWP 144917)]
[New Thread 0x7fff1ffff6c0 (LWP 144918)]
[New Thread 0x7fff1f7fe6c0 (LWP 144919)]
[New Thread 0x7fff1effd6c0 (LWP 144920)]
[New Thread 0x7fff1e7fc6c0 (LWP 144921)]
[New Thread 0x7fff1dffb6c0 (LWP 144922)]
[New Thread 0x7fff1d7fa6c0 (LWP 144923)]
[New Thread 0x7fff1cff96c0 (LWP 144924)]
[New Thread 0x7fff03fff6c0 (LWP 144925)]
[New Thread 0x7fff037fe6c0 (LWP 144926)]
vips_image_dispose: temp-231 icc_transform computed 132%
[New Thread 0x7fff02ffd6c0 (LWP 144927)]
[New Thread 0x7fff027fc6c0 (LWP 144929)]
vips_image_dispose: temp-201 icc_transform computed 132%

Thread 1 "bun" received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in  ()
#1  0x00007fff8f39c1a9 in Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::{lambda()#1}::operator()() const (this=<synthetic pointer>) at /home/todbot/projects/node/node-hid/node_modules/node-addon-api/napi-inl.h:3565
#2  Napi::details::WrapCallback<Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::{lambda()#1}>(Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::{lambda()#1}) (callback=...)
    at /home/todbot/projects/node/node-hid/node_modules/node-addon-api/napi-inl.h:74
#3  Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*) (env=<optimized out>, info=<optimized out>)
    at /home/todbot/projects/node/node-hid/node_modules/node-addon-api/napi-inl.h:3558
#4  0x00007fffad4741b8 in  ()
#5  0x00007ffffff924e0 in  ()
#6  0x00007fffad47013c in  ()
#7  0x0000000000000000 in  ()
(gdb) exit
lldb output
  (lldb) run run src/index.ts
Process 142516 launched: '/home/fernando/.bun/bin/bun' (x86_64)

(process:142516): VIPS-WARNING **: 06:24:36.945: unable to load "/usr/lib/vips-modules-8.14/vips-openslide.so" -- libopenslide.so.0: cannot open shared object file: No such file or directory
Process 142516 stopped and restarted: thread 2 received signal: SIGCHLD
Process 142516 stopped
* thread #1, name = 'bun', stop reason = signal SIGSEGV: invalid address (fault address: 0x55500e269272)
    frame #0: 0x000055500e269272
error: memory read failed for 0x55500e269200
(lldb) bt
* thread #1, name = 'bun', stop reason = signal SIGSEGV: invalid address (fault address: 0x55500e269272)
  * frame #0: 0x000055500e269272
    frame #1: 0x00007fff8f39c1a9 HID_hidraw.node`Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*) at napi-inl.h:3565:27
    frame #2: 0x00007fff8f39c0bf HID_hidraw.node`Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*) [inlined] napi_value__* Napi::details::WrapCallback<Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(napi_env__*, napi_callback_info__*)::'lambda'()>(callback=<unavailable>) at napi-inl.h:74:20
    frame #3: 0x00007fff8f39c0bf HID_hidraw.node`Napi::InstanceWrap<HID>::InstanceMethodCallbackWrapper(env=<unavailable>, info=<unavailable>) at napi-inl.h:3558:31
    frame #4: 0x00007fffad4741b8
    frame #5: 0x00007fffad47013c
    frame #6: 0x00007fffad4fbb1d
    frame #7: 0x00007fffad50b0f9
    frame #8: 0x0000555558faae71 bun`___lldb_unnamed_symbol31059 + 125729
    frame #9: 0x00007fffad4faf59
    frame #10: 0x00007fffad50b0f9
    frame #11: 0x00007fffad53d7fc
    frame #12: 0x00007fffad4e320d
    frame #13: 0x0000555558f8c9f0 bun`___lldb_unnamed_symbol31059 + 1696
    frame #14: 0x0000555559e31129 bun`___lldb_unnamed_symbol49750 + 1961
    frame #15: 0x000055555a12c944 bun`___lldb_unnamed_symbol52058 + 212
    frame #16: 0x000055555a2d43db bun`___lldb_unnamed_symbol53714 + 379
    frame #17: 0x000055555a4f7bcd bun`___lldb_unnamed_symbol55442 + 285
    frame #18: 0x000055555902c47d bun`___lldb_unnamed_symbol31436 + 13
    frame #19: 0x00007fffad4741b8
    frame #20: 0x00007fffad4fd1c3
    frame #21: 0x0000555558f8c9f0 bun`___lldb_unnamed_symbol31059 + 1696
    frame #22: 0x0000555559e31129 bun`___lldb_unnamed_symbol49750 + 1961
    frame #23: 0x000055555a12c6cb bun`___lldb_unnamed_symbol52054 + 235
    frame #24: 0x00005555590676a3 bun`___lldb_unnamed_symbol31805 + 259
    frame #25: 0x0000555558477ef2 bun`___lldb_unnamed_symbol6403 + 1458
    frame #26: 0x0000555558106887 bun`___lldb_unnamed_symbol2949 + 135
    frame #27: 0x0000555558052087 bun`___lldb_unnamed_symbol2394 + 983
    frame #28: 0x0000555559163574 bun`___lldb_unnamed_symbol32992 + 36
    frame #29: 0x0000555557fc1101 bun`___lldb_unnamed_symbol2154 + 1313
    frame #30: 0x0000555557fc2187 bun`___lldb_unnamed_symbol2155 + 4023
    frame #31: 0x0000555557d3f53f bun`___lldb_unnamed_symbol998 + 3791
    frame #32: 0x0000555557d3e33a bun`___lldb_unnamed_symbol991 + 842
    frame #33: 0x00007ffff7dd4cd0 libc.so.6`___lldb_unnamed_symbol3187 + 128
    frame #34: 0x00007ffff7dd4d8a libc.so.6`__libc_start_main + 138
    frame #35: 0x0000555557d3df2a bun`___lldb_unnamed_symbol990 + 42
(lldb) exit

@BRAVO68WEB
Copy link

Any updates on this?

@jackyzha0
Copy link

Support resolving .node files doesn't seem to work with the --compile flag, bun will report a successful build but no binary will be produced

@TomieAi
Copy link

TomieAi commented Feb 22, 2024

i got the error at uWS.js also

TypeError: symbol 'napi_register_module_v1' not found in native module. Is this a Node API (napi) module?

@kjvalencik
Copy link
Contributor

@TomieAi uWebSockets.js isn't a Node-API addon.

@TomieAi
Copy link

TomieAi commented Feb 22, 2024

@TomieAi uWebSockets.js isn't a Node-API addon.

hmm i know but i just wanna say uws dint work at bun sadly. throwing me error about "napi_register_module_v1" then i google about it XD and it leads me here.

@kjvalencik
Copy link
Contributor

@TomieAi That issue would need to be filed with uWebSockets.js. This isn't an issue with bun. It's unlikely that bun will support native addons that don't use Node-API since they generally interact directly with V8 (which bun doesn't use).

@tomholford
Copy link

For anyone experiencing NAPI issues with bun and the sqlite3 npm package, there is a built-in package available:

https://bun.sh/docs/api/sqlite

@BRAVO68WEB
Copy link

My issue regarding napi-nanoid or any other rust based napi packages

@ArthurTimofey
Copy link

Hey,

Excuse me ignorance but I am working with OpenCV, I see that the NAPI Register module is indeed complete but at the same time I am running into an issue with @u4/opencv4nodejs where by I run into a node API error:

TypeError: symbol 'napi_register_module_v1' not found in native module. Is this a Node API (napi) module?

As mentioned by @kjvalencik, I will also ask opencv4nodejs repo to see if there is a solution other than needing the make .mjs files to run scripts using the shell from bun and pipe the result back to bun. Any suggestions welcome.

@kjvalencik
Copy link
Contributor

@ArthurTimofey that addon looks like it's built with NAN and not Node-API. It won't be portable.

@chung-leong
Copy link

One thing I've noticed is that Node can handle null napi_value in a reasonable manner whereas Bun would crash. For example, I have the following code:

        if (napi_get_reference_value(env, md->js_env, &js_env) == napi_ok
          && napi_get_boolean(env, true, &released) == napi_ok) {
            napi_set_named_property(env, js_env, "released", released);
        }

md->js_env is a weak reference so js_env can be null if the object has been gc'ed. Node doesn't have a problem with this. Preseumbly, the call to napi_set_named_property would just return a error code. napi_create_function in Node also doesn't have a problem with the callback returning null.

@nicolasembleton
Copy link

It seems that napi_type_tag_object is the latest that's not supported in this list. Is there any chance it gets supported sometimes?

@di-sukharev
Copy link

di-sukharev commented Sep 11, 2024

It seems that napi_type_tag_object is the latest that's not supported in this list. Is there any chance it gets supported sometimes?

+1

trying to run tree-sitter binding for node

get:

warning: Node-API function "napi_type_tag_object" is not implemented yet.
 Track the status of Node-API in Bun: https://github.com/oven-sh/bun/issues/158
17 | var uv = (process.versions.uv || '').split('.')[0]
18 | 
19 | module.exports = load
20 | 
21 | function load (dir) {
22 |   return runtimeRequire(load.resolve(dir))
              ^
error: ENOENT: No such file or directory
      at load (/Users/my_path/node_modules/node-gyp-build/node-gyp-build.js:22:10)
      at /Users/my_path/node_modules/tree-sitter-javascript/bindings/node/index.js:3:8

Bun v1.1.27 (macOS arm64)

@ashvardanian
Copy link

Hey everyone! I've been following this issue for over a year and am very excited to see progress. Is it possible to slightly extend the list?

NAPI doesn't provide a single good interface to inspect the contents of strings and other buffers without copying them, which makes writing high-performance native extensions for binary data a complete nightmare. I was stuck with this while working on StringZilla JS bindings and can't afford to copy a string if the operation in question is something like substring search, fuzzy matching, hashing, or something else lightweight.

Assuming Bun's focus on performance and development velocity, I felt it's wiser to propose such extensions here rather than to NAPI directly. I'm happy to open a separate issue if it makes sense 🤗

Thanks to everyone involved!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tracking An umbrella issue for tracking big features
Projects
None yet
Development

No branches or pull requests