oro:extension
oro:extension loads app-bundled native extensions and Wasm extensions, then exposes their registered runtime state to
JavaScript.
Use it when ordinary JavaScript modules are not the right boundary: platform-specific code, a C/C++ library that already exists, a small Wasm module, or a runtime route that needs to live beside native resources.
Related guides#
Start with the guide when you need to write the C/C++ or Wasm extension itself.
Authoring contract#
At a high level:
- extension names are filesystem-safe identifiers such as
image_toolsorsimple-ipc-ping, - C/C++ extensions include
oro/extension.hand export__oapi_extension_initthroughORO_RUNTIME_REGISTER_EXTENSION, - Wasm extensions use the same registration contract with
target = "wasm32", - extension code usually maps one or more IPC routes with
oapi_ipc_router_map, - app code loads the extension with
oro:extensionand talks to those routes withoro:ipc, - production apps should constrain load locations with
extensions.allowed_roots.
Example#
import extension from 'oro:extension'
import ipc from 'oro:ipc'
const imageTools = await extension.load('image_tools', {
allow: ['ipc'],
})
const resized = await ipc.request('image_tools.resize', {
path: 'input/avatar.png',
width: 256,
height: 256,
})
console.log(imageTools.type)
console.log(resized.data)
await imageTools.unload()
allow is the extension capability policy. If the native initializer or a route handler calls an API that is not
allowed, that call fails instead of silently expanding the extension's authority.
API reference#
Module specifiers#
oro:extension
TypeScript declarations#
These declarations are generated from the runtime's published TypeScript surface.
oro:extension#
declare module "oro:extension" {
/**
* Load an extension by name.
* @template {Record<string, any> T}
* @param {string} name
* @param {ExtensionLoadOptions} [options]
* @return {Promise<Extension<T>>}
*/
export function load<T extends Record<string, any>>(name: string, options?: ExtensionLoadOptions): Promise<Extension<T>>;
/**
* Provides current stats about the loaded extensions.
* @return {Promise<ExtensionStats>}
*/
export function stats(): Promise<ExtensionStats>;
/**
* @typedef {{
* allow: string[] | string,
* imports?: object,
* type?: 'shared' | 'wasm32',
* path?: string,
* stats?: object,
* instance?: WebAssembly.Instance,
* adapter?: WebAssemblyExtensionAdapter
* }} ExtensionLoadOptions
*/
/**
* @typedef {{ abi: number, version: string, description: string }} ExtensionInfo
*/
/**
* @typedef {{ abi: number, loaded: number }} ExtensionStats
*/
/**
* A interface for a native extension.
* @template {Record<string, any> T}
*/
export class Extension<T extends Record<string, any>> extends EventTarget {
/**
* Load an extension by name.
* @template {Record<string, any> T}
* @param {string} name
* @param {ExtensionLoadOptions} [options]
* @return {Promise<Extension<T>>}
*/
static load<T_1 extends Record<string, any>>(name: string, options?: ExtensionLoadOptions): Promise<Extension<T_1>>;
/**
* Query type of extension by name.
* @param {string} name
* @return {Promise<'shared'|'wasm32'|'unknown'|null>}
*/
static type(name: string): Promise<"shared" | "wasm32" | "unknown" | null>;
/**
* Provides current stats about the loaded extensions or one by name.
* @param {?string} name
* @return {Promise<ExtensionStats|null>}
*/
static stats(name: string | null): Promise<ExtensionStats | null>;
/**
* `Extension` class constructor.
* @param {string} name
* @param {ExtensionInfo} info
* @param {ExtensionLoadOptions} [options]
*/
constructor(name: string, info: ExtensionInfo, options?: ExtensionLoadOptions);
/**
* The name of the extension
* @type {string?}
*/
name: string | null;
/**
* The version of the extension
* @type {string?}
*/
version: string | null;
/**
* The description of the extension
* @type {string?}
*/
description: string | null;
/**
* The abi of the extension
* @type {number}
*/
abi: number;
/**
* @type {object}
*/
options: object;
/**
* @type {T}
*/
binding: T;
/**
* Not `null` if extension is of type 'wasm32'
* @type {?WebAssemblyExtensionAdapter}
*/
adapter: WebAssemblyExtensionAdapter | null;
/**
* `true` if the extension was loaded, otherwise `false`
* @type {boolean}
*/
get loaded(): boolean;
/**
* The extension type: 'shared' or 'wasm32'
* @type {'shared'|'wasm32'}
*/
get type(): "shared" | "wasm32";
/**
* Unloads the loaded extension.
* @throws Error
*/
unload(): Promise<boolean>;
instance: any;
[$type]: "shared" | "wasm32";
[$loaded]: boolean;
}
namespace _default {
export { load };
export { stats };
}
export default _default;
export type Pointer = number;
export type ExtensionLoadOptions = {
allow: string[] | string;
imports?: object;
type?: "shared" | "wasm32";
path?: string;
stats?: object;
instance?: WebAssembly.Instance;
adapter?: WebAssemblyExtensionAdapter;
};
export type ExtensionInfo = {
abi: number;
version: string;
description: string;
};
export type ExtensionStats = {
abi: number;
loaded: number;
};
/**
* An adapter for reading and writing various values from a WebAssembly instance's
* memory buffer.
* @ignore
*/
class WebAssemblyExtensionAdapter {
constructor({ instance, module, table, memory, policies }: {
instance: any;
module: any;
table: any;
memory: any;
policies: any;
});
view: any;
heap: any;
table: any;
stack: any;
buffer: any;
module: any;
memory: any;
context: any;
policies: any[];
externalReferences: Map<any, any>;
instance: any;
exitStatus: any;
textDecoder: TextDecoder;
textEncoder: TextEncoder;
errorMessagePointers: {};
indirectFunctionTable: any;
get globalBaseOffset(): any;
destroy(): void;
init(): boolean;
getExtensionExport(...names: any[]): any;
get(pointer: any, size?: number): any;
set(pointer: any, value: any): void;
createExternalReferenceValue(value: any): any;
getExternalReferenceValue(pointer: any): any;
setExternalReferenceValue(pointer: any, value: any): Map<any, any>;
removeExternalReferenceValue(pointer: any): void;
getExternalReferencePointer(value: any): any;
getFloat32(pointer: any): any;
setFloat32(pointer: any, value: any): boolean;
getFloat64(pointer: any): any;
setFloat64(pointer: any, value: any): boolean;
getInt8(pointer: any): any;
setInt8(pointer: any, value: any): boolean;
getInt16(pointer: any): any;
setInt16(pointer: any, value: any): boolean;
getInt32(pointer: any): any;
setInt32(pointer: any, value: any): boolean;
getUint8(pointer: any): any;
setUint8(pointer: any, value: any): boolean;
getUint16(pointer: any): any;
setUint16(pointer: any, value: any): boolean;
getUint32(pointer: any): any;
setUint32(pointer: any, value: any): boolean;
getString(pointer: any, buffer: any, size: any): string;
setString(pointer: any, string: any, buffer?: any): boolean;
}
const $type: unique symbol;
/**
* @typedef {number} Pointer
*/
const $loaded: unique symbol;
}
See also#
Source repository · Edit this page · View Markdown