@ebowwa/sandbox 0.1.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 (108) hide show
  1. package/dist/compilers/index.d.ts +24 -0
  2. package/dist/compilers/index.d.ts.map +1 -0
  3. package/dist/compilers/index.js +42 -0
  4. package/dist/compilers/index.js.map +1 -0
  5. package/dist/compilers/javascript.d.ts +117 -0
  6. package/dist/compilers/javascript.d.ts.map +1 -0
  7. package/dist/compilers/javascript.js +462 -0
  8. package/dist/compilers/javascript.js.map +1 -0
  9. package/dist/compilers/python.d.ts +140 -0
  10. package/dist/compilers/python.d.ts.map +1 -0
  11. package/dist/compilers/python.js +650 -0
  12. package/dist/compilers/python.js.map +1 -0
  13. package/dist/compilers/typescript.d.ts +99 -0
  14. package/dist/compilers/typescript.d.ts.map +1 -0
  15. package/dist/compilers/typescript.js +323 -0
  16. package/dist/compilers/typescript.js.map +1 -0
  17. package/dist/core/cell.d.ts +160 -0
  18. package/dist/core/cell.d.ts.map +1 -0
  19. package/dist/core/cell.js +319 -0
  20. package/dist/core/cell.js.map +1 -0
  21. package/dist/core/compiler.d.ts +126 -0
  22. package/dist/core/compiler.d.ts.map +1 -0
  23. package/dist/core/compiler.js +123 -0
  24. package/dist/core/compiler.js.map +1 -0
  25. package/dist/core/index.d.ts +19 -0
  26. package/dist/core/index.d.ts.map +1 -0
  27. package/dist/core/index.js +14 -0
  28. package/dist/core/index.js.map +1 -0
  29. package/dist/core/limits.d.ts +173 -0
  30. package/dist/core/limits.d.ts.map +1 -0
  31. package/dist/core/limits.js +440 -0
  32. package/dist/core/limits.js.map +1 -0
  33. package/dist/core/permissions.d.ts +103 -0
  34. package/dist/core/permissions.d.ts.map +1 -0
  35. package/dist/core/permissions.js +341 -0
  36. package/dist/core/permissions.js.map +1 -0
  37. package/dist/core/runtime.d.ts +127 -0
  38. package/dist/core/runtime.d.ts.map +1 -0
  39. package/dist/core/runtime.js +325 -0
  40. package/dist/core/runtime.js.map +1 -0
  41. package/dist/core/types.d.ts +380 -0
  42. package/dist/core/types.d.ts.map +1 -0
  43. package/dist/core/types.js +67 -0
  44. package/dist/core/types.js.map +1 -0
  45. package/dist/index.d.ts +145 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +279 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/multi/index.d.ts +9 -0
  50. package/dist/multi/index.d.ts.map +1 -0
  51. package/dist/multi/index.js +7 -0
  52. package/dist/multi/index.js.map +1 -0
  53. package/dist/multi/polyglot.d.ts +179 -0
  54. package/dist/multi/polyglot.d.ts.map +1 -0
  55. package/dist/multi/polyglot.js +319 -0
  56. package/dist/multi/polyglot.js.map +1 -0
  57. package/dist/runtimes/docker.d.ts +97 -0
  58. package/dist/runtimes/docker.d.ts.map +1 -0
  59. package/dist/runtimes/docker.js +368 -0
  60. package/dist/runtimes/docker.js.map +1 -0
  61. package/dist/runtimes/index.d.ts +11 -0
  62. package/dist/runtimes/index.d.ts.map +1 -0
  63. package/dist/runtimes/index.js +9 -0
  64. package/dist/runtimes/index.js.map +1 -0
  65. package/dist/runtimes/process.d.ts +47 -0
  66. package/dist/runtimes/process.d.ts.map +1 -0
  67. package/dist/runtimes/process.js +230 -0
  68. package/dist/runtimes/process.js.map +1 -0
  69. package/dist/session/index.d.ts +12 -0
  70. package/dist/session/index.d.ts.map +1 -0
  71. package/dist/session/index.js +9 -0
  72. package/dist/session/index.js.map +1 -0
  73. package/dist/session/kernel.d.ts +199 -0
  74. package/dist/session/kernel.d.ts.map +1 -0
  75. package/dist/session/kernel.js +400 -0
  76. package/dist/session/kernel.js.map +1 -0
  77. package/dist/session/notebook.d.ts +168 -0
  78. package/dist/session/notebook.d.ts.map +1 -0
  79. package/dist/session/notebook.js +499 -0
  80. package/dist/session/notebook.js.map +1 -0
  81. package/dist/session/repl.d.ts +159 -0
  82. package/dist/session/repl.d.ts.map +1 -0
  83. package/dist/session/repl.js +409 -0
  84. package/dist/session/repl.js.map +1 -0
  85. package/package.json +142 -0
  86. package/src/compilers/index.ts +80 -0
  87. package/src/compilers/javascript.ts +571 -0
  88. package/src/compilers/python.ts +785 -0
  89. package/src/compilers/typescript.ts +442 -0
  90. package/src/core/cell.ts +439 -0
  91. package/src/core/compiler.ts +250 -0
  92. package/src/core/index.ts +123 -0
  93. package/src/core/limits.ts +508 -0
  94. package/src/core/permissions.ts +409 -0
  95. package/src/core/runtime.ts +499 -0
  96. package/src/core/types.ts +528 -0
  97. package/src/global.d.ts +59 -0
  98. package/src/index.ts +515 -0
  99. package/src/multi/index.ts +22 -0
  100. package/src/multi/polyglot.ts +461 -0
  101. package/src/runtimes/docker.ts +501 -0
  102. package/src/runtimes/index.ts +21 -0
  103. package/src/runtimes/process.ts +316 -0
  104. package/src/session/index.ts +41 -0
  105. package/src/session/kernel.ts +553 -0
  106. package/src/session/notebook.ts +635 -0
  107. package/src/session/repl.ts +521 -0
  108. package/src/wasm2wasm.d.ts +35 -0
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Process Runtime
3
+ *
4
+ * Spawns child processes for code execution with elevated permissions.
5
+ * Supports filesystem and network access with configurable limits.
6
+ *
7
+ * Isolation level: 'process'
8
+ */
9
+
10
+ import { spawn, type ChildProcess } from "node:child_process";
11
+ import { setTimeout as setTimeoutPromise } from "node:timers/promises";
12
+ import type {
13
+ ExecutionResult,
14
+ Permissions,
15
+ Limits,
16
+ DisplayOutput,
17
+ } from "../core/types.js";
18
+ import type {
19
+ IRuntime,
20
+ RuntimeOptions,
21
+ ExecutionRequest,
22
+ RuntimeCapabilities,
23
+ } from "../core/runtime.js";
24
+
25
+ /** Process runtime configuration */
26
+ export interface ProcessRuntimeConfig {
27
+ /** Default shell to use */
28
+ shell?: string;
29
+ /** Timeout for availability check */
30
+ availabilityTimeout?: number;
31
+ }
32
+
33
+ /**
34
+ * Process Runtime
35
+ *
36
+ * Executes code in child processes with configurable permissions.
37
+ * Provides filesystem and network access based on permission level.
38
+ */
39
+ export class ProcessRuntime implements IRuntime {
40
+ readonly name = "process";
41
+ readonly capabilities: RuntimeCapabilities = {
42
+ isolation: "process",
43
+ stateful: true,
44
+ async: true,
45
+ filesystem: true,
46
+ network: true,
47
+ maxMemory: 4 * 1024 * 1024 * 1024, // 4GB
48
+ wasi: false,
49
+ };
50
+
51
+ private executing = false;
52
+ private config: ProcessRuntimeConfig;
53
+
54
+ constructor(config: ProcessRuntimeConfig = {}) {
55
+ this.config = {
56
+ shell: config.shell ?? "/bin/sh",
57
+ availabilityTimeout: config.availabilityTimeout ?? 5000,
58
+ };
59
+ }
60
+
61
+ async init(): Promise<void> {
62
+ // No special initialization needed for process runtime
63
+ }
64
+
65
+ async isAvailable(): Promise<boolean> {
66
+ // Process spawning is always available in Node.js
67
+ return typeof process !== "undefined" && typeof spawn === "function";
68
+ }
69
+
70
+ async execute(
71
+ request: ExecutionRequest,
72
+ options: RuntimeOptions
73
+ ): Promise<ExecutionResult> {
74
+ const startTime = Date.now();
75
+ this.executing = true;
76
+
77
+ const stdout: string[] = [];
78
+ const stderr: string[] = [];
79
+ const displays: DisplayOutput[] = [];
80
+
81
+ try {
82
+ // Parse limits
83
+ const timeout = this.parseTimeout(options.limits?.timeout);
84
+ const maxMemory = this.parseMemory(options.limits?.memory);
85
+
86
+ // Build execution command based on code type
87
+ const { command, args } = this.buildCommand(request, options);
88
+
89
+ // Create abort controller for timeout
90
+ const controller = new AbortController();
91
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
92
+
93
+ // Combine with external signal if provided
94
+ if (options.signal) {
95
+ options.signal.addEventListener("abort", () => {
96
+ controller.abort();
97
+ clearTimeout(timeoutId);
98
+ });
99
+ }
100
+
101
+ // Spawn child process
102
+ const childProcess = spawn(command, args, {
103
+ cwd: options.cwd ?? process.cwd(),
104
+ env: {
105
+ ...process.env,
106
+ ...options.env,
107
+ NODE_OPTIONS: `--max-old-space-size=${Math.floor(maxMemory / (1024 * 1024))}`,
108
+ },
109
+ signal: controller.signal,
110
+ shell: false,
111
+ stdio: ["pipe", "pipe", "pipe"],
112
+ });
113
+
114
+ // Collect stdout
115
+ childProcess.stdout?.on("data", (data: Buffer) => {
116
+ stdout.push(data.toString("utf8"));
117
+ });
118
+
119
+ // Collect stderr
120
+ childProcess.stderr?.on("data", (data: Buffer) => {
121
+ stderr.push(data.toString("utf8"));
122
+ });
123
+
124
+ // Handle process events
125
+ const result = await new Promise<ExecutionResult>((resolve) => {
126
+ let returnValue: unknown = undefined;
127
+
128
+ childProcess.on("error", (error: Error) => {
129
+ clearTimeout(timeoutId);
130
+ resolve(
131
+ this.createErrorResult(
132
+ `Process error: ${error.message}`,
133
+ "runtime",
134
+ startTime,
135
+ stdout,
136
+ stderr
137
+ )
138
+ );
139
+ });
140
+
141
+ childProcess.on("close", (code: number, signal: NodeJS.Signals | null) => {
142
+ clearTimeout(timeoutId);
143
+
144
+ if (signal) {
145
+ resolve(
146
+ this.createErrorResult(
147
+ `Process killed by signal: ${signal}`,
148
+ signal === "SIGTERM" ? "timeout" : "cancel",
149
+ startTime,
150
+ stdout,
151
+ stderr
152
+ )
153
+ );
154
+ return;
155
+ }
156
+
157
+ // Try to parse stdout as JSON for return value
158
+ const output = stdout.join("");
159
+ try {
160
+ const parsed = JSON.parse(output);
161
+ if (parsed.__return_value !== undefined) {
162
+ returnValue = parsed.__return_value;
163
+ }
164
+ } catch {
165
+ // Not JSON, use raw output as value
166
+ returnValue = output.trim() || undefined;
167
+ }
168
+
169
+ resolve({
170
+ success: code === 0,
171
+ value: returnValue,
172
+ metrics: {
173
+ duration: Date.now() - startTime,
174
+ memoryUsed: 0, // Not tracked at process level
175
+ },
176
+ output: { stdout, stderr, displays },
177
+ });
178
+ });
179
+
180
+ // Write input if provided
181
+ if (request.input !== undefined) {
182
+ const inputStr =
183
+ typeof request.input === "string"
184
+ ? request.input
185
+ : JSON.stringify(request.input);
186
+ childProcess.stdin?.write(inputStr);
187
+ childProcess.stdin?.end();
188
+ }
189
+ });
190
+
191
+ return result;
192
+ } catch (error) {
193
+ if (error instanceof Error && error.name === "AbortError") {
194
+ return this.createErrorResult(
195
+ "Execution timed out",
196
+ "timeout",
197
+ startTime,
198
+ stdout,
199
+ stderr
200
+ );
201
+ }
202
+
203
+ return this.createErrorResult(
204
+ error instanceof Error ? error.message : String(error),
205
+ "runtime",
206
+ startTime,
207
+ stdout,
208
+ stderr
209
+ );
210
+ } finally {
211
+ this.executing = false;
212
+ }
213
+ }
214
+
215
+ async terminate(): Promise<void> {
216
+ this.executing = false;
217
+ }
218
+
219
+ isExecuting(): boolean {
220
+ return this.executing;
221
+ }
222
+
223
+ /**
224
+ * Build command and arguments for execution
225
+ */
226
+ private buildCommand(
227
+ request: ExecutionRequest,
228
+ options: RuntimeOptions
229
+ ): { command: string; args: string[] } {
230
+ // Execute WASM using node with WASI support
231
+ return {
232
+ command: "node",
233
+ args: [
234
+ "--experimental-wasi-unstable-preview1",
235
+ "-e",
236
+ this.generateWasmRunner(request.wasm.wasmBytes, options.permissions),
237
+ ],
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Generate WASM runner script
243
+ */
244
+ private generateWasmRunner(
245
+ wasmBytes: Uint8Array,
246
+ permissions: Permissions
247
+ ): string {
248
+ const hasFs = permissions.fs?.read || permissions.fs?.write;
249
+ const hasNetwork = permissions.network?.outbound || permissions.network?.inbound;
250
+
251
+ return `
252
+ const { WASI } = require('wasi');
253
+ const { readFile } = require('fs/promises');
254
+
255
+ async function run() {
256
+ const wasmBuffer = Buffer.from([${Array.from(wasmBytes).join(",")}]);
257
+
258
+ const wasi = new WASI({
259
+ version: 'preview1',
260
+ preopens: ${hasFs ? "{ '/': process.cwd() }" : "{}"},
261
+ env: process.env,
262
+ });
263
+
264
+ const { instance } = await WebAssembly.instantiate(wasmBuffer, {
265
+ wasi_snapshot_preview1: wasi.wasiImport,
266
+ });
267
+
268
+ wasi.start(instance);
269
+ }
270
+
271
+ run().catch(console.error);
272
+ `;
273
+ }
274
+
275
+ private createErrorResult(
276
+ message: string,
277
+ type: "compile" | "runtime" | "permission" | "limit" | "timeout" | "cancel",
278
+ startTime: number,
279
+ stdout: string[] = [],
280
+ stderr: string[] = []
281
+ ): ExecutionResult {
282
+ return {
283
+ success: false,
284
+ error: { message, type },
285
+ metrics: {
286
+ duration: Date.now() - startTime,
287
+ memoryUsed: 0,
288
+ },
289
+ output: { stdout, stderr, displays: [] },
290
+ };
291
+ }
292
+
293
+ private parseMemory(memory: string | number | undefined): number {
294
+ if (!memory) return 256 * 1024 * 1024; // 256MB default
295
+ if (typeof memory === "number") return memory;
296
+ const match = memory.match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/i);
297
+ if (!match) return 256 * 1024 * 1024;
298
+ const [, num, unit] = match;
299
+ const multipliers: Record<string, number> = {
300
+ b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3,
301
+ };
302
+ return Math.floor(parseFloat(num) * (multipliers[unit?.toLowerCase() ?? "b"] ?? 1));
303
+ }
304
+
305
+ private parseTimeout(timeout: string | number | undefined): number {
306
+ if (!timeout) return 60000; // 60s default for process
307
+ if (typeof timeout === "number") return timeout;
308
+ const match = timeout.match(/^(\d+(?:\.\d+)?)\s*(ms|s|m)?$/i);
309
+ if (!match) return 60000;
310
+ const [, num, unit] = match;
311
+ const multipliers: Record<string, number> = {
312
+ ms: 1, s: 1000, m: 60000,
313
+ };
314
+ return Math.floor(parseFloat(num) * (multipliers[unit?.toLowerCase() ?? "ms"] ?? 1));
315
+ }
316
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Session Primitives
3
+ *
4
+ * Stateful execution contexts for interactive use.
5
+ */
6
+
7
+ // Kernel - Language-specific execution session
8
+ export type {
9
+ KernelState,
10
+ KernelOptions,
11
+ KernelStats,
12
+ } from "./kernel.js";
13
+
14
+ export {
15
+ BaseKernel,
16
+ KernelManager,
17
+ } from "./kernel.js";
18
+
19
+ // Notebook - Multi-cell document execution
20
+ export type {
21
+ NotebookOptions,
22
+ NotebookState,
23
+ NotebookEvents,
24
+ } from "./notebook.js";
25
+
26
+ export {
27
+ BaseNotebook,
28
+ createNotebook,
29
+ } from "./notebook.js";
30
+
31
+ // REPL - Interactive Read-Eval-Print-Loop
32
+ export type {
33
+ REPLOptions,
34
+ REPLHistoryEntry,
35
+ REPLState,
36
+ } from "./repl.js";
37
+
38
+ export {
39
+ BaseREPL,
40
+ createREPL,
41
+ } from "./repl.js";