runframe 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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +351 -0
  3. package/dist/async.d.ts +38 -0
  4. package/dist/async.d.ts.map +1 -0
  5. package/dist/async.js +98 -0
  6. package/dist/async.js.map +1 -0
  7. package/dist/benchmark.d.ts +9 -0
  8. package/dist/benchmark.d.ts.map +1 -0
  9. package/dist/benchmark.js +216 -0
  10. package/dist/benchmark.js.map +1 -0
  11. package/dist/capabilities.d.ts +26 -0
  12. package/dist/capabilities.d.ts.map +1 -0
  13. package/dist/capabilities.js +110 -0
  14. package/dist/capabilities.js.map +1 -0
  15. package/dist/deterministic.d.ts +81 -0
  16. package/dist/deterministic.d.ts.map +1 -0
  17. package/dist/deterministic.js +135 -0
  18. package/dist/deterministic.js.map +1 -0
  19. package/dist/index.d.ts +17 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +12 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/limits.d.ts +24 -0
  24. package/dist/limits.d.ts.map +1 -0
  25. package/dist/limits.js +42 -0
  26. package/dist/limits.js.map +1 -0
  27. package/dist/memory-optimization.d.ts +43 -0
  28. package/dist/memory-optimization.d.ts.map +1 -0
  29. package/dist/memory-optimization.js +103 -0
  30. package/dist/memory-optimization.js.map +1 -0
  31. package/dist/optimization-examples.d.ts +33 -0
  32. package/dist/optimization-examples.d.ts.map +1 -0
  33. package/dist/optimization-examples.js +255 -0
  34. package/dist/optimization-examples.js.map +1 -0
  35. package/dist/optimized-index.d.ts +12 -0
  36. package/dist/optimized-index.d.ts.map +1 -0
  37. package/dist/optimized-index.js +9 -0
  38. package/dist/optimized-index.js.map +1 -0
  39. package/dist/optimized-sandbox.d.ts +77 -0
  40. package/dist/optimized-sandbox.d.ts.map +1 -0
  41. package/dist/optimized-sandbox.js +153 -0
  42. package/dist/optimized-sandbox.js.map +1 -0
  43. package/dist/sandbox.d.ts +25 -0
  44. package/dist/sandbox.d.ts.map +1 -0
  45. package/dist/sandbox.js +55 -0
  46. package/dist/sandbox.js.map +1 -0
  47. package/dist/script-cache.d.ts +48 -0
  48. package/dist/script-cache.d.ts.map +1 -0
  49. package/dist/script-cache.js +97 -0
  50. package/dist/script-cache.js.map +1 -0
  51. package/dist/stats.d.ts +41 -0
  52. package/dist/stats.d.ts.map +1 -0
  53. package/dist/stats.js +70 -0
  54. package/dist/stats.js.map +1 -0
  55. package/dist/test-corpus.d.ts +15 -0
  56. package/dist/test-corpus.d.ts.map +1 -0
  57. package/dist/test-corpus.js +225 -0
  58. package/dist/test-corpus.js.map +1 -0
  59. package/dist/vm-runtime.d.ts +21 -0
  60. package/dist/vm-runtime.d.ts.map +1 -0
  61. package/dist/vm-runtime.js +276 -0
  62. package/dist/vm-runtime.js.map +1 -0
  63. package/dist/worker-pool.d.ts +62 -0
  64. package/dist/worker-pool.d.ts.map +1 -0
  65. package/dist/worker-pool.js +144 -0
  66. package/dist/worker-pool.js.map +1 -0
  67. package/dist/worker.d.ts +2 -0
  68. package/dist/worker.d.ts.map +1 -0
  69. package/dist/worker.js +39 -0
  70. package/dist/worker.js.map +1 -0
  71. package/package.json +67 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Worker thread pool for reusing workers
3
+ * Dramatically reduces memory and spawn overhead
4
+ */
5
+ import { Worker } from "node:worker_threads";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ export class WorkerPool {
11
+ constructor(config) {
12
+ this.workers = [];
13
+ this.waitQueue = [];
14
+ this.config = config;
15
+ // Pre-spawn minimum workers
16
+ for (let i = 0; i < config.minWorkers; i++) {
17
+ this.workers.push(this.createPooledWorker());
18
+ }
19
+ }
20
+ createPooledWorker() {
21
+ const worker = new Worker(path.resolve(__dirname, "worker.js"), {
22
+ execArgv: [`--max-old-space-size=${this.config.memoryMb}`]
23
+ });
24
+ return {
25
+ worker,
26
+ busy: false,
27
+ lastUsed: Date.now()
28
+ };
29
+ }
30
+ /**
31
+ * Get an available worker from the pool
32
+ */
33
+ async acquire() {
34
+ // Find idle worker
35
+ const idle = this.workers.find((w) => !w.busy);
36
+ if (idle) {
37
+ idle.busy = true;
38
+ idle.lastUsed = Date.now();
39
+ return idle.worker;
40
+ }
41
+ // Create new if under max
42
+ if (this.workers.length < this.config.maxWorkers) {
43
+ const pooled = this.createPooledWorker();
44
+ pooled.busy = true;
45
+ pooled.lastUsed = Date.now();
46
+ this.workers.push(pooled);
47
+ return pooled.worker;
48
+ }
49
+ // Wait for one to free up
50
+ return new Promise((resolve, reject) => {
51
+ this.waitQueue.push({ resolve, reject });
52
+ // Timeout after 30s
53
+ setTimeout(() => {
54
+ reject(new Error("Worker pool timeout: no available workers"));
55
+ }, 30000);
56
+ });
57
+ }
58
+ /**
59
+ * Release worker back to pool
60
+ */
61
+ release(worker) {
62
+ const pooled = this.workers.find((w) => w.worker === worker);
63
+ if (!pooled)
64
+ return;
65
+ pooled.busy = false;
66
+ pooled.lastUsed = Date.now();
67
+ // Check if anyone is waiting
68
+ const waiter = this.waitQueue.shift();
69
+ if (waiter) {
70
+ pooled.busy = true;
71
+ pooled.lastUsed = Date.now();
72
+ waiter.resolve(worker);
73
+ }
74
+ }
75
+ /**
76
+ * Clean up idle workers
77
+ */
78
+ cleanup() {
79
+ const now = Date.now();
80
+ let idx = this.workers.length - 1;
81
+ while (idx >= 0) {
82
+ const pooled = this.workers[idx];
83
+ // Keep minimum workers
84
+ if (this.workers.length <= this.config.minWorkers) {
85
+ break;
86
+ }
87
+ // Kill if idle and not busy
88
+ if (!pooled.busy && now - pooled.lastUsed > this.config.idleTimeout) {
89
+ pooled.worker.terminate();
90
+ this.workers.splice(idx, 1);
91
+ }
92
+ idx--;
93
+ }
94
+ }
95
+ /**
96
+ * Terminate all workers
97
+ */
98
+ async destroy() {
99
+ for (const pooled of this.workers) {
100
+ await pooled.worker.terminate();
101
+ }
102
+ this.workers = [];
103
+ this.waitQueue = [];
104
+ }
105
+ /**
106
+ * Get pool stats
107
+ */
108
+ stats() {
109
+ return {
110
+ totalWorkers: this.workers.length,
111
+ busyWorkers: this.workers.filter((w) => w.busy).length,
112
+ idleWorkers: this.workers.filter((w) => !w.busy).length,
113
+ waitingRequests: this.waitQueue.length
114
+ };
115
+ }
116
+ }
117
+ /**
118
+ * Default pool configuration
119
+ */
120
+ export const DEFAULT_POOL_CONFIG = {
121
+ minWorkers: 2, // Keep 2 warm
122
+ maxWorkers: 8, // Max 8 total
123
+ idleTimeout: 60000, // Kill after 1 min idle
124
+ memoryMb: 128
125
+ };
126
+ /**
127
+ * High-concurrency configuration
128
+ */
129
+ export const HIGH_CONCURRENCY_CONFIG = {
130
+ minWorkers: 4,
131
+ maxWorkers: 16,
132
+ idleTimeout: 30000,
133
+ memoryMb: 64
134
+ };
135
+ /**
136
+ * Low-resource configuration
137
+ */
138
+ export const LOW_RESOURCE_CONFIG = {
139
+ minWorkers: 1,
140
+ maxWorkers: 2,
141
+ idleTimeout: 10000,
142
+ memoryMb: 32
143
+ };
144
+ //# sourceMappingURL=worker-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-pool.js","sourceRoot":"","sources":["../src/worker-pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":""}
package/dist/worker.js ADDED
@@ -0,0 +1,39 @@
1
+ import { parentPort, workerData } from "node:worker_threads";
2
+ import { runInSandbox } from "./vm-runtime.js";
3
+ (async () => {
4
+ try {
5
+ const { code, options, capabilities, seed } = workerData;
6
+ const { result, stats } = await runInSandbox(code, {
7
+ capabilities,
8
+ seed
9
+ });
10
+ stats.updateMemory();
11
+ const finalStats = stats.finish();
12
+ parentPort?.postMessage({
13
+ type: "result",
14
+ result,
15
+ stats: finalStats
16
+ });
17
+ }
18
+ catch (err) {
19
+ parentPort?.postMessage({
20
+ type: "error",
21
+ error: sanitizeError(err)
22
+ });
23
+ }
24
+ })();
25
+ /**
26
+ * Sanitize errors before returning to parent thread
27
+ * Prevents leaking internal implementation details
28
+ */
29
+ function sanitizeError(err) {
30
+ if (err instanceof Error) {
31
+ // Only expose error message, not stack
32
+ return err.message;
33
+ }
34
+ if (typeof err === "string") {
35
+ return err;
36
+ }
37
+ return "Unknown error in sandbox";
38
+ }
39
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAY/C,CAAC,KAAK,IAAI,EAAE;IACV,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,UAAwB,CAAC;QAEvE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE;YACjD,YAAY;YACZ,IAAI;SACL,CAAC,CAAC;QAEH,KAAK,CAAC,YAAY,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAElC,UAAU,EAAE,WAAW,CAAC;YACtB,IAAI,EAAE,QAAQ;YACd,MAAM;YACN,KAAK,EAAE,UAAU;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,UAAU,EAAE,WAAW,CAAC;YACtB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL;;;GAGG;AACH,SAAS,aAAa,CAAC,GAAY;IACjC,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,uCAAuC;QACvC,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,0BAA0B,CAAC;AACpC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "runframe",
3
+ "version": "1.0.0",
4
+ "description": "High-performance, security-hardened JavaScript sandbox for executing untrusted code with worker pooling, script caching, and resource limits",
5
+ "type": "module",
6
+ "main": "dist/sandbox.js",
7
+ "types": "dist/sandbox.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/sandbox.d.ts",
11
+ "import": "./dist/sandbox.js"
12
+ },
13
+ "./optimized": {
14
+ "types": "./dist/optimized-sandbox.d.ts",
15
+ "import": "./dist/optimized-sandbox.js"
16
+ },
17
+ "./pool": {
18
+ "types": "./dist/worker-pool.d.ts",
19
+ "import": "./dist/worker-pool.js"
20
+ },
21
+ "./cache": {
22
+ "types": "./dist/script-cache.d.ts",
23
+ "import": "./dist/script-cache.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc",
33
+ "dev": "tsc --watch",
34
+ "prepublishOnly": "npm run build",
35
+ "test": "node --loader tsx ./test.ts"
36
+ },
37
+ "keywords": [
38
+ "sandbox",
39
+ "vm",
40
+ "worker",
41
+ "untrusted",
42
+ "code-execution",
43
+ "security",
44
+ "isolation",
45
+ "pool",
46
+ "cache",
47
+ "performance"
48
+ ],
49
+ "author": "Soojyon",
50
+ "license": "MIT",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/soojyon/nodebox"
54
+ },
55
+ "bugs": {
56
+ "url": "https://github.com/soojyon/nodebox/issues"
57
+ },
58
+ "homepage": "https://github.com/soojyon/nodebox#readme",
59
+ "engines": {
60
+ "node": ">=18.0.0"
61
+ },
62
+ "devDependencies": {
63
+ "@types/node": "^20.19.27",
64
+ "tsx": "^4.7.0",
65
+ "typescript": "^5.3.3"
66
+ }
67
+ }