@@ -78,7 +78,7 @@ it still gets the benefits of the ABI stability provided by the C API. |
78 | 78 | When using `node-addon-api` instead of the C APIs, start with the API [docs][] |
79 | 79 | for `node-addon-api`. |
80 | 80 |
|
81 | | -The [Node-API Resource](https://nodejs.github.io/node-addon-examples/) offers |
| 81 | +The [Node-API Resource](https://nodejs.github.io/node-addon-examples/) offers |
82 | 82 | an excellent orientation and tips for developers just getting started with |
83 | 83 | Node-API and `node-addon-api`. Additional media resources can be found on the |
84 | 84 | [Node-API Media][] page. |
@@ -175,7 +175,8 @@ developers have run into limitations in node-gyp. |
175 | 175 | [CMake.js][] is an alternative build system based on [CMake][]. |
176 | 176 |
|
177 | 177 | CMake.js is a good choice for projects that already use CMake or for |
178 | | -developers affected by limitations in node-gyp. |
| 178 | +developers affected by limitations in node-gyp. [`build_with_cmake`][] is an |
| 179 | +example of a CMake-based native addon project. |
179 | 180 |
|
180 | 181 | ### Uploading precompiled binaries |
181 | 182 |
|
@@ -237,6 +238,18 @@ Some of the Node-API surface is experimental and requires explicit opt-in: |
237 | 238 | In this case the entire API surface, including any experimental APIs, will be |
238 | 239 | available to the module code. |
239 | 240 |
|
| 241 | +Occasionally, experimental features are introduced that affect already-released |
| 242 | +and stable APIs. These features can be disabled by an opt-out: |
| 243 | + |
| 244 | +```c |
| 245 | +#define NAPI_EXPERIMENTAL |
| 246 | +#define NODE_API_EXPERIMENTAL_<FEATURE_NAME>_OPT_OUT |
| 247 | +#include <node_api.h> |
| 248 | +``` |
| 249 | + |
| 250 | +where `<FEATURE_NAME>` is the name of an experimental feature that affects both |
| 251 | +experimental and stable APIs. |
| 252 | + |
240 | 253 | ## Node-API version matrix |
241 | 254 |
|
242 | 255 | Node-API versions are additive and versioned independently from Node.js. |
@@ -398,7 +411,7 @@ napi_value create_addon(napi_env env) { |
398 | 411 | #include <node_api.h> |
399 | 412 | #include "addon.h" |
400 | 413 |
|
401 | | -NAPI_MODULE_INIT() { |
| 414 | +NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) { |
402 | 415 | // This function body is expected to return a `napi_value`. |
403 | 416 | // The variables `napi_env env` and `napi_value exports` may be used within |
404 | 417 | // the body, as they are provided by the definition of `NAPI_MODULE_INIT()`. |
@@ -443,7 +456,7 @@ napiVersion: 6 |
443 | 456 | --> |
444 | 457 |
|
445 | 458 | ```c |
446 | | -napi_status napi_set_instance_data(napi_env env, |
| 459 | +napi_status napi_set_instance_data(node_api_nogc_env env, |
447 | 460 | void* data, |
448 | 461 | napi_finalize finalize_cb, |
449 | 462 | void* finalize_hint); |
@@ -475,7 +488,7 @@ napiVersion: 6 |
475 | 488 | --> |
476 | 489 |
|
477 | 490 | ```c |
478 | | -napi_status napi_get_instance_data(napi_env env, |
| 491 | +napi_status napi_get_instance_data(node_api_nogc_env env, |
479 | 492 | void** data); |
480 | 493 | ``` |
481 | 494 |
|
@@ -577,6 +590,22 @@ when an instance of a native addon is unloaded. Notification of this event is |
577 | 590 | delivered through the callbacks given to [`napi_add_env_cleanup_hook`][] and |
578 | 591 | [`napi_set_instance_data`][]. |
579 | 592 |
|
| 593 | +### `node_api_nogc_env` |
| 594 | + |
| 595 | +> Stability: 1 - Experimental |
| 596 | + |
| 597 | +This variant of `napi_env` is passed to synchronous finalizers |
| 598 | +([`node_api_nogc_finalize`][]). There is a subset of Node-APIs which accept |
| 599 | +a parameter of type `node_api_nogc_env` as their first argument. These APIs do |
| 600 | +not access the state of the JavaScript engine and are thus safe to call from |
| 601 | +synchronous finalizers. Passing a parameter of type `napi_env` to these APIs is |
| 602 | +allowed, however, passing a parameter of type `node_api_nogc_env` to APIs that |
| 603 | +access the JavaScript engine state is not allowed. Attempting to do so without |
| 604 | +a cast will produce a compiler warning or an error when add-ons are compiled |
| 605 | +with flags which cause them to emit warnings and/or errors when incorrect |
| 606 | +pointer types are passed into a function. Calling such APIs from a synchronous |
| 607 | +finalizer will ultimately result in the termination of the application. |
| 608 | + |
580 | 609 | ### `napi_value` |
581 | 610 |
|
582 | 611 | This is an opaque pointer that is used to represent a JavaScript value. |
@@ -741,32 +770,36 @@ typedef napi_value (*napi_callback)(napi_env, napi_callback_info); |
741 | 770 | Unless for reasons discussed in [Object Lifetime Management][], creating a |
742 | 771 | handle and/or callback scope inside a `napi_callback` is not necessary. |
743 | 772 |
|
744 | | -#### `napi_finalize` |
| 773 | +#### `node_api_nogc_finalize` |
745 | 774 |
|
746 | 775 | <!-- YAML |
747 | | -added: v8.0.0 |
748 | | -napiVersion: 1 |
| 776 | +added: REPLACEME |
749 | 777 | --> |
750 | 778 |
|
| 779 | +> Stability: 1 - Experimental |
| 780 | + |
751 | 781 | Function pointer type for add-on provided functions that allow the user to be |
752 | 782 | notified when externally-owned data is ready to be cleaned up because the |
753 | | -object with which it was associated with has been garbage-collected. The user |
754 | | -must provide a function satisfying the following signature which would get |
755 | | -called upon the object's collection. Currently, `napi_finalize` can be used for |
| 783 | +object it was associated with has been garbage-collected. The user must provide |
| 784 | +a function satisfying the following signature which would get called upon the |
| 785 | +object's collection. Currently, `node_api_nogc_finalize` can be used for |
756 | 786 | finding out when objects that have external data are collected. |
757 | 787 |
|
758 | 788 | ```c |
759 | | -typedef void (*napi_finalize)(napi_env env, |
760 | | - void* finalize_data, |
761 | | - void* finalize_hint); |
| 789 | +typedef void (*node_api_nogc_finalize)(node_api_nogc_env env, |
| 790 | + void* finalize_data, |
| 791 | + void* finalize_hint); |
762 | 792 | ``` |
763 | 793 |
|
764 | 794 | Unless for reasons discussed in [Object Lifetime Management][], creating a |
765 | 795 | handle and/or callback scope inside the function body is not necessary. |
766 | 796 |
|
767 | 797 | Since these functions may be called while the JavaScript engine is in a state |
768 | | -where it cannot execute JavaScript code, some Node-API calls may return |
769 | | -`napi_pending_exception` even when there is no exception pending. |
| 798 | +where it cannot execute JavaScript code, only Node-APIs which accept a |
| 799 | +`node_api_nogc_env` as their first parameter may be called. |
| 800 | +[`node_api_post_finalizer`][] can be used to schedule Node-API calls that |
| 801 | +require access to the JavaScript engine's state to run after the current |
| 802 | +garbage collection cycle has completed. |
770 | 803 |
|
771 | 804 | In the case of [`node_api_create_external_string_latin1`][] and |
772 | 805 | [`node_api_create_external_string_utf16`][] the `env` parameter may be null, |
@@ -775,11 +808,39 @@ shutdown. |
775 | 808 |
|
776 | 809 | Change History: |
777 | 810 |
|
| 811 | +* experimental (`NAPI_EXPERIMENTAL`): |
| 812 | + |
| 813 | + Only Node-API calls that accept a `node_api_nogc_env` as their first |
| 814 | + parameter may be called, otherwise the application will be terminated with an |
| 815 | + appropriate error message. This feature can be turned off by defining |
| 816 | + `NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT`. |
| 817 | + |
| 818 | +#### `napi_finalize` |
| 819 | + |
| 820 | +<!-- YAML |
| 821 | +added: v8.0.0 |
| 822 | +napiVersion: 1 |
| 823 | +--> |
| 824 | + |
| 825 | +Function pointer type for add-on provided function that allow the user to |
| 826 | +schedule a group of calls to Node-APIs in response to a garbage collection |
| 827 | +event, after the garbage collection cycle has completed. These function |
| 828 | +pointers can be used with [`node_api_post_finalizer`][]. |
| 829 | + |
| 830 | +```c |
| 831 | +typedef void (*napi_finalize)(napi_env env, |
| 832 | + void* finalize_data, |
| 833 | + void* finalize_hint); |
| 834 | +``` |
| 835 | + |
| 836 | +Change History: |
| 837 | + |
778 | 838 | * experimental (`NAPI_EXPERIMENTAL` is defined): |
779 | 839 |
|
780 | | - Node-API calls made from a finalizer will return `napi_cannot_run_js` when |
781 | | - the JavaScript engine is unable to execute JavaScript, and will return |
782 | | - `napi_exception_pending` if there is a pending exception. |
| 840 | + A function of this type may no longer be used as a finalizer, except with |
| 841 | + [`node_api_post_finalizer`][]. [`node_api_nogc_finalize`][] must be used |
| 842 | + instead. This feature can be turned off by defining |
| 843 | + `NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT`. |
783 | 844 |
|
784 | 845 | #### `napi_async_execute_callback` |
785 | 846 |
|
@@ -979,7 +1040,7 @@ napiVersion: 1 |
979 | 1040 |
|
980 | 1041 | ```c |
981 | 1042 | napi_status |
982 | | -napi_get_last_error_info(napi_env env, |
| 1043 | +napi_get_last_error_info(node_api_nogc_env env, |
983 | 1044 | const napi_extended_error_info** result); |
984 | 1045 | ``` |
985 | 1046 |
|
@@ -1798,7 +1859,7 @@ napiVersion: 3 |
1798 | 1859 | --> |
1799 | 1860 |
|
1800 | 1861 | ```c |
1801 | | -NODE_EXTERN napi_status napi_add_env_cleanup_hook(napi_env env, |
| 1862 | +NODE_EXTERN napi_status napi_add_env_cleanup_hook(node_api_nogc_env env, |
1802 | 1863 | napi_cleanup_hook fun, |
1803 | 1864 | void* arg); |
1804 | 1865 | ``` |
@@ -1828,7 +1889,7 @@ napiVersion: 3 |
1828 | 1889 | --> |
1829 | 1890 |
|
1830 | 1891 | ```c |
1831 | | -NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(napi_env env, |
| 1892 | +NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(node_api_nogc_env env, |
1832 | 1893 | void (*fun)(void* arg), |
1833 | 1894 | void* arg); |
1834 | 1895 | ``` |
@@ -1857,7 +1918,7 @@ changes: |
1857 | 1918 |
|
1858 | 1919 | ```c |
1859 | 1920 | NAPI_EXTERN napi_status napi_add_async_cleanup_hook( |
1860 | | - napi_env env, |
| 1921 | + node_api_nogc_env env, |
1861 | 1922 | napi_async_cleanup_hook hook, |
1862 | 1923 | void* arg, |
1863 | 1924 | napi_async_cleanup_hook_handle* remove_handle); |
@@ -2015,7 +2076,7 @@ You can also use the `NAPI_MODULE_INIT` macro, which acts as a shorthand |
2015 | 2076 | for `NAPI_MODULE` and defining an `Init` function: |
2016 | 2077 |
|
2017 | 2078 | ```c |
2018 | | -NAPI_MODULE_INIT() { |
| 2079 | +NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) { |
2019 | 2080 | napi_value answer; |
2020 | 2081 | napi_status result; |
2021 | 2082 |
|
@@ -2029,6 +2090,9 @@ NAPI_MODULE_INIT() { |
2029 | 2090 | } |
2030 | 2091 | ``` |
2031 | 2092 |
|
| 2093 | +The parameters `env` and `exports` are provided to the body of the |
| 2094 | +`NAPI_MODULE_INIT` macro. |
| 2095 | + |
2032 | 2096 | All Node-API addons are context-aware, meaning they may be loaded multiple |
2033 | 2097 | times. There are a few design considerations when declaring such a module. |
2034 | 2098 | The documentation on [context-aware addons][] provides more details. |
@@ -5391,7 +5455,7 @@ napiVersion: 5 |
5391 | 5455 | napi_status napi_add_finalizer(napi_env env, |
5392 | 5456 | napi_value js_object, |
5393 | 5457 | void* finalize_data, |
5394 | | - napi_finalize finalize_cb, |
| 5458 | + node_api_nogc_finalize finalize_cb, |
5395 | 5459 | void* finalize_hint, |
5396 | 5460 | napi_ref* result); |
5397 | 5461 | ``` |
@@ -5429,7 +5493,7 @@ added: v18.19.0 |
5429 | 5493 | > Stability: 1 - Experimental |
5430 | 5494 |
|
5431 | 5495 | ```c |
5432 | | -napi_status node_api_post_finalizer(napi_env env, |
| 5496 | +napi_status node_api_post_finalizer(node_api_nogc_env env, |
5433 | 5497 | napi_finalize finalize_cb, |
5434 | 5498 | void* finalize_data, |
5435 | 5499 | void* finalize_hint); |
@@ -5499,7 +5563,7 @@ Once created the async worker can be queued |
5499 | 5563 | for execution using the [`napi_queue_async_work`][] function: |
5500 | 5564 |
|
5501 | 5565 | ```c |
5502 | | -napi_status napi_queue_async_work(napi_env env, |
| 5566 | +napi_status napi_queue_async_work(node_api_nogc_env env, |
5503 | 5567 | napi_async_work work); |
5504 | 5568 | ``` |
5505 | 5569 |
|
@@ -5591,7 +5655,7 @@ napiVersion: 1 |
5591 | 5655 | --> |
5592 | 5656 |
|
5593 | 5657 | ```c |
5594 | | -napi_status napi_queue_async_work(napi_env env, |
| 5658 | +napi_status napi_queue_async_work(node_api_nogc_env env, |
5595 | 5659 | napi_async_work work); |
5596 | 5660 | ``` |
5597 | 5661 |
|
@@ -5612,7 +5676,7 @@ napiVersion: 1 |
5612 | 5676 | --> |
5613 | 5677 |
|
5614 | 5678 | ```c |
5615 | | -napi_status napi_cancel_async_work(napi_env env, |
| 5679 | +napi_status napi_cancel_async_work(node_api_nogc_env env, |
5616 | 5680 | napi_async_work work); |
5617 | 5681 | ``` |
5618 | 5682 |
|
@@ -5816,7 +5880,7 @@ typedef struct { |
5816 | 5880 | const char* release; |
5817 | 5881 | } napi_node_version; |
5818 | 5882 |
|
5819 | | -napi_status napi_get_node_version(napi_env env, |
| 5883 | +napi_status napi_get_node_version(node_api_nogc_env env, |
5820 | 5884 | const napi_node_version** version); |
5821 | 5885 | ``` |
5822 | 5886 |
|
@@ -5839,7 +5903,7 @@ napiVersion: 1 |
5839 | 5903 | --> |
5840 | 5904 |
|
5841 | 5905 | ```c |
5842 | | -napi_status napi_get_version(napi_env env, |
| 5906 | +napi_status napi_get_version(node_api_nogc_env env, |
5843 | 5907 | uint32_t* result); |
5844 | 5908 | ``` |
5845 | 5909 |
|
@@ -5872,7 +5936,7 @@ napiVersion: 1 |
5872 | 5936 | --> |
5873 | 5937 |
|
5874 | 5938 | ```c |
5875 | | -NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env, |
| 5939 | +NAPI_EXTERN napi_status napi_adjust_external_memory(node_api_nogc_env env, |
5876 | 5940 | int64_t change_in_bytes, |
5877 | 5941 | int64_t* result); |
5878 | 5942 | ``` |
@@ -6089,7 +6153,7 @@ napiVersion: 2 |
6089 | 6153 | --> |
6090 | 6154 |
|
6091 | 6155 | ```c |
6092 | | -NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, |
| 6156 | +NAPI_EXTERN napi_status napi_get_uv_event_loop(node_api_nogc_env env, |
6093 | 6157 | struct uv_loop_s** loop); |
6094 | 6158 | ``` |
6095 | 6159 |
|
@@ -6403,7 +6467,7 @@ napiVersion: 4 |
6403 | 6467 |
|
6404 | 6468 | ```c |
6405 | 6469 | NAPI_EXTERN napi_status |
6406 | | -napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func); |
| 6470 | +napi_ref_threadsafe_function(node_api_nogc_env env, napi_threadsafe_function func); |
6407 | 6471 | ``` |
6408 | 6472 |
|
6409 | 6473 | * `[in] env`: The environment that the API is invoked under. |
@@ -6429,7 +6493,7 @@ napiVersion: 4 |
6429 | 6493 |
|
6430 | 6494 | ```c |
6431 | 6495 | NAPI_EXTERN napi_status |
6432 | | -napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func); |
| 6496 | +napi_unref_threadsafe_function(node_api_nogc_env env, napi_threadsafe_function func); |
6433 | 6497 | ``` |
6434 | 6498 |
|
6435 | 6499 | * `[in] env`: The environment that the API is invoked under. |
@@ -6455,7 +6519,7 @@ napiVersion: 9 |
6455 | 6519 |
|
6456 | 6520 | ```c |
6457 | 6521 | NAPI_EXTERN napi_status |
6458 | | -node_api_get_module_file_name(napi_env env, const char** result); |
| 6522 | +node_api_get_module_file_name(node_api_nogc_env env, const char** result); |
6459 | 6523 |
|
6460 | 6524 | ``` |
6461 | 6525 |
|
@@ -6519,6 +6583,7 @@ the add-on's file name during loading. |
6519 | 6583 | [`Number.MIN_SAFE_INTEGER`]: https://tc39.github.io/ecma262/#sec-number.min_safe_integer |
6520 | 6584 | [`Worker`]: worker_threads.md#class-worker |
6521 | 6585 | [`async_hooks.executionAsyncResource()`]: async_hooks.md#async_hooksexecutionasyncresource |
| 6586 | +[`build_with_cmake`]: https://github.com/nodejs/node-addon-examples/tree/main/build_with_cmake |
6522 | 6587 | [`global`]: globals.md#global |
6523 | 6588 | [`init` hooks]: async_hooks.md#initasyncid-type-triggerasyncid-resource |
6524 | 6589 | [`napi_add_async_cleanup_hook`]: #napi_add_async_cleanup_hook |
@@ -6582,6 +6647,8 @@ the add-on's file name during loading. |
6582 | 6647 | [`node_api_create_external_string_latin1`]: #node_api_create_external_string_latin1 |
6583 | 6648 | [`node_api_create_external_string_utf16`]: #node_api_create_external_string_utf16 |
6584 | 6649 | [`node_api_create_syntax_error`]: #node_api_create_syntax_error |
| 6650 | +[`node_api_nogc_finalize`]: #node_api_nogc_finalize |
| 6651 | +[`node_api_post_finalizer`]: #node_api_post_finalizer |
6585 | 6652 | [`node_api_throw_syntax_error`]: #node_api_throw_syntax_error |
6586 | 6653 | [`process.release`]: process.md#processrelease |
6587 | 6654 | [`uv_ref`]: https://docs.libuv.org/en/v1.x/handle.html#c.uv_ref |
|