import { QuickJSContextLike, QuickJSHandleLike, QuickJSModuleFactory, QuickJSModuleLike, QuickJSRuntimeLike, } from "./serverScripts"; class UnsafeHandle implements QuickJSHandleLike { constructor( public value: any, public isError = false ) {} consume(fn: (handle: QuickJSHandleLike) => T): T { return fn(this); } dispose(): void { // no-op } } class UnsafeQuickJSRuntime implements QuickJSRuntimeLike { private moduleLoader: | ((moduleName: string) => string | { error: Error }) | undefined; private moduleCache = new Map(); setModuleLoader( loader: ( moduleName: string ) => string | { error: Error } | Promise ): void { this.moduleLoader = (moduleName) => { const result = loader(moduleName); if (result && typeof (result as PromiseLike).then === "function") { throw new Error( "Async module loaders are not supported in unsafe QuickJS runtime" ); } return result as string | { error: Error }; }; } newContext(): QuickJSContextLike { return new UnsafeQuickJSContext(this); } dispose(): void { this.moduleCache.clear(); this.moduleLoader = undefined; } importModule(specifier: string, context: UnsafeQuickJSContext) { const cached = this.moduleCache.get(specifier); if (cached) { return cached; } if (!this.moduleLoader) { throw new Error(`No module loader configured for ${specifier}`); } const loaded = this.moduleLoader(specifier); if (typeof loaded !== "string") { throw loaded?.error ?? new Error(`Failed to load module ${specifier}`); } const moduleSource = compileModule(loaded, specifier); const exports = this.evaluateModuleSource(moduleSource, context); this.moduleCache.set(specifier, exports); return exports; } executeModule(code: string, context: UnsafeQuickJSContext) { const moduleSource = compileModule(code); this.evaluateModuleSource(moduleSource, context); } private evaluateModuleSource( source: string, context: UnsafeQuickJSContext ) { const globalObject = context.getGlobalObject(); const consoleObject = globalObject?.console ?? globalThis.console; // eslint-disable-next-line no-new-func const evaluator = new Function( "runtimeParam", "contextParam", "globalParam", "consoleParam", `"use strict"; const globalThis = globalParam; const console = consoleParam ?? globalThis.console; const __runtime = runtimeParam; const __context = contextParam; return (${source});` ); return evaluator(this, context, globalObject, consoleObject); } } function createGlobalObject() { const global = Object.create(null); global.globalThis = global; return global; } class UnsafeQuickJSContext implements QuickJSContextLike { private globalObject = createGlobalObject(); private globalHandle = new UnsafeHandle(this.globalObject); private undefinedHandle = new UnsafeHandle(undefined); constructor(private runtime: UnsafeQuickJSRuntime) {} get global(): QuickJSHandleLike { return this.globalHandle; } get undefined(): QuickJSHandleLike { return this.undefinedHandle; } evalCode( code: string, _filename?: string, options?: { type?: "global" | "module" } ): QuickJSHandleLike { try { if (options?.type === "module") { this.runtime.executeModule(code, this); return new UnsafeHandle(undefined); } const result = executeScript(code, this.globalObject); return new UnsafeHandle(result); } catch (error) { return new UnsafeHandle(error, true); } } getGlobalObject() { return this.globalObject; } unwrapResult(handle: QuickJSHandleLike): QuickJSHandleLike { const unsafeHandle = handle as UnsafeHandle; if (unsafeHandle.isError) { throw unsafeHandle.value; } return unsafeHandle; } newFunction( name: string, fn: (...args: QuickJSHandleLike[]) => QuickJSHandleLike ): QuickJSHandleLike { const wrapped = (...args: any[]) => { const handles = args.map((value) => new UnsafeHandle(value)); const result = fn(...handles) as UnsafeHandle; return result?.value; }; Object.defineProperty(wrapped, "name", { value: name, configurable: true }); return new UnsafeHandle(wrapped); } newObject(): QuickJSHandleLike { return new UnsafeHandle({}); } newString(value: string): QuickJSHandleLike { return new UnsafeHandle(value); } setProp( object: QuickJSHandleLike, prop: string, value: QuickJSHandleLike ): void { const target = (object as UnsafeHandle).value; target[prop] = (value as UnsafeHandle).value; } dump(handle: QuickJSHandleLike): T { return (handle as UnsafeHandle).value as T; } dispose(): void { // no-op } } function executeScript(code: string, globalObject: any) { const consoleObject = globalObject?.console ?? globalThis.console; // eslint-disable-next-line no-new-func const wrapped = new Function( "script", "globalObject", "consoleObject", `"use strict"; const globalThis = globalObject; const console = consoleObject ?? globalObject.console; return eval(script);` ); return wrapped(code, globalObject, consoleObject); } function compileModule(source: string, specifier?: string): string { let transformed = source; transformed = transformed.replace( /import\s+([A-Za-z0-9_$]+)\s+from\s+["']([^"']+)["'];?/g, (_match, identifier, moduleName) => `const ${identifier} = __runtime.importModule(${JSON.stringify( moduleName )}, __context).default;` ); transformed = transformed.replace( /export\s+default\s+function\s+([A-Za-z0-9_$]*)\s*\(/g, (_match, maybeName) => `__default = function ${maybeName || ""}(` ); transformed = transformed.replace(/export\s+default\s+/g, "__default = "); const moduleSource = ` (() => { let __default; const exports = {}; ${transformed} if (__default !== undefined) { exports.default = __default; } return exports; })() `; try { // Validate syntax // eslint-disable-next-line no-new-func new Function(moduleSource); return moduleSource; } catch (error) { throw new Error( `Failed to compile module${specifier ? ` ${specifier}` : ""}: ${ (error as Error)?.message ?? error }` ); } } class UnsafeQuickJSModule implements QuickJSModuleLike { newRuntime(): QuickJSRuntimeLike { return new UnsafeQuickJSRuntime(); } } export function createUnsafeQuickJSModule(): QuickJSModuleLike { return new UnsafeQuickJSModule(); } export function createUnsafeQuickJSModuleFactory(): QuickJSModuleFactory { return () => createUnsafeQuickJSModule(); }