UNPKG

@sebastianwessel/quickjs

Version:

A typescript package to execute JavaScript and TypeScript code in a WebAssembly QuickJS sandbox

82 lines (81 loc) 4.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadQuickJs = void 0; const quickjs_emscripten_core_1 = require("quickjs-emscripten-core"); const getTypescriptSupport_js_1 = require("./getTypescriptSupport.js"); const pendingHostPromises_js_1 = require("./sandbox/expose/pendingHostPromises.js"); const setupFileSystem_js_1 = require("./sandbox/setupFileSystem.js"); const executeSandboxFunction_js_1 = require("./sandbox/syncVersion/executeSandboxFunction.js"); const getModuleLoader_js_1 = require("./sandbox/syncVersion/getModuleLoader.js"); const modulePathNormalizer_js_1 = require("./sandbox/syncVersion/modulePathNormalizer.js"); const prepareNodeCompatibility_js_1 = require("./sandbox/syncVersion/prepareNodeCompatibility.js"); const prepareSandbox_js_1 = require("./sandbox/syncVersion/prepareSandbox.js"); /** * Loads the QuickJS module and returns a sandbox execution function. * @param variant - Options for loading the QuickJS module. Defaults to '@jitl/quickjs-ng-wasmfile-release-sync'. * @returns An object containing the runSandboxed function and the loaded module. */ const loadQuickJs = async (variant) => { const module = await (0, quickjs_emscripten_core_1.newQuickJSWASMModuleFromVariant)(variant); /** * 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(); let ctx; try { 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, getModuleLoader_js_1.getModuleLoader)(fs, sandboxOptions); ctx.runtime.setModuleLoader(moduleLoader, sandboxOptions.modulePathNormalizer ?? modulePathNormalizer_js_1.modulePathNormalizer); // Register Globals to be more Node.js compatible (0, prepareNodeCompatibility_js_1.prepareNodeCompatibility)(ctx, sandboxOptions); // Prepare the Sandbox // Expose Data and Functions to Client (0, prepareSandbox_js_1.prepareSandbox)(ctx, scope, sandboxOptions, fs); // Run the given Function const result = await (0, executeSandboxFunction_js_1.executeSandboxFunction)({ ctx, fs, scope, sandboxOptions, sandboxedFunction, transpileFile, }); return result; } catch (error) { throw error instanceof Error ? error : new Error('Internal Error'); } finally { if (ctx) { await (0, pendingHostPromises_js_1.rejectAndFlushPendingHostPromises)(ctx); } scope.dispose(); } }; return { runSandboxed, module }; }; exports.loadQuickJs = loadQuickJs;