Repository navigation
Expand file tree
/
Copy pathnode-dotnet.h
More file actions
317 lines (267 loc) · 16.9 KB
/
Copy pathnode-dotnet.h
File metadata and controls
317 lines (267 loc) · 16.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
// Copyright (c) 2026 Alethic.
// Licensed under the MIT License.
// node-dotnet: the libnode embedding shim.
//
// A C ABI that mirrors Node.js's public C++ embedding API (src/node.h in the Node.js source tree)
// one-to-one, plus the small slice of v8.h an embedder needs: Locker, Isolate/Handle/Context scopes
// and running a script. Nothing here is a new abstraction: each function corresponds to one C++
// declaration, named node_<type>_<method> / v8_<type>_<method>, so that keeping the shim current
// with a new Node.js major is a mechanical diff against node.h.
//
// Rules carried over from the C++ API:
// - Every v8_local is only valid while the v8_handle_scope it was created in is open, and must be
// used on the isolate's thread with the v8_locker / v8_isolate_scope entered, exactly like
// v8::Local<T>. A v8_local has the same representation as napi_value (a pointer to the handle
// slot), so it can be passed straight to Node-API functions given a napi_env.
// - Scopes are strictly LIFO: close them in reverse order of opening.
// - Handles returned by *_create/*_new are owned by the caller and released with the matching
// *_delete; handles returned by other getters are borrowed.
//
// Node-API access for an embedder: register a linked binding (node_add_linked_binding_napi) before
// loading the environment, then have the main script call process._linkedBinding(name); Node calls
// the registered napi_addon_register_func with a napi_env for the environment.
#ifndef LIBNODE_DOTNET_H_
#define LIBNODE_DOTNET_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "node_api.h"
#if defined(_WIN32)
#define NODE_DOTNET_CDECL __cdecl
#if defined(NODE_DOTNET_EXPORTS)
#define NODE_DOTNET_API __declspec(dllexport)
#else
#define NODE_DOTNET_API __declspec(dllimport)
#endif
#else
#define NODE_DOTNET_CDECL
#define NODE_DOTNET_API __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
extern "C" {
#endif
// ---------------------------------------------------------------------------------------------
// Handles
// ---------------------------------------------------------------------------------------------
typedef struct node_initialization_result_s* node_initialization_result; // std::shared_ptr<node::InitializationResult>
typedef struct node_multi_isolate_platform_s* node_multi_isolate_platform; // node::MultiIsolatePlatform*
typedef struct node_common_environment_setup_s* node_common_environment_setup; // std::unique_ptr<node::CommonEnvironmentSetup>
typedef struct node_environment_s* node_environment; // node::Environment* (borrowed)
typedef struct node_string_list_s* node_string_list; // std::vector<std::string>
typedef struct uv_loop_s uv_loop_t; // libuv (exported by libnode itself)
typedef struct v8_isolate_s* v8_isolate; // v8::Isolate* (borrowed)
typedef struct v8_local_s* v8_local; // v8::Local<T> slot; same representation as napi_value
typedef struct v8_locker_s* v8_locker; // v8::Locker
typedef struct v8_isolate_scope_s* v8_isolate_scope; // v8::Isolate::Scope
typedef struct v8_handle_scope_s* v8_handle_scope; // v8::HandleScope
typedef struct v8_context_scope_s* v8_context_scope; // v8::Context::Scope
// ---------------------------------------------------------------------------------------------
// Flags (values mirror node.h; the implementation static_asserts them)
// ---------------------------------------------------------------------------------------------
// node::ProcessInitializationFlags::Flags
typedef enum {
node_process_initialization_flags_no_flags = 0,
node_process_initialization_flags_enable_stdio_inheritance = 1 << 0,
node_process_initialization_flags_disable_node_options_env = 1 << 1,
node_process_initialization_flags_disable_cli_options = 1 << 2,
node_process_initialization_flags_no_icu = 1 << 3,
node_process_initialization_flags_no_stdio_initialization = 1 << 4,
node_process_initialization_flags_no_default_signal_handling = 1 << 5,
node_process_initialization_flags_no_initialize_v8 = 1 << 6,
node_process_initialization_flags_no_initialize_node_v8_platform = 1 << 7,
node_process_initialization_flags_no_init_openssl = 1 << 8,
node_process_initialization_flags_no_parse_global_debug_variables = 1 << 9,
node_process_initialization_flags_no_adjust_resource_limits = 1 << 10,
node_process_initialization_flags_no_use_large_pages = 1 << 11,
node_process_initialization_flags_no_print_help_or_version_output = 1 << 12,
node_process_initialization_flags_no_initialize_cppgc = 1 << 13,
node_process_initialization_flags_generate_predictable_snapshot = 1 << 14,
} node_process_initialization_flags;
// node::EnvironmentFlags::Flags
typedef enum {
node_environment_flags_no_flags = 0,
node_environment_flags_default_flags = 1 << 0,
node_environment_flags_owns_process_state = 1 << 1,
node_environment_flags_owns_inspector = 1 << 2,
node_environment_flags_no_register_esm_loader = 1 << 3,
node_environment_flags_track_unmanaged_fds = 1 << 4,
node_environment_flags_hide_console_windows = 1 << 5,
node_environment_flags_no_native_addons = 1 << 6,
node_environment_flags_no_global_search_paths = 1 << 7,
node_environment_flags_no_browser_globals = 1 << 8,
node_environment_flags_no_create_inspector = 1 << 9,
node_environment_flags_no_start_debug_signal_handler = 1 << 10,
node_environment_flags_no_wait_for_inspector_frontend = 1 << 11,
} node_environment_flags;
// node::StopFlags::Flags
typedef enum {
node_stop_flags_no_flags = 0,
node_stop_flags_do_not_terminate_isolate = 1 << 0,
} node_stop_flags;
// ---------------------------------------------------------------------------------------------
// Callbacks
// ---------------------------------------------------------------------------------------------
// node::StartExecutionCallback: receives StartExecutionCallbackInfo{process_object, native_require,
// run_cjs}; returns the environment's load result, or NULL for an empty MaybeLocal.
typedef v8_local(NODE_DOTNET_CDECL* node_start_execution_callback)(
void* data,
node_environment env,
v8_local process_object,
v8_local native_require,
v8_local run_cjs);
// node::EmbedderPreloadCallback: runs before the entry point in the main environment and in every
// worker thread's environment.
typedef void(NODE_DOTNET_CDECL* node_embedder_preload_callback)(
void* data,
node_environment env,
v8_local process,
v8_local require);
// node::AddEnvironmentCleanupHook callback.
typedef void(NODE_DOTNET_CDECL* node_cleanup_hook_callback)(void* arg);
// ---------------------------------------------------------------------------------------------
// Strings
// ---------------------------------------------------------------------------------------------
NODE_DOTNET_API size_t NODE_DOTNET_CDECL node_string_list_count(node_string_list list);
NODE_DOTNET_API const char* NODE_DOTNET_CDECL node_string_list_get(node_string_list list, size_t index);
NODE_DOTNET_API void NODE_DOTNET_CDECL node_string_list_delete(node_string_list list);
// ---------------------------------------------------------------------------------------------
// Process initialization (node.h: InitializeOncePerProcess / TearDownOncePerProcess)
// ---------------------------------------------------------------------------------------------
// node::InitializeOncePerProcess(args, flags). The result is owned by the caller.
NODE_DOTNET_API node_initialization_result NODE_DOTNET_CDECL node_initialize_once_per_process(
int argc,
const char* const* argv,
uint32_t flags);
// node::InitializationResult accessors. String lists are borrowed from the result.
NODE_DOTNET_API int NODE_DOTNET_CDECL node_initialization_result_exit_code(node_initialization_result result);
NODE_DOTNET_API bool NODE_DOTNET_CDECL node_initialization_result_early_return(node_initialization_result result);
NODE_DOTNET_API node_string_list NODE_DOTNET_CDECL node_initialization_result_args(node_initialization_result result);
NODE_DOTNET_API node_string_list NODE_DOTNET_CDECL node_initialization_result_exec_args(node_initialization_result result);
NODE_DOTNET_API node_string_list NODE_DOTNET_CDECL node_initialization_result_errors(node_initialization_result result);
// The platform Node.js created, unless no_initialize_node_v8_platform was set. Borrowed.
NODE_DOTNET_API node_multi_isolate_platform NODE_DOTNET_CDECL node_initialization_result_platform(node_initialization_result result);
NODE_DOTNET_API void NODE_DOTNET_CDECL node_initialization_result_delete(node_initialization_result result);
// node::TearDownOncePerProcess()
NODE_DOTNET_API void NODE_DOTNET_CDECL node_tear_down_once_per_process(void);
// ---------------------------------------------------------------------------------------------
// Platform (node.h: MultiIsolatePlatform; v8.h: V8::InitializePlatform etc.)
// For embedders that opt out of Node's platform/V8 initialization via the process flags.
// ---------------------------------------------------------------------------------------------
// node::MultiIsolatePlatform::Create(thread_pool_size). Owned by the caller.
NODE_DOTNET_API node_multi_isolate_platform NODE_DOTNET_CDECL node_multi_isolate_platform_create(int thread_pool_size);
NODE_DOTNET_API void NODE_DOTNET_CDECL node_multi_isolate_platform_delete(node_multi_isolate_platform platform);
// node::MultiIsolatePlatform::DrainTasks(isolate)
NODE_DOTNET_API void NODE_DOTNET_CDECL node_multi_isolate_platform_drain_tasks(node_multi_isolate_platform platform, v8_isolate isolate);
// v8::V8::InitializePlatform / Initialize / Dispose / DisposePlatform
NODE_DOTNET_API void NODE_DOTNET_CDECL v8_initialize_platform(node_multi_isolate_platform platform);
NODE_DOTNET_API bool NODE_DOTNET_CDECL v8_initialize(void);
NODE_DOTNET_API bool NODE_DOTNET_CDECL v8_dispose(void);
NODE_DOTNET_API void NODE_DOTNET_CDECL v8_dispose_platform(void);
// ---------------------------------------------------------------------------------------------
// Environment setup (node.h: CommonEnvironmentSetup)
// ---------------------------------------------------------------------------------------------
// node::CommonEnvironmentSetup::Create(platform, &errors, args, exec_args, flags).
// Returns NULL on failure; *errors (owned by the caller, may be NULL) receives any messages.
NODE_DOTNET_API node_common_environment_setup NODE_DOTNET_CDECL node_common_environment_setup_create(
node_multi_isolate_platform platform,
node_string_list* errors,
int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv,
uint64_t flags);
NODE_DOTNET_API v8_isolate NODE_DOTNET_CDECL node_common_environment_setup_isolate(node_common_environment_setup setup);
NODE_DOTNET_API node_environment NODE_DOTNET_CDECL node_common_environment_setup_env(node_common_environment_setup setup);
// Requires an open v8_handle_scope.
NODE_DOTNET_API v8_local NODE_DOTNET_CDECL node_common_environment_setup_context(node_common_environment_setup setup);
NODE_DOTNET_API uv_loop_t* NODE_DOTNET_CDECL node_common_environment_setup_event_loop(node_common_environment_setup setup);
// Destroys the environment, isolate and loop (CommonEnvironmentSetup destructor).
NODE_DOTNET_API void NODE_DOTNET_CDECL node_common_environment_setup_delete(node_common_environment_setup setup);
// ---------------------------------------------------------------------------------------------
// Environment (node.h: LoadEnvironment, SpinEventLoop, Stop, ...)
// All of these require the locker, isolate scope, a handle scope and the context scope to be entered.
// ---------------------------------------------------------------------------------------------
// node::LoadEnvironment(env, StartExecutionCallback, EmbedderPreloadCallback).
// Returns false for an empty MaybeLocal (exception / termination); otherwise *result is the value.
NODE_DOTNET_API bool NODE_DOTNET_CDECL node_load_environment(
node_environment env,
node_start_execution_callback start_execution,
void* start_execution_data,
node_embedder_preload_callback preload,
void* preload_data,
v8_local* result);
// node::LoadEnvironment(env, main_script_source_utf8, EmbedderPreloadCallback)
NODE_DOTNET_API bool NODE_DOTNET_CDECL node_load_environment_script(
node_environment env,
const char* main_script_source_utf8,
node_embedder_preload_callback preload,
void* preload_data,
v8_local* result);
// node::SpinEventLoop(env): runs the loop to completion, emitting beforeExit/exit.
// Returns false for Nothing (node::Stop was called); otherwise *exit_code is the exit code.
NODE_DOTNET_API bool NODE_DOTNET_CDECL node_spin_event_loop(node_environment env, int* exit_code);
// node::EmitProcessBeforeExit / EmitProcessExit (for embedders driving uv_run themselves).
// Both return false for Nothing (an exception was thrown while emitting).
NODE_DOTNET_API bool NODE_DOTNET_CDECL node_emit_process_before_exit(node_environment env, bool* result);
NODE_DOTNET_API bool NODE_DOTNET_CDECL node_emit_process_exit(node_environment env, int* exit_code);
// node::Stop(env, flags)
NODE_DOTNET_API int NODE_DOTNET_CDECL node_stop(node_environment env, uint32_t flags);
// node::GetMainContext(env). Requires an open v8_handle_scope.
NODE_DOTNET_API v8_local NODE_DOTNET_CDECL node_get_main_context(node_environment env);
// node::GetCurrentEnvironment(context)
NODE_DOTNET_API node_environment NODE_DOTNET_CDECL node_get_current_environment(v8_local context);
// node::GetCurrentEventLoop(isolate)
NODE_DOTNET_API uv_loop_t* NODE_DOTNET_CDECL node_get_current_event_loop(v8_isolate isolate);
// node::AddLinkedBinding(env, name, napi_addon_register_func, module_api_version).
// Makes process._linkedBinding(name) available; name is copied. Node creates a napi_env for the
// binding and passes it to init.
NODE_DOTNET_API void NODE_DOTNET_CDECL node_add_linked_binding_napi(
node_environment env,
const char* name,
napi_addon_register_func init,
int32_t module_api_version);
// node::addon_context_register_func: the non-Node-API linked binding entry point. exports, module
// and context are v8 locals (exports/module usable as napi_value given a napi_env for the
// environment); priv is the pointer given to node_add_linked_binding.
typedef void(NODE_DOTNET_CDECL* node_addon_context_register_func)(
v8_local exports,
v8_local module,
v8_local context,
void* priv);
// node::AddLinkedBinding(env, name, addon_context_register_func, priv). Name is copied.
NODE_DOTNET_API void NODE_DOTNET_CDECL node_add_linked_binding(
node_environment env,
const char* name,
node_addon_context_register_func fn,
void* priv);
// node::AddEnvironmentCleanupHook / RemoveEnvironmentCleanupHook
NODE_DOTNET_API void NODE_DOTNET_CDECL node_add_environment_cleanup_hook(v8_isolate isolate, node_cleanup_hook_callback fun, void* arg);
NODE_DOTNET_API void NODE_DOTNET_CDECL node_remove_environment_cleanup_hook(v8_isolate isolate, node_cleanup_hook_callback fun, void* arg);
// ---------------------------------------------------------------------------------------------
// V8 scopes (v8.h: Locker, Isolate::Scope, HandleScope, Context::Scope)
// ---------------------------------------------------------------------------------------------
// v8::Isolate::GetCurrent(): the isolate entered on the current thread (e.g. in a worker's preload).
NODE_DOTNET_API v8_isolate NODE_DOTNET_CDECL v8_isolate_get_current(void);
NODE_DOTNET_API v8_locker NODE_DOTNET_CDECL v8_locker_new(v8_isolate isolate);
NODE_DOTNET_API void NODE_DOTNET_CDECL v8_locker_delete(v8_locker locker);
NODE_DOTNET_API bool NODE_DOTNET_CDECL v8_locker_is_locked(v8_isolate isolate);
NODE_DOTNET_API v8_isolate_scope NODE_DOTNET_CDECL v8_isolate_scope_new(v8_isolate isolate);
NODE_DOTNET_API void NODE_DOTNET_CDECL v8_isolate_scope_delete(v8_isolate_scope scope);
NODE_DOTNET_API v8_handle_scope NODE_DOTNET_CDECL v8_handle_scope_new(v8_isolate isolate);
NODE_DOTNET_API void NODE_DOTNET_CDECL v8_handle_scope_delete(v8_handle_scope scope);
NODE_DOTNET_API v8_context_scope NODE_DOTNET_CDECL v8_context_scope_new(v8_local context);
NODE_DOTNET_API void NODE_DOTNET_CDECL v8_context_scope_delete(v8_context_scope scope);
// ---------------------------------------------------------------------------------------------
// V8 scripts (v8.h: Script::Compile + Run), for running JS before a napi_env exists.
// Returns false if compilation or execution threw; *result receives the completion value.
// ---------------------------------------------------------------------------------------------
NODE_DOTNET_API bool NODE_DOTNET_CDECL v8_script_compile_and_run(
v8_isolate isolate,
v8_local context,
const char* source_utf8,
const char* resource_name_utf8,
v8_local* result);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // LIBNODE_DOTNET_H_