@scelar/nodepod 1.0.0

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 (134) hide show
  1. package/LICENSE +43 -0
  2. package/README.md +240 -0
  3. package/dist/child_process-BJOMsZje.js +8233 -0
  4. package/dist/child_process-BJOMsZje.js.map +1 -0
  5. package/dist/child_process-Cj8vOcuc.cjs +7434 -0
  6. package/dist/child_process-Cj8vOcuc.cjs.map +1 -0
  7. package/dist/index-Cb1Cgdnd.js +35308 -0
  8. package/dist/index-Cb1Cgdnd.js.map +1 -0
  9. package/dist/index-DsMGS-xc.cjs +37195 -0
  10. package/dist/index-DsMGS-xc.cjs.map +1 -0
  11. package/dist/index.cjs +65 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.mjs +59 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/package.json +95 -0
  16. package/src/__tests__/smoke.test.ts +11 -0
  17. package/src/constants/cdn-urls.ts +18 -0
  18. package/src/constants/config.ts +236 -0
  19. package/src/cross-origin.ts +26 -0
  20. package/src/engine-factory.ts +176 -0
  21. package/src/engine-types.ts +56 -0
  22. package/src/helpers/byte-encoding.ts +39 -0
  23. package/src/helpers/digest.ts +9 -0
  24. package/src/helpers/event-loop.ts +96 -0
  25. package/src/helpers/wasm-cache.ts +133 -0
  26. package/src/iframe-sandbox.ts +141 -0
  27. package/src/index.ts +192 -0
  28. package/src/isolation-helpers.ts +148 -0
  29. package/src/memory-volume.ts +941 -0
  30. package/src/module-transformer.ts +368 -0
  31. package/src/packages/archive-extractor.ts +248 -0
  32. package/src/packages/browser-bundler.ts +284 -0
  33. package/src/packages/installer.ts +396 -0
  34. package/src/packages/registry-client.ts +131 -0
  35. package/src/packages/version-resolver.ts +411 -0
  36. package/src/polyfills/assert.ts +384 -0
  37. package/src/polyfills/async_hooks.ts +144 -0
  38. package/src/polyfills/buffer.ts +628 -0
  39. package/src/polyfills/child_process.ts +2288 -0
  40. package/src/polyfills/chokidar.ts +336 -0
  41. package/src/polyfills/cluster.ts +106 -0
  42. package/src/polyfills/console.ts +136 -0
  43. package/src/polyfills/constants.ts +123 -0
  44. package/src/polyfills/crypto.ts +885 -0
  45. package/src/polyfills/dgram.ts +87 -0
  46. package/src/polyfills/diagnostics_channel.ts +76 -0
  47. package/src/polyfills/dns.ts +134 -0
  48. package/src/polyfills/domain.ts +68 -0
  49. package/src/polyfills/esbuild.ts +854 -0
  50. package/src/polyfills/events.ts +276 -0
  51. package/src/polyfills/fs.ts +2888 -0
  52. package/src/polyfills/fsevents.ts +79 -0
  53. package/src/polyfills/http.ts +1449 -0
  54. package/src/polyfills/http2.ts +199 -0
  55. package/src/polyfills/https.ts +76 -0
  56. package/src/polyfills/inspector.ts +62 -0
  57. package/src/polyfills/lightningcss.ts +105 -0
  58. package/src/polyfills/module.ts +191 -0
  59. package/src/polyfills/net.ts +353 -0
  60. package/src/polyfills/os.ts +238 -0
  61. package/src/polyfills/path.ts +206 -0
  62. package/src/polyfills/perf_hooks.ts +102 -0
  63. package/src/polyfills/process.ts +690 -0
  64. package/src/polyfills/punycode.ts +159 -0
  65. package/src/polyfills/querystring.ts +93 -0
  66. package/src/polyfills/quic.ts +118 -0
  67. package/src/polyfills/readdirp.ts +229 -0
  68. package/src/polyfills/readline.ts +692 -0
  69. package/src/polyfills/repl.ts +134 -0
  70. package/src/polyfills/rollup.ts +119 -0
  71. package/src/polyfills/sea.ts +33 -0
  72. package/src/polyfills/sqlite.ts +78 -0
  73. package/src/polyfills/stream.ts +1620 -0
  74. package/src/polyfills/string_decoder.ts +25 -0
  75. package/src/polyfills/tailwindcss-oxide.ts +309 -0
  76. package/src/polyfills/test.ts +197 -0
  77. package/src/polyfills/timers.ts +32 -0
  78. package/src/polyfills/tls.ts +105 -0
  79. package/src/polyfills/trace_events.ts +50 -0
  80. package/src/polyfills/tty.ts +71 -0
  81. package/src/polyfills/url.ts +174 -0
  82. package/src/polyfills/util.ts +559 -0
  83. package/src/polyfills/v8.ts +126 -0
  84. package/src/polyfills/vm.ts +132 -0
  85. package/src/polyfills/volume-registry.ts +15 -0
  86. package/src/polyfills/wasi.ts +44 -0
  87. package/src/polyfills/worker_threads.ts +326 -0
  88. package/src/polyfills/ws.ts +595 -0
  89. package/src/polyfills/zlib.ts +881 -0
  90. package/src/request-proxy.ts +716 -0
  91. package/src/script-engine.ts +3375 -0
  92. package/src/sdk/nodepod-fs.ts +93 -0
  93. package/src/sdk/nodepod-process.ts +86 -0
  94. package/src/sdk/nodepod-terminal.ts +350 -0
  95. package/src/sdk/nodepod.ts +509 -0
  96. package/src/sdk/types.ts +70 -0
  97. package/src/shell/commands/bun.ts +121 -0
  98. package/src/shell/commands/directory.ts +297 -0
  99. package/src/shell/commands/file-ops.ts +525 -0
  100. package/src/shell/commands/git.ts +2142 -0
  101. package/src/shell/commands/node.ts +80 -0
  102. package/src/shell/commands/npm.ts +198 -0
  103. package/src/shell/commands/pm-types.ts +45 -0
  104. package/src/shell/commands/pnpm.ts +82 -0
  105. package/src/shell/commands/search.ts +264 -0
  106. package/src/shell/commands/shell-env.ts +352 -0
  107. package/src/shell/commands/text-processing.ts +1152 -0
  108. package/src/shell/commands/yarn.ts +84 -0
  109. package/src/shell/shell-builtins.ts +19 -0
  110. package/src/shell/shell-helpers.ts +250 -0
  111. package/src/shell/shell-interpreter.ts +514 -0
  112. package/src/shell/shell-parser.ts +429 -0
  113. package/src/shell/shell-types.ts +85 -0
  114. package/src/syntax-transforms.ts +561 -0
  115. package/src/threading/engine-worker.ts +64 -0
  116. package/src/threading/inline-worker.ts +372 -0
  117. package/src/threading/offload-types.ts +112 -0
  118. package/src/threading/offload-worker.ts +383 -0
  119. package/src/threading/offload.ts +271 -0
  120. package/src/threading/process-context.ts +92 -0
  121. package/src/threading/process-handle.ts +275 -0
  122. package/src/threading/process-manager.ts +956 -0
  123. package/src/threading/process-worker-entry.ts +854 -0
  124. package/src/threading/shared-vfs.ts +352 -0
  125. package/src/threading/sync-channel.ts +135 -0
  126. package/src/threading/task-queue.ts +177 -0
  127. package/src/threading/vfs-bridge.ts +231 -0
  128. package/src/threading/worker-pool.ts +233 -0
  129. package/src/threading/worker-protocol.ts +358 -0
  130. package/src/threading/worker-vfs.ts +218 -0
  131. package/src/types/externals.d.ts +38 -0
  132. package/src/types/fs-streams.ts +142 -0
  133. package/src/types/manifest.ts +17 -0
  134. package/src/worker-sandbox.ts +90 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
4
+
5
+ const index = require('./index-DsMGS-xc.cjs');
6
+
7
+
8
+
9
+ exports.DependencyInstaller = index.DependencyInstaller;
10
+ exports.IframeSandbox = index.IframeSandbox;
11
+ exports.MemoryVolume = index.MemoryVolume;
12
+ exports.Nodepod = index.Nodepod;
13
+ exports.NodepodFS = index.NodepodFS;
14
+ exports.NodepodProcess = index.NodepodProcess;
15
+ exports.NodepodTerminal = index.NodepodTerminal;
16
+ exports.ProcessHandle = index.ProcessHandle;
17
+ exports.ProcessManager = index.ProcessManager;
18
+ exports.ProcessWorkerAdapter = index.ProcessWorkerAdapter;
19
+ exports.RequestProxy = index.RequestProxy;
20
+ exports.SANDBOX_DEPLOYMENT_GUIDE = index.SANDBOX_DEPLOYMENT_GUIDE;
21
+ exports.ScriptEngine = index.ScriptEngine;
22
+ exports.SharedVFSController = index.SharedVFSController;
23
+ exports.SharedVFSReader = index.SharedVFSReader;
24
+ exports.SyncChannelController = index.SyncChannelController;
25
+ exports.SyncChannelWorker = index.SyncChannelWorker;
26
+ exports.VFSBridge = index.VFSBridge;
27
+ exports.WorkerSandbox = index.WorkerSandbox;
28
+ exports.WorkerVFS = index.WorkerVFS;
29
+ exports.assert = index.assert;
30
+ exports.buildFileSystemBridge = index.buildFileSystemBridge;
31
+ exports.buildProcessEnv = index.buildProcessEnv;
32
+ exports.chokidar = index.watcherPolyfill;
33
+ exports.createProcessContext = index.createProcessContext;
34
+ exports.createWorkspace = index.createWorkspace;
35
+ exports.default = index.createWorkspace;
36
+ exports.esbuild = index.esbuildPolyfill;
37
+ exports.events = index.events;
38
+ exports.executeCode = index.executeCode;
39
+ exports.fsevents = index.macEventsPolyfill;
40
+ exports.generateSandboxDeployment = index.generateSandboxDeployment;
41
+ exports.getActiveContext = index.getActiveContext;
42
+ exports.getProxyInstance = index.getProxyInstance;
43
+ exports.getSandboxHostingConfig = index.getSandboxHostingConfig;
44
+ exports.getSandboxPageHtml = index.getSandboxPageHtml;
45
+ exports.http = index.httpPolyfill;
46
+ exports.install = index.install;
47
+ exports.isSharedArrayBufferAvailable = index.isSharedArrayBufferAvailable;
48
+ exports.module = index.module;
49
+ exports.net = index.tcpPolyfill;
50
+ exports.npm = index.installer;
51
+ exports.path = index.pathPolyfill;
52
+ exports.perf_hooks = index.perfPolyfill;
53
+ exports.querystring = index.qsPolyfill;
54
+ exports.readdirp = index.scannerPolyfill;
55
+ exports.resetProxy = index.resetProxy;
56
+ exports.rollup = index.rollupPolyfill;
57
+ exports.setActiveContext = index.setActiveContext;
58
+ exports.spawnEngine = index.spawnEngine;
59
+ exports.spawnProcessWorkerEngine = index.spawnProcessWorkerEngine;
60
+ exports.stream = index.stream;
61
+ exports.url = index.urlPolyfill;
62
+ exports.util = index.helpersPolyfill;
63
+ exports.worker_threads = index.threadPoolPolyfill;
64
+ exports.ws = index.wsPolyfill;
65
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.mjs ADDED
@@ -0,0 +1,59 @@
1
+ import { p, I, q, s, t, v, w, P, x, y, z, A, S, C, F, G, H, J, K, O, Q, U, X, Z, _, $, $ as $2, a0, a1, a2, a3, a4, l, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, ao, ap, aq, ar } from "./index-Cb1Cgdnd.js";
2
+ export {
3
+ p as DependencyInstaller,
4
+ I as IframeSandbox,
5
+ q as MemoryVolume,
6
+ s as Nodepod,
7
+ t as NodepodFS,
8
+ v as NodepodProcess,
9
+ w as NodepodTerminal,
10
+ P as ProcessHandle,
11
+ x as ProcessManager,
12
+ y as ProcessWorkerAdapter,
13
+ z as RequestProxy,
14
+ A as SANDBOX_DEPLOYMENT_GUIDE,
15
+ S as ScriptEngine,
16
+ C as SharedVFSController,
17
+ F as SharedVFSReader,
18
+ G as SyncChannelController,
19
+ H as SyncChannelWorker,
20
+ J as VFSBridge,
21
+ K as WorkerSandbox,
22
+ O as WorkerVFS,
23
+ Q as assert,
24
+ U as buildFileSystemBridge,
25
+ X as buildProcessEnv,
26
+ Z as chokidar,
27
+ _ as createProcessContext,
28
+ $ as createWorkspace,
29
+ $2 as default,
30
+ a0 as esbuild,
31
+ a1 as events,
32
+ a2 as executeCode,
33
+ a3 as fsevents,
34
+ a4 as generateSandboxDeployment,
35
+ l as getActiveContext,
36
+ a5 as getProxyInstance,
37
+ a6 as getSandboxHostingConfig,
38
+ a7 as getSandboxPageHtml,
39
+ a8 as http,
40
+ a9 as install,
41
+ aa as isSharedArrayBufferAvailable,
42
+ ab as module,
43
+ ac as net,
44
+ ad as npm,
45
+ ae as path,
46
+ af as perf_hooks,
47
+ ag as querystring,
48
+ ah as readdirp,
49
+ ai as resetProxy,
50
+ aj as rollup,
51
+ ak as setActiveContext,
52
+ al as spawnEngine,
53
+ am as spawnProcessWorkerEngine,
54
+ an as stream,
55
+ ao as url,
56
+ ap as util,
57
+ aq as worker_threads,
58
+ ar as ws
59
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "@scelar/nodepod",
3
+ "version": "1.0.0",
4
+ "description": "Browser-native Node.js runtime environment",
5
+ "type": "module",
6
+ "license": "MIT WITH Commons-Clause",
7
+ "author": "R1ck404 (https://github.com/R1ck404)",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/ScelarOrg/Nodepod.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/ScelarOrg/Nodepod/issues"
14
+ },
15
+ "homepage": "https://github.com/ScelarOrg/Nodepod#readme",
16
+ "keywords": [
17
+ "node",
18
+ "browser",
19
+ "runtime",
20
+ "sandbox",
21
+ "typescript",
22
+ "virtual-filesystem",
23
+ "polyfill",
24
+ "webcontainer",
25
+ "in-browser",
26
+ "nodejs"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20.0.0"
30
+ },
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.mjs",
33
+ "types": "./dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "import": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.mjs"
39
+ },
40
+ "require": {
41
+ "types": "./dist/index.d.ts",
42
+ "default": "./dist/index.cjs"
43
+ }
44
+ }
45
+ },
46
+ "files": [
47
+ "src",
48
+ "dist"
49
+ ],
50
+ "sideEffects": false,
51
+ "scripts": {
52
+ "build:lib": "vite build --config vite.lib.config.js && cp static/__sw__.js dist/__sw__.js",
53
+ "build:types": "tsc --project tsconfig.build.json",
54
+ "build:publish": "npm run build:lib && npm run build:types",
55
+ "type-check": "tsc --noEmit",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest"
58
+ },
59
+ "dependencies": {
60
+ "acorn": "^8.15.0",
61
+ "acorn-jsx": "^5.3.2",
62
+ "brotli": "^1.3.3",
63
+ "brotli-wasm": "^3.0.1",
64
+ "comlink": "^4.4.2",
65
+ "pako": "^2.1.0",
66
+ "resolve.exports": "^2.0.3",
67
+ "zod": "^4.3.6"
68
+ },
69
+ "peerDependencies": {
70
+ "@xterm/xterm": "^6.0.0",
71
+ "@xterm/addon-fit": "^0.11.0",
72
+ "@xterm/addon-webgl": "^0.19.0"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "@xterm/xterm": {
76
+ "optional": true
77
+ },
78
+ "@xterm/addon-fit": {
79
+ "optional": true
80
+ },
81
+ "@xterm/addon-webgl": {
82
+ "optional": true
83
+ }
84
+ },
85
+ "devDependencies": {
86
+ "@types/node": "^25.0.10",
87
+ "@types/pako": "^2.0.4",
88
+ "esbuild": "^0.27.2",
89
+ "typescript": "^5.9.3",
90
+ "vite": "^5.4.0",
91
+ "vite-plugin-top-level-await": "^1.6.0",
92
+ "vite-plugin-wasm": "^3.5.0",
93
+ "vitest": "^4.0.18"
94
+ }
95
+ }
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { MemoryVolume } from "../memory-volume";
3
+
4
+ describe("smoke", () => {
5
+ it("MemoryVolume read/write round-trip", () => {
6
+ const vol = new MemoryVolume();
7
+ vol.mkdirSync("/tmp", { recursive: true });
8
+ vol.writeFileSync("/tmp/hello.txt", "world");
9
+ expect(vol.readFileSync("/tmp/hello.txt", "utf8")).toBe("world");
10
+ });
11
+ });
@@ -0,0 +1,18 @@
1
+ // Pinned CDN versions and URLs
2
+
3
+ export const PINNED_ESBUILD_WASM = '0.20.0';
4
+ export const PINNED_ROLLUP_BROWSER = '4.9.0';
5
+ export const PINNED_BROTLI_WASM = '3.0.1';
6
+ export const PINNED_LIGHTNINGCSS_WASM = '1.31.1';
7
+
8
+ export const CDN_ESBUILD_ESM = `https://esm.sh/esbuild-wasm@${PINNED_ESBUILD_WASM}`;
9
+ export const CDN_ESBUILD_BINARY = `https://esm.sh/esbuild-wasm@${PINNED_ESBUILD_WASM}/esbuild.wasm`;
10
+ export const CDN_ESBUILD_BROWSER = `https://esm.sh/esbuild-wasm@${PINNED_ESBUILD_WASM}/esm/browser.min.js`;
11
+ export const CDN_ROLLUP_BROWSER = `https://esm.sh/@rollup/browser@${PINNED_ROLLUP_BROWSER}`;
12
+ export const CDN_BROTLI_WASM = `https://esm.sh/brotli-wasm@${PINNED_BROTLI_WASM}`;
13
+ export const CDN_LIGHTNINGCSS_WASM = `https://esm.sh/lightningcss-wasm@${PINNED_LIGHTNINGCSS_WASM}`;
14
+
15
+ // new Function hides import() from bundler static analysis so CDN URLs work at runtime
16
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
17
+ const _dynamicImport = new Function("url", "return import(url)") as (url: string) => Promise<any>;
18
+ export { _dynamicImport as cdnImport };
@@ -0,0 +1,236 @@
1
+ // Centralized config constants. Import from here instead of hardcoding.
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Runtime version strings
5
+ // ---------------------------------------------------------------------------
6
+
7
+ export const VERSIONS = {
8
+ NODE: "v22.12.0",
9
+ NODE_BARE: "22.12.0",
10
+ NPM: "10.0.0",
11
+ PNPM: "9.15.4",
12
+ YARN: "4.6.0",
13
+ BUN: "1.1.38",
14
+ BUN_V: "v1.1.38",
15
+ GIT: "2.43.0",
16
+ } as const;
17
+
18
+ export const NODE_SUB_VERSIONS = {
19
+ node: VERSIONS.NODE_BARE,
20
+ v8: "11.3.244.8",
21
+ uv: "1.44.2",
22
+ modules: "115",
23
+ openssl: "3.0.13",
24
+ napi: "9",
25
+ webcontainer: "1.0.0",
26
+ } as const;
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // npm registry
30
+ // ---------------------------------------------------------------------------
31
+
32
+ export const NPM_REGISTRY_URL = "https://registry.npmjs.org";
33
+ export const NPM_REGISTRY_URL_SLASH = "https://registry.npmjs.org/";
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // CDN (pako only -- the rest are in cdn-urls.ts)
37
+ // ---------------------------------------------------------------------------
38
+
39
+ export const PINNED_PAKO = "2.1.0";
40
+ export const CDN_PAKO = `https://esm.sh/pako@${PINNED_PAKO}`;
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Module resolution file extensions
44
+ // ---------------------------------------------------------------------------
45
+
46
+ export const RESOLVE_EXTENSIONS = [
47
+ ".js",
48
+ ".ts",
49
+ ".jsx",
50
+ ".tsx",
51
+ ".mjs",
52
+ ".cjs",
53
+ ".json",
54
+ ] as const;
55
+
56
+ export const MAIN_FIELD_EXTENSIONS = [
57
+ ".js",
58
+ ".ts",
59
+ ".tsx",
60
+ ".mts",
61
+ ".jsx",
62
+ ".json",
63
+ ".mjs",
64
+ ".cjs",
65
+ ] as const;
66
+
67
+ export const INDEX_FILES = [
68
+ "index.js",
69
+ "index.ts",
70
+ "index.tsx",
71
+ "index.mjs",
72
+ "index.cjs",
73
+ ] as const;
74
+
75
+ export const IMPORTS_FIELD_EXTENSIONS = [
76
+ ".js",
77
+ ".ts",
78
+ ".cjs",
79
+ ".mjs",
80
+ ".json",
81
+ ] as const;
82
+
83
+ export const ESBUILD_LOADER_MAP: Record<string, string> = {
84
+ ".ts": "ts",
85
+ ".tsx": "tsx",
86
+ ".js": "js",
87
+ ".mjs": "js",
88
+ ".cjs": "js",
89
+ ".jsx": "jsx",
90
+ ".json": "json",
91
+ ".css": "css",
92
+ ".map": "json",
93
+ ".txt": "text",
94
+ ".wasm": "file",
95
+ };
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // Mock system environment
99
+ // ---------------------------------------------------------------------------
100
+
101
+ export const MOCK_OS = {
102
+ PLATFORM: "linux" as const,
103
+ ARCH: "x64" as const,
104
+ TYPE: "Linux",
105
+ RELEASE: "5.10.0",
106
+ VERSION: "#1 SMP",
107
+ MACHINE: "x86_64",
108
+ HOSTNAME: "localhost",
109
+ HOMEDIR: "/home/user",
110
+ TMPDIR: "/tmp",
111
+ SHELL: "/bin/bash",
112
+ USERNAME: "user",
113
+ ENDIANNESS: "LE" as const,
114
+ } as const;
115
+
116
+ export const MOCK_IDS = {
117
+ UID: 1000,
118
+ GID: 1000,
119
+ } as const;
120
+
121
+ export const MOCK_FS = {
122
+ BLOCK_SIZE: 4096,
123
+ BLOCK_CALC_SIZE: 512,
124
+ } as const;
125
+
126
+ export const MOCK_CPU = {
127
+ MODEL: "Virtual CPU",
128
+ SPEED: 2400,
129
+ COUNT: 2,
130
+ } as const;
131
+
132
+ export const MOCK_MEMORY = {
133
+ TOTAL: 4 * 1024 * 1024 * 1024,
134
+ FREE: 2 * 1024 * 1024 * 1024,
135
+ RSS: 50 * 1024 * 1024,
136
+ HEAP_TOTAL: 30 * 1024 * 1024,
137
+ HEAP_USED: 20 * 1024 * 1024,
138
+ EXTERNAL: 1 * 1024 * 1024,
139
+ } as const;
140
+
141
+ export const MOCK_LOADAVG: readonly [number, number, number] = [0.5, 0.5, 0.5];
142
+
143
+ export const DEFAULT_TERMINAL = {
144
+ COLUMNS: 80,
145
+ ROWS: 24,
146
+ FONT_SIZE: 13,
147
+ } as const;
148
+
149
+ export const MOCK_PROCESS = {
150
+ PID: 1,
151
+ PPID: 0,
152
+ TITLE: "node",
153
+ EXEC_PATH: "/usr/local/bin/node",
154
+ } as const;
155
+
156
+ // ---------------------------------------------------------------------------
157
+ // Default environment variables
158
+ // ---------------------------------------------------------------------------
159
+
160
+ export const DEFAULT_ENV = {
161
+ NODE_ENV: "development",
162
+ PATH: "/usr/local/bin:/usr/bin:/bin",
163
+ HOME: "/",
164
+ SHELL: "/bin/sh",
165
+ TERM: "xterm-256color",
166
+ COLORTERM: "truecolor",
167
+ REQUIRES_WASM: "true",
168
+ npm_config_user_agent: `npm/${VERSIONS.NPM} node/${VERSIONS.NODE} linux x64 workspaces/false`,
169
+ npm_execpath: "/usr/local/lib/node_modules/npm/bin/npm-cli.js",
170
+ npm_node_execpath: "/usr/local/bin/node",
171
+ } as const;
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Timeouts and limits
175
+ // ---------------------------------------------------------------------------
176
+
177
+ export const TIMEOUTS = {
178
+ SYNC_OP: 120_000,
179
+ WAIT_LOOP_TICK: 200,
180
+ SW_HEARTBEAT: 20_000,
181
+ WORKER_REAP_INTERVAL: 10_000,
182
+ WORKER_IDLE_TIMEOUT: 30_000,
183
+ WORKER_INIT_TIMEOUT: 30_000,
184
+ HTTP_KEEP_ALIVE: 5000,
185
+ HTTP_HEADERS: 60000,
186
+ HTTP_DISPATCH_SAFETY: 120000,
187
+ } as const;
188
+
189
+ export const LIMITS = {
190
+ MAX_RESOLVE_DEPTH: 50,
191
+ MODULE_CACHE_MAX: 2000,
192
+ MAX_WORKERS_CAP: 6,
193
+ } as const;
194
+
195
+ // ---------------------------------------------------------------------------
196
+ // Port range for net.Server.listen(0)
197
+ // ---------------------------------------------------------------------------
198
+
199
+ export const PORT_RANGE = {
200
+ BASE: 3000,
201
+ RANGE: 1000,
202
+ } as const;
203
+
204
+ // ---------------------------------------------------------------------------
205
+ // CDN
206
+ // ---------------------------------------------------------------------------
207
+
208
+ export const DEFAULT_NODEPOD_CDN = "https://unpkg.com/@scelar/nodepod/dist/index.js";
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // PIDs
212
+ // ---------------------------------------------------------------------------
213
+
214
+ export const MOCK_PID = {
215
+ BASE: 1000,
216
+ RANGE: 10000,
217
+ } as const;
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // Shell constants
221
+ // ---------------------------------------------------------------------------
222
+
223
+ export const LS_BLOCK_SIZE = 512;
224
+ export const YES_REPEAT_COUNT = 100;
225
+
226
+ // ---------------------------------------------------------------------------
227
+ // WebSocket opcodes (RFC 6455)
228
+ // ---------------------------------------------------------------------------
229
+
230
+ export const WS_OPCODE = {
231
+ TEXT: 0x01,
232
+ BINARY: 0x02,
233
+ CLOSE: 0x08,
234
+ PING: 0x09,
235
+ PONG: 0x0a,
236
+ } as const;
@@ -0,0 +1,26 @@
1
+ // optional CORS proxy for APIs that don't allow browser origins
2
+
3
+ let activeProxy: string | null = null;
4
+
5
+ export function setProxy(url: string | null): void {
6
+ activeProxy = url;
7
+ }
8
+
9
+ export function getProxy(): string | null {
10
+ return activeProxy;
11
+ }
12
+
13
+ export function isProxyActive(): boolean {
14
+ return activeProxy !== null;
15
+ }
16
+
17
+ export async function proxiedFetch(url: string, init?: RequestInit): Promise<Response> {
18
+ if (activeProxy) {
19
+ return fetch(activeProxy + encodeURIComponent(url), init);
20
+ }
21
+ return fetch(url, init);
22
+ }
23
+
24
+ export function resolveProxyUrl(url: string): string {
25
+ return activeProxy ? activeProxy + encodeURIComponent(url) : url;
26
+ }
@@ -0,0 +1,176 @@
1
+ // spawns a ScriptEngine in the requested execution mode:
2
+ // sandboxUrl → cross-origin iframe, useWorker → Worker thread, otherwise main thread
3
+
4
+ import { ScriptEngine } from './script-engine';
5
+ import { WorkerSandbox } from './worker-sandbox';
6
+ import { IframeSandbox } from './iframe-sandbox';
7
+ import type { MemoryVolume } from './memory-volume';
8
+ import type { IScriptEngine, ExecutionOutcome, SpawnEngineConfig, EngineConfig } from './engine-types';
9
+ import { ProcessManager } from './threading/process-manager';
10
+ import { VFSBridge } from './threading/vfs-bridge';
11
+
12
+ function canUseWorker(): boolean {
13
+ return typeof Worker !== 'undefined';
14
+ }
15
+
16
+ // wraps the synchronous ScriptEngine behind the async IScriptEngine interface
17
+ class SyncEngineAdapter implements IScriptEngine {
18
+ private engine: ScriptEngine;
19
+
20
+ constructor(vol: MemoryVolume, cfg: EngineConfig = {}) {
21
+ this.engine = new ScriptEngine(vol, cfg);
22
+ }
23
+
24
+ async execute(code: string, filename?: string): Promise<ExecutionOutcome> {
25
+ return Promise.resolve(this.engine.execute(code, filename));
26
+ }
27
+
28
+ async runFile(filename: string): Promise<ExecutionOutcome> {
29
+ return Promise.resolve(this.engine.runFile(filename));
30
+ }
31
+
32
+ clearCache(): void { this.engine.clearCache(); }
33
+ getVolume(): MemoryVolume { return this.engine.getVolume(); }
34
+
35
+ unwrap(): ScriptEngine { return this.engine; }
36
+ }
37
+
38
+ // create a script engine in the appropriate execution mode
39
+ // throws if neither sandboxUrl nor allowUnsafeEval is specified
40
+ export async function spawnEngine(
41
+ vol: MemoryVolume,
42
+ config: SpawnEngineConfig = {},
43
+ ): Promise<IScriptEngine> {
44
+ const { sandboxUrl, allowUnsafeEval, useWorker = false, ...engineCfg } = config;
45
+
46
+ if (sandboxUrl) {
47
+ const sandbox = new IframeSandbox(sandboxUrl, vol, engineCfg);
48
+ await sandbox.execute('/* sandbox ready check */', '/__sandbox_init__.js');
49
+ return sandbox;
50
+ }
51
+
52
+ if (!allowUnsafeEval) {
53
+ throw new Error(
54
+ 'nodepod: For security, you must either:\n' +
55
+ ' 1. Use sandbox mode: { sandboxUrl: "https://your-sandbox.example.com" }\n' +
56
+ ' 2. Explicitly opt-in to same-origin: { allowUnsafeEval: true }\n\n' +
57
+ 'Same-origin execution allows code to access cookies, localStorage, and IndexedDB.\n' +
58
+ 'Only use allowUnsafeEval for trusted code or demos.'
59
+ );
60
+ }
61
+
62
+ let shouldUseWorker = false;
63
+ if (useWorker === true) {
64
+ shouldUseWorker = canUseWorker();
65
+ } else if (useWorker === 'auto') {
66
+ shouldUseWorker = canUseWorker();
67
+ }
68
+
69
+ if (shouldUseWorker) {
70
+ const worker = new WorkerSandbox(vol, engineCfg);
71
+ await worker.execute('/* worker ready check */', '/__worker_init__.js');
72
+ return worker;
73
+ }
74
+
75
+ return new SyncEngineAdapter(vol, engineCfg);
76
+ }
77
+
78
+ // ---- Process-worker engine adapter ----
79
+
80
+ // wraps ProcessManager-based workers behind IScriptEngine.
81
+ // each execute()/runFile() spawns a new worker process.
82
+ class ProcessWorkerAdapter implements IScriptEngine {
83
+ private _vol: MemoryVolume;
84
+ private _processManager: ProcessManager;
85
+ private _vfsBridge: VFSBridge;
86
+ private _cfg: EngineConfig;
87
+
88
+ constructor(vol: MemoryVolume, cfg: EngineConfig = {}) {
89
+ this._vol = vol;
90
+ this._cfg = cfg;
91
+ this._processManager = new ProcessManager(vol);
92
+ this._vfsBridge = new VFSBridge(vol);
93
+ this._processManager.setVFSBridge(this._vfsBridge);
94
+
95
+ this._vfsBridge.setBroadcaster((path, content, excludePid) => {
96
+ const isDirectory = content !== null && content.byteLength === 0;
97
+ this._processManager.broadcastVFSChange(path, content, isDirectory, excludePid);
98
+ });
99
+ }
100
+
101
+ async execute(code: string, filename?: string): Promise<ExecutionOutcome> {
102
+ const tmpFile = filename ?? '/__exec_tmp__.js';
103
+ this._vol.writeFileSync(tmpFile, code as any);
104
+
105
+ const result = await this._runInWorker(tmpFile);
106
+ return result;
107
+ }
108
+
109
+ async runFile(filename: string): Promise<ExecutionOutcome> {
110
+ return this._runInWorker(filename);
111
+ }
112
+
113
+ private async _runInWorker(filePath: string): Promise<ExecutionOutcome> {
114
+ return new Promise<ExecutionOutcome>((resolve) => {
115
+ const handle = this._processManager.spawn({
116
+ command: 'node',
117
+ args: [filePath],
118
+ cwd: this._cfg.cwd ?? '/',
119
+ env: (this._cfg as any).env ?? {},
120
+ });
121
+
122
+ let stdout = '';
123
+ let stderr = '';
124
+
125
+ handle.on('stdout', (data: string) => { stdout += data; });
126
+ handle.on('stderr', (data: string) => { stderr += data; });
127
+
128
+ handle.on('ready', () => {
129
+ handle.exec({
130
+ type: 'exec',
131
+ filePath,
132
+ args: [],
133
+ cwd: this._cfg.cwd,
134
+ env: (this._cfg as any).env,
135
+ });
136
+ });
137
+
138
+ handle.on('exit', (_exitCode: number) => {
139
+ resolve({
140
+ exports: {},
141
+ module: {
142
+ id: filePath,
143
+ filename: filePath,
144
+ exports: {},
145
+ loaded: true,
146
+ children: [],
147
+ paths: [],
148
+ },
149
+ });
150
+ });
151
+ });
152
+ }
153
+
154
+ clearCache(): void { }
155
+ getVolume(): MemoryVolume { return this._vol; }
156
+
157
+ getProcessManager(): ProcessManager { return this._processManager; }
158
+
159
+ teardown(): void {
160
+ this._processManager.teardown();
161
+ }
162
+ }
163
+
164
+ // create a process-worker engine where each execution runs in a dedicated Web Worker
165
+ export async function spawnProcessWorkerEngine(
166
+ vol: MemoryVolume,
167
+ config: EngineConfig = {},
168
+ ): Promise<ProcessWorkerAdapter> {
169
+ return new ProcessWorkerAdapter(vol, config);
170
+ }
171
+
172
+ export { ScriptEngine } from './script-engine';
173
+ export { WorkerSandbox } from './worker-sandbox';
174
+ export { IframeSandbox } from './iframe-sandbox';
175
+ export { ProcessWorkerAdapter };
176
+ export type { IScriptEngine, ExecutionOutcome, EngineConfig, SpawnEngineConfig, VolumeSnapshot } from './engine-types';