@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.
- package/dist/compilers/index.d.ts +24 -0
- package/dist/compilers/index.d.ts.map +1 -0
- package/dist/compilers/index.js +42 -0
- package/dist/compilers/index.js.map +1 -0
- package/dist/compilers/javascript.d.ts +117 -0
- package/dist/compilers/javascript.d.ts.map +1 -0
- package/dist/compilers/javascript.js +462 -0
- package/dist/compilers/javascript.js.map +1 -0
- package/dist/compilers/python.d.ts +140 -0
- package/dist/compilers/python.d.ts.map +1 -0
- package/dist/compilers/python.js +650 -0
- package/dist/compilers/python.js.map +1 -0
- package/dist/compilers/typescript.d.ts +99 -0
- package/dist/compilers/typescript.d.ts.map +1 -0
- package/dist/compilers/typescript.js +323 -0
- package/dist/compilers/typescript.js.map +1 -0
- package/dist/core/cell.d.ts +160 -0
- package/dist/core/cell.d.ts.map +1 -0
- package/dist/core/cell.js +319 -0
- package/dist/core/cell.js.map +1 -0
- package/dist/core/compiler.d.ts +126 -0
- package/dist/core/compiler.d.ts.map +1 -0
- package/dist/core/compiler.js +123 -0
- package/dist/core/compiler.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/limits.d.ts +173 -0
- package/dist/core/limits.d.ts.map +1 -0
- package/dist/core/limits.js +440 -0
- package/dist/core/limits.js.map +1 -0
- package/dist/core/permissions.d.ts +103 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +341 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/runtime.d.ts +127 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +325 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/types.d.ts +380 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +67 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/dist/multi/index.d.ts +9 -0
- package/dist/multi/index.d.ts.map +1 -0
- package/dist/multi/index.js +7 -0
- package/dist/multi/index.js.map +1 -0
- package/dist/multi/polyglot.d.ts +179 -0
- package/dist/multi/polyglot.d.ts.map +1 -0
- package/dist/multi/polyglot.js +319 -0
- package/dist/multi/polyglot.js.map +1 -0
- package/dist/runtimes/docker.d.ts +97 -0
- package/dist/runtimes/docker.d.ts.map +1 -0
- package/dist/runtimes/docker.js +368 -0
- package/dist/runtimes/docker.js.map +1 -0
- package/dist/runtimes/index.d.ts +11 -0
- package/dist/runtimes/index.d.ts.map +1 -0
- package/dist/runtimes/index.js +9 -0
- package/dist/runtimes/index.js.map +1 -0
- package/dist/runtimes/process.d.ts +47 -0
- package/dist/runtimes/process.d.ts.map +1 -0
- package/dist/runtimes/process.js +230 -0
- package/dist/runtimes/process.js.map +1 -0
- package/dist/session/index.d.ts +12 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +9 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/kernel.d.ts +199 -0
- package/dist/session/kernel.d.ts.map +1 -0
- package/dist/session/kernel.js +400 -0
- package/dist/session/kernel.js.map +1 -0
- package/dist/session/notebook.d.ts +168 -0
- package/dist/session/notebook.d.ts.map +1 -0
- package/dist/session/notebook.js +499 -0
- package/dist/session/notebook.js.map +1 -0
- package/dist/session/repl.d.ts +159 -0
- package/dist/session/repl.d.ts.map +1 -0
- package/dist/session/repl.js +409 -0
- package/dist/session/repl.js.map +1 -0
- package/package.json +142 -0
- package/src/compilers/index.ts +80 -0
- package/src/compilers/javascript.ts +571 -0
- package/src/compilers/python.ts +785 -0
- package/src/compilers/typescript.ts +442 -0
- package/src/core/cell.ts +439 -0
- package/src/core/compiler.ts +250 -0
- package/src/core/index.ts +123 -0
- package/src/core/limits.ts +508 -0
- package/src/core/permissions.ts +409 -0
- package/src/core/runtime.ts +499 -0
- package/src/core/types.ts +528 -0
- package/src/global.d.ts +59 -0
- package/src/index.ts +515 -0
- package/src/multi/index.ts +22 -0
- package/src/multi/polyglot.ts +461 -0
- package/src/runtimes/docker.ts +501 -0
- package/src/runtimes/index.ts +21 -0
- package/src/runtimes/process.ts +316 -0
- package/src/session/index.ts +41 -0
- package/src/session/kernel.ts +553 -0
- package/src/session/notebook.ts +635 -0
- package/src/session/repl.ts +521 -0
- package/src/wasm2wasm.d.ts +35 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language Compilers
|
|
3
|
+
*
|
|
4
|
+
* Export all available compilers for the sandbox.
|
|
5
|
+
* Each compiler transforms source code to WASM format.
|
|
6
|
+
*/
|
|
7
|
+
export { PythonCompiler, createPythonCompiler, pythonCompiler, type PythonValidationResult, } from "./python.js";
|
|
8
|
+
export { JavaScriptCompiler, javascriptCompiler, type JavaScriptCompilerOptions, } from "./javascript.js";
|
|
9
|
+
export { TypeScriptCompiler, typescriptCompiler, type TypeScriptCompilerOptions, } from "./typescript.js";
|
|
10
|
+
export type { CompileResult, ImportDefinition, CompilerOptions, ICompiler, LanguageCapabilities, } from "../core/compiler.js";
|
|
11
|
+
export { BaseCompiler, WasmCompiler, CompilerRegistry, defaultCompilerRegistry, } from "../core/compiler.js";
|
|
12
|
+
/**
|
|
13
|
+
* Create a compiler registry with all available compilers
|
|
14
|
+
*/
|
|
15
|
+
import { CompilerRegistry } from "../core/compiler.js";
|
|
16
|
+
/**
|
|
17
|
+
* Create a compiler registry pre-populated with all available compilers
|
|
18
|
+
*/
|
|
19
|
+
export declare function createCompilerRegistry(): CompilerRegistry;
|
|
20
|
+
/**
|
|
21
|
+
* Default compiler registry with all language support
|
|
22
|
+
*/
|
|
23
|
+
export declare const compilers: CompilerRegistry;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compilers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,OAAO,EAAE,gBAAgB,EAA2B,MAAM,qBAAqB,CAAC;AAKhF;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAazD;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,kBAA2B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language Compilers
|
|
3
|
+
*
|
|
4
|
+
* Export all available compilers for the sandbox.
|
|
5
|
+
* Each compiler transforms source code to WASM format.
|
|
6
|
+
*/
|
|
7
|
+
// Python compiler
|
|
8
|
+
export { PythonCompiler, createPythonCompiler, pythonCompiler, } from "./python.js";
|
|
9
|
+
// JavaScript compiler
|
|
10
|
+
export { JavaScriptCompiler, javascriptCompiler, } from "./javascript.js";
|
|
11
|
+
// TypeScript compiler
|
|
12
|
+
export { TypeScriptCompiler, typescriptCompiler, } from "./typescript.js";
|
|
13
|
+
export { BaseCompiler, WasmCompiler, CompilerRegistry, defaultCompilerRegistry, } from "../core/compiler.js";
|
|
14
|
+
/**
|
|
15
|
+
* Create a compiler registry with all available compilers
|
|
16
|
+
*/
|
|
17
|
+
import { CompilerRegistry, defaultCompilerRegistry } from "../core/compiler.js";
|
|
18
|
+
import { PythonCompiler } from "./python.js";
|
|
19
|
+
import { JavaScriptCompiler } from "./javascript.js";
|
|
20
|
+
import { TypeScriptCompiler } from "./typescript.js";
|
|
21
|
+
/**
|
|
22
|
+
* Create a compiler registry pre-populated with all available compilers
|
|
23
|
+
*/
|
|
24
|
+
export function createCompilerRegistry() {
|
|
25
|
+
const registry = new CompilerRegistry();
|
|
26
|
+
// Register Python compiler
|
|
27
|
+
registry.register(new PythonCompiler());
|
|
28
|
+
// Register JavaScript compiler
|
|
29
|
+
registry.register(new JavaScriptCompiler());
|
|
30
|
+
// Register TypeScript compiler
|
|
31
|
+
registry.register(new TypeScriptCompiler());
|
|
32
|
+
return registry;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Default compiler registry with all language support
|
|
36
|
+
*/
|
|
37
|
+
export const compilers = createCompilerRegistry();
|
|
38
|
+
// Register all compilers with the default registry
|
|
39
|
+
defaultCompilerRegistry.register(new PythonCompiler());
|
|
40
|
+
defaultCompilerRegistry.register(new JavaScriptCompiler());
|
|
41
|
+
defaultCompilerRegistry.register(new TypeScriptCompiler());
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compilers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,kBAAkB;AAClB,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,cAAc,GAEf,MAAM,aAAa,CAAC;AAErB,sBAAsB;AACtB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,iBAAiB,CAAC;AAEzB,sBAAsB;AACtB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,iBAAiB,CAAC;AAWzB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAExC,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;IAExC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC;IAE5C,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC;IAE5C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,sBAAsB,EAAE,CAAC;AAElD,mDAAmD;AACnD,uBAAuB,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;AACvD,uBAAuB,CAAC,QAAQ,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC;AAC3D,uBAAuB,CAAC,QAAQ,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JavaScript Compiler for @ebowwa/sandbox
|
|
3
|
+
*
|
|
4
|
+
* Compiles JavaScript to WASM or provides sandboxed execution.
|
|
5
|
+
* Uses AssemblyScript for strict JS/TS-to-WASM compilation when possible,
|
|
6
|
+
* falls back to sandboxed QuickJS or native execution for dynamic JS.
|
|
7
|
+
*/
|
|
8
|
+
import { BaseCompiler, type CompileResult, type CompilerOptions, type LanguageCapabilities } from "../core/compiler.js";
|
|
9
|
+
import type { Permissions, Limits } from "../core/types.js";
|
|
10
|
+
/** JavaScript compiler options */
|
|
11
|
+
export interface JavaScriptCompilerOptions extends CompilerOptions {
|
|
12
|
+
/** Target ES version */
|
|
13
|
+
target?: "es2015" | "es2016" | "es2017" | "es2018" | "es2019" | "es2020" | "es2021" | "es2022" | "esnext";
|
|
14
|
+
/** Module format */
|
|
15
|
+
module?: "esm" | "cjs" | "iife";
|
|
16
|
+
/** Enable strict mode */
|
|
17
|
+
strict?: boolean;
|
|
18
|
+
/** Use AssemblyScript for compilation (requires strict typing) */
|
|
19
|
+
useAssemblyScript?: boolean;
|
|
20
|
+
/** Sandbox mode when not using WASM */
|
|
21
|
+
sandboxMode?: "quickjs" | "isolated-vm" | "vm" | "none";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* JavaScript Compiler
|
|
25
|
+
*
|
|
26
|
+
* Provides JavaScript execution in a sandboxed environment.
|
|
27
|
+
* For true WASM compilation, AssemblyScript is used but requires
|
|
28
|
+
* strict typing with WebAssembly types (i32, i64, f32, f64).
|
|
29
|
+
*/
|
|
30
|
+
export declare class JavaScriptCompiler extends BaseCompiler {
|
|
31
|
+
readonly language: "javascript";
|
|
32
|
+
private assemblyScriptAvailable;
|
|
33
|
+
private esbuildAvailable;
|
|
34
|
+
/**
|
|
35
|
+
* Check if AssemblyScript is available for WASM compilation
|
|
36
|
+
*/
|
|
37
|
+
isAvailable(): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Validate JavaScript syntax
|
|
40
|
+
*/
|
|
41
|
+
validate(source: string): Promise<{
|
|
42
|
+
valid: boolean;
|
|
43
|
+
error?: string;
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Compile JavaScript to WASM or prepare for sandboxed execution
|
|
47
|
+
*
|
|
48
|
+
* For dynamic JavaScript (with closures, objects, etc.), we create a WASM
|
|
49
|
+
* wrapper that includes a minimal JS runtime or use sandboxed execution.
|
|
50
|
+
*/
|
|
51
|
+
compile(source: string, permissions: Permissions, limits: Limits, options?: JavaScriptCompilerOptions): Promise<CompileResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Get language capabilities
|
|
54
|
+
*/
|
|
55
|
+
getCapabilities(): LanguageCapabilities;
|
|
56
|
+
/**
|
|
57
|
+
* Compile with AssemblyScript
|
|
58
|
+
*
|
|
59
|
+
* Note: AssemblyScript requires strict typing with WASM types.
|
|
60
|
+
* Standard JavaScript with dynamic features won't compile.
|
|
61
|
+
*/
|
|
62
|
+
private compileWithAssemblyScript;
|
|
63
|
+
/**
|
|
64
|
+
* Create a sandboxed execution wrapper
|
|
65
|
+
*
|
|
66
|
+
* Instead of compiling to WASM, we create a WASM module that
|
|
67
|
+
* provides a sandboxed JavaScript execution environment.
|
|
68
|
+
* For simplicity, we use a minimal wrapper that can be executed
|
|
69
|
+
* by a JavaScript runtime.
|
|
70
|
+
*/
|
|
71
|
+
private createSandboxedWrapper;
|
|
72
|
+
/**
|
|
73
|
+
* Create a WASM wrapper for sandboxed JavaScript execution
|
|
74
|
+
*
|
|
75
|
+
* This creates a WASM module that:
|
|
76
|
+
* 1. Contains the JavaScript source code as data
|
|
77
|
+
* 2. Exports functions for the runtime to execute
|
|
78
|
+
* 3. Provides memory for execution results
|
|
79
|
+
*/
|
|
80
|
+
private createSandboxWasmWrapper;
|
|
81
|
+
/**
|
|
82
|
+
* Build the sandbox WASM module
|
|
83
|
+
*
|
|
84
|
+
* Creates a minimal WASM binary that contains:
|
|
85
|
+
* - Data section with JS source
|
|
86
|
+
* - Exported functions for runtime interaction
|
|
87
|
+
*/
|
|
88
|
+
private buildSandboxWasm;
|
|
89
|
+
private buildTypeSection;
|
|
90
|
+
private buildFunctionSection;
|
|
91
|
+
private buildMemorySection;
|
|
92
|
+
private buildExportSection;
|
|
93
|
+
private buildCodeSection;
|
|
94
|
+
private buildDataSection;
|
|
95
|
+
private encodeLEB128;
|
|
96
|
+
/**
|
|
97
|
+
* Wrap JavaScript source for AssemblyScript compilation
|
|
98
|
+
*
|
|
99
|
+
* AssemblyScript requires explicit types and specific syntax.
|
|
100
|
+
* This wrapper attempts to make standard JS compatible.
|
|
101
|
+
*/
|
|
102
|
+
private wrapForAssemblyScript;
|
|
103
|
+
/**
|
|
104
|
+
* Get esbuild instance for transpilation
|
|
105
|
+
*/
|
|
106
|
+
private getEsbuild;
|
|
107
|
+
/**
|
|
108
|
+
* Parse memory string to bytes
|
|
109
|
+
*/
|
|
110
|
+
private parseMemory;
|
|
111
|
+
/**
|
|
112
|
+
* Parse time string to milliseconds
|
|
113
|
+
*/
|
|
114
|
+
private parseTime;
|
|
115
|
+
}
|
|
116
|
+
export declare const javascriptCompiler: JavaScriptCompiler;
|
|
117
|
+
//# sourceMappingURL=javascript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"javascript.d.ts","sourceRoot":"","sources":["../../src/compilers/javascript.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE5D,kCAAkC;AAClC,MAAM,WAAW,yBAA0B,SAAQ,eAAe;IAChE,wBAAwB;IACxB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1G,oBAAoB;IACpB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uCAAuC;IACvC,WAAW,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,IAAI,GAAG,MAAM,CAAC;CACzD;AAcD;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,QAAQ,CAAC,QAAQ,EAAG,YAAY,CAAU;IAE1C,OAAO,CAAC,uBAAuB,CAAwB;IACvD,OAAO,CAAC,gBAAgB,CAAwB;IAEhD;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAerC;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAwB3E;;;;;OAKG;IACG,OAAO,CACX,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,aAAa,CAAC;IAmBzB;;OAEG;IACH,eAAe,IAAI,oBAAoB;IAWvC;;;;;OAKG;YACW,yBAAyB;IAqEvC;;;;;;;OAOG;YACW,sBAAsB;IA0BpC;;;;;;;OAOG;YACW,wBAAwB;IAiDtC;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAoDxB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,YAAY;IAgBpB;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;YACW,UAAU;IAexB;;OAEG;IACH,OAAO,CAAC,WAAW;IAanB;;OAEG;IACH,OAAO,CAAC,SAAS;CAYlB;AAGD,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JavaScript Compiler for @ebowwa/sandbox
|
|
3
|
+
*
|
|
4
|
+
* Compiles JavaScript to WASM or provides sandboxed execution.
|
|
5
|
+
* Uses AssemblyScript for strict JS/TS-to-WASM compilation when possible,
|
|
6
|
+
* falls back to sandboxed QuickJS or native execution for dynamic JS.
|
|
7
|
+
*/
|
|
8
|
+
import { BaseCompiler, } from "../core/compiler.js";
|
|
9
|
+
/**
|
|
10
|
+
* JavaScript Compiler
|
|
11
|
+
*
|
|
12
|
+
* Provides JavaScript execution in a sandboxed environment.
|
|
13
|
+
* For true WASM compilation, AssemblyScript is used but requires
|
|
14
|
+
* strict typing with WebAssembly types (i32, i64, f32, f64).
|
|
15
|
+
*/
|
|
16
|
+
export class JavaScriptCompiler extends BaseCompiler {
|
|
17
|
+
language = "javascript";
|
|
18
|
+
assemblyScriptAvailable = null;
|
|
19
|
+
esbuildAvailable = null;
|
|
20
|
+
/**
|
|
21
|
+
* Check if AssemblyScript is available for WASM compilation
|
|
22
|
+
*/
|
|
23
|
+
async isAvailable() {
|
|
24
|
+
if (this.assemblyScriptAvailable !== null) {
|
|
25
|
+
return this.assemblyScriptAvailable;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
await import("assemblyscript");
|
|
29
|
+
this.assemblyScriptAvailable = true;
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
this.assemblyScriptAvailable = false;
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validate JavaScript syntax
|
|
39
|
+
*/
|
|
40
|
+
async validate(source) {
|
|
41
|
+
try {
|
|
42
|
+
// Use esbuild for syntax validation if available
|
|
43
|
+
const esbuild = await this.getEsbuild();
|
|
44
|
+
if (esbuild) {
|
|
45
|
+
await esbuild.transform(source, {
|
|
46
|
+
loader: "js",
|
|
47
|
+
target: "es2020",
|
|
48
|
+
});
|
|
49
|
+
return { valid: true };
|
|
50
|
+
}
|
|
51
|
+
// Fallback: use Function constructor for basic syntax check
|
|
52
|
+
// This doesn't execute the code, just parses it
|
|
53
|
+
new Function(source);
|
|
54
|
+
return { valid: true };
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return {
|
|
58
|
+
valid: false,
|
|
59
|
+
error: error instanceof Error ? error.message : String(error),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Compile JavaScript to WASM or prepare for sandboxed execution
|
|
65
|
+
*
|
|
66
|
+
* For dynamic JavaScript (with closures, objects, etc.), we create a WASM
|
|
67
|
+
* wrapper that includes a minimal JS runtime or use sandboxed execution.
|
|
68
|
+
*/
|
|
69
|
+
async compile(source, permissions, limits, options) {
|
|
70
|
+
const opts = {
|
|
71
|
+
target: "es2020",
|
|
72
|
+
module: "esm",
|
|
73
|
+
strict: true,
|
|
74
|
+
useAssemblyScript: false, // Default to sandboxed execution
|
|
75
|
+
sandboxMode: "vm",
|
|
76
|
+
...options,
|
|
77
|
+
};
|
|
78
|
+
// Try AssemblyScript compilation if explicitly requested and available
|
|
79
|
+
if (opts.useAssemblyScript && (await this.isAvailable())) {
|
|
80
|
+
return this.compileWithAssemblyScript(source, permissions, limits, opts);
|
|
81
|
+
}
|
|
82
|
+
// For standard JavaScript, create a sandboxed execution wrapper
|
|
83
|
+
return this.createSandboxedWrapper(source, permissions, limits, opts);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get language capabilities
|
|
87
|
+
*/
|
|
88
|
+
getCapabilities() {
|
|
89
|
+
return {
|
|
90
|
+
repl: true,
|
|
91
|
+
stateful: true,
|
|
92
|
+
compiled: false, // JS is interpreted, not compiled to WASM
|
|
93
|
+
gc: true, // JavaScript has garbage collection
|
|
94
|
+
imports: true,
|
|
95
|
+
async: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Compile with AssemblyScript
|
|
100
|
+
*
|
|
101
|
+
* Note: AssemblyScript requires strict typing with WASM types.
|
|
102
|
+
* Standard JavaScript with dynamic features won't compile.
|
|
103
|
+
*/
|
|
104
|
+
async compileWithAssemblyScript(source, _permissions, _limits, _options) {
|
|
105
|
+
try {
|
|
106
|
+
const asc = (await import("assemblyscript"));
|
|
107
|
+
// Wrap user code in a module structure
|
|
108
|
+
const assemblyScriptSource = this.wrapForAssemblyScript(source);
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
asc.main([
|
|
111
|
+
"--textFile", "/dev/stdout",
|
|
112
|
+
"--outFile", "/dev/stdout",
|
|
113
|
+
"--optimize",
|
|
114
|
+
"--target", "release",
|
|
115
|
+
], {
|
|
116
|
+
stdin: () => assemblyScriptSource,
|
|
117
|
+
listBuiltins: () => asc.builtins,
|
|
118
|
+
reportDiagnostic: (diagnostic) => {
|
|
119
|
+
console.error(diagnostic.messageText);
|
|
120
|
+
},
|
|
121
|
+
}, (error, result) => {
|
|
122
|
+
if (error) {
|
|
123
|
+
reject(new Error(`AssemblyScript compilation failed: ${error.message}`));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!result?.stdout) {
|
|
127
|
+
reject(new Error("AssemblyScript produced no output"));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Parse the WASM module to extract exports/imports
|
|
131
|
+
WebAssembly.compile(result.stdout)
|
|
132
|
+
.then((module) => {
|
|
133
|
+
const exports = WebAssembly.Module.exports(module).map((e) => e.name);
|
|
134
|
+
const imports = WebAssembly.Module.imports(module).map((i) => ({
|
|
135
|
+
module: i.module,
|
|
136
|
+
name: i.name,
|
|
137
|
+
type: i.kind,
|
|
138
|
+
}));
|
|
139
|
+
resolve({
|
|
140
|
+
wasmBytes: result.stdout,
|
|
141
|
+
exports,
|
|
142
|
+
imports,
|
|
143
|
+
memoryRequirements: {
|
|
144
|
+
initial: 1,
|
|
145
|
+
maximum: 256, // 16MB max
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
})
|
|
149
|
+
.catch(reject);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
throw new Error(`AssemblyScript compilation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Create a sandboxed execution wrapper
|
|
159
|
+
*
|
|
160
|
+
* Instead of compiling to WASM, we create a WASM module that
|
|
161
|
+
* provides a sandboxed JavaScript execution environment.
|
|
162
|
+
* For simplicity, we use a minimal wrapper that can be executed
|
|
163
|
+
* by a JavaScript runtime.
|
|
164
|
+
*/
|
|
165
|
+
async createSandboxedWrapper(source, permissions, limits, options) {
|
|
166
|
+
// Transpile with esbuild if available
|
|
167
|
+
let processedSource = source;
|
|
168
|
+
const esbuild = await this.getEsbuild();
|
|
169
|
+
if (esbuild) {
|
|
170
|
+
const result = await esbuild.transform(source, {
|
|
171
|
+
loader: "js",
|
|
172
|
+
target: options.target || "es2020",
|
|
173
|
+
format: options.module === "cjs" ? "cjs" : "esm",
|
|
174
|
+
minify: options.optimize,
|
|
175
|
+
});
|
|
176
|
+
processedSource = result.code;
|
|
177
|
+
}
|
|
178
|
+
// Create a WASM wrapper that provides sandboxed execution
|
|
179
|
+
// This is a minimal WASM module that exports a function to get the JS source
|
|
180
|
+
// The actual execution happens in the JavaScript runtime
|
|
181
|
+
return this.createSandboxWasmWrapper(processedSource, permissions, limits);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Create a WASM wrapper for sandboxed JavaScript execution
|
|
185
|
+
*
|
|
186
|
+
* This creates a WASM module that:
|
|
187
|
+
* 1. Contains the JavaScript source code as data
|
|
188
|
+
* 2. Exports functions for the runtime to execute
|
|
189
|
+
* 3. Provides memory for execution results
|
|
190
|
+
*/
|
|
191
|
+
async createSandboxWasmWrapper(source, permissions, limits) {
|
|
192
|
+
// Encode the source and configuration
|
|
193
|
+
const sourceBytes = new TextEncoder().encode(source);
|
|
194
|
+
const configBytes = new TextEncoder().encode(JSON.stringify({
|
|
195
|
+
permissions: {
|
|
196
|
+
fs: permissions.fs ? {
|
|
197
|
+
read: permissions.fs.read ?? false,
|
|
198
|
+
write: permissions.fs.write ?? false,
|
|
199
|
+
delete: permissions.fs.delete ?? false,
|
|
200
|
+
} : undefined,
|
|
201
|
+
network: permissions.network ? {
|
|
202
|
+
outbound: permissions.network.outbound ?? false,
|
|
203
|
+
inbound: permissions.network.inbound ?? false,
|
|
204
|
+
} : undefined,
|
|
205
|
+
},
|
|
206
|
+
limits: {
|
|
207
|
+
timeout: typeof limits.timeout === "string"
|
|
208
|
+
? this.parseTime(limits.timeout)
|
|
209
|
+
: limits.timeout ?? 30000,
|
|
210
|
+
memory: typeof limits.memory === "string"
|
|
211
|
+
? this.parseMemory(limits.memory)
|
|
212
|
+
: limits.memory ?? 16 * 1024 * 1024,
|
|
213
|
+
},
|
|
214
|
+
}));
|
|
215
|
+
// Create a minimal WASM module that holds the JavaScript source
|
|
216
|
+
// This module exports functions to access the source and config
|
|
217
|
+
const wasmBytes = this.buildSandboxWasm(sourceBytes, configBytes);
|
|
218
|
+
return {
|
|
219
|
+
wasmBytes,
|
|
220
|
+
exports: ["getSource", "getConfig", "execute", "getResult"],
|
|
221
|
+
imports: [
|
|
222
|
+
{ module: "env", name: "log", type: "function" },
|
|
223
|
+
{ module: "env", name: "abort", type: "function" },
|
|
224
|
+
],
|
|
225
|
+
memoryRequirements: {
|
|
226
|
+
initial: Math.max(1, Math.ceil((sourceBytes.length + configBytes.length) / 65536)),
|
|
227
|
+
maximum: 256,
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Build the sandbox WASM module
|
|
233
|
+
*
|
|
234
|
+
* Creates a minimal WASM binary that contains:
|
|
235
|
+
* - Data section with JS source
|
|
236
|
+
* - Exported functions for runtime interaction
|
|
237
|
+
*/
|
|
238
|
+
buildSandboxWasm(sourceBytes, configBytes) {
|
|
239
|
+
// WASM module structure:
|
|
240
|
+
// - Magic number + version
|
|
241
|
+
// - Type section (function signatures)
|
|
242
|
+
// - Function section
|
|
243
|
+
// - Memory section
|
|
244
|
+
// - Export section
|
|
245
|
+
// - Code section
|
|
246
|
+
// - Data section (JS source and config)
|
|
247
|
+
const magicNumber = new Uint8Array([0x00, 0x61, 0x73, 0x6D]); // \0asm
|
|
248
|
+
const version = new Uint8Array([0x01, 0x00, 0x00, 0x00]); // version 1
|
|
249
|
+
// Build sections
|
|
250
|
+
const typeSection = this.buildTypeSection();
|
|
251
|
+
const functionSection = this.buildFunctionSection();
|
|
252
|
+
const memorySection = this.buildMemorySection(sourceBytes.length + configBytes.length + 1024);
|
|
253
|
+
const exportSection = this.buildExportSection();
|
|
254
|
+
const codeSection = this.buildCodeSection();
|
|
255
|
+
const dataSection = this.buildDataSection(sourceBytes, configBytes);
|
|
256
|
+
// Combine all sections
|
|
257
|
+
const sections = [
|
|
258
|
+
typeSection,
|
|
259
|
+
functionSection,
|
|
260
|
+
memorySection,
|
|
261
|
+
exportSection,
|
|
262
|
+
codeSection,
|
|
263
|
+
dataSection,
|
|
264
|
+
];
|
|
265
|
+
const totalLength = magicNumber.length + version.length +
|
|
266
|
+
sections.reduce((sum, s) => sum + s.length, 0);
|
|
267
|
+
const wasm = new Uint8Array(totalLength);
|
|
268
|
+
let offset = 0;
|
|
269
|
+
// Write header
|
|
270
|
+
wasm.set(magicNumber, offset);
|
|
271
|
+
offset += magicNumber.length;
|
|
272
|
+
wasm.set(version, offset);
|
|
273
|
+
offset += version.length;
|
|
274
|
+
// Write sections
|
|
275
|
+
for (const section of sections) {
|
|
276
|
+
wasm.set(section, offset);
|
|
277
|
+
offset += section.length;
|
|
278
|
+
}
|
|
279
|
+
return wasm;
|
|
280
|
+
}
|
|
281
|
+
buildTypeSection() {
|
|
282
|
+
// Section ID 1 (type), 1 type, function type () -> i32
|
|
283
|
+
return new Uint8Array([
|
|
284
|
+
0x01, // section id
|
|
285
|
+
0x04, // section size
|
|
286
|
+
0x01, // num types
|
|
287
|
+
0x60, // func type
|
|
288
|
+
0x00, // 0 params
|
|
289
|
+
0x01, 0x7F, // 1 result: i32
|
|
290
|
+
]);
|
|
291
|
+
}
|
|
292
|
+
buildFunctionSection() {
|
|
293
|
+
// Section ID 3 (function), 4 functions
|
|
294
|
+
return new Uint8Array([
|
|
295
|
+
0x03, // section id
|
|
296
|
+
0x05, // section size
|
|
297
|
+
0x04, // num functions
|
|
298
|
+
0x00, 0x00, 0x00, 0x00, // function indices (all type 0)
|
|
299
|
+
]);
|
|
300
|
+
}
|
|
301
|
+
buildMemorySection(dataSize) {
|
|
302
|
+
const pages = Math.max(1, Math.ceil(dataSize / 65536));
|
|
303
|
+
// Section ID 5 (memory), 1 memory, limits
|
|
304
|
+
return new Uint8Array([
|
|
305
|
+
0x05, // section id
|
|
306
|
+
0x03, // section size
|
|
307
|
+
0x01, // num memories
|
|
308
|
+
0x01, // has max
|
|
309
|
+
pages, // initial pages
|
|
310
|
+
0x80, 0x02, // max pages (256)
|
|
311
|
+
]);
|
|
312
|
+
}
|
|
313
|
+
buildExportSection() {
|
|
314
|
+
// Section ID 7 (export)
|
|
315
|
+
// Export: memory, getSource, getConfig, execute, getResult
|
|
316
|
+
const exports = [
|
|
317
|
+
{ name: "memory", kind: 0x02, index: 0 }, // memory
|
|
318
|
+
{ name: "getSource", kind: 0x00, index: 0 }, // func 0
|
|
319
|
+
{ name: "getConfig", kind: 0x00, index: 1 }, // func 1
|
|
320
|
+
{ name: "execute", kind: 0x00, index: 2 }, // func 2
|
|
321
|
+
{ name: "getResult", kind: 0x00, index: 3 }, // func 3
|
|
322
|
+
];
|
|
323
|
+
const nameBytes = [];
|
|
324
|
+
for (const exp of exports) {
|
|
325
|
+
const nameEncoded = new TextEncoder().encode(exp.name);
|
|
326
|
+
nameBytes.push(nameEncoded.length);
|
|
327
|
+
nameBytes.push(...nameEncoded);
|
|
328
|
+
nameBytes.push(exp.kind);
|
|
329
|
+
nameBytes.push(exp.index);
|
|
330
|
+
}
|
|
331
|
+
const sectionContent = [exports.length, ...nameBytes];
|
|
332
|
+
const sectionSize = sectionContent.length;
|
|
333
|
+
return new Uint8Array([0x07, sectionSize, ...sectionContent]);
|
|
334
|
+
}
|
|
335
|
+
buildCodeSection() {
|
|
336
|
+
// Section ID 10 (code)
|
|
337
|
+
// 4 function bodies, each returning a constant
|
|
338
|
+
const functions = [
|
|
339
|
+
[0x00, 0x41, 0x00, 0x0B], // getSource: return 0 (offset)
|
|
340
|
+
[0x00, 0x41, 0x00, 0x0B], // getConfig: return 0 (placeholder)
|
|
341
|
+
[0x00, 0x41, 0x00, 0x0B], // execute: return 0 (placeholder)
|
|
342
|
+
[0x00, 0x41, 0x00, 0x0B], // getResult: return 0 (placeholder)
|
|
343
|
+
];
|
|
344
|
+
const bodies = [];
|
|
345
|
+
for (const body of functions) {
|
|
346
|
+
bodies.push(body.length);
|
|
347
|
+
bodies.push(...body);
|
|
348
|
+
}
|
|
349
|
+
const sectionContent = [functions.length, ...bodies];
|
|
350
|
+
const sectionSize = sectionContent.length;
|
|
351
|
+
return new Uint8Array([0x0A, sectionSize, ...sectionContent]);
|
|
352
|
+
}
|
|
353
|
+
buildDataSection(sourceBytes, configBytes) {
|
|
354
|
+
// Section ID 11 (data)
|
|
355
|
+
// 2 data segments: source and config
|
|
356
|
+
const sourceLen = this.encodeLEB128(sourceBytes.length);
|
|
357
|
+
const configLen = this.encodeLEB128(configBytes.length);
|
|
358
|
+
const segment1 = [
|
|
359
|
+
0x00, // active, memory 0
|
|
360
|
+
0x41, 0x00, 0x23, 0x00, // i32.const 0 (offset placeholder)
|
|
361
|
+
...sourceLen,
|
|
362
|
+
...sourceBytes,
|
|
363
|
+
];
|
|
364
|
+
const segment2 = [
|
|
365
|
+
0x00, // active, memory 0
|
|
366
|
+
0x41, 0x00, 0x23, 0x00, // i32.const 0 (offset placeholder)
|
|
367
|
+
...configLen,
|
|
368
|
+
...configBytes,
|
|
369
|
+
];
|
|
370
|
+
const sectionContent = [
|
|
371
|
+
0x02, // 2 data segments
|
|
372
|
+
...segment1,
|
|
373
|
+
...segment2,
|
|
374
|
+
];
|
|
375
|
+
const sectionSize = sectionContent.length;
|
|
376
|
+
return new Uint8Array([0x0B, sectionSize, ...sectionContent]);
|
|
377
|
+
}
|
|
378
|
+
encodeLEB128(value) {
|
|
379
|
+
const result = [];
|
|
380
|
+
let remaining = value;
|
|
381
|
+
do {
|
|
382
|
+
let byte = remaining & 0x7F;
|
|
383
|
+
remaining >>>= 7;
|
|
384
|
+
if (remaining !== 0) {
|
|
385
|
+
byte |= 0x80;
|
|
386
|
+
}
|
|
387
|
+
result.push(byte);
|
|
388
|
+
} while (remaining !== 0);
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Wrap JavaScript source for AssemblyScript compilation
|
|
393
|
+
*
|
|
394
|
+
* AssemblyScript requires explicit types and specific syntax.
|
|
395
|
+
* This wrapper attempts to make standard JS compatible.
|
|
396
|
+
*/
|
|
397
|
+
wrapForAssemblyScript(source) {
|
|
398
|
+
return `
|
|
399
|
+
// AssemblyScript wrapper
|
|
400
|
+
// Note: AssemblyScript requires strict typing with i32, i64, f32, f64
|
|
401
|
+
|
|
402
|
+
${source}
|
|
403
|
+
|
|
404
|
+
// Export a main function if not present
|
|
405
|
+
export function _start(): void {
|
|
406
|
+
// Entry point
|
|
407
|
+
}
|
|
408
|
+
`;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get esbuild instance for transpilation
|
|
412
|
+
*/
|
|
413
|
+
async getEsbuild() {
|
|
414
|
+
if (this.esbuildAvailable === false) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const esbuild = await import("esbuild");
|
|
419
|
+
this.esbuildAvailable = true;
|
|
420
|
+
return esbuild;
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
this.esbuildAvailable = false;
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Parse memory string to bytes
|
|
429
|
+
*/
|
|
430
|
+
parseMemory(mem) {
|
|
431
|
+
const match = mem.match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/i);
|
|
432
|
+
if (!match)
|
|
433
|
+
return 16 * 1024 * 1024;
|
|
434
|
+
const [, num, unit] = match;
|
|
435
|
+
const multipliers = {
|
|
436
|
+
b: 1,
|
|
437
|
+
kb: 1024,
|
|
438
|
+
mb: 1024 ** 2,
|
|
439
|
+
gb: 1024 ** 3,
|
|
440
|
+
};
|
|
441
|
+
return Math.floor(parseFloat(num) * (multipliers[unit?.toLowerCase() ?? "b"] ?? 1));
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Parse time string to milliseconds
|
|
445
|
+
*/
|
|
446
|
+
parseTime(time) {
|
|
447
|
+
const match = time.match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/i);
|
|
448
|
+
if (!match)
|
|
449
|
+
return 30000;
|
|
450
|
+
const [, num, unit] = match;
|
|
451
|
+
const multipliers = {
|
|
452
|
+
ms: 1,
|
|
453
|
+
s: 1000,
|
|
454
|
+
m: 60000,
|
|
455
|
+
h: 3600000,
|
|
456
|
+
};
|
|
457
|
+
return Math.floor(parseFloat(num) * (multipliers[unit?.toLowerCase() ?? "ms"] ?? 1));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// Default instance
|
|
461
|
+
export const javascriptCompiler = new JavaScriptCompiler();
|
|
462
|
+
//# sourceMappingURL=javascript.js.map
|