@sebastianwessel/quickjs
Version:
A typescript package to execute JavaScript and TypeScript code in a WebAssembly QuickJS sandbox
71 lines (70 loc) • 3.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadAsyncQuickJs = void 0;
const quickjs_emscripten_core_1 = require("quickjs-emscripten-core");
const getTypescriptSupport_js_1 = require("./getTypescriptSupport.js");
const getAsyncModuleLoader_js_1 = require("./sandbox/asyncVersion/getAsyncModuleLoader.js");
const modulePathNormalizerAsync_js_1 = require("./sandbox/asyncVersion/modulePathNormalizerAsync.js");
const executeAsyncSandboxFunction_js_1 = require("./sandbox/asyncVersion/executeAsyncSandboxFunction.js");
const prepareAsyncNodeCompatibility_js_1 = require("./sandbox/asyncVersion/prepareAsyncNodeCompatibility.js");
const prepareAsyncSandbox_js_1 = require("./sandbox/asyncVersion/prepareAsyncSandbox.js");
const loadAsyncWasmModule_js_1 = require("./sandbox/loadAsyncWasmModule.js");
const setupFileSystem_js_1 = require("./sandbox/setupFileSystem.js");
/**
* Loads the QuickJS async module and returns a sandbox execution function.
* @param loadOptions - Options for loading the QuickJS module. Defaults to '@jitl/quickjs-ng-wasmfile-release-asyncify'.
* @returns An object containing the runSandboxed function and the loaded module.
*/
const loadAsyncQuickJs = async (loadOptions = '@jitl/quickjs-ng-wasmfile-release-asyncify') => {
const module = await (0, loadAsyncWasmModule_js_1.loadAsyncWasmModule)(loadOptions);
/**
* Provides a new sandbox and executes the given function.
* When the function has been finished, the sandbox gets disposed and can longer be used.
*
* @param sandboxedFunction
* @param sandboxOptions
* @returns
*/
const runSandboxed = async (sandboxedFunction, sandboxOptions = {}) => {
const scope = new quickjs_emscripten_core_1.Scope();
const ctx = scope.manage(module.newContext());
if (sandboxOptions.executionTimeout) {
ctx.runtime.setInterruptHandler((0, quickjs_emscripten_core_1.shouldInterruptAfterDeadline)(Date.now() + sandboxOptions.executionTimeout));
}
if (sandboxOptions.maxStackSize) {
ctx.runtime.setMaxStackSize(sandboxOptions.maxStackSize);
}
if (sandboxOptions.memoryLimit) {
ctx.runtime.setMemoryLimit(sandboxOptions.memoryLimit);
}
// Virtual File System,
const fs = (0, setupFileSystem_js_1.setupFileSystem)(sandboxOptions);
// TypeScript Support:
const { transpileVirtualFs, transpileFile } = await (0, getTypescriptSupport_js_1.getTypescriptSupport)(sandboxOptions.transformTypescript, sandboxOptions.typescriptImportFile, sandboxOptions.transformCompilerOptions);
// if typescript support is enabled, transpile all ts files in file system
transpileVirtualFs(fs);
// JS Module Loader
const moduleLoader = sandboxOptions.getModuleLoader
? sandboxOptions.getModuleLoader(fs, sandboxOptions)
: (0, getAsyncModuleLoader_js_1.getAsyncModuleLoader)(fs, sandboxOptions);
ctx.runtime.setModuleLoader(moduleLoader, sandboxOptions.modulePathNormalizer ?? modulePathNormalizerAsync_js_1.modulePathNormalizerAsync);
// Register Globals to be more Node.js compatible
await (0, prepareAsyncNodeCompatibility_js_1.prepareAsyncNodeCompatibility)(ctx, sandboxOptions);
// Prepare the Sandbox
// Expose Data and Functions to Client
(0, prepareAsyncSandbox_js_1.prepareAsyncSandbox)(ctx, scope, sandboxOptions, fs);
// Run the given Function
const result = await (0, executeAsyncSandboxFunction_js_1.executeAsyncSandboxFunction)({
ctx,
fs,
scope,
sandboxOptions,
sandboxedFunction,
transpileFile,
});
scope.dispose();
return result;
};
return { runSandboxed, module };
};
exports.loadAsyncQuickJs = loadAsyncQuickJs;