@secure-exec/nodejs 0.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +7 -0
  3. package/dist/bindings.d.ts +31 -0
  4. package/dist/bindings.js +67 -0
  5. package/dist/bridge/active-handles.d.ts +22 -0
  6. package/dist/bridge/active-handles.js +112 -0
  7. package/dist/bridge/child-process.d.ts +99 -0
  8. package/dist/bridge/child-process.js +672 -0
  9. package/dist/bridge/dispatch.d.ts +2 -0
  10. package/dist/bridge/dispatch.js +40 -0
  11. package/dist/bridge/fs.d.ts +502 -0
  12. package/dist/bridge/fs.js +3307 -0
  13. package/dist/bridge/index.d.ts +10 -0
  14. package/dist/bridge/index.js +41 -0
  15. package/dist/bridge/module.d.ts +75 -0
  16. package/dist/bridge/module.js +325 -0
  17. package/dist/bridge/network.d.ts +1093 -0
  18. package/dist/bridge/network.js +8651 -0
  19. package/dist/bridge/os.d.ts +13 -0
  20. package/dist/bridge/os.js +256 -0
  21. package/dist/bridge/polyfills.d.ts +9 -0
  22. package/dist/bridge/polyfills.js +67 -0
  23. package/dist/bridge/process.d.ts +121 -0
  24. package/dist/bridge/process.js +1382 -0
  25. package/dist/bridge/whatwg-url.d.ts +67 -0
  26. package/dist/bridge/whatwg-url.js +712 -0
  27. package/dist/bridge-contract.d.ts +774 -0
  28. package/dist/bridge-contract.js +172 -0
  29. package/dist/bridge-handlers.d.ts +199 -0
  30. package/dist/bridge-handlers.js +4263 -0
  31. package/dist/bridge-loader.d.ts +9 -0
  32. package/dist/bridge-loader.js +87 -0
  33. package/dist/bridge-setup.d.ts +1 -0
  34. package/dist/bridge-setup.js +3 -0
  35. package/dist/bridge.js +21652 -0
  36. package/dist/builtin-modules.d.ts +25 -0
  37. package/dist/builtin-modules.js +312 -0
  38. package/dist/default-network-adapter.d.ts +13 -0
  39. package/dist/default-network-adapter.js +351 -0
  40. package/dist/driver.d.ts +87 -0
  41. package/dist/driver.js +191 -0
  42. package/dist/esm-compiler.d.ts +14 -0
  43. package/dist/esm-compiler.js +68 -0
  44. package/dist/execution-driver.d.ts +37 -0
  45. package/dist/execution-driver.js +977 -0
  46. package/dist/host-network-adapter.d.ts +7 -0
  47. package/dist/host-network-adapter.js +279 -0
  48. package/dist/index.d.ts +20 -0
  49. package/dist/index.js +23 -0
  50. package/dist/isolate-bootstrap.d.ts +86 -0
  51. package/dist/isolate-bootstrap.js +125 -0
  52. package/dist/ivm-compat.d.ts +7 -0
  53. package/dist/ivm-compat.js +31 -0
  54. package/dist/kernel-runtime.d.ts +58 -0
  55. package/dist/kernel-runtime.js +535 -0
  56. package/dist/module-access.d.ts +75 -0
  57. package/dist/module-access.js +606 -0
  58. package/dist/module-resolver.d.ts +8 -0
  59. package/dist/module-resolver.js +150 -0
  60. package/dist/os-filesystem.d.ts +42 -0
  61. package/dist/os-filesystem.js +161 -0
  62. package/dist/package-bundler.d.ts +36 -0
  63. package/dist/package-bundler.js +497 -0
  64. package/dist/polyfills.d.ts +17 -0
  65. package/dist/polyfills.js +97 -0
  66. package/dist/worker-adapter.d.ts +21 -0
  67. package/dist/worker-adapter.js +34 -0
  68. package/package.json +123 -0
@@ -0,0 +1,87 @@
1
+ import { filterEnv } from "@secure-exec/core/internal/shared/permissions";
2
+ import { NodeExecutionDriver } from "./execution-driver.js";
3
+ import { createDefaultNetworkAdapter, isPrivateIp } from "./default-network-adapter.js";
4
+ import type { OSConfig, ProcessConfig } from "@secure-exec/core/internal/shared/api-types";
5
+ import type { Permissions, VirtualFileSystem } from "@secure-exec/core";
6
+ import type { CommandExecutor, NetworkAdapter, NodeRuntimeDriverFactory, SystemDriver } from "@secure-exec/core";
7
+ import type { ModuleAccessOptions } from "./module-access.js";
8
+ /** Options for assembling a Node.js-backed SystemDriver. */
9
+ export interface NodeDriverOptions {
10
+ filesystem?: VirtualFileSystem;
11
+ moduleAccess?: ModuleAccessOptions;
12
+ networkAdapter?: NetworkAdapter;
13
+ commandExecutor?: CommandExecutor;
14
+ permissions?: Permissions;
15
+ useDefaultNetwork?: boolean;
16
+ processConfig?: ProcessConfig;
17
+ osConfig?: OSConfig;
18
+ }
19
+ export interface NodeRuntimeDriverFactoryOptions {
20
+ createIsolate?(memoryLimit: number): unknown;
21
+ }
22
+ /** Thin VFS adapter that delegates directly to `node:fs/promises`. */
23
+ export declare class NodeFileSystem implements VirtualFileSystem {
24
+ prepareOpenSync(filePath: string, flags: number): boolean;
25
+ readFile(path: string): Promise<Uint8Array>;
26
+ readTextFile(path: string): Promise<string>;
27
+ readDir(path: string): Promise<string[]>;
28
+ readDirWithTypes(path: string): Promise<Array<{
29
+ name: string;
30
+ isDirectory: boolean;
31
+ }>>;
32
+ writeFile(path: string, content: string | Uint8Array): Promise<void>;
33
+ createDir(path: string): Promise<void>;
34
+ mkdir(path: string, _options?: {
35
+ recursive?: boolean;
36
+ }): Promise<void>;
37
+ exists(path: string): Promise<boolean>;
38
+ stat(path: string): Promise<{
39
+ mode: number;
40
+ size: number;
41
+ isDirectory: boolean;
42
+ isSymbolicLink: boolean;
43
+ atimeMs: number;
44
+ mtimeMs: number;
45
+ ctimeMs: number;
46
+ birthtimeMs: number;
47
+ ino: number;
48
+ nlink: number;
49
+ uid: number;
50
+ gid: number;
51
+ }>;
52
+ removeFile(path: string): Promise<void>;
53
+ removeDir(path: string): Promise<void>;
54
+ rename(oldPath: string, newPath: string): Promise<void>;
55
+ symlink(target: string, linkPath: string): Promise<void>;
56
+ readlink(path: string): Promise<string>;
57
+ lstat(path: string): Promise<{
58
+ mode: number;
59
+ size: number;
60
+ isDirectory: boolean;
61
+ isSymbolicLink: boolean;
62
+ atimeMs: number;
63
+ mtimeMs: number;
64
+ ctimeMs: number;
65
+ birthtimeMs: number;
66
+ ino: number;
67
+ nlink: number;
68
+ uid: number;
69
+ gid: number;
70
+ }>;
71
+ link(oldPath: string, newPath: string): Promise<void>;
72
+ chmod(path: string, mode: number): Promise<void>;
73
+ chown(path: string, uid: number, gid: number): Promise<void>;
74
+ utimes(path: string, atime: number, mtime: number): Promise<void>;
75
+ truncate(path: string, length: number): Promise<void>;
76
+ realpath(path: string): Promise<string>;
77
+ pread(path: string, offset: number, length: number): Promise<Uint8Array>;
78
+ }
79
+ /**
80
+ * Assemble a SystemDriver from Node.js-native adapters. Wraps the filesystem
81
+ * in a ModuleAccessFileSystem overlay and keeps capabilities deny-by-default
82
+ * unless explicit permissions are provided.
83
+ */
84
+ export declare function createNodeDriver(options?: NodeDriverOptions): SystemDriver;
85
+ export declare function createNodeRuntimeDriverFactory(options?: NodeRuntimeDriverFactoryOptions): NodeRuntimeDriverFactory;
86
+ export { createDefaultNetworkAdapter, filterEnv, isPrivateIp, NodeExecutionDriver, };
87
+ export type { ModuleAccessOptions };
package/dist/driver.js ADDED
@@ -0,0 +1,191 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as fsSync from "node:fs";
3
+ import path from "node:path";
4
+ import { filterEnv, } from "@secure-exec/core/internal/shared/permissions";
5
+ import { ModuleAccessFileSystem } from "./module-access.js";
6
+ import { NodeExecutionDriver } from "./execution-driver.js";
7
+ import { createDefaultNetworkAdapter, isPrivateIp, } from "./default-network-adapter.js";
8
+ import { KernelError, O_CREAT, O_EXCL, O_TRUNC } from "@secure-exec/core";
9
+ /** Thin VFS adapter that delegates directly to `node:fs/promises`. */
10
+ export class NodeFileSystem {
11
+ prepareOpenSync(filePath, flags) {
12
+ const hasCreate = (flags & O_CREAT) !== 0;
13
+ const hasExcl = (flags & O_EXCL) !== 0;
14
+ const hasTrunc = (flags & O_TRUNC) !== 0;
15
+ const exists = fsSync.existsSync(filePath);
16
+ if (hasCreate && hasExcl && exists) {
17
+ throw new KernelError("EEXIST", `file already exists, open '${filePath}'`);
18
+ }
19
+ let created = false;
20
+ if (!exists && hasCreate) {
21
+ fsSync.mkdirSync(path.dirname(filePath), { recursive: true });
22
+ fsSync.writeFileSync(filePath, new Uint8Array(0));
23
+ created = true;
24
+ }
25
+ if (hasTrunc) {
26
+ try {
27
+ fsSync.truncateSync(filePath, 0);
28
+ }
29
+ catch (error) {
30
+ const err = error;
31
+ if (err.code === "ENOENT") {
32
+ throw new KernelError("ENOENT", `no such file or directory, open '${filePath}'`);
33
+ }
34
+ if (err.code === "EISDIR") {
35
+ throw new KernelError("EISDIR", `illegal operation on a directory, open '${filePath}'`);
36
+ }
37
+ throw error;
38
+ }
39
+ }
40
+ return created;
41
+ }
42
+ async readFile(path) {
43
+ return fs.readFile(path);
44
+ }
45
+ async readTextFile(path) {
46
+ return fs.readFile(path, "utf8");
47
+ }
48
+ async readDir(path) {
49
+ return fs.readdir(path);
50
+ }
51
+ async readDirWithTypes(path) {
52
+ const entries = await fs.readdir(path, { withFileTypes: true });
53
+ return entries.map((entry) => ({
54
+ name: entry.name,
55
+ isDirectory: entry.isDirectory(),
56
+ }));
57
+ }
58
+ async writeFile(path, content) {
59
+ await fs.writeFile(path, content);
60
+ }
61
+ async createDir(path) {
62
+ await fs.mkdir(path);
63
+ }
64
+ async mkdir(path, _options) {
65
+ await fs.mkdir(path, { recursive: true });
66
+ }
67
+ async exists(path) {
68
+ try {
69
+ await fs.access(path);
70
+ return true;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ async stat(path) {
77
+ const info = await fs.stat(path);
78
+ return {
79
+ mode: info.mode,
80
+ size: info.size,
81
+ isDirectory: info.isDirectory(),
82
+ isSymbolicLink: false,
83
+ atimeMs: info.atimeMs,
84
+ mtimeMs: info.mtimeMs,
85
+ ctimeMs: info.ctimeMs,
86
+ birthtimeMs: info.birthtimeMs,
87
+ ino: info.ino,
88
+ nlink: info.nlink,
89
+ uid: info.uid,
90
+ gid: info.gid,
91
+ };
92
+ }
93
+ async removeFile(path) {
94
+ await fs.unlink(path);
95
+ }
96
+ async removeDir(path) {
97
+ await fs.rmdir(path);
98
+ }
99
+ async rename(oldPath, newPath) {
100
+ await fs.rename(oldPath, newPath);
101
+ }
102
+ async symlink(target, linkPath) {
103
+ await fs.symlink(target, linkPath);
104
+ }
105
+ async readlink(path) {
106
+ return fs.readlink(path);
107
+ }
108
+ async lstat(path) {
109
+ const info = await fs.lstat(path);
110
+ return {
111
+ mode: info.mode,
112
+ size: info.size,
113
+ isDirectory: info.isDirectory(),
114
+ isSymbolicLink: info.isSymbolicLink(),
115
+ atimeMs: info.atimeMs,
116
+ mtimeMs: info.mtimeMs,
117
+ ctimeMs: info.ctimeMs,
118
+ birthtimeMs: info.birthtimeMs,
119
+ ino: info.ino,
120
+ nlink: info.nlink,
121
+ uid: info.uid,
122
+ gid: info.gid,
123
+ };
124
+ }
125
+ async link(oldPath, newPath) {
126
+ await fs.link(oldPath, newPath);
127
+ }
128
+ async chmod(path, mode) {
129
+ await fs.chmod(path, mode);
130
+ }
131
+ async chown(path, uid, gid) {
132
+ await fs.chown(path, uid, gid);
133
+ }
134
+ async utimes(path, atime, mtime) {
135
+ await fs.utimes(path, atime, mtime);
136
+ }
137
+ async truncate(path, length) {
138
+ await fs.truncate(path, length);
139
+ }
140
+ async realpath(path) {
141
+ return fs.realpath(path);
142
+ }
143
+ async pread(path, offset, length) {
144
+ const handle = await fs.open(path, "r");
145
+ try {
146
+ const buf = new Uint8Array(length);
147
+ const { bytesRead } = await handle.read(buf, 0, length, offset);
148
+ return buf.slice(0, bytesRead);
149
+ }
150
+ finally {
151
+ await handle.close();
152
+ }
153
+ }
154
+ }
155
+ /**
156
+ * Assemble a SystemDriver from Node.js-native adapters. Wraps the filesystem
157
+ * in a ModuleAccessFileSystem overlay and keeps capabilities deny-by-default
158
+ * unless explicit permissions are provided.
159
+ */
160
+ export function createNodeDriver(options = {}) {
161
+ const filesystem = new ModuleAccessFileSystem(options.filesystem, options.moduleAccess ?? {});
162
+ const permissions = options.permissions;
163
+ const networkAdapter = options.networkAdapter
164
+ ? options.networkAdapter
165
+ : options.useDefaultNetwork
166
+ ? createDefaultNetworkAdapter()
167
+ : undefined;
168
+ return {
169
+ filesystem,
170
+ network: networkAdapter,
171
+ commandExecutor: options.commandExecutor,
172
+ permissions,
173
+ runtime: {
174
+ process: {
175
+ ...(options.processConfig ?? {}),
176
+ },
177
+ os: {
178
+ ...(options.osConfig ?? {}),
179
+ },
180
+ },
181
+ };
182
+ }
183
+ export function createNodeRuntimeDriverFactory(options = {}) {
184
+ return {
185
+ createRuntimeDriver: (runtimeOptions) => new NodeExecutionDriver({
186
+ ...runtimeOptions,
187
+ createIsolate: options.createIsolate,
188
+ }),
189
+ };
190
+ }
191
+ export { createDefaultNetworkAdapter, filterEnv, isPrivateIp, NodeExecutionDriver, };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ESM wrapper generator for built-in modules inside the isolate.
3
+ *
4
+ * The V8 isolate's ESM `import` can only resolve modules we explicitly provide.
5
+ * For Node built-ins (fs, path, etc.) we generate thin ESM wrappers that
6
+ * re-export the bridge-provided globalThis objects as proper ESM modules
7
+ * with both default and named exports.
8
+ */
9
+ /** Get a pre-built ESM wrapper for a bridge-backed built-in, or null if not bridge-handled. */
10
+ export declare function getStaticBuiltinWrapperSource(moduleName: string): string | null;
11
+ /** Build a custom ESM wrapper for a dynamically-resolved module (e.g. polyfills). */
12
+ export declare function createBuiltinESMWrapper(bindingExpression: string, namedExports: string[]): string;
13
+ /** Wrapper for unsupported built-ins: exports an empty object as default. */
14
+ export declare function getEmptyBuiltinESMWrapper(): string;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * ESM wrapper generator for built-in modules inside the isolate.
3
+ *
4
+ * The V8 isolate's ESM `import` can only resolve modules we explicitly provide.
5
+ * For Node built-ins (fs, path, etc.) we generate thin ESM wrappers that
6
+ * re-export the bridge-provided globalThis objects as proper ESM modules
7
+ * with both default and named exports.
8
+ */
9
+ import { BUILTIN_NAMED_EXPORTS } from "./builtin-modules.js";
10
+ function isValidIdentifier(value) {
11
+ return /^[$A-Z_][0-9A-Z_$]*$/i.test(value);
12
+ }
13
+ /** Generate `export const X = _builtin.X;` lines for each known named export. */
14
+ function buildNamedExportLines(namedExports) {
15
+ return Array.from(new Set(namedExports))
16
+ .filter(isValidIdentifier)
17
+ .map((name) => "export const " +
18
+ name +
19
+ " = _builtin == null ? undefined : _builtin[" +
20
+ JSON.stringify(name) +
21
+ "];");
22
+ }
23
+ /**
24
+ * Build a complete ESM wrapper that reads a bridge global via `bindingExpression`
25
+ * and re-exports it as `default` plus individual named exports.
26
+ */
27
+ function buildWrapperSource(bindingExpression, namedExports) {
28
+ const lines = [
29
+ "const _builtin = " + bindingExpression + ";",
30
+ "export default _builtin;",
31
+ ...buildNamedExportLines(namedExports),
32
+ ];
33
+ return lines.join("\n");
34
+ }
35
+ const MODULE_FALLBACK_BINDING = "globalThis.bridge?.module || {" +
36
+ "createRequire: globalThis._createRequire || function(f) {" +
37
+ "const dir = f.replace(/\\\\[^\\\\]*$/, '') || '/';" +
38
+ "return function(m) { return globalThis._requireFrom(m, dir); };" +
39
+ "}," +
40
+ "Module: { builtinModules: [] }," +
41
+ "isBuiltin: () => false," +
42
+ "builtinModules: []" +
43
+ "}";
44
+ const STATIC_BUILTIN_WRAPPER_SOURCES = {
45
+ fs: buildWrapperSource("globalThis.bridge?.fs || globalThis.bridge?.default || {}", BUILTIN_NAMED_EXPORTS.fs),
46
+ "fs/promises": buildWrapperSource("(globalThis.bridge?.fs || globalThis.bridge?.default || {}).promises || {}", BUILTIN_NAMED_EXPORTS["fs/promises"]),
47
+ module: buildWrapperSource(MODULE_FALLBACK_BINDING, BUILTIN_NAMED_EXPORTS.module),
48
+ os: buildWrapperSource("globalThis.bridge?.os || {}", BUILTIN_NAMED_EXPORTS.os),
49
+ http: buildWrapperSource("globalThis._httpModule || globalThis.bridge?.network?.http || {}", BUILTIN_NAMED_EXPORTS.http),
50
+ https: buildWrapperSource("globalThis._httpsModule || globalThis.bridge?.network?.https || {}", BUILTIN_NAMED_EXPORTS.https),
51
+ http2: buildWrapperSource("globalThis._http2Module || {}", []),
52
+ dns: buildWrapperSource("globalThis._dnsModule || globalThis.bridge?.network?.dns || {}", BUILTIN_NAMED_EXPORTS.dns),
53
+ child_process: buildWrapperSource("globalThis._childProcessModule || globalThis.bridge?.childProcess || {}", BUILTIN_NAMED_EXPORTS.child_process),
54
+ process: buildWrapperSource("globalThis.process || {}", BUILTIN_NAMED_EXPORTS.process),
55
+ v8: buildWrapperSource("globalThis._moduleCache?.v8 || {}", []),
56
+ };
57
+ /** Get a pre-built ESM wrapper for a bridge-backed built-in, or null if not bridge-handled. */
58
+ export function getStaticBuiltinWrapperSource(moduleName) {
59
+ return STATIC_BUILTIN_WRAPPER_SOURCES[moduleName] ?? null;
60
+ }
61
+ /** Build a custom ESM wrapper for a dynamically-resolved module (e.g. polyfills). */
62
+ export function createBuiltinESMWrapper(bindingExpression, namedExports) {
63
+ return buildWrapperSource(bindingExpression, namedExports);
64
+ }
65
+ /** Wrapper for unsupported built-ins: exports an empty object as default. */
66
+ export function getEmptyBuiltinESMWrapper() {
67
+ return buildWrapperSource("{}", []);
68
+ }
@@ -0,0 +1,37 @@
1
+ import type { NetworkAdapter, RuntimeDriver } from "@secure-exec/core";
2
+ import type { ExecOptions, ExecResult, RunResult } from "@secure-exec/core/internal/shared/api-types";
3
+ import { type NodeExecutionDriverOptions } from "./isolate-bootstrap.js";
4
+ export { NodeExecutionDriverOptions };
5
+ export declare class NodeExecutionDriver implements RuntimeDriver {
6
+ private state;
7
+ private memoryLimit;
8
+ private disposed;
9
+ private flattenedBindings;
10
+ private rawFilesystem;
11
+ private socketTable?;
12
+ private processTable?;
13
+ private timerTable;
14
+ private ownsProcessTable;
15
+ private ownsTimerTable;
16
+ private configuredMaxTimers?;
17
+ private configuredMaxHandles?;
18
+ private pid?;
19
+ constructor(options: NodeExecutionDriverOptions);
20
+ get network(): Pick<NetworkAdapter, "fetch" | "dnsLookup" | "httpRequest">;
21
+ get unsafeIsolate(): unknown;
22
+ private hasManagedResources;
23
+ private waitForManagedResources;
24
+ private ensureBridgeProcessEntry;
25
+ private clearKernelTimersForProcess;
26
+ private finalizeExecutionState;
27
+ createUnsafeContext(_options?: {
28
+ env?: Record<string, string>;
29
+ cwd?: string;
30
+ filePath?: string;
31
+ }): Promise<unknown>;
32
+ run<T = unknown>(code: string, filePath?: string): Promise<RunResult<T>>;
33
+ exec(code: string, options?: ExecOptions): Promise<ExecResult>;
34
+ private executeInternal;
35
+ dispose(): void;
36
+ terminate(): Promise<void>;
37
+ }