@secure-exec/core 0.1.1-rc.3 → 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 (102) hide show
  1. package/dist/esm-compiler.d.ts +5 -1
  2. package/dist/esm-compiler.js +5 -1
  3. package/dist/fs-helpers.d.ts +1 -1
  4. package/dist/generated/isolate-runtime.d.ts +15 -15
  5. package/dist/generated/isolate-runtime.js +15 -15
  6. package/dist/index.d.ts +24 -5
  7. package/dist/index.js +23 -3
  8. package/dist/isolate-runtime/apply-custom-global-policy.js +3 -3
  9. package/dist/isolate-runtime/apply-timing-mitigation-freeze.js +2 -2
  10. package/dist/isolate-runtime/apply-timing-mitigation-off.js +2 -2
  11. package/dist/isolate-runtime/bridge-attach.js +2 -2
  12. package/dist/isolate-runtime/bridge-initial-globals.js +145 -6
  13. package/dist/isolate-runtime/eval-script-result.js +1 -1
  14. package/dist/isolate-runtime/global-exposure-helpers.js +2 -2
  15. package/dist/isolate-runtime/init-commonjs-module-globals.js +2 -2
  16. package/dist/isolate-runtime/override-process-cwd.js +1 -1
  17. package/dist/isolate-runtime/override-process-env.js +1 -1
  18. package/dist/isolate-runtime/require-setup.js +1600 -338
  19. package/dist/isolate-runtime/set-commonjs-file-globals.js +2 -2
  20. package/dist/isolate-runtime/set-stdin-data.js +1 -1
  21. package/dist/isolate-runtime/setup-dynamic-import.js +47 -19
  22. package/dist/isolate-runtime/setup-fs-facade.js +62 -23
  23. package/dist/kernel/command-registry.d.ts +44 -0
  24. package/dist/kernel/command-registry.js +114 -0
  25. package/dist/kernel/device-layer.d.ts +12 -0
  26. package/dist/kernel/device-layer.js +262 -0
  27. package/dist/kernel/dns-cache.d.ts +29 -0
  28. package/dist/kernel/dns-cache.js +52 -0
  29. package/dist/kernel/fd-table.d.ts +84 -0
  30. package/dist/kernel/fd-table.js +278 -0
  31. package/dist/kernel/file-lock.d.ts +34 -0
  32. package/dist/kernel/file-lock.js +123 -0
  33. package/dist/kernel/host-adapter.d.ts +50 -0
  34. package/dist/kernel/host-adapter.js +8 -0
  35. package/dist/kernel/index.d.ts +36 -0
  36. package/dist/kernel/index.js +34 -0
  37. package/dist/kernel/inode-table.d.ts +43 -0
  38. package/dist/kernel/inode-table.js +85 -0
  39. package/dist/kernel/kernel.d.ts +9 -0
  40. package/dist/kernel/kernel.js +1396 -0
  41. package/dist/kernel/permissions.d.ts +27 -0
  42. package/dist/kernel/permissions.js +118 -0
  43. package/dist/kernel/pipe-manager.d.ts +64 -0
  44. package/dist/kernel/pipe-manager.js +267 -0
  45. package/dist/kernel/proc-layer.d.ts +11 -0
  46. package/dist/kernel/proc-layer.js +501 -0
  47. package/dist/kernel/process-table.d.ts +124 -0
  48. package/dist/kernel/process-table.js +631 -0
  49. package/dist/kernel/pty.d.ts +108 -0
  50. package/dist/kernel/pty.js +541 -0
  51. package/dist/kernel/socket-table.d.ts +305 -0
  52. package/dist/kernel/socket-table.js +1124 -0
  53. package/dist/kernel/timer-table.d.ts +54 -0
  54. package/dist/kernel/timer-table.js +108 -0
  55. package/dist/kernel/types.d.ts +500 -0
  56. package/dist/kernel/types.js +89 -0
  57. package/dist/kernel/user.d.ts +29 -0
  58. package/dist/kernel/user.js +35 -0
  59. package/dist/kernel/vfs.d.ts +54 -0
  60. package/dist/kernel/vfs.js +8 -0
  61. package/dist/kernel/wait.d.ts +45 -0
  62. package/dist/kernel/wait.js +112 -0
  63. package/dist/kernel/wstatus.d.ts +21 -0
  64. package/dist/kernel/wstatus.js +33 -0
  65. package/dist/module-resolver.d.ts +4 -0
  66. package/dist/module-resolver.js +4 -0
  67. package/dist/package-bundler.d.ts +6 -1
  68. package/dist/runtime-driver.d.ts +3 -1
  69. package/dist/shared/bridge-contract.d.ts +329 -20
  70. package/dist/shared/bridge-contract.js +60 -5
  71. package/dist/shared/console-formatter.js +8 -4
  72. package/dist/shared/global-exposure.js +269 -19
  73. package/dist/shared/in-memory-fs.d.ts +30 -11
  74. package/dist/shared/in-memory-fs.js +383 -109
  75. package/dist/shared/permissions.d.ts +4 -6
  76. package/dist/shared/permissions.js +19 -39
  77. package/dist/types.d.ts +8 -159
  78. package/dist/types.js +5 -0
  79. package/package.json +12 -22
  80. package/dist/bridge/active-handles.d.ts +0 -22
  81. package/dist/bridge/active-handles.js +0 -55
  82. package/dist/bridge/child-process.d.ts +0 -99
  83. package/dist/bridge/child-process.js +0 -670
  84. package/dist/bridge/fs.d.ts +0 -281
  85. package/dist/bridge/fs.js +0 -2235
  86. package/dist/bridge/index.d.ts +0 -10
  87. package/dist/bridge/index.js +0 -41
  88. package/dist/bridge/module.d.ts +0 -75
  89. package/dist/bridge/module.js +0 -308
  90. package/dist/bridge/network.d.ts +0 -350
  91. package/dist/bridge/network.js +0 -2050
  92. package/dist/bridge/os.d.ts +0 -13
  93. package/dist/bridge/os.js +0 -256
  94. package/dist/bridge/polyfills.d.ts +0 -2
  95. package/dist/bridge/polyfills.js +0 -11
  96. package/dist/bridge/process.d.ts +0 -89
  97. package/dist/bridge/process.js +0 -1015
  98. package/dist/bridge.js +0 -12496
  99. package/dist/python-runtime.d.ts +0 -16
  100. package/dist/python-runtime.js +0 -45
  101. package/dist/runtime.d.ts +0 -31
  102. package/dist/runtime.js +0 -69
@@ -133,9 +133,9 @@ export function wrapFileSystem(fs, permissions) {
133
133
  checkFs("createDir", path);
134
134
  return fs.createDir(path);
135
135
  },
136
- mkdir: async (path) => {
136
+ mkdir: async (path, options) => {
137
137
  checkFs("mkdir", path);
138
- return fs.mkdir(path);
138
+ return fs.mkdir(path, options);
139
139
  },
140
140
  exists: async (path) => {
141
141
  checkFs("exists", path);
@@ -190,33 +190,20 @@ export function wrapFileSystem(fs, permissions) {
190
190
  checkFs("truncate", path);
191
191
  return fs.truncate(path, length);
192
192
  },
193
+ realpath: async (path) => {
194
+ checkFs("read", path);
195
+ return fs.realpath(path);
196
+ },
197
+ pread: async (path, offset, length) => {
198
+ checkFs("read", path);
199
+ return fs.pread(path, offset, length);
200
+ },
193
201
  };
194
202
  }
195
- /**
196
- * Wrap a NetworkAdapter so externally-originating operations (`listen`, `fetch`,
197
- * `dns`, `http`) pass through the network permission check.
198
- * `httpServerClose` is forwarded as-is.
199
- */
203
+ /** Wrap a NetworkAdapter so external client operations pass through the network permission check. */
200
204
  export function wrapNetworkAdapter(adapter, permissions) {
201
- return {
202
- httpServerListen: adapter.httpServerListen
203
- ? async (options) => {
204
- checkPermission(permissions?.network, {
205
- op: "listen",
206
- hostname: options.hostname,
207
- url: options.hostname
208
- ? `http://${options.hostname}:${options.port ?? 3000}`
209
- : `http://0.0.0.0:${options.port ?? 3000}`,
210
- method: "LISTEN",
211
- }, (req, reason) => createEaccesError("listen", req.url, reason));
212
- return adapter.httpServerListen(options);
213
- }
214
- : undefined,
215
- httpServerClose: adapter.httpServerClose
216
- ? async (serverId) => {
217
- return adapter.httpServerClose(serverId);
218
- }
219
- : undefined,
205
+ const loopbackAwareAdapter = adapter;
206
+ const wrapped = {
220
207
  fetch: async (url, options) => {
221
208
  checkPermission(permissions?.network, { op: "fetch", url, method: options?.method }, (req, reason) => createEaccesError("connect", req.url, reason));
222
209
  return adapter.fetch(url, options);
@@ -234,18 +221,11 @@ export function wrapNetworkAdapter(adapter, permissions) {
234
221
  upgradeSocketEnd: adapter.upgradeSocketEnd?.bind(adapter),
235
222
  upgradeSocketDestroy: adapter.upgradeSocketDestroy?.bind(adapter),
236
223
  setUpgradeSocketCallbacks: adapter.setUpgradeSocketCallbacks?.bind(adapter),
237
- // Forward TCP socket (net module) methods with permission check on connect
238
- netSocketConnect: adapter.netSocketConnect
239
- ? (host, port, callbacks) => {
240
- checkPermission(permissions?.network, { op: "connect", hostname: host, port }, (req, reason) => createEaccesError("connect", `${req.hostname}:${req.port}`, reason));
241
- return adapter.netSocketConnect(host, port, callbacks);
242
- }
243
- : undefined,
244
- netSocketWrite: adapter.netSocketWrite?.bind(adapter),
245
- netSocketEnd: adapter.netSocketEnd?.bind(adapter),
246
- netSocketDestroy: adapter.netSocketDestroy?.bind(adapter),
247
- netSocketUpgradeTls: adapter.netSocketUpgradeTls?.bind(adapter),
248
224
  };
225
+ if (typeof loopbackAwareAdapter.__setLoopbackPortChecker === "function") {
226
+ wrapped.__setLoopbackPortChecker = (checker) => loopbackAwareAdapter.__setLoopbackPortChecker(checker);
227
+ }
228
+ return wrapped;
249
229
  }
250
230
  /** Wrap a CommandExecutor so spawn passes through the childProcess permission check. */
251
231
  export function wrapCommandExecutor(executor, permissions) {
@@ -285,6 +265,8 @@ export function createFsStub() {
285
265
  chown: async (path) => stub("chown", path),
286
266
  utimes: async (path) => stub("utimes", path),
287
267
  truncate: async (path) => stub("open", path),
268
+ realpath: async (path) => stub("realpath", path),
269
+ pread: async (path) => stub("open", path),
288
270
  };
289
271
  }
290
272
  /** Create a stub network adapter where every operation throws ENOSYS. */
@@ -293,8 +275,6 @@ export function createNetworkStub() {
293
275
  throw createEnosysError(op, path);
294
276
  };
295
277
  return {
296
- httpServerListen: async () => stub("listen"),
297
- httpServerClose: async () => stub("close"),
298
278
  fetch: async (url) => stub("connect", url),
299
279
  dnsLookup: async (hostname) => stub("connect", hostname),
300
280
  httpRequest: async (url) => stub("connect", url),
package/dist/types.d.ts CHANGED
@@ -1,100 +1,8 @@
1
1
  /**
2
- * Minimal filesystem interface for secure-exec.
2
+ * Core-only types for secure-exec SDK.
3
3
  *
4
- * This interface abstracts filesystem operations needed by the sandbox.
4
+ * VFS and permission types are now defined in src/kernel/ (canonical source).
5
5
  */
6
- export interface VirtualDirEntry {
7
- name: string;
8
- isDirectory: boolean;
9
- }
10
- export interface VirtualStat {
11
- mode: number;
12
- size: number;
13
- isDirectory: boolean;
14
- isSymbolicLink?: boolean;
15
- atimeMs: number;
16
- mtimeMs: number;
17
- ctimeMs: number;
18
- birthtimeMs: number;
19
- }
20
- export interface VirtualFileSystem {
21
- /**
22
- * Read a file as binary data.
23
- * @throws Error if file doesn't exist.
24
- */
25
- readFile(path: string): Promise<Uint8Array>;
26
- /**
27
- * Read a file as text (UTF-8).
28
- * @throws Error if file doesn't exist.
29
- */
30
- readTextFile(path: string): Promise<string>;
31
- /**
32
- * Read directory entries (file/folder names).
33
- * @throws Error if directory doesn't exist.
34
- */
35
- readDir(path: string): Promise<string[]>;
36
- /**
37
- * Read directory entries with type metadata.
38
- * @throws Error if directory doesn't exist.
39
- */
40
- readDirWithTypes(path: string): Promise<VirtualDirEntry[]>;
41
- /**
42
- * Write a file (creates parent directories as needed).
43
- * @param path - Absolute path to the file.
44
- * @param content - String or binary content.
45
- */
46
- writeFile(path: string, content: string | Uint8Array): Promise<void>;
47
- /**
48
- * Create a single directory level.
49
- * @throws Error if parent doesn't exist.
50
- */
51
- createDir(path: string): Promise<void>;
52
- /**
53
- * Create a directory recursively (creates parent directories as needed).
54
- * Should not throw if directory already exists.
55
- */
56
- mkdir(path: string): Promise<void>;
57
- /**
58
- * Check if a path exists (file or directory).
59
- */
60
- exists(path: string): Promise<boolean>;
61
- /**
62
- * Get file or directory metadata.
63
- * @throws Error if path doesn't exist.
64
- */
65
- stat(path: string): Promise<VirtualStat>;
66
- /**
67
- * Remove a file.
68
- * @throws Error if file doesn't exist.
69
- */
70
- removeFile(path: string): Promise<void>;
71
- /**
72
- * Remove an empty directory.
73
- * @throws Error if directory doesn't exist or is not empty.
74
- */
75
- removeDir(path: string): Promise<void>;
76
- /**
77
- * Rename or move a file/directory.
78
- * Behavior SHOULD be atomic when supported by the backing store.
79
- */
80
- rename(oldPath: string, newPath: string): Promise<void>;
81
- /** Create a symbolic link at linkPath pointing to target. */
82
- symlink(target: string, linkPath: string): Promise<void>;
83
- /** Read the target of a symbolic link. */
84
- readlink(path: string): Promise<string>;
85
- /** Like stat but does not follow symlinks. */
86
- lstat(path: string): Promise<VirtualStat>;
87
- /** Create a hard link from oldPath to newPath. */
88
- link(oldPath: string, newPath: string): Promise<void>;
89
- /** Change file mode bits. */
90
- chmod(path: string, mode: number): Promise<void>;
91
- /** Change file owner and group. */
92
- chown(path: string, uid: number, gid: number): Promise<void>;
93
- /** Update access and modification timestamps. */
94
- utimes(path: string, atime: number, mtime: number): Promise<void>;
95
- /** Truncate a file to a specified length. */
96
- truncate(path: string, length: number): Promise<void>;
97
- }
98
6
  export interface SpawnedProcess {
99
7
  writeStdin(data: Uint8Array | string): void;
100
8
  closeStdin(): void;
@@ -140,16 +48,6 @@ export interface NetworkServerListenOptions {
140
48
  onUpgradeSocketEnd?(socketId: number): void;
141
49
  }
142
50
  export interface NetworkAdapter {
143
- httpServerListen?(options: NetworkServerListenOptions): Promise<{
144
- address: NetworkServerAddress | null;
145
- }>;
146
- httpServerClose?(serverId: number): Promise<void>;
147
- /** Write data from the sandbox to a real upgrade socket on the host. */
148
- upgradeSocketWrite?(socketId: number, dataBase64: string): void;
149
- /** End a real upgrade socket on the host. */
150
- upgradeSocketEnd?(socketId: number): void;
151
- /** Destroy a real upgrade socket on the host. */
152
- upgradeSocketDestroy?(socketId: number): void;
153
51
  fetch(url: string, options: {
154
52
  method?: string;
155
53
  headers?: Record<string, string>;
@@ -184,65 +82,16 @@ export interface NetworkAdapter {
184
82
  trailers?: Record<string, string>;
185
83
  upgradeSocketId?: number;
186
84
  }>;
85
+ /** Write data from the sandbox to a real upgrade socket on the host. */
86
+ upgradeSocketWrite?(socketId: number, dataBase64: string): void;
87
+ /** End a real upgrade socket on the host. */
88
+ upgradeSocketEnd?(socketId: number): void;
89
+ /** Destroy a real upgrade socket on the host. */
90
+ upgradeSocketDestroy?(socketId: number): void;
187
91
  /** Register callbacks for client-side upgrade socket data push. */
188
92
  setUpgradeSocketCallbacks?(callbacks: {
189
93
  onData: (socketId: number, dataBase64: string) => void;
190
94
  onEnd: (socketId: number) => void;
191
95
  }): void;
192
- /** Create a TCP socket and connect to host:port. Returns a socketId. */
193
- netSocketConnect?(host: string, port: number, callbacks: {
194
- onConnect: () => void;
195
- onData: (dataBase64: string) => void;
196
- onEnd: () => void;
197
- onError: (message: string) => void;
198
- onClose: (hadError: boolean) => void;
199
- }): number;
200
- /** Write data to a TCP socket. */
201
- netSocketWrite?(socketId: number, dataBase64: string): void;
202
- /** End a TCP socket (half-close). */
203
- netSocketEnd?(socketId: number): void;
204
- /** Destroy a TCP socket. */
205
- netSocketDestroy?(socketId: number): void;
206
- /** Upgrade an existing TCP socket to TLS. */
207
- netSocketUpgradeTls?(socketId: number, optionsJson: string, callbacks: {
208
- onData: (dataBase64: string) => void;
209
- onEnd: () => void;
210
- onError: (message: string) => void;
211
- onClose: (hadError: boolean) => void;
212
- onSecureConnect: () => void;
213
- }): void;
214
- }
215
- export interface PermissionDecision {
216
- allow: boolean;
217
- reason?: string;
218
- }
219
- export type PermissionCheck<T> = (request: T) => PermissionDecision;
220
- export interface FsAccessRequest {
221
- op: "read" | "write" | "mkdir" | "createDir" | "readdir" | "stat" | "rm" | "rename" | "exists" | "chmod" | "chown" | "link" | "symlink" | "readlink" | "truncate" | "utimes";
222
- path: string;
223
- }
224
- export interface NetworkAccessRequest {
225
- op: "fetch" | "http" | "dns" | "listen" | "connect";
226
- url?: string;
227
- method?: string;
228
- hostname?: string;
229
- port?: number;
230
- }
231
- export interface ChildProcessAccessRequest {
232
- command: string;
233
- args: string[];
234
- cwd?: string;
235
- env?: Record<string, string>;
236
- }
237
- export interface EnvAccessRequest {
238
- op: "read" | "write";
239
- key: string;
240
- value?: string;
241
- }
242
- export interface Permissions {
243
- fs?: PermissionCheck<FsAccessRequest>;
244
- network?: PermissionCheck<NetworkAccessRequest>;
245
- childProcess?: PermissionCheck<ChildProcessAccessRequest>;
246
- env?: PermissionCheck<EnvAccessRequest>;
247
96
  }
248
97
  export type { DriverRuntimeConfig, NodeRuntimeDriver, NodeRuntimeDriverFactory, PythonRuntimeDriver, PythonRuntimeDriverFactory, RuntimeDriver, RuntimeDriverFactory, RuntimeDriverOptions, SharedRuntimeDriver, SystemDriver, } from "./runtime-driver.js";
package/dist/types.js CHANGED
@@ -1 +1,6 @@
1
+ /**
2
+ * Core-only types for secure-exec SDK.
3
+ *
4
+ * VFS and permission types are now defined in src/kernel/ (canonical source).
5
+ */
1
6
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secure-exec/core",
3
- "version": "0.1.1-rc.3",
3
+ "version": "0.2.0-rc.1",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -60,6 +60,11 @@
60
60
  "import": "./dist/types.js",
61
61
  "default": "./dist/types.js"
62
62
  },
63
+ "./internal/kernel": {
64
+ "types": "./dist/kernel/index.d.ts",
65
+ "import": "./dist/kernel/index.js",
66
+ "default": "./dist/kernel/index.js"
67
+ },
63
68
  "./internal/generated/isolate-runtime": {
64
69
  "types": "./dist/generated/isolate-runtime.d.ts",
65
70
  "import": "./dist/generated/isolate-runtime.js",
@@ -74,34 +79,19 @@
74
79
  "types": "./dist/shared/*.d.ts",
75
80
  "import": "./dist/shared/*.js",
76
81
  "default": "./dist/shared/*.js"
77
- },
78
- "./internal/bridge": {
79
- "types": "./dist/bridge/index.d.ts",
80
- "import": "./dist/bridge/index.js",
81
- "default": "./dist/bridge/index.js"
82
82
  }
83
83
  },
84
- "dependencies": {
85
- "buffer": "^6.0.3",
86
- "esbuild": "^0.27.1",
87
- "node-stdlib-browser": "^1.3.1",
88
- "sucrase": "^3.35.0",
89
- "text-encoding-utf-8": "^1.0.2",
90
- "whatwg-url": "^15.1.0"
91
- },
92
84
  "devDependencies": {
93
85
  "@types/node": "^22.10.2",
94
- "typescript": "^5.7.2"
86
+ "@xterm/headless": "^6.0.0",
87
+ "typescript": "^5.7.2",
88
+ "vitest": "^2.1.8"
95
89
  },
96
90
  "scripts": {
97
91
  "check-types:src": "tsc --noEmit",
98
92
  "check-types:isolate-runtime": "tsc -p tsconfig.isolate-runtime.json --noEmit",
99
- "check-types": "pnpm run build:generated && pnpm run check-types:src && pnpm run check-types:isolate-runtime",
100
- "build:bridge": "esbuild src/bridge/index.ts --bundle --format=iife --global-name=bridge --outfile=dist/bridge.js",
101
- "build:polyfills": "node scripts/build-polyfills.mjs",
102
- "build:isolate-runtime": "node scripts/build-isolate-runtime.mjs",
103
- "build:generated": "pnpm run build:polyfills && pnpm run build:isolate-runtime",
104
- "build": "pnpm run build:bridge && pnpm run build:generated && tsc",
105
- "test": "echo 'no tests yet'"
93
+ "check-types": "pnpm run check-types:src && pnpm run check-types:isolate-runtime",
94
+ "build": "tsc",
95
+ "test": "vitest run"
106
96
  }
107
97
  }
@@ -1,22 +0,0 @@
1
- /**
2
- * Register an active handle that keeps the sandbox alive.
3
- * Throws if the handle cap (_maxHandles) would be exceeded.
4
- * @param id Unique identifier for the handle
5
- * @param description Human-readable description for debugging
6
- */
7
- export declare function _registerHandle(id: string, description: string): void;
8
- /**
9
- * Unregister a handle. If no handles remain, resolves all waiters.
10
- * @param id The handle identifier to unregister
11
- */
12
- export declare function _unregisterHandle(id: string): void;
13
- /**
14
- * Wait for all active handles to complete.
15
- * Returns immediately if no handles are active.
16
- */
17
- export declare function _waitForActiveHandles(): Promise<void>;
18
- /**
19
- * Get list of currently active handles (for debugging).
20
- * Returns array of [id, description] tuples.
21
- */
22
- export declare function _getActiveHandles(): Array<[string, string]>;
@@ -1,55 +0,0 @@
1
- import { exposeCustomGlobal } from "../shared/global-exposure.js";
2
- // Map of active handles: id -> description (for debugging)
3
- const _activeHandles = new Map();
4
- // Resolvers waiting for all handles to complete
5
- let _waitResolvers = [];
6
- /**
7
- * Register an active handle that keeps the sandbox alive.
8
- * Throws if the handle cap (_maxHandles) would be exceeded.
9
- * @param id Unique identifier for the handle
10
- * @param description Human-readable description for debugging
11
- */
12
- export function _registerHandle(id, description) {
13
- // Enforce handle cap (skip check for re-registration of existing handle)
14
- if (typeof _maxHandles !== "undefined" && !_activeHandles.has(id) && _activeHandles.size >= _maxHandles) {
15
- throw new Error("ERR_RESOURCE_BUDGET_EXCEEDED: maximum active handles exceeded");
16
- }
17
- _activeHandles.set(id, description);
18
- }
19
- /**
20
- * Unregister a handle. If no handles remain, resolves all waiters.
21
- * @param id The handle identifier to unregister
22
- */
23
- export function _unregisterHandle(id) {
24
- _activeHandles.delete(id);
25
- if (_activeHandles.size === 0 && _waitResolvers.length > 0) {
26
- const resolvers = _waitResolvers;
27
- _waitResolvers = [];
28
- resolvers.forEach((r) => r());
29
- }
30
- }
31
- /**
32
- * Wait for all active handles to complete.
33
- * Returns immediately if no handles are active.
34
- */
35
- export function _waitForActiveHandles() {
36
- if (_activeHandles.size === 0) {
37
- return Promise.resolve();
38
- }
39
- return new Promise((resolve) => {
40
- _waitResolvers.push(resolve);
41
- });
42
- }
43
- /**
44
- * Get list of currently active handles (for debugging).
45
- * Returns array of [id, description] tuples.
46
- */
47
- export function _getActiveHandles() {
48
- return Array.from(_activeHandles.entries());
49
- }
50
- // Install on globalThis for use by other bridge modules and exec().
51
- // Lock bridge internals so sandbox code cannot replace lifecycle hooks.
52
- exposeCustomGlobal("_registerHandle", _registerHandle);
53
- exposeCustomGlobal("_unregisterHandle", _unregisterHandle);
54
- exposeCustomGlobal("_waitForActiveHandles", _waitForActiveHandles);
55
- exposeCustomGlobal("_getActiveHandles", _getActiveHandles);
@@ -1,99 +0,0 @@
1
- import type * as nodeChildProcess from "child_process";
2
- type EventListener = (...args: unknown[]) => void;
3
- interface StdinStream {
4
- writable: boolean;
5
- write(data: unknown): boolean;
6
- end(): void;
7
- on(): StdinStream;
8
- once(): StdinStream;
9
- emit(): boolean;
10
- }
11
- interface OutputStreamStub {
12
- readable: boolean;
13
- _listeners: Record<string, EventListener[]>;
14
- _onceListeners: Record<string, EventListener[]>;
15
- _maxListeners: number;
16
- _maxListenersWarned: Set<string>;
17
- on(event: string, listener: EventListener): OutputStreamStub;
18
- once(event: string, listener: EventListener): OutputStreamStub;
19
- emit(event: string, ...args: unknown[]): boolean;
20
- read(): null;
21
- setEncoding(): OutputStreamStub;
22
- setMaxListeners(n: number): OutputStreamStub;
23
- getMaxListeners(): number;
24
- pipe<T extends NodeJS.WritableStream>(dest: T): T;
25
- }
26
- /**
27
- * Polyfill of Node.js `ChildProcess`. Provides event-emitting stdin/stdout/stderr
28
- * streams. In streaming mode, data arrives via the `_childProcessDispatch` global
29
- * that the host calls with stdout/stderr/exit events keyed by session ID.
30
- */
31
- declare class ChildProcess {
32
- private _listeners;
33
- private _onceListeners;
34
- private _maxListeners;
35
- private _maxListenersWarned;
36
- pid: number;
37
- killed: boolean;
38
- exitCode: number | null;
39
- signalCode: NodeJS.Signals | null;
40
- connected: boolean;
41
- spawnfile: string;
42
- spawnargs: string[];
43
- stdin: StdinStream;
44
- stdout: OutputStreamStub;
45
- stderr: OutputStreamStub;
46
- stdio: [StdinStream, OutputStreamStub, OutputStreamStub];
47
- constructor();
48
- on(event: string, listener: EventListener): this;
49
- once(event: string, listener: EventListener): this;
50
- off(event: string, listener: EventListener): this;
51
- removeListener(event: string, listener: EventListener): this;
52
- setMaxListeners(n: number): this;
53
- getMaxListeners(): number;
54
- private _checkMaxListeners;
55
- emit(event: string, ...args: unknown[]): boolean;
56
- kill(_signal?: NodeJS.Signals | number): boolean;
57
- ref(): this;
58
- unref(): this;
59
- disconnect(): void;
60
- _complete(stdout: string, stderr: string, code: number): void;
61
- }
62
- interface ExecError extends Error {
63
- code?: number;
64
- killed?: boolean;
65
- signal?: string | null;
66
- cmd?: string;
67
- stdout?: string;
68
- stderr?: string;
69
- status?: number;
70
- output?: [null, string, string];
71
- }
72
- declare function exec(command: string, options?: nodeChildProcess.ExecOptions | ((error: ExecError | null, stdout: string, stderr: string) => void), callback?: (error: ExecError | null, stdout: string, stderr: string) => void): ChildProcess;
73
- declare function execSync(command: string, options?: nodeChildProcess.ExecSyncOptions): string | Buffer;
74
- declare function spawn(command: string, args?: readonly string[] | nodeChildProcess.SpawnOptions, options?: nodeChildProcess.SpawnOptions): ChildProcess;
75
- interface SpawnSyncResult {
76
- pid: number;
77
- output: [null, string | Buffer, string | Buffer];
78
- stdout: string | Buffer;
79
- stderr: string | Buffer;
80
- status: number | null;
81
- signal: NodeJS.Signals | null;
82
- error?: Error;
83
- }
84
- declare function spawnSync(command: string, args?: readonly string[] | nodeChildProcess.SpawnSyncOptions, options?: nodeChildProcess.SpawnSyncOptions): SpawnSyncResult;
85
- declare function execFile(file: string, args?: readonly string[] | nodeChildProcess.ExecFileOptions | ((error: ExecError | null, stdout: string, stderr: string) => void), options?: nodeChildProcess.ExecFileOptions | ((error: ExecError | null, stdout: string, stderr: string) => void), callback?: (error: ExecError | null, stdout: string, stderr: string) => void): ChildProcess;
86
- declare function execFileSync(file: string, args?: readonly string[] | nodeChildProcess.ExecFileSyncOptions, options?: nodeChildProcess.ExecFileSyncOptions): string | Buffer;
87
- declare function fork(_modulePath: string, _args?: readonly string[] | nodeChildProcess.ForkOptions, _options?: nodeChildProcess.ForkOptions): never;
88
- declare const childProcess: {
89
- ChildProcess: typeof ChildProcess;
90
- exec: typeof exec;
91
- execSync: typeof execSync;
92
- spawn: typeof spawn;
93
- spawnSync: typeof spawnSync;
94
- execFile: typeof execFile;
95
- execFileSync: typeof execFileSync;
96
- fork: typeof fork;
97
- };
98
- export { ChildProcess, exec, execSync, spawn, spawnSync, execFile, execFileSync, fork };
99
- export default childProcess;