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
TypeScript
/**
* 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