UNPKG

hakojs

Version:

A secure, embeddable JavaScript engine that runs untrusted code inside WebAssembly sandboxes with fine-grained permissions and resource limits

459 lines 16.7 kB
/** * This module provides the VMContext class, which represents a JavaScript * execution context within the PrimJS virtual machine. It serves as the * primary interface for evaluating code, creating values, and interacting * with the JavaScript environment inside the VM. */ import { type ContextEvalOptions, type HostCallbackFunction, type JSContextPointer, type JSValuePointer, type PromiseExecutor, type VMContextResult } from "../etc/types"; import { HakoDeferredPromise } from "../helpers/deferred-promise"; import { VMIterator } from "../helpers/iterator-helper"; import type { Container } from "../host/container"; import type { HakoRuntime } from "../host/runtime"; import { type DisposableFail, type DisposableSuccess } from "../mem/lifetime"; import { VMValue } from "./value"; import type { SuccessOrFail } from "./vm-interface"; /** * Represents a JavaScript execution context within the PrimJS virtual machine. * * VMContext provides the environment in which JavaScript code executes, * including global objects, standard libraries, and memory constraints. * It offers methods for evaluating code, creating values, calling functions, * and managing resources within the virtual machine. * * @implements {Disposable} - Implements the Disposable interface for resource cleanup */ export declare class VMContext implements Disposable { /** * Reference to the service container providing access to core Hako services */ container: Container; /** * WebAssembly pointer to the underlying context * @private */ private ctxPtr; /** * Flag indicating if this context has been released * @private */ private isReleased; /** * Reference to the runtime this context belongs to * @private */ private __runtime; /** * Factory for creating JavaScript values in this context * @private */ private valueFactory; /** * Cached reference to the Symbol constructor * @private */ protected _Symbol: VMValue | undefined; /** * Cached reference to Symbol.iterator * @private */ protected _SymbolIterator: VMValue | undefined; /** * Cached reference to Symbol.asyncIterator * @private */ protected _SymbolAsyncIterator: VMValue | undefined; private opaqueDataPointer; /** * Creates a new VMContext instance. * * @param container - The service container providing access to Hako services * @param runtime - The runtime this context belongs to * @param ctxPtr - WebAssembly pointer to the context */ constructor(container: Container, runtime: HakoRuntime, ctxPtr: JSContextPointer); /** * Gets the WebAssembly pointer to this context. */ get pointer(): JSContextPointer; /** * Gets the runtime this context belongs to. * * @returns The parent runtime */ get runtime(): HakoRuntime; /** * Sets the maximum stack size for this context. * * This limits the depth of call stacks to prevent stack overflow attacks. * * @param size - The stack size in bytes */ setMaxStackSize(size: number): void; /** * Sets the virtual stack size for this context. * * This is an advanced feature for fine-tuning JavaScript execution. * * @param size - The virtual stack size in bytes * @unstable The FFI interface is considered private and may change. */ setVirtualStackSize(size: number): void; /** * Sets opaque data for the context. * * If opaque data is already set, the existing data is freed before storing the new string. * The provided string is allocated in memory and then registered with the context by invoking * the native {@link HAKO_SetContextData} function. * * @param opaque - The opaque data to set as a string. * * @remarks * You are responsible for freeing the opaque data when no longer needed by calling {@link freeOpaqueData} or releasing the context. */ setOpaqueData(opaque: string): void; /** * Retrieves the opaque data associated with the context. * * @returns A string containing the opaque data if one is set; otherwise, returns `undefined`. * * @remarks * The string is obtained by reading the memory pointed to by the opaque data pointer. * If no opaque data is set, the method returns `undefined`. */ getOpaqueData(): string | undefined; /** * Frees the opaque data associated with the context. * * If opaque data is present, this method releases the allocated memory and resets the * opaque data pointer to `undefined`. It is safe to call this method even if no opaque data * has been set. */ freeOpaqueData(): void; /** * Evaluates JavaScript code in this context. * * This is the primary method for executing JavaScript code within the VM. * It supports both global code and ES modules, with various configuration options. * * @param code - JavaScript code to evaluate * @param options - Evaluation options: * - type: "global" or "module" (default: "global") * - fileName: Name for error messages (default: "eval") * - strict: Whether to enforce strict mode * - detectModule: Whether to auto-detect module code * @returns Result containing either the evaluation result or an error */ evalCode(code: string, options?: ContextEvalOptions): VMContextResult<VMValue>; /** * Compiles JavaScript code to portable bytecode. * * This method compiles JavaScript source code into bytecode that can be * cached, transmitted, or evaluated later. It automatically detects ES6 * modules vs regular scripts and compiles accordingly. * * @param code - JavaScript source code to compile * @param options - Compilation options: * - type: "global" or "module" (default: auto-detect) * - fileName: Name for error messages (default: "eval") * - strict: Whether to enforce strict mode * - detectModule: Whether to auto-detect module code * @returns Result containing either the bytecode buffer or an error */ compileToByteCode(code: string, options?: ContextEvalOptions): VMContextResult<Uint8Array>; /** * Evaluates precompiled JavaScript bytecode. * * @param bytecode - Bytecode buffer from compileToByteCode * @param options - loadOnly: Only load bytecode without executing * @returns Evaluation result or error */ evalByteCode(bytecode: Uint8Array, options?: { loadOnly?: boolean; }): VMContextResult<VMValue>; /** * Unwraps a SuccessOrFail result, throwing an error if it's a failure. * * This converts VM errors to native JavaScript errors that can be caught * by standard try/catch blocks in the host environment. * * @template T - The success value type * @param result - The result to unwrap * @returns The success value * @throws Converted JavaScript error if the result is a failure */ unwrapResult<T>(result: SuccessOrFail<T, VMValue>): T; /** * Calls a function value in this context. * * This invokes a JavaScript function with the specified this value and arguments. * * @param func - The function value to call * @param thisArg - The 'this' value for the function call (null uses undefined) * @param args - Arguments to pass to the function * @returns Result containing either the function's return value or an error */ callFunction(func: VMValue, thisArg?: VMValue | null, ...args: VMValue[]): VMContextResult<VMValue>; /** * Converts a Promise-like value in the VM to a native Promise. * * This bridges the gap between Promises in the VM and Promises in the * host environment. It calls Promise.resolve on the value inside the VM, * then hooks up native Promise handlers. * * @param promiseLikeHandle - VM value that should be a Promise or thenable * @returns A native Promise that resolves/rejects with the VM promise result * @remarks You may need to call runtime.executePendingJobs() to ensure the promise is resolved */ resolvePromise(promiseLikeHandle: VMValue): Promise<VMContextResult<VMValue>>; /** * Gets the last error from the context, or checks if a value is an error. * * @param maybe_exception - Optional value or pointer to check for error status * @returns The error object if an error occurred, undefined otherwise */ getLastError(maybe_exception?: VMValue | JSValuePointer): import("../etc/errors").PrimJSError | undefined; /** * Gets the module namespace object after evaluating a module. * * This extracts the exports object from an ES module. * * @param moduleValue - Module function object from evalCode * @returns Module namespace object containing all exports * @throws If the value is not a module or another error occurs */ getModuleNamespace(moduleValue: VMValue): VMValue | undefined; /** * Gets the global object for this context. * * @returns The global object (like 'window' or 'global') */ getGlobalObject(): VMValue; /** * Creates a new Error object with the given error details. * * @param error - JavaScript Error object to convert to a VM error * @returns The VM error object */ newError(error: Error): VMValue; /** * Throws an error in the context. * * This creates and throws an exception in the VM environment. * * @param error - Error object or message to throw * @returns The exception object */ throwError(error: VMValue | string): VMValue; /** * Gets an iterator for a VM value that implements the iterable protocol. * * This creates a host iterator that proxies to the guest iterator, * allowing iteration over collections in the VM. * * @param iterableHandle - VM value implementing the iterable protocol * @returns Result containing an iterator or an error * * @example * ```typescript * for (using entriesHandle of context.getIterator(mapHandle).unwrap()) { * using keyHandle = context.getProp(entriesHandle, 0) * using valueHandle = context.getProp(entriesHandle, 1) * console.log(context.dump(keyHandle), '->', context.dump(valueHandle)) * } * ``` */ getIterator(iterableHandle: VMValue): VMContextResult<VMIterator>; /** * Gets a well-known symbol from the global Symbol object. * * Examples include Symbol.iterator, Symbol.asyncIterator, etc. * * @param name - Name of the well-known symbol * @returns The symbol value */ getWellKnownSymbol(name: string): VMValue; /** * Creates a new empty object. * * @returns A new object value */ newObject(): VMValue; /** * Creates a new object with the specified prototype. * * @param proto - Prototype object * @returns A new object with the specified prototype */ newObjectWithPrototype(proto: VMValue): VMValue; /** * Creates a new empty array. * * @returns A new array value */ newArray(): VMValue; /** * Creates a new ArrayBuffer with the specified data. * * @param data - The binary data to store in the ArrayBuffer * @returns A new ArrayBuffer value */ newArrayBuffer(data: Uint8Array): VMValue; /** * Creates a new number value. * * @param value - The number value * @returns A new number value */ newNumber(value: number): VMValue; /** * Creates a new string value. * * @param value - The string value * @returns A new string value */ newString(value: string): VMValue; /** * Creates a new symbol value. * * @param description - Symbol description or an existing symbol * @param isGlobal - Whether to create a global symbol (using Symbol.for) * @returns A new symbol value */ newSymbol(description: string | symbol, isGlobal?: boolean): VMValue; dump(value: VMValue): object; /** * Creates a new function that calls a host function. * * This bridges between host JavaScript functions and the VM environment. * * @param name - Function name for debugging and error messages * @param callback - Host function to call when the VM function is invoked * @returns A new function value */ newFunction(name: string, callback: HostCallbackFunction<VMValue>): VMValue; /** * Creates a new Promise in the VM. * * @overload * @returns A deferred promise with resolve/reject methods */ newPromise(): HakoDeferredPromise; /** * Creates a new Promise in the VM that follows a host Promise. * * @overload * @param promise - Host Promise to connect to the VM Promise * @returns A deferred promise that resolves/rejects when the host Promise does */ newPromise(promise: Promise<VMValue>): HakoDeferredPromise; /** * Creates a new Promise in the VM with an executor function. * * @overload * @param executor - Standard Promise executor function * @returns A deferred promise controlled by the executor */ newPromise(executor: PromiseExecutor<VMValue, Error | VMValue>): HakoDeferredPromise; /** * Gets the undefined value. * * @returns The undefined value */ undefined(): VMValue; /** * Gets the null value. * * @returns The null value */ null(): VMValue; /** * Gets the true value. * * @returns The true value */ true(): VMValue; /** * Gets the false value. * * @returns The false value */ false(): VMValue; /** * Creates a borrowed reference to a value from its pointer. * * A borrowed reference doesn't own the underlying value and won't * free it when disposed. * * @param ptr - The value pointer * @returns A borrowed VMValue */ borrowValue(ptr: JSValuePointer): VMValue; /** * Creates a duplicated (owned) reference to a value from its pointer. * * An owned reference will free the underlying value when disposed. * * @param ptr - The value pointer * @returns An owned VMValue */ duplicateValue(ptr: JSValuePointer): VMValue; /** * Converts a JavaScript value to a VM value. * * This is the general-purpose conversion method for any JavaScript value. * * @param value - The JavaScript value to convert * @param options - Optional conversion options * @returns The VM value */ newValue(value: unknown, options?: Record<string, unknown>): VMValue; /** * Encodes a VM value to binary JSON format. * * This is a more efficient serialization format than standard JSON. * * @param value - The VM value to encode * @returns Binary JSON data as a Uint8Array * @throws If encoding fails */ bjsonEncode(value: VMValue): Uint8Array; /** * Decodes a binary JSON buffer to a VM value. * * @param data - The binary JSON data to decode * @returns The decoded VM value * @throws If decoding fails */ bjsonDecode(data: Uint8Array): VMValue; /** * Releases all resources associated with this context. * * This frees the underlying WebAssembly context and all cached values. */ release(): void; /** * Implements the Symbol.dispose method for the Disposable interface. * * This allows the context to be used with the using statement * in environments that support the Disposable pattern. */ [Symbol.dispose](): void; /** * Helper method to create a success result. * * @template S - The success value type * @param value - The success value * @returns A disposable success result * @protected */ protected success<S>(value: S): DisposableSuccess<S>; /** * Helper method to create a failure result. * * @param error - The error value * @returns A disposable failure result * @protected */ protected fail(error: VMValue): DisposableFail<VMValue>; } //# sourceMappingURL=context.d.ts.map