Product API

This commit is contained in:
2026-08-10 22:59:43 +02:00
parent 0b84803f5e
commit 09e3fa7516
108 changed files with 94569 additions and 8 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Toyobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1
View File
@@ -0,0 +1 @@
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,419 @@
/// <reference types="node" />
import type { Context } from '@emnapi/runtime';
import type { ReferenceOwnership } from '@emnapi/runtime';
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare type BaseCreateOptions = {
filename?: string
nodeBinding?: NodeBinding
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
asyncWorkPoolSize?: number
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
onCreateWorker?: (info: CreateWorkerInfo) => any
print?: (str: string) => void
printErr?: (str: string) => void
postMessage?: (msg: any) => any
}
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function createNapiModule (
options: CreateOptions
): NapiModule
/** @public */
export declare type CreateOptions = BaseCreateOptions & ({
context: Context
childThread?: boolean
} | {
context?: Context
childThread: true
})
/** @public */
export declare interface CreateWorkerInfo {
type: 'thread' | 'async-work'
name: string
}
/** @public */
export declare interface InitOptions {
instance: WebAssembly.Instance
module: WebAssembly.Module
memory?: WebAssembly.Memory
table?: WebAssembly.Table
}
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
/** @public */
export declare interface InstantiatedSource extends LoadedSource {
napiModule: NapiModule;
}
/** @public */
export declare function instantiateNapiModule(
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
/** @public */
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
/** @public */
export declare type InstantiateOptions = CreateOptions & LoadOptions;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
usedInstance: WebAssembly.Instance;
}
/** @public */
export declare function loadNapiModule(napiModule: NapiModule,
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
/** @public */
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
/** @public */
export declare interface LoadOptions {
wasi?: WASIInstance;
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare class MessageHandler extends ThreadMessageHandler {
napiModule: NapiModule | undefined;
constructor(options: MessageHandlerOptions);
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
handle(e: WorkerMessageEvent): void;
}
/** @public */
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
}
/** @public */
export declare interface NapiModule {
imports: {
env: any
napi: any
emnapi: any
}
exports: any
loaded: boolean
filename: string
childThread: boolean
emnapi: {
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
js_to_wasm: boolean,
arrayBufferOrView: T,
offset?: number,
len?: number
): T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}
init (options: InitOptions): any
initWorker (arg: number, func: [number, number]): void
postMessage?: (msg: any) => any
waitThreadStart: boolean | number
/* Excluded from this release type: PThread */}
/** @public */
export declare interface NodeBinding {
node: {
emitAsyncInit: Function
emitAsyncDestroy: Function
makeCallback: Function
}
napi: {
asyncInit: Function
asyncDestroy: Function
makeCallback: Function
}
}
/** @public */
export declare interface PointerInfo {
address: number
ownership: ReferenceOwnership
runtimeAllocated: 0 | 1
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare const version: string;
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
File diff suppressed because one or more lines are too long
@@ -0,0 +1,419 @@
/// <reference types="node" />
import type { Context } from '@emnapi/runtime';
import type { ReferenceOwnership } from '@emnapi/runtime';
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare type BaseCreateOptions = {
filename?: string
nodeBinding?: NodeBinding
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
asyncWorkPoolSize?: number
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
onCreateWorker?: (info: CreateWorkerInfo) => any
print?: (str: string) => void
printErr?: (str: string) => void
postMessage?: (msg: any) => any
}
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function createNapiModule (
options: CreateOptions
): NapiModule
/** @public */
export declare type CreateOptions = BaseCreateOptions & ({
context: Context
childThread?: boolean
} | {
context?: Context
childThread: true
})
/** @public */
export declare interface CreateWorkerInfo {
type: 'thread' | 'async-work'
name: string
}
/** @public */
export declare interface InitOptions {
instance: WebAssembly.Instance
module: WebAssembly.Module
memory?: WebAssembly.Memory
table?: WebAssembly.Table
}
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
/** @public */
export declare interface InstantiatedSource extends LoadedSource {
napiModule: NapiModule;
}
/** @public */
export declare function instantiateNapiModule(
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
/** @public */
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
/** @public */
export declare type InstantiateOptions = CreateOptions & LoadOptions;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
usedInstance: WebAssembly.Instance;
}
/** @public */
export declare function loadNapiModule(napiModule: NapiModule,
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
/** @public */
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
/** @public */
export declare interface LoadOptions {
wasi?: WASIInstance;
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare class MessageHandler extends ThreadMessageHandler {
napiModule: NapiModule | undefined;
constructor(options: MessageHandlerOptions);
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
handle(e: WorkerMessageEvent): void;
}
/** @public */
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
}
/** @public */
export declare interface NapiModule {
imports: {
env: any
napi: any
emnapi: any
}
exports: any
loaded: boolean
filename: string
childThread: boolean
emnapi: {
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
js_to_wasm: boolean,
arrayBufferOrView: T,
offset?: number,
len?: number
): T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}
init (options: InitOptions): any
initWorker (arg: number, func: [number, number]): void
postMessage?: (msg: any) => any
waitThreadStart: boolean | number
/* Excluded from this release type: PThread */}
/** @public */
export declare interface NodeBinding {
node: {
emitAsyncInit: Function
emitAsyncDestroy: Function
makeCallback: Function
}
napi: {
asyncInit: Function
asyncDestroy: Function
makeCallback: Function
}
}
/** @public */
export declare interface PointerInfo {
address: number
ownership: ReferenceOwnership
runtimeAllocated: 0 | 1
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare const version: string;
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
@@ -0,0 +1,421 @@
/// <reference types="node" />
import type { Context } from '@emnapi/runtime';
import type { ReferenceOwnership } from '@emnapi/runtime';
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare type BaseCreateOptions = {
filename?: string
nodeBinding?: NodeBinding
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
asyncWorkPoolSize?: number
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
onCreateWorker?: (info: CreateWorkerInfo) => any
print?: (str: string) => void
printErr?: (str: string) => void
postMessage?: (msg: any) => any
}
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function createNapiModule (
options: CreateOptions
): NapiModule
/** @public */
export declare type CreateOptions = BaseCreateOptions & ({
context: Context
childThread?: boolean
} | {
context?: Context
childThread: true
})
/** @public */
export declare interface CreateWorkerInfo {
type: 'thread' | 'async-work'
name: string
}
/** @public */
export declare interface InitOptions {
instance: WebAssembly.Instance
module: WebAssembly.Module
memory?: WebAssembly.Memory
table?: WebAssembly.Table
}
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
/** @public */
export declare interface InstantiatedSource extends LoadedSource {
napiModule: NapiModule;
}
/** @public */
export declare function instantiateNapiModule(
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
/** @public */
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
/** @public */
export declare type InstantiateOptions = CreateOptions & LoadOptions;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
usedInstance: WebAssembly.Instance;
}
/** @public */
export declare function loadNapiModule(napiModule: NapiModule,
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
/** @public */
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
/** @public */
export declare interface LoadOptions {
wasi?: WASIInstance;
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare class MessageHandler extends ThreadMessageHandler {
napiModule: NapiModule | undefined;
constructor(options: MessageHandlerOptions);
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
handle(e: WorkerMessageEvent): void;
}
/** @public */
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
}
/** @public */
export declare interface NapiModule {
imports: {
env: any
napi: any
emnapi: any
}
exports: any
loaded: boolean
filename: string
childThread: boolean
emnapi: {
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
js_to_wasm: boolean,
arrayBufferOrView: T,
offset?: number,
len?: number
): T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}
init (options: InitOptions): any
initWorker (arg: number, func: [number, number]): void
postMessage?: (msg: any) => any
waitThreadStart: boolean | number
/* Excluded from this release type: PThread */}
/** @public */
export declare interface NodeBinding {
node: {
emitAsyncInit: Function
emitAsyncDestroy: Function
makeCallback: Function
}
napi: {
asyncInit: Function
asyncDestroy: Function
makeCallback: Function
}
}
/** @public */
export declare interface PointerInfo {
address: number
ownership: ReferenceOwnership
runtimeAllocated: 0 | 1
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare const version: string;
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
export as namespace emnapiCore;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,419 @@
/// <reference types="node" />
import type { Context } from '@emnapi/runtime';
import type { ReferenceOwnership } from '@emnapi/runtime';
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare type BaseCreateOptions = {
filename?: string
nodeBinding?: NodeBinding
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
asyncWorkPoolSize?: number
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
onCreateWorker?: (info: CreateWorkerInfo) => any
print?: (str: string) => void
printErr?: (str: string) => void
postMessage?: (msg: any) => any
}
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function createNapiModule (
options: CreateOptions
): NapiModule
/** @public */
export declare type CreateOptions = BaseCreateOptions & ({
context: Context
childThread?: boolean
} | {
context?: Context
childThread: true
})
/** @public */
export declare interface CreateWorkerInfo {
type: 'thread' | 'async-work'
name: string
}
/** @public */
export declare interface InitOptions {
instance: WebAssembly.Instance
module: WebAssembly.Module
memory?: WebAssembly.Memory
table?: WebAssembly.Table
}
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
/** @public */
export declare interface InstantiatedSource extends LoadedSource {
napiModule: NapiModule;
}
/** @public */
export declare function instantiateNapiModule(
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
/** @public */
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
/** @public */
export declare type InstantiateOptions = CreateOptions & LoadOptions;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
usedInstance: WebAssembly.Instance;
}
/** @public */
export declare function loadNapiModule(napiModule: NapiModule,
/** Only support `BufferSource` or `WebAssembly.Module` on Node.js */
wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
/** @public */
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
/** @public */
export declare interface LoadOptions {
wasi?: WASIInstance;
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare class MessageHandler extends ThreadMessageHandler {
napiModule: NapiModule | undefined;
constructor(options: MessageHandlerOptions);
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
handle(e: WorkerMessageEvent): void;
}
/** @public */
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
}
/** @public */
export declare interface NapiModule {
imports: {
env: any
napi: any
emnapi: any
}
exports: any
loaded: boolean
filename: string
childThread: boolean
emnapi: {
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
js_to_wasm: boolean,
arrayBufferOrView: T,
offset?: number,
len?: number
): T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}
init (options: InitOptions): any
initWorker (arg: number, func: [number, number]): void
postMessage?: (msg: any) => any
waitThreadStart: boolean | number
/* Excluded from this release type: PThread */}
/** @public */
export declare interface NodeBinding {
node: {
emitAsyncInit: Function
emitAsyncDestroy: Function
makeCallback: Function
}
napi: {
asyncInit: Function
asyncDestroy: Function
makeCallback: Function
}
}
/** @public */
export declare interface PointerInfo {
address: number
ownership: ReferenceOwnership
runtimeAllocated: 0 | 1
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare const version: string;
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
module.exports = require('./dist/emnapi-core.cjs.min.js')
} else {
module.exports = require('./dist/emnapi-core.cjs.js')
}
+49
View File
@@ -0,0 +1,49 @@
{
"name": "@emnapi/core",
"version": "1.11.1",
"description": "emnapi core",
"main": "index.js",
"module": "./dist/emnapi-core.esm-bundler.js",
"types": "./dist/emnapi-core.d.ts",
"sideEffects": false,
"exports": {
".": {
"types": {
"module": "./dist/emnapi-core.d.ts",
"import": "./dist/emnapi-core.d.mts",
"default": "./dist/emnapi-core.d.ts"
},
"module": "./dist/emnapi-core.esm-bundler.js",
"import": "./dist/emnapi-core.mjs",
"default": "./index.js"
},
"./dist/emnapi-core.cjs.min": {
"types": "./dist/emnapi-core.d.ts",
"default": "./dist/emnapi-core.cjs.min.js"
},
"./dist/emnapi-core.min.mjs": {
"types": "./dist/emnapi-core.d.mts",
"default": "./dist/emnapi-core.min.mjs"
}
},
"dependencies": {
"@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
},
"scripts": {
"build": "node ./script/build.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/toyobayashi/emnapi.git"
},
"author": "toyobayashi",
"license": "MIT",
"bugs": {
"url": "https://github.com/toyobayashi/emnapi/issues"
},
"homepage": "https://github.com/toyobayashi/emnapi#readme",
"publishConfig": {
"access": "public"
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Toyobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1 @@
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,671 @@
export declare type Ptr = number | bigint
export declare interface IBuffer extends Uint8Array {}
export declare interface BufferCtor {
readonly prototype: IBuffer
/** @deprecated */
new (...args: any[]): IBuffer
from: {
(buffer: ArrayBufferLike): IBuffer
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
}
alloc: (size: number) => IBuffer
isBuffer: (obj: unknown) => obj is IBuffer
}
export declare const enum GlobalHandle {
UNDEFINED = 1,
NULL,
FALSE,
TRUE,
GLOBAL
}
export declare const enum Version {
NODE_API_SUPPORTED_VERSION_MIN = 1,
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
NODE_API_SUPPORTED_VERSION_MAX = 10,
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type Pointer<T> = number
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type PointerPointer<T> = number
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
export declare type Const<T> = T
export declare type void_p = Pointer<void>
export declare type void_pp = Pointer<void_p>
export declare type bool = number
export declare type char = number
export declare type char_p = Pointer<char>
export declare type unsigned_char = number
export declare type const_char = Const<char>
export declare type const_char_p = Pointer<const_char>
export declare type char16_t_p = number
export declare type const_char16_t_p = number
export declare type short = number
export declare type unsigned_short = number
export declare type int = number
export declare type unsigned_int = number
export declare type long = number
export declare type unsigned_long = number
export declare type long_long = bigint
export declare type unsigned_long_long = bigint
export declare type float = number
export declare type double = number
export declare type long_double = number
export declare type size_t = number
export declare type int8_t = number
export declare type uint8_t = number
export declare type int16_t = number
export declare type uint16_t = number
export declare type int32_t = number
export declare type uint32_t = number
export declare type int64_t = bigint
export declare type uint64_t = bigint
export declare type napi_env = Pointer<unknown>
export declare type napi_value = Pointer<unknown>
export declare type napi_ref = Pointer<unknown>
export declare type napi_deferred = Pointer<unknown>
export declare type napi_handle_scope = Pointer<unknown>
export declare type napi_escapable_handle_scope = Pointer<unknown>
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
export declare type napi_callback_info = Pointer<unknown>
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
export declare interface napi_extended_error_info {
error_message: const_char_p
engine_reserved: void_p
engine_error_code: uint32_t
error_code: napi_status
}
export declare interface napi_property_descriptor {
// One of utf8name or name should be NULL.
utf8name: const_char_p
name: napi_value
method: napi_callback
getter: napi_callback
setter: napi_callback
value: napi_value
/* napi_property_attributes */
attributes: number
data: void_p
}
export declare type napi_finalize = FunctionPointer<(
env: napi_env,
finalize_data: void_p,
finalize_hint: void_p
) => void>
export declare interface node_module {
nm_version: int32_t
nm_flags: uint32_t
nm_filename: Pointer<const_char>
nm_register_func: napi_addon_register_func
nm_modname: Pointer<const_char>
nm_priv: Pointer<void>
reserved: PointerPointer<void>
}
export declare interface napi_node_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
release: const_char_p
}
export declare interface emnapi_emscripten_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
}
export declare const enum napi_status {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, // unused
napi_no_external_buffers_allowed,
napi_cannot_run_js
}
export declare const enum napi_property_attributes {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
/// #ifdef NAPI_EXPERIMENTAL
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
/// #endif // NAPI_EXPERIMENTAL
}
export declare const enum napi_valuetype {
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint
}
export declare const enum napi_typedarray_type {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
napi_float16_array,
}
export declare const enum napi_key_collection_mode {
napi_key_include_prototypes,
napi_key_own_only
}
export declare const enum napi_key_filter {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
}
export declare const enum napi_key_conversion {
napi_key_keep_numbers,
napi_key_numbers_to_strings
}
export declare const enum emnapi_memory_view_type {
emnapi_int8_array,
emnapi_uint8_array,
emnapi_uint8_clamped_array,
emnapi_int16_array,
emnapi_uint16_array,
emnapi_int32_array,
emnapi_uint32_array,
emnapi_float32_array,
emnapi_float64_array,
emnapi_bigint64_array,
emnapi_biguint64_array,
emnapi_float16_array,
emnapi_data_view = -1,
emnapi_buffer = -2
}
export declare const enum napi_threadsafe_function_call_mode {
napi_tsfn_nonblocking,
napi_tsfn_blocking
}
export declare const enum napi_threadsafe_function_release_mode {
napi_tsfn_release,
napi_tsfn_abort
}
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
constructor(id: number, value: S);
dispose(): void;
}
export declare class Context {
private _isStopping;
private _canCallIntoJs;
private _suppressDestroy;
envStore: Store<Env>;
scopeStore: ScopeStore;
refStore: Store<Reference>;
deferredStore: Store<Deferred<any>>;
handleStore: HandleStore;
private readonly refCounter?;
private readonly cleanupQueue;
private readonly _externalMemory;
feature: {
supportReflect: boolean;
supportFinalizer: boolean;
supportWeakSymbol: boolean;
supportBigInt: boolean;
supportNewFunction: boolean;
canSetFunctionName: boolean;
setImmediate: (callback: () => void) => void;
Buffer: BufferCtor | undefined;
MessageChannel: {
new (): MessageChannel;
prototype: MessageChannel;
} | undefined;
};
constructor(options?: ContextOptions);
/**
* Suppress the destroy on `beforeExit` event in Node.js.
* Call this method if you want to keep the context and
* all associated {@link Env | Env} alive,
* this also means that cleanup hooks will not be called.
* After call this method, you should call
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
*/
suppressDestroy(): void;
getRuntimeVersions(): {
version: string;
NODE_API_SUPPORTED_VERSION_MAX: Version;
NAPI_VERSION_EXPERIMENTAL: Version;
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
};
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
getCurrentScope(): HandleScope | null;
addToCurrentScope<V>(value: V): Handle<V>;
openScope(envObject?: Env): HandleScope;
closeScope(envObject?: Env, _scope?: HandleScope): void;
ensureHandle<S>(value: S): Handle<S>;
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
runCleanup(): void;
increaseWaitingRequestCounter(): void;
decreaseWaitingRequestCounter(): void;
setCanCallIntoJs(value: boolean): void;
setStopping(value: boolean): void;
canCallIntoJs(): boolean;
/**
* Destroy the context and call cleanup hooks.
* Associated {@link Env | Env} will be destroyed.
*/
destroy(): void;
}
export declare interface ContextOptions {
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
}
export declare function createContext(options?: ContextOptions): Context;
export declare class Deferred<T = any> implements IStoreValue {
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
id: number;
ctx: Context;
value: IDeferrdValue<T>;
constructor(ctx: Context, value: IDeferrdValue<T>);
resolve(value: T): void;
reject(reason?: any): void;
dispose(): void;
}
export declare class EmnapiError extends Error {
constructor(message?: string);
}
export declare abstract class Env implements IStoreValue {
readonly ctx: Context;
moduleApiVersion: number;
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
abort: (msg?: string) => never;
id: number;
openHandleScopes: number;
instanceData: TrackedFinalizer | null;
tryCatch: TryCatch;
refs: number;
reflist: RefTracker;
finalizing_reflist: RefTracker;
pendingFinalizers: RefTracker[];
lastError: {
errorCode: napi_status;
engineErrorCode: number;
engineReserved: Ptr;
};
inGcFinalizer: boolean;
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
/** @virtual */
canCallIntoJs(): boolean;
terminatedOrTerminating(): boolean;
ref(): void;
unref(): void;
ensureHandle<S>(value: S): Handle<S>;
ensureHandleId(value: any): napi_value;
clearLastError(): napi_status;
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
getReturnStatus(): napi_status;
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
/** @virtual */
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
invokeFinalizerFromGC(finalizer: RefTracker): void;
checkGCAccess(): void;
/** @virtual */
enqueueFinalizer(finalizer: RefTracker): void;
/** @virtual */
dequeueFinalizer(finalizer: RefTracker): void;
/** @virtual */
deleteMe(): void;
dispose(): void;
private readonly _bindingMap;
initObjectBinding<S extends object>(value: S): IReferenceBinding;
getObjectBinding<S extends object>(value: S): IReferenceBinding;
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
getInstanceData(): number;
}
/** @public */
declare interface External_2 extends Record<any, any> {
}
/** @public */
declare const External_2: {
new (value: number | bigint): External_2;
prototype: null;
};
export { External_2 as External }
export declare class Finalizer {
envObject: Env;
private _finalizeCallback;
private _finalizeData;
private _finalizeHint;
private _makeDynCall_vppp;
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
callback(): napi_finalize;
data(): void_p;
hint(): void_p;
resetEnv(): void;
resetFinalizer(): void;
callFinalizer(): void;
dispose(): void;
}
export declare function getDefaultContext(): Context;
/** @public */
export declare function getExternalValue(external: External_2): number | bigint;
export declare class Handle<S> {
id: number;
value: S;
constructor(id: number, value: S);
data(): void_p;
isNumber(): boolean;
isBigInt(): boolean;
isString(): boolean;
isFunction(): boolean;
isExternal(): boolean;
isObject(): boolean;
isArray(): boolean;
isArrayBuffer(): boolean;
isTypedArray(): boolean;
isBuffer(BufferConstructor?: BufferCtor): boolean;
isDataView(): boolean;
isDate(): boolean;
isPromise(): boolean;
isBoolean(): boolean;
isUndefined(): boolean;
isSymbol(): boolean;
isNull(): boolean;
dispose(): void;
}
export declare class HandleScope {
handleStore: HandleStore;
id: number;
parent: HandleScope | null;
child: HandleScope | null;
start: number;
end: number;
private _escapeCalled;
callbackInfo: ICallbackInfo;
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
add<V>(value: V): Handle<V>;
addExternal(data: void_p): Handle<object>;
dispose(): void;
escape(handle: number): Handle<any> | null;
escapeCalled(): boolean;
}
export declare class HandleStore {
static UNDEFINED: ConstHandle<undefined>;
static NULL: ConstHandle<null>;
static FALSE: ConstHandle<false>;
static TRUE: ConstHandle<true>;
static GLOBAL: ConstHandle<typeof globalThis>;
static MIN_ID: 6;
private readonly _values;
private _next;
push<S>(value: S): Handle<S>;
erase(start: number, end: number): void;
get(id: Ptr): Handle<any> | undefined;
swap(a: number, b: number): void;
dispose(): void;
}
export declare interface ICallbackInfo {
thiz: any;
data: void_p;
args: ArrayLike<any>;
fn: Function;
}
export declare interface IDeferrdValue<T = any> {
resolve: (value: T) => void;
reject: (reason?: any) => void;
}
export declare interface IReferenceBinding {
wrapped: number;
tag: Uint32Array | null;
}
/** @public */
export declare function isExternal(object: unknown): object is External_2;
export declare function isReferenceType(v: any): v is object;
export declare interface IStoreValue {
id: number;
dispose(): void;
[x: string]: any;
}
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
export declare class NodeEnv extends Env {
filename: string;
private readonly nodeBinding?;
destructing: boolean;
finalizationScheduled: boolean;
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
deleteMe(): void;
canCallIntoJs(): boolean;
triggerFatalException(err: any): void;
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
enqueueFinalizer(finalizer: RefTracker): void;
drainFinalizerQueue(): void;
}
export declare class NotSupportBufferError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class NotSupportWeakRefError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class Persistent<T> {
private _ref;
private _param;
private _callback;
private static readonly _registry;
constructor(value: T);
setWeak<P>(param: P, callback: (param: P) => void): void;
clearWeak(): void;
reset(): void;
isEmpty(): boolean;
deref(): T | undefined;
}
export declare class Reference extends RefTracker implements IStoreValue {
private static weakCallback;
id: number;
envObject: Env;
private readonly canBeWeak;
private _refcount;
private readonly _ownership;
persistent: Persistent<object>;
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
ref(): number;
unref(): number;
get(envObject?: Env): napi_value;
/** @virtual */
resetFinalizer(): void;
/** @virtual */
data(): void_p;
refcount(): number;
ownership(): ReferenceOwnership;
/** @virtual */
protected callUserFinalizer(): void;
/** @virtual */
protected invokeFinalizerFromGC(): void;
private _setWeak;
finalize(): void;
dispose(): void;
}
export declare enum ReferenceOwnership {
kRuntime = 0,
kUserland = 1
}
export declare class ReferenceWithData extends Reference {
private readonly _data;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
private constructor();
data(): void_p;
}
export declare class ReferenceWithFinalizer extends Reference {
private _finalizer;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
private constructor();
resetFinalizer(): void;
data(): void_p;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
dispose(): void;
}
export declare class RefTracker {
/** @virtual */
dispose(): void;
/** @virtual */
finalize(): void;
private _next;
private _prev;
link(list: RefTracker): void;
unlink(): void;
static finalizeAll(list: RefTracker): void;
}
export declare class ScopeStore {
private readonly _rootScope;
currentScope: HandleScope;
private readonly _values;
constructor();
get(id: number): HandleScope | undefined;
openScope(handleStore: HandleStore): HandleScope;
closeScope(): void;
dispose(): void;
}
export declare class Store<V extends IStoreValue> {
protected _values: Array<V | undefined>;
private _freeList;
private _size;
constructor();
add(value: V): void;
get(id: Ptr): V | undefined;
has(id: Ptr): boolean;
remove(id: Ptr): void;
dispose(): void;
}
export declare class TrackedFinalizer extends RefTracker {
private _finalizer;
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
private constructor();
data(): void_p;
dispose(): void;
finalize(): void;
}
export declare class TryCatch {
private _exception;
private _caught;
isEmpty(): boolean;
hasCaught(): boolean;
exception(): any;
setError(err: any): void;
reset(): void;
extractException(): any;
}
export declare const version: string;
export { }
File diff suppressed because one or more lines are too long
@@ -0,0 +1,671 @@
export declare type Ptr = number | bigint
export declare interface IBuffer extends Uint8Array {}
export declare interface BufferCtor {
readonly prototype: IBuffer
/** @deprecated */
new (...args: any[]): IBuffer
from: {
(buffer: ArrayBufferLike): IBuffer
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
}
alloc: (size: number) => IBuffer
isBuffer: (obj: unknown) => obj is IBuffer
}
export declare const enum GlobalHandle {
UNDEFINED = 1,
NULL,
FALSE,
TRUE,
GLOBAL
}
export declare const enum Version {
NODE_API_SUPPORTED_VERSION_MIN = 1,
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
NODE_API_SUPPORTED_VERSION_MAX = 10,
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type Pointer<T> = number
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type PointerPointer<T> = number
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
export declare type Const<T> = T
export declare type void_p = Pointer<void>
export declare type void_pp = Pointer<void_p>
export declare type bool = number
export declare type char = number
export declare type char_p = Pointer<char>
export declare type unsigned_char = number
export declare type const_char = Const<char>
export declare type const_char_p = Pointer<const_char>
export declare type char16_t_p = number
export declare type const_char16_t_p = number
export declare type short = number
export declare type unsigned_short = number
export declare type int = number
export declare type unsigned_int = number
export declare type long = number
export declare type unsigned_long = number
export declare type long_long = bigint
export declare type unsigned_long_long = bigint
export declare type float = number
export declare type double = number
export declare type long_double = number
export declare type size_t = number
export declare type int8_t = number
export declare type uint8_t = number
export declare type int16_t = number
export declare type uint16_t = number
export declare type int32_t = number
export declare type uint32_t = number
export declare type int64_t = bigint
export declare type uint64_t = bigint
export declare type napi_env = Pointer<unknown>
export declare type napi_value = Pointer<unknown>
export declare type napi_ref = Pointer<unknown>
export declare type napi_deferred = Pointer<unknown>
export declare type napi_handle_scope = Pointer<unknown>
export declare type napi_escapable_handle_scope = Pointer<unknown>
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
export declare type napi_callback_info = Pointer<unknown>
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
export declare interface napi_extended_error_info {
error_message: const_char_p
engine_reserved: void_p
engine_error_code: uint32_t
error_code: napi_status
}
export declare interface napi_property_descriptor {
// One of utf8name or name should be NULL.
utf8name: const_char_p
name: napi_value
method: napi_callback
getter: napi_callback
setter: napi_callback
value: napi_value
/* napi_property_attributes */
attributes: number
data: void_p
}
export declare type napi_finalize = FunctionPointer<(
env: napi_env,
finalize_data: void_p,
finalize_hint: void_p
) => void>
export declare interface node_module {
nm_version: int32_t
nm_flags: uint32_t
nm_filename: Pointer<const_char>
nm_register_func: napi_addon_register_func
nm_modname: Pointer<const_char>
nm_priv: Pointer<void>
reserved: PointerPointer<void>
}
export declare interface napi_node_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
release: const_char_p
}
export declare interface emnapi_emscripten_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
}
export declare const enum napi_status {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, // unused
napi_no_external_buffers_allowed,
napi_cannot_run_js
}
export declare const enum napi_property_attributes {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
/// #ifdef NAPI_EXPERIMENTAL
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
/// #endif // NAPI_EXPERIMENTAL
}
export declare const enum napi_valuetype {
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint
}
export declare const enum napi_typedarray_type {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
napi_float16_array,
}
export declare const enum napi_key_collection_mode {
napi_key_include_prototypes,
napi_key_own_only
}
export declare const enum napi_key_filter {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
}
export declare const enum napi_key_conversion {
napi_key_keep_numbers,
napi_key_numbers_to_strings
}
export declare const enum emnapi_memory_view_type {
emnapi_int8_array,
emnapi_uint8_array,
emnapi_uint8_clamped_array,
emnapi_int16_array,
emnapi_uint16_array,
emnapi_int32_array,
emnapi_uint32_array,
emnapi_float32_array,
emnapi_float64_array,
emnapi_bigint64_array,
emnapi_biguint64_array,
emnapi_float16_array,
emnapi_data_view = -1,
emnapi_buffer = -2
}
export declare const enum napi_threadsafe_function_call_mode {
napi_tsfn_nonblocking,
napi_tsfn_blocking
}
export declare const enum napi_threadsafe_function_release_mode {
napi_tsfn_release,
napi_tsfn_abort
}
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
constructor(id: number, value: S);
dispose(): void;
}
export declare class Context {
private _isStopping;
private _canCallIntoJs;
private _suppressDestroy;
envStore: Store<Env>;
scopeStore: ScopeStore;
refStore: Store<Reference>;
deferredStore: Store<Deferred<any>>;
handleStore: HandleStore;
private readonly refCounter?;
private readonly cleanupQueue;
private readonly _externalMemory;
feature: {
supportReflect: boolean;
supportFinalizer: boolean;
supportWeakSymbol: boolean;
supportBigInt: boolean;
supportNewFunction: boolean;
canSetFunctionName: boolean;
setImmediate: (callback: () => void) => void;
Buffer: BufferCtor | undefined;
MessageChannel: {
new (): MessageChannel;
prototype: MessageChannel;
} | undefined;
};
constructor(options?: ContextOptions);
/**
* Suppress the destroy on `beforeExit` event in Node.js.
* Call this method if you want to keep the context and
* all associated {@link Env | Env} alive,
* this also means that cleanup hooks will not be called.
* After call this method, you should call
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
*/
suppressDestroy(): void;
getRuntimeVersions(): {
version: string;
NODE_API_SUPPORTED_VERSION_MAX: Version;
NAPI_VERSION_EXPERIMENTAL: Version;
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
};
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
getCurrentScope(): HandleScope | null;
addToCurrentScope<V>(value: V): Handle<V>;
openScope(envObject?: Env): HandleScope;
closeScope(envObject?: Env, _scope?: HandleScope): void;
ensureHandle<S>(value: S): Handle<S>;
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
runCleanup(): void;
increaseWaitingRequestCounter(): void;
decreaseWaitingRequestCounter(): void;
setCanCallIntoJs(value: boolean): void;
setStopping(value: boolean): void;
canCallIntoJs(): boolean;
/**
* Destroy the context and call cleanup hooks.
* Associated {@link Env | Env} will be destroyed.
*/
destroy(): void;
}
export declare interface ContextOptions {
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
}
export declare function createContext(options?: ContextOptions): Context;
export declare class Deferred<T = any> implements IStoreValue {
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
id: number;
ctx: Context;
value: IDeferrdValue<T>;
constructor(ctx: Context, value: IDeferrdValue<T>);
resolve(value: T): void;
reject(reason?: any): void;
dispose(): void;
}
export declare class EmnapiError extends Error {
constructor(message?: string);
}
export declare abstract class Env implements IStoreValue {
readonly ctx: Context;
moduleApiVersion: number;
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
abort: (msg?: string) => never;
id: number;
openHandleScopes: number;
instanceData: TrackedFinalizer | null;
tryCatch: TryCatch;
refs: number;
reflist: RefTracker;
finalizing_reflist: RefTracker;
pendingFinalizers: RefTracker[];
lastError: {
errorCode: napi_status;
engineErrorCode: number;
engineReserved: Ptr;
};
inGcFinalizer: boolean;
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
/** @virtual */
canCallIntoJs(): boolean;
terminatedOrTerminating(): boolean;
ref(): void;
unref(): void;
ensureHandle<S>(value: S): Handle<S>;
ensureHandleId(value: any): napi_value;
clearLastError(): napi_status;
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
getReturnStatus(): napi_status;
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
/** @virtual */
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
invokeFinalizerFromGC(finalizer: RefTracker): void;
checkGCAccess(): void;
/** @virtual */
enqueueFinalizer(finalizer: RefTracker): void;
/** @virtual */
dequeueFinalizer(finalizer: RefTracker): void;
/** @virtual */
deleteMe(): void;
dispose(): void;
private readonly _bindingMap;
initObjectBinding<S extends object>(value: S): IReferenceBinding;
getObjectBinding<S extends object>(value: S): IReferenceBinding;
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
getInstanceData(): number;
}
/** @public */
declare interface External_2 extends Record<any, any> {
}
/** @public */
declare const External_2: {
new (value: number | bigint): External_2;
prototype: null;
};
export { External_2 as External }
export declare class Finalizer {
envObject: Env;
private _finalizeCallback;
private _finalizeData;
private _finalizeHint;
private _makeDynCall_vppp;
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
callback(): napi_finalize;
data(): void_p;
hint(): void_p;
resetEnv(): void;
resetFinalizer(): void;
callFinalizer(): void;
dispose(): void;
}
export declare function getDefaultContext(): Context;
/** @public */
export declare function getExternalValue(external: External_2): number | bigint;
export declare class Handle<S> {
id: number;
value: S;
constructor(id: number, value: S);
data(): void_p;
isNumber(): boolean;
isBigInt(): boolean;
isString(): boolean;
isFunction(): boolean;
isExternal(): boolean;
isObject(): boolean;
isArray(): boolean;
isArrayBuffer(): boolean;
isTypedArray(): boolean;
isBuffer(BufferConstructor?: BufferCtor): boolean;
isDataView(): boolean;
isDate(): boolean;
isPromise(): boolean;
isBoolean(): boolean;
isUndefined(): boolean;
isSymbol(): boolean;
isNull(): boolean;
dispose(): void;
}
export declare class HandleScope {
handleStore: HandleStore;
id: number;
parent: HandleScope | null;
child: HandleScope | null;
start: number;
end: number;
private _escapeCalled;
callbackInfo: ICallbackInfo;
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
add<V>(value: V): Handle<V>;
addExternal(data: void_p): Handle<object>;
dispose(): void;
escape(handle: number): Handle<any> | null;
escapeCalled(): boolean;
}
export declare class HandleStore {
static UNDEFINED: ConstHandle<undefined>;
static NULL: ConstHandle<null>;
static FALSE: ConstHandle<false>;
static TRUE: ConstHandle<true>;
static GLOBAL: ConstHandle<typeof globalThis>;
static MIN_ID: 6;
private readonly _values;
private _next;
push<S>(value: S): Handle<S>;
erase(start: number, end: number): void;
get(id: Ptr): Handle<any> | undefined;
swap(a: number, b: number): void;
dispose(): void;
}
export declare interface ICallbackInfo {
thiz: any;
data: void_p;
args: ArrayLike<any>;
fn: Function;
}
export declare interface IDeferrdValue<T = any> {
resolve: (value: T) => void;
reject: (reason?: any) => void;
}
export declare interface IReferenceBinding {
wrapped: number;
tag: Uint32Array | null;
}
/** @public */
export declare function isExternal(object: unknown): object is External_2;
export declare function isReferenceType(v: any): v is object;
export declare interface IStoreValue {
id: number;
dispose(): void;
[x: string]: any;
}
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
export declare class NodeEnv extends Env {
filename: string;
private readonly nodeBinding?;
destructing: boolean;
finalizationScheduled: boolean;
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
deleteMe(): void;
canCallIntoJs(): boolean;
triggerFatalException(err: any): void;
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
enqueueFinalizer(finalizer: RefTracker): void;
drainFinalizerQueue(): void;
}
export declare class NotSupportBufferError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class NotSupportWeakRefError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class Persistent<T> {
private _ref;
private _param;
private _callback;
private static readonly _registry;
constructor(value: T);
setWeak<P>(param: P, callback: (param: P) => void): void;
clearWeak(): void;
reset(): void;
isEmpty(): boolean;
deref(): T | undefined;
}
export declare class Reference extends RefTracker implements IStoreValue {
private static weakCallback;
id: number;
envObject: Env;
private readonly canBeWeak;
private _refcount;
private readonly _ownership;
persistent: Persistent<object>;
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
ref(): number;
unref(): number;
get(envObject?: Env): napi_value;
/** @virtual */
resetFinalizer(): void;
/** @virtual */
data(): void_p;
refcount(): number;
ownership(): ReferenceOwnership;
/** @virtual */
protected callUserFinalizer(): void;
/** @virtual */
protected invokeFinalizerFromGC(): void;
private _setWeak;
finalize(): void;
dispose(): void;
}
export declare enum ReferenceOwnership {
kRuntime = 0,
kUserland = 1
}
export declare class ReferenceWithData extends Reference {
private readonly _data;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
private constructor();
data(): void_p;
}
export declare class ReferenceWithFinalizer extends Reference {
private _finalizer;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
private constructor();
resetFinalizer(): void;
data(): void_p;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
dispose(): void;
}
export declare class RefTracker {
/** @virtual */
dispose(): void;
/** @virtual */
finalize(): void;
private _next;
private _prev;
link(list: RefTracker): void;
unlink(): void;
static finalizeAll(list: RefTracker): void;
}
export declare class ScopeStore {
private readonly _rootScope;
currentScope: HandleScope;
private readonly _values;
constructor();
get(id: number): HandleScope | undefined;
openScope(handleStore: HandleStore): HandleScope;
closeScope(): void;
dispose(): void;
}
export declare class Store<V extends IStoreValue> {
protected _values: Array<V | undefined>;
private _freeList;
private _size;
constructor();
add(value: V): void;
get(id: Ptr): V | undefined;
has(id: Ptr): boolean;
remove(id: Ptr): void;
dispose(): void;
}
export declare class TrackedFinalizer extends RefTracker {
private _finalizer;
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
private constructor();
data(): void_p;
dispose(): void;
finalize(): void;
}
export declare class TryCatch {
private _exception;
private _caught;
isEmpty(): boolean;
hasCaught(): boolean;
exception(): any;
setError(err: any): void;
reset(): void;
extractException(): any;
}
export declare const version: string;
export { }
@@ -0,0 +1,673 @@
export declare type Ptr = number | bigint
export declare interface IBuffer extends Uint8Array {}
export declare interface BufferCtor {
readonly prototype: IBuffer
/** @deprecated */
new (...args: any[]): IBuffer
from: {
(buffer: ArrayBufferLike): IBuffer
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
}
alloc: (size: number) => IBuffer
isBuffer: (obj: unknown) => obj is IBuffer
}
export declare const enum GlobalHandle {
UNDEFINED = 1,
NULL,
FALSE,
TRUE,
GLOBAL
}
export declare const enum Version {
NODE_API_SUPPORTED_VERSION_MIN = 1,
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
NODE_API_SUPPORTED_VERSION_MAX = 10,
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type Pointer<T> = number
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type PointerPointer<T> = number
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
export declare type Const<T> = T
export declare type void_p = Pointer<void>
export declare type void_pp = Pointer<void_p>
export declare type bool = number
export declare type char = number
export declare type char_p = Pointer<char>
export declare type unsigned_char = number
export declare type const_char = Const<char>
export declare type const_char_p = Pointer<const_char>
export declare type char16_t_p = number
export declare type const_char16_t_p = number
export declare type short = number
export declare type unsigned_short = number
export declare type int = number
export declare type unsigned_int = number
export declare type long = number
export declare type unsigned_long = number
export declare type long_long = bigint
export declare type unsigned_long_long = bigint
export declare type float = number
export declare type double = number
export declare type long_double = number
export declare type size_t = number
export declare type int8_t = number
export declare type uint8_t = number
export declare type int16_t = number
export declare type uint16_t = number
export declare type int32_t = number
export declare type uint32_t = number
export declare type int64_t = bigint
export declare type uint64_t = bigint
export declare type napi_env = Pointer<unknown>
export declare type napi_value = Pointer<unknown>
export declare type napi_ref = Pointer<unknown>
export declare type napi_deferred = Pointer<unknown>
export declare type napi_handle_scope = Pointer<unknown>
export declare type napi_escapable_handle_scope = Pointer<unknown>
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
export declare type napi_callback_info = Pointer<unknown>
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
export declare interface napi_extended_error_info {
error_message: const_char_p
engine_reserved: void_p
engine_error_code: uint32_t
error_code: napi_status
}
export declare interface napi_property_descriptor {
// One of utf8name or name should be NULL.
utf8name: const_char_p
name: napi_value
method: napi_callback
getter: napi_callback
setter: napi_callback
value: napi_value
/* napi_property_attributes */
attributes: number
data: void_p
}
export declare type napi_finalize = FunctionPointer<(
env: napi_env,
finalize_data: void_p,
finalize_hint: void_p
) => void>
export declare interface node_module {
nm_version: int32_t
nm_flags: uint32_t
nm_filename: Pointer<const_char>
nm_register_func: napi_addon_register_func
nm_modname: Pointer<const_char>
nm_priv: Pointer<void>
reserved: PointerPointer<void>
}
export declare interface napi_node_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
release: const_char_p
}
export declare interface emnapi_emscripten_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
}
export declare const enum napi_status {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, // unused
napi_no_external_buffers_allowed,
napi_cannot_run_js
}
export declare const enum napi_property_attributes {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
/// #ifdef NAPI_EXPERIMENTAL
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
/// #endif // NAPI_EXPERIMENTAL
}
export declare const enum napi_valuetype {
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint
}
export declare const enum napi_typedarray_type {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
napi_float16_array,
}
export declare const enum napi_key_collection_mode {
napi_key_include_prototypes,
napi_key_own_only
}
export declare const enum napi_key_filter {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
}
export declare const enum napi_key_conversion {
napi_key_keep_numbers,
napi_key_numbers_to_strings
}
export declare const enum emnapi_memory_view_type {
emnapi_int8_array,
emnapi_uint8_array,
emnapi_uint8_clamped_array,
emnapi_int16_array,
emnapi_uint16_array,
emnapi_int32_array,
emnapi_uint32_array,
emnapi_float32_array,
emnapi_float64_array,
emnapi_bigint64_array,
emnapi_biguint64_array,
emnapi_float16_array,
emnapi_data_view = -1,
emnapi_buffer = -2
}
export declare const enum napi_threadsafe_function_call_mode {
napi_tsfn_nonblocking,
napi_tsfn_blocking
}
export declare const enum napi_threadsafe_function_release_mode {
napi_tsfn_release,
napi_tsfn_abort
}
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
constructor(id: number, value: S);
dispose(): void;
}
export declare class Context {
private _isStopping;
private _canCallIntoJs;
private _suppressDestroy;
envStore: Store<Env>;
scopeStore: ScopeStore;
refStore: Store<Reference>;
deferredStore: Store<Deferred<any>>;
handleStore: HandleStore;
private readonly refCounter?;
private readonly cleanupQueue;
private readonly _externalMemory;
feature: {
supportReflect: boolean;
supportFinalizer: boolean;
supportWeakSymbol: boolean;
supportBigInt: boolean;
supportNewFunction: boolean;
canSetFunctionName: boolean;
setImmediate: (callback: () => void) => void;
Buffer: BufferCtor | undefined;
MessageChannel: {
new (): MessageChannel;
prototype: MessageChannel;
} | undefined;
};
constructor(options?: ContextOptions);
/**
* Suppress the destroy on `beforeExit` event in Node.js.
* Call this method if you want to keep the context and
* all associated {@link Env | Env} alive,
* this also means that cleanup hooks will not be called.
* After call this method, you should call
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
*/
suppressDestroy(): void;
getRuntimeVersions(): {
version: string;
NODE_API_SUPPORTED_VERSION_MAX: Version;
NAPI_VERSION_EXPERIMENTAL: Version;
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
};
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
getCurrentScope(): HandleScope | null;
addToCurrentScope<V>(value: V): Handle<V>;
openScope(envObject?: Env): HandleScope;
closeScope(envObject?: Env, _scope?: HandleScope): void;
ensureHandle<S>(value: S): Handle<S>;
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
runCleanup(): void;
increaseWaitingRequestCounter(): void;
decreaseWaitingRequestCounter(): void;
setCanCallIntoJs(value: boolean): void;
setStopping(value: boolean): void;
canCallIntoJs(): boolean;
/**
* Destroy the context and call cleanup hooks.
* Associated {@link Env | Env} will be destroyed.
*/
destroy(): void;
}
export declare interface ContextOptions {
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
}
export declare function createContext(options?: ContextOptions): Context;
export declare class Deferred<T = any> implements IStoreValue {
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
id: number;
ctx: Context;
value: IDeferrdValue<T>;
constructor(ctx: Context, value: IDeferrdValue<T>);
resolve(value: T): void;
reject(reason?: any): void;
dispose(): void;
}
export declare class EmnapiError extends Error {
constructor(message?: string);
}
export declare abstract class Env implements IStoreValue {
readonly ctx: Context;
moduleApiVersion: number;
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
abort: (msg?: string) => never;
id: number;
openHandleScopes: number;
instanceData: TrackedFinalizer | null;
tryCatch: TryCatch;
refs: number;
reflist: RefTracker;
finalizing_reflist: RefTracker;
pendingFinalizers: RefTracker[];
lastError: {
errorCode: napi_status;
engineErrorCode: number;
engineReserved: Ptr;
};
inGcFinalizer: boolean;
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
/** @virtual */
canCallIntoJs(): boolean;
terminatedOrTerminating(): boolean;
ref(): void;
unref(): void;
ensureHandle<S>(value: S): Handle<S>;
ensureHandleId(value: any): napi_value;
clearLastError(): napi_status;
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
getReturnStatus(): napi_status;
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
/** @virtual */
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
invokeFinalizerFromGC(finalizer: RefTracker): void;
checkGCAccess(): void;
/** @virtual */
enqueueFinalizer(finalizer: RefTracker): void;
/** @virtual */
dequeueFinalizer(finalizer: RefTracker): void;
/** @virtual */
deleteMe(): void;
dispose(): void;
private readonly _bindingMap;
initObjectBinding<S extends object>(value: S): IReferenceBinding;
getObjectBinding<S extends object>(value: S): IReferenceBinding;
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
getInstanceData(): number;
}
/** @public */
declare interface External_2 extends Record<any, any> {
}
/** @public */
declare const External_2: {
new (value: number | bigint): External_2;
prototype: null;
};
export { External_2 as External }
export declare class Finalizer {
envObject: Env;
private _finalizeCallback;
private _finalizeData;
private _finalizeHint;
private _makeDynCall_vppp;
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
callback(): napi_finalize;
data(): void_p;
hint(): void_p;
resetEnv(): void;
resetFinalizer(): void;
callFinalizer(): void;
dispose(): void;
}
export declare function getDefaultContext(): Context;
/** @public */
export declare function getExternalValue(external: External_2): number | bigint;
export declare class Handle<S> {
id: number;
value: S;
constructor(id: number, value: S);
data(): void_p;
isNumber(): boolean;
isBigInt(): boolean;
isString(): boolean;
isFunction(): boolean;
isExternal(): boolean;
isObject(): boolean;
isArray(): boolean;
isArrayBuffer(): boolean;
isTypedArray(): boolean;
isBuffer(BufferConstructor?: BufferCtor): boolean;
isDataView(): boolean;
isDate(): boolean;
isPromise(): boolean;
isBoolean(): boolean;
isUndefined(): boolean;
isSymbol(): boolean;
isNull(): boolean;
dispose(): void;
}
export declare class HandleScope {
handleStore: HandleStore;
id: number;
parent: HandleScope | null;
child: HandleScope | null;
start: number;
end: number;
private _escapeCalled;
callbackInfo: ICallbackInfo;
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
add<V>(value: V): Handle<V>;
addExternal(data: void_p): Handle<object>;
dispose(): void;
escape(handle: number): Handle<any> | null;
escapeCalled(): boolean;
}
export declare class HandleStore {
static UNDEFINED: ConstHandle<undefined>;
static NULL: ConstHandle<null>;
static FALSE: ConstHandle<false>;
static TRUE: ConstHandle<true>;
static GLOBAL: ConstHandle<typeof globalThis>;
static MIN_ID: 6;
private readonly _values;
private _next;
push<S>(value: S): Handle<S>;
erase(start: number, end: number): void;
get(id: Ptr): Handle<any> | undefined;
swap(a: number, b: number): void;
dispose(): void;
}
export declare interface ICallbackInfo {
thiz: any;
data: void_p;
args: ArrayLike<any>;
fn: Function;
}
export declare interface IDeferrdValue<T = any> {
resolve: (value: T) => void;
reject: (reason?: any) => void;
}
export declare interface IReferenceBinding {
wrapped: number;
tag: Uint32Array | null;
}
/** @public */
export declare function isExternal(object: unknown): object is External_2;
export declare function isReferenceType(v: any): v is object;
export declare interface IStoreValue {
id: number;
dispose(): void;
[x: string]: any;
}
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
export declare class NodeEnv extends Env {
filename: string;
private readonly nodeBinding?;
destructing: boolean;
finalizationScheduled: boolean;
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
deleteMe(): void;
canCallIntoJs(): boolean;
triggerFatalException(err: any): void;
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
enqueueFinalizer(finalizer: RefTracker): void;
drainFinalizerQueue(): void;
}
export declare class NotSupportBufferError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class NotSupportWeakRefError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class Persistent<T> {
private _ref;
private _param;
private _callback;
private static readonly _registry;
constructor(value: T);
setWeak<P>(param: P, callback: (param: P) => void): void;
clearWeak(): void;
reset(): void;
isEmpty(): boolean;
deref(): T | undefined;
}
export declare class Reference extends RefTracker implements IStoreValue {
private static weakCallback;
id: number;
envObject: Env;
private readonly canBeWeak;
private _refcount;
private readonly _ownership;
persistent: Persistent<object>;
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
ref(): number;
unref(): number;
get(envObject?: Env): napi_value;
/** @virtual */
resetFinalizer(): void;
/** @virtual */
data(): void_p;
refcount(): number;
ownership(): ReferenceOwnership;
/** @virtual */
protected callUserFinalizer(): void;
/** @virtual */
protected invokeFinalizerFromGC(): void;
private _setWeak;
finalize(): void;
dispose(): void;
}
export declare enum ReferenceOwnership {
kRuntime = 0,
kUserland = 1
}
export declare class ReferenceWithData extends Reference {
private readonly _data;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
private constructor();
data(): void_p;
}
export declare class ReferenceWithFinalizer extends Reference {
private _finalizer;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
private constructor();
resetFinalizer(): void;
data(): void_p;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
dispose(): void;
}
export declare class RefTracker {
/** @virtual */
dispose(): void;
/** @virtual */
finalize(): void;
private _next;
private _prev;
link(list: RefTracker): void;
unlink(): void;
static finalizeAll(list: RefTracker): void;
}
export declare class ScopeStore {
private readonly _rootScope;
currentScope: HandleScope;
private readonly _values;
constructor();
get(id: number): HandleScope | undefined;
openScope(handleStore: HandleStore): HandleScope;
closeScope(): void;
dispose(): void;
}
export declare class Store<V extends IStoreValue> {
protected _values: Array<V | undefined>;
private _freeList;
private _size;
constructor();
add(value: V): void;
get(id: Ptr): V | undefined;
has(id: Ptr): boolean;
remove(id: Ptr): void;
dispose(): void;
}
export declare class TrackedFinalizer extends RefTracker {
private _finalizer;
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
private constructor();
data(): void_p;
dispose(): void;
finalize(): void;
}
export declare class TryCatch {
private _exception;
private _caught;
isEmpty(): boolean;
hasCaught(): boolean;
exception(): any;
setError(err: any): void;
reset(): void;
extractException(): any;
}
export declare const version: string;
export { }
export as namespace emnapi;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,426 @@
declare namespace emnapi {
export type CleanupHookCallbackFunction = number | ((arg: number) => void);
export class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
constructor(id: number, value: S);
dispose(): void;
}
export class Context {
private _isStopping;
private _canCallIntoJs;
private _suppressDestroy;
envStore: Store<Env>;
scopeStore: ScopeStore;
refStore: Store<Reference>;
deferredStore: Store<Deferred<any>>;
handleStore: HandleStore;
private readonly refCounter?;
private readonly cleanupQueue;
private readonly _externalMemory;
feature: {
supportReflect: boolean;
supportFinalizer: boolean;
supportWeakSymbol: boolean;
supportBigInt: boolean;
supportNewFunction: boolean;
canSetFunctionName: boolean;
setImmediate: (callback: () => void) => void;
Buffer: BufferCtor | undefined;
MessageChannel: {
new (): MessageChannel;
prototype: MessageChannel;
} | undefined;
};
constructor(options?: ContextOptions);
/**
* Suppress the destroy on `beforeExit` event in Node.js.
* Call this method if you want to keep the context and
* all associated {@link Env | Env} alive,
* this also means that cleanup hooks will not be called.
* After call this method, you should call
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
*/
suppressDestroy(): void;
getRuntimeVersions(): {
version: string;
NODE_API_SUPPORTED_VERSION_MAX: Version;
NAPI_VERSION_EXPERIMENTAL: Version;
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
};
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
getCurrentScope(): HandleScope | null;
addToCurrentScope<V>(value: V): Handle<V>;
openScope(envObject?: Env): HandleScope;
closeScope(envObject?: Env, _scope?: HandleScope): void;
ensureHandle<S>(value: S): Handle<S>;
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
runCleanup(): void;
increaseWaitingRequestCounter(): void;
decreaseWaitingRequestCounter(): void;
setCanCallIntoJs(value: boolean): void;
setStopping(value: boolean): void;
canCallIntoJs(): boolean;
/**
* Destroy the context and call cleanup hooks.
* Associated {@link Env | Env} will be destroyed.
*/
destroy(): void;
}
export interface ContextOptions {
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
}
export function createContext(options?: ContextOptions): Context;
export class Deferred<T = any> implements IStoreValue {
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
id: number;
ctx: Context;
value: IDeferrdValue<T>;
constructor(ctx: Context, value: IDeferrdValue<T>);
resolve(value: T): void;
reject(reason?: any): void;
dispose(): void;
}
export class EmnapiError extends Error {
constructor(message?: string);
}
export abstract class Env implements IStoreValue {
readonly ctx: Context;
moduleApiVersion: number;
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
abort: (msg?: string) => never;
id: number;
openHandleScopes: number;
instanceData: TrackedFinalizer | null;
tryCatch: TryCatch;
refs: number;
reflist: RefTracker;
finalizing_reflist: RefTracker;
pendingFinalizers: RefTracker[];
lastError: {
errorCode: napi_status;
engineErrorCode: number;
engineReserved: Ptr;
};
inGcFinalizer: boolean;
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
/** @virtual */
canCallIntoJs(): boolean;
terminatedOrTerminating(): boolean;
ref(): void;
unref(): void;
ensureHandle<S>(value: S): Handle<S>;
ensureHandleId(value: any): napi_value;
clearLastError(): napi_status;
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
getReturnStatus(): napi_status;
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
/** @virtual */
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
invokeFinalizerFromGC(finalizer: RefTracker): void;
checkGCAccess(): void;
/** @virtual */
enqueueFinalizer(finalizer: RefTracker): void;
/** @virtual */
dequeueFinalizer(finalizer: RefTracker): void;
/** @virtual */
deleteMe(): void;
dispose(): void;
private readonly _bindingMap;
initObjectBinding<S extends object>(value: S): IReferenceBinding;
getObjectBinding<S extends object>(value: S): IReferenceBinding;
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
getInstanceData(): number;
}
/** @public */
interface External_2 extends Record<any, any> {
}
/** @public */
const External_2: {
new (value: number | bigint): External_2;
prototype: null;
};
export { External_2 as External }
export class Finalizer {
envObject: Env;
private _finalizeCallback;
private _finalizeData;
private _finalizeHint;
private _makeDynCall_vppp;
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
callback(): napi_finalize;
data(): void_p;
hint(): void_p;
resetEnv(): void;
resetFinalizer(): void;
callFinalizer(): void;
dispose(): void;
}
export function getDefaultContext(): Context;
/** @public */
export function getExternalValue(external: External_2): number | bigint;
export class Handle<S> {
id: number;
value: S;
constructor(id: number, value: S);
data(): void_p;
isNumber(): boolean;
isBigInt(): boolean;
isString(): boolean;
isFunction(): boolean;
isExternal(): boolean;
isObject(): boolean;
isArray(): boolean;
isArrayBuffer(): boolean;
isTypedArray(): boolean;
isBuffer(BufferConstructor?: BufferCtor): boolean;
isDataView(): boolean;
isDate(): boolean;
isPromise(): boolean;
isBoolean(): boolean;
isUndefined(): boolean;
isSymbol(): boolean;
isNull(): boolean;
dispose(): void;
}
export class HandleScope {
handleStore: HandleStore;
id: number;
parent: HandleScope | null;
child: HandleScope | null;
start: number;
end: number;
private _escapeCalled;
callbackInfo: ICallbackInfo;
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
add<V>(value: V): Handle<V>;
addExternal(data: void_p): Handle<object>;
dispose(): void;
escape(handle: number): Handle<any> | null;
escapeCalled(): boolean;
}
export class HandleStore {
static UNDEFINED: ConstHandle<undefined>;
static NULL: ConstHandle<null>;
static FALSE: ConstHandle<false>;
static TRUE: ConstHandle<true>;
static GLOBAL: ConstHandle<typeof globalThis>;
static MIN_ID: 6;
private readonly _values;
private _next;
push<S>(value: S): Handle<S>;
erase(start: number, end: number): void;
get(id: Ptr): Handle<any> | undefined;
swap(a: number, b: number): void;
dispose(): void;
}
export interface ICallbackInfo {
thiz: any;
data: void_p;
args: ArrayLike<any>;
fn: Function;
}
export interface IDeferrdValue<T = any> {
resolve: (value: T) => void;
reject: (reason?: any) => void;
}
export interface IReferenceBinding {
wrapped: number;
tag: Uint32Array | null;
}
/** @public */
export function isExternal(object: unknown): object is External_2;
export function isReferenceType(v: any): v is object;
export interface IStoreValue {
id: number;
dispose(): void;
[x: string]: any;
}
export const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
export const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
export const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
export const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
export class NodeEnv extends Env {
filename: string;
private readonly nodeBinding?;
destructing: boolean;
finalizationScheduled: boolean;
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
deleteMe(): void;
canCallIntoJs(): boolean;
triggerFatalException(err: any): void;
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
enqueueFinalizer(finalizer: RefTracker): void;
drainFinalizerQueue(): void;
}
export class NotSupportBufferError extends EmnapiError {
constructor(api: string, message: string);
}
export class NotSupportWeakRefError extends EmnapiError {
constructor(api: string, message: string);
}
export class Persistent<T> {
private _ref;
private _param;
private _callback;
private static readonly _registry;
constructor(value: T);
setWeak<P>(param: P, callback: (param: P) => void): void;
clearWeak(): void;
reset(): void;
isEmpty(): boolean;
deref(): T | undefined;
}
export class Reference extends RefTracker implements IStoreValue {
private static weakCallback;
id: number;
envObject: Env;
private readonly canBeWeak;
private _refcount;
private readonly _ownership;
persistent: Persistent<object>;
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
ref(): number;
unref(): number;
get(envObject?: Env): napi_value;
/** @virtual */
resetFinalizer(): void;
/** @virtual */
data(): void_p;
refcount(): number;
ownership(): ReferenceOwnership;
/** @virtual */
protected callUserFinalizer(): void;
/** @virtual */
protected invokeFinalizerFromGC(): void;
private _setWeak;
finalize(): void;
dispose(): void;
}
export enum ReferenceOwnership {
kRuntime = 0,
kUserland = 1
}
export class ReferenceWithData extends Reference {
private readonly _data;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
private constructor();
data(): void_p;
}
export class ReferenceWithFinalizer extends Reference {
private _finalizer;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
private constructor();
resetFinalizer(): void;
data(): void_p;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
dispose(): void;
}
export class RefTracker {
/** @virtual */
dispose(): void;
/** @virtual */
finalize(): void;
private _next;
private _prev;
link(list: RefTracker): void;
unlink(): void;
static finalizeAll(list: RefTracker): void;
}
export class ScopeStore {
private readonly _rootScope;
currentScope: HandleScope;
private readonly _values;
constructor();
get(id: number): HandleScope | undefined;
openScope(handleStore: HandleStore): HandleScope;
closeScope(): void;
dispose(): void;
}
export class Store<V extends IStoreValue> {
protected _values: Array<V | undefined>;
private _freeList;
private _size;
constructor();
add(value: V): void;
get(id: Ptr): V | undefined;
has(id: Ptr): boolean;
remove(id: Ptr): void;
dispose(): void;
}
export class TrackedFinalizer extends RefTracker {
private _finalizer;
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
private constructor();
data(): void_p;
dispose(): void;
finalize(): void;
}
export class TryCatch {
private _exception;
private _caught;
isEmpty(): boolean;
hasCaught(): boolean;
exception(): any;
setError(err: any): void;
reset(): void;
extractException(): any;
}
export const version: string;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,671 @@
export declare type Ptr = number | bigint
export declare interface IBuffer extends Uint8Array {}
export declare interface BufferCtor {
readonly prototype: IBuffer
/** @deprecated */
new (...args: any[]): IBuffer
from: {
(buffer: ArrayBufferLike): IBuffer
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
}
alloc: (size: number) => IBuffer
isBuffer: (obj: unknown) => obj is IBuffer
}
export declare const enum GlobalHandle {
UNDEFINED = 1,
NULL,
FALSE,
TRUE,
GLOBAL
}
export declare const enum Version {
NODE_API_SUPPORTED_VERSION_MIN = 1,
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
NODE_API_SUPPORTED_VERSION_MAX = 10,
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type Pointer<T> = number
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type PointerPointer<T> = number
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
export declare type Const<T> = T
export declare type void_p = Pointer<void>
export declare type void_pp = Pointer<void_p>
export declare type bool = number
export declare type char = number
export declare type char_p = Pointer<char>
export declare type unsigned_char = number
export declare type const_char = Const<char>
export declare type const_char_p = Pointer<const_char>
export declare type char16_t_p = number
export declare type const_char16_t_p = number
export declare type short = number
export declare type unsigned_short = number
export declare type int = number
export declare type unsigned_int = number
export declare type long = number
export declare type unsigned_long = number
export declare type long_long = bigint
export declare type unsigned_long_long = bigint
export declare type float = number
export declare type double = number
export declare type long_double = number
export declare type size_t = number
export declare type int8_t = number
export declare type uint8_t = number
export declare type int16_t = number
export declare type uint16_t = number
export declare type int32_t = number
export declare type uint32_t = number
export declare type int64_t = bigint
export declare type uint64_t = bigint
export declare type napi_env = Pointer<unknown>
export declare type napi_value = Pointer<unknown>
export declare type napi_ref = Pointer<unknown>
export declare type napi_deferred = Pointer<unknown>
export declare type napi_handle_scope = Pointer<unknown>
export declare type napi_escapable_handle_scope = Pointer<unknown>
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
export declare type napi_callback_info = Pointer<unknown>
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
export declare interface napi_extended_error_info {
error_message: const_char_p
engine_reserved: void_p
engine_error_code: uint32_t
error_code: napi_status
}
export declare interface napi_property_descriptor {
// One of utf8name or name should be NULL.
utf8name: const_char_p
name: napi_value
method: napi_callback
getter: napi_callback
setter: napi_callback
value: napi_value
/* napi_property_attributes */
attributes: number
data: void_p
}
export declare type napi_finalize = FunctionPointer<(
env: napi_env,
finalize_data: void_p,
finalize_hint: void_p
) => void>
export declare interface node_module {
nm_version: int32_t
nm_flags: uint32_t
nm_filename: Pointer<const_char>
nm_register_func: napi_addon_register_func
nm_modname: Pointer<const_char>
nm_priv: Pointer<void>
reserved: PointerPointer<void>
}
export declare interface napi_node_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
release: const_char_p
}
export declare interface emnapi_emscripten_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
}
export declare const enum napi_status {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, // unused
napi_no_external_buffers_allowed,
napi_cannot_run_js
}
export declare const enum napi_property_attributes {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
/// #ifdef NAPI_EXPERIMENTAL
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
/// #endif // NAPI_EXPERIMENTAL
}
export declare const enum napi_valuetype {
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint
}
export declare const enum napi_typedarray_type {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
napi_float16_array,
}
export declare const enum napi_key_collection_mode {
napi_key_include_prototypes,
napi_key_own_only
}
export declare const enum napi_key_filter {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
}
export declare const enum napi_key_conversion {
napi_key_keep_numbers,
napi_key_numbers_to_strings
}
export declare const enum emnapi_memory_view_type {
emnapi_int8_array,
emnapi_uint8_array,
emnapi_uint8_clamped_array,
emnapi_int16_array,
emnapi_uint16_array,
emnapi_int32_array,
emnapi_uint32_array,
emnapi_float32_array,
emnapi_float64_array,
emnapi_bigint64_array,
emnapi_biguint64_array,
emnapi_float16_array,
emnapi_data_view = -1,
emnapi_buffer = -2
}
export declare const enum napi_threadsafe_function_call_mode {
napi_tsfn_nonblocking,
napi_tsfn_blocking
}
export declare const enum napi_threadsafe_function_release_mode {
napi_tsfn_release,
napi_tsfn_abort
}
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
export declare class ConstHandle<S extends undefined | null | boolean | typeof globalThis> extends Handle<S> {
constructor(id: number, value: S);
dispose(): void;
}
export declare class Context {
private _isStopping;
private _canCallIntoJs;
private _suppressDestroy;
envStore: Store<Env>;
scopeStore: ScopeStore;
refStore: Store<Reference>;
deferredStore: Store<Deferred<any>>;
handleStore: HandleStore;
private readonly refCounter?;
private readonly cleanupQueue;
private readonly _externalMemory;
feature: {
supportReflect: boolean;
supportFinalizer: boolean;
supportWeakSymbol: boolean;
supportBigInt: boolean;
supportNewFunction: boolean;
canSetFunctionName: boolean;
setImmediate: (callback: () => void) => void;
Buffer: BufferCtor | undefined;
MessageChannel: {
new (): MessageChannel;
prototype: MessageChannel;
} | undefined;
};
constructor(options?: ContextOptions);
/**
* Suppress the destroy on `beforeExit` event in Node.js.
* Call this method if you want to keep the context and
* all associated {@link Env | Env} alive,
* this also means that cleanup hooks will not be called.
* After call this method, you should call
* {@link Context.destroy | `Context.prototype.destroy`} method manually.
*/
suppressDestroy(): void;
getRuntimeVersions(): {
version: string;
NODE_API_SUPPORTED_VERSION_MAX: Version;
NAPI_VERSION_EXPERIMENTAL: Version;
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
};
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
createDeferred<T = any>(value: IDeferrdValue<T>): Deferred<T>;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createEnv(filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any): Env;
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
getCurrentScope(): HandleScope | null;
addToCurrentScope<V>(value: V): Handle<V>;
openScope(envObject?: Env): HandleScope;
closeScope(envObject?: Env, _scope?: HandleScope): void;
ensureHandle<S>(value: S): Handle<S>;
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
runCleanup(): void;
increaseWaitingRequestCounter(): void;
decreaseWaitingRequestCounter(): void;
setCanCallIntoJs(value: boolean): void;
setStopping(value: boolean): void;
canCallIntoJs(): boolean;
/**
* Destroy the context and call cleanup hooks.
* Associated {@link Env | Env} will be destroyed.
*/
destroy(): void;
}
export declare interface ContextOptions {
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
}
export declare function createContext(options?: ContextOptions): Context;
export declare class Deferred<T = any> implements IStoreValue {
static create<T = any>(ctx: Context, value: IDeferrdValue<T>): Deferred;
id: number;
ctx: Context;
value: IDeferrdValue<T>;
constructor(ctx: Context, value: IDeferrdValue<T>);
resolve(value: T): void;
reject(reason?: any): void;
dispose(): void;
}
export declare class EmnapiError extends Error {
constructor(message?: string);
}
export declare abstract class Env implements IStoreValue {
readonly ctx: Context;
moduleApiVersion: number;
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
abort: (msg?: string) => never;
id: number;
openHandleScopes: number;
instanceData: TrackedFinalizer | null;
tryCatch: TryCatch;
refs: number;
reflist: RefTracker;
finalizing_reflist: RefTracker;
pendingFinalizers: RefTracker[];
lastError: {
errorCode: napi_status;
engineErrorCode: number;
engineReserved: Ptr;
};
inGcFinalizer: boolean;
constructor(ctx: Context, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never);
/** @virtual */
canCallIntoJs(): boolean;
terminatedOrTerminating(): boolean;
ref(): void;
unref(): void;
ensureHandle<S>(value: S): Handle<S>;
ensureHandleId(value: any): napi_value;
clearLastError(): napi_status;
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: void_p): napi_status;
getReturnStatus(): napi_status;
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
/** @virtual */
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
invokeFinalizerFromGC(finalizer: RefTracker): void;
checkGCAccess(): void;
/** @virtual */
enqueueFinalizer(finalizer: RefTracker): void;
/** @virtual */
dequeueFinalizer(finalizer: RefTracker): void;
/** @virtual */
deleteMe(): void;
dispose(): void;
private readonly _bindingMap;
initObjectBinding<S extends object>(value: S): IReferenceBinding;
getObjectBinding<S extends object>(value: S): IReferenceBinding;
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
getInstanceData(): number;
}
/** @public */
declare interface External_2 extends Record<any, any> {
}
/** @public */
declare const External_2: {
new (value: number | bigint): External_2;
prototype: null;
};
export { External_2 as External }
export declare class Finalizer {
envObject: Env;
private _finalizeCallback;
private _finalizeData;
private _finalizeHint;
private _makeDynCall_vppp;
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
callback(): napi_finalize;
data(): void_p;
hint(): void_p;
resetEnv(): void;
resetFinalizer(): void;
callFinalizer(): void;
dispose(): void;
}
export declare function getDefaultContext(): Context;
/** @public */
export declare function getExternalValue(external: External_2): number | bigint;
export declare class Handle<S> {
id: number;
value: S;
constructor(id: number, value: S);
data(): void_p;
isNumber(): boolean;
isBigInt(): boolean;
isString(): boolean;
isFunction(): boolean;
isExternal(): boolean;
isObject(): boolean;
isArray(): boolean;
isArrayBuffer(): boolean;
isTypedArray(): boolean;
isBuffer(BufferConstructor?: BufferCtor): boolean;
isDataView(): boolean;
isDate(): boolean;
isPromise(): boolean;
isBoolean(): boolean;
isUndefined(): boolean;
isSymbol(): boolean;
isNull(): boolean;
dispose(): void;
}
export declare class HandleScope {
handleStore: HandleStore;
id: number;
parent: HandleScope | null;
child: HandleScope | null;
start: number;
end: number;
private _escapeCalled;
callbackInfo: ICallbackInfo;
constructor(handleStore: HandleStore, id: number, parentScope: HandleScope | null, start: number, end?: number);
add<V>(value: V): Handle<V>;
addExternal(data: void_p): Handle<object>;
dispose(): void;
escape(handle: number): Handle<any> | null;
escapeCalled(): boolean;
}
export declare class HandleStore {
static UNDEFINED: ConstHandle<undefined>;
static NULL: ConstHandle<null>;
static FALSE: ConstHandle<false>;
static TRUE: ConstHandle<true>;
static GLOBAL: ConstHandle<typeof globalThis>;
static MIN_ID: 6;
private readonly _values;
private _next;
push<S>(value: S): Handle<S>;
erase(start: number, end: number): void;
get(id: Ptr): Handle<any> | undefined;
swap(a: number, b: number): void;
dispose(): void;
}
export declare interface ICallbackInfo {
thiz: any;
data: void_p;
args: ArrayLike<any>;
fn: Function;
}
export declare interface IDeferrdValue<T = any> {
resolve: (value: T) => void;
reject: (reason?: any) => void;
}
export declare interface IReferenceBinding {
wrapped: number;
tag: Uint32Array | null;
}
/** @public */
export declare function isExternal(object: unknown): object is External_2;
export declare function isReferenceType(v: any): v is object;
export declare interface IStoreValue {
id: number;
dispose(): void;
[x: string]: any;
}
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
export declare class NodeEnv extends Env {
filename: string;
private readonly nodeBinding?;
destructing: boolean;
finalizationScheduled: boolean;
constructor(ctx: Context, filename: string, moduleApiVersion: number, makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void, makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void, abort: (msg?: string) => never, nodeBinding?: any);
deleteMe(): void;
canCallIntoJs(): boolean;
triggerFatalException(err: any): void;
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
enqueueFinalizer(finalizer: RefTracker): void;
drainFinalizerQueue(): void;
}
export declare class NotSupportBufferError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class NotSupportWeakRefError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class Persistent<T> {
private _ref;
private _param;
private _callback;
private static readonly _registry;
constructor(value: T);
setWeak<P>(param: P, callback: (param: P) => void): void;
clearWeak(): void;
reset(): void;
isEmpty(): boolean;
deref(): T | undefined;
}
export declare class Reference extends RefTracker implements IStoreValue {
private static weakCallback;
id: number;
envObject: Env;
private readonly canBeWeak;
private _refcount;
private readonly _ownership;
persistent: Persistent<object>;
static create(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
protected constructor(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
ref(): number;
unref(): number;
get(envObject?: Env): napi_value;
/** @virtual */
resetFinalizer(): void;
/** @virtual */
data(): void_p;
refcount(): number;
ownership(): ReferenceOwnership;
/** @virtual */
protected callUserFinalizer(): void;
/** @virtual */
protected invokeFinalizerFromGC(): void;
private _setWeak;
finalize(): void;
dispose(): void;
}
export declare enum ReferenceOwnership {
kRuntime = 0,
kUserland = 1
}
export declare class ReferenceWithData extends Reference {
private readonly _data;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
private constructor();
data(): void_p;
}
export declare class ReferenceWithFinalizer extends Reference {
private _finalizer;
static create(envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
private constructor();
resetFinalizer(): void;
data(): void_p;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
dispose(): void;
}
export declare class RefTracker {
/** @virtual */
dispose(): void;
/** @virtual */
finalize(): void;
private _next;
private _prev;
link(list: RefTracker): void;
unlink(): void;
static finalizeAll(list: RefTracker): void;
}
export declare class ScopeStore {
private readonly _rootScope;
currentScope: HandleScope;
private readonly _values;
constructor();
get(id: number): HandleScope | undefined;
openScope(handleStore: HandleStore): HandleScope;
closeScope(): void;
dispose(): void;
}
export declare class Store<V extends IStoreValue> {
protected _values: Array<V | undefined>;
private _freeList;
private _size;
constructor();
add(value: V): void;
get(id: Ptr): V | undefined;
has(id: Ptr): boolean;
remove(id: Ptr): void;
dispose(): void;
}
export declare class TrackedFinalizer extends RefTracker {
private _finalizer;
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
private constructor();
data(): void_p;
dispose(): void;
finalize(): void;
}
export declare class TryCatch {
private _exception;
private _caught;
isEmpty(): boolean;
hasCaught(): boolean;
exception(): any;
setError(err: any): void;
reset(): void;
extractException(): any;
}
export declare const version: string;
export { }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,5 @@
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
module.exports = require('./dist/emnapi.cjs.min.js')
} else {
module.exports = require('./dist/emnapi.cjs.js')
}
@@ -0,0 +1,48 @@
{
"name": "@emnapi/runtime",
"version": "1.11.1",
"description": "emnapi runtime",
"main": "index.js",
"module": "./dist/emnapi.esm-bundler.js",
"types": "./dist/emnapi.d.ts",
"sideEffects": false,
"exports": {
".": {
"types": {
"module": "./dist/emnapi.d.ts",
"import": "./dist/emnapi.d.mts",
"default": "./dist/emnapi.d.ts"
},
"module": "./dist/emnapi.esm-bundler.js",
"import": "./dist/emnapi.mjs",
"default": "./index.js"
},
"./dist/emnapi.cjs.min": {
"types": "./dist/emnapi.d.ts",
"default": "./dist/emnapi.cjs.min.js"
},
"./dist/emnapi.min.mjs": {
"types": "./dist/emnapi.d.mts",
"default": "./dist/emnapi.min.mjs"
}
},
"dependencies": {
"tslib": "^2.4.0"
},
"scripts": {
"build": "node ./script/build.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/toyobayashi/emnapi.git"
},
"author": "toyobayashi",
"license": "MIT",
"bugs": {
"url": "https://github.com/toyobayashi/emnapi/issues"
},
"homepage": "https://github.com/toyobayashi/emnapi#readme",
"publishConfig": {
"access": "public"
}
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Toyobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,203 @@
# @emnapi/wasi-threads
This package makes [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads) based WASI modules work in Node.js and browser.
## Quick Start
`index.html`
```html
<script src="./node_modules/@tybys/wasm-util/dist/wasm-util.js"></script>
<script src="./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js"></script>
<script src="./index.js"></script>
```
If your application will block browser main thread (for example `pthread_join`), please run it in worker instead.
```html
<script>
// pthread_join (Atomics.wait) cannot be called in browser main thread
new Worker('./index.js')
</script>
```
`index.js`
```js
const ENVIRONMENT_IS_NODE =
typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
(function (main) {
if (ENVIRONMENT_IS_NODE) {
main(require)
} else {
if (typeof importScripts === 'function') {
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.js')
importScripts('./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js')
}
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
const nodeWorkerThreads = {
Worker: globalThis.Worker
}
const _require = function (request) {
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
throw new Error('Can not find module: ' + request)
}
main(_require)
}
})(async function (require) {
const { WASI } = require('wasi')
const { Worker } = require('worker_threads')
const { WASIThreads } = require('@emnapi/wasi-threads')
const wasi = new WASI({
version: 'preview1'
})
const wasiThreads = new WASIThreads({
wasi,
/**
* avoid Atomics.wait() deadlock during thread creation in browser
* see https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size
*/
reuseWorker: ENVIRONMENT_IS_NODE
? false
: {
size: 4 /** greater than actual needs (2) */,
strict: true
},
/**
* Synchronous thread creation
* pthread_create will not return until thread worker actually starts
*/
waitThreadStart: typeof window === 'undefined' ? 1000 : false,
onCreateWorker: () => {
return new Worker('./worker.js', {
execArgv: ['--experimental-wasi-unstable-preview1']
})
}
})
const memory = new WebAssembly.Memory({
initial: 16777216 / 65536,
maximum: 2147483648 / 65536,
shared: true
})
let input
const file = 'path/to/your/wasi-module.wasm'
try {
input = require('fs').readFileSync(require('path').join(__dirname, file))
} catch (err) {
const response = await fetch(file)
input = await response.arrayBuffer()
}
let { module, instance } = await WebAssembly.instantiate(input, {
env: { memory },
wasi_snapshot_preview1: wasi.wasiImport,
...wasiThreads.getImportObject()
})
wasiThreads.setup(instance, module, memory)
await wasiThreads.preloadWorkers()
if (typeof instance.exports._start === 'function') {
return wasi.start(instance)
} else {
wasi.initialize(instance)
// instance.exports.exported_wasm_function()
}
})
```
`worker.js`
```js
(function (main) {
const ENVIRONMENT_IS_NODE =
typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string'
if (ENVIRONMENT_IS_NODE) {
const _require = function (request) {
return require(request)
}
const _init = function () {
const nodeWorkerThreads = require('worker_threads')
const parentPort = nodeWorkerThreads.parentPort
parentPort.on('message', (data) => {
globalThis.onmessage({ data })
})
Object.assign(globalThis, {
self: globalThis,
require,
Worker: nodeWorkerThreads.Worker,
importScripts: function (f) {
(0, eval)(require('fs').readFileSync(f, 'utf8') + '//# sourceURL=' + f)
},
postMessage: function (msg) {
parentPort.postMessage(msg)
}
})
}
main(_require, _init)
} else {
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.js')
importScripts('./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js')
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
const _require = function (request) {
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
throw new Error('Can not find module: ' + request)
}
const _init = function () {}
main(_require, _init)
}
})(function main (require, init) {
init()
const { WASI } = require('wasi')
const { ThreadMessageHandler, WASIThreads } = require('@emnapi/wasi-threads')
const handler = new ThreadMessageHandler({
async onLoad ({ wasmModule, wasmMemory }) {
const wasi = new WASI({
version: 'preview1'
})
const wasiThreads = new WASIThreads({
wasi,
childThread: true
})
const originalInstance = await WebAssembly.instantiate(wasmModule, {
env: {
memory: wasmMemory,
},
wasi_snapshot_preview1: wasi.wasiImport,
...wasiThreads.getImportObject()
})
// must call `initialize` instead of `start` in child thread
const instance = wasiThreads.initialize(originalInstance, wasmModule, wasmMemory)
return { module: wasmModule, instance }
}
})
globalThis.onmessage = function (e) {
handler.handle(e)
// handle other messages
}
})
```
@@ -0,0 +1,885 @@
const _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
function getPostMessage(options) {
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
? options.postMessage
: typeof postMessage === 'function'
? postMessage
: undefined;
}
function serizeErrorToBuffer(sab, code, error) {
const i32array = new Int32Array(sab);
Atomics.store(i32array, 0, code);
if (code > 1 && error) {
const name = error.name;
const message = error.message;
const stack = error.stack;
const nameBuffer = new TextEncoder().encode(name);
const messageBuffer = new TextEncoder().encode(message);
const stackBuffer = new TextEncoder().encode(stack);
Atomics.store(i32array, 1, nameBuffer.length);
Atomics.store(i32array, 2, messageBuffer.length);
Atomics.store(i32array, 3, stackBuffer.length);
const buffer = new Uint8Array(sab);
buffer.set(nameBuffer, 16);
buffer.set(messageBuffer, 16 + nameBuffer.length);
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
}
}
function deserizeErrorFromBuffer(sab) {
var _a, _b;
const i32array = new Int32Array(sab);
const status = Atomics.load(i32array, 0);
if (status <= 1) {
return null;
}
const nameLength = Atomics.load(i32array, 1);
const messageLength = Atomics.load(i32array, 2);
const stackLength = Atomics.load(i32array, 3);
const buffer = new Uint8Array(sab);
const nameBuffer = buffer.slice(16, 16 + nameLength);
const messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
const stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
const name = new TextDecoder().decode(nameBuffer);
const message = new TextDecoder().decode(messageBuffer);
const stack = new TextDecoder().decode(stackBuffer);
const ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
const error = new ErrorConstructor(message);
Object.defineProperty(error, 'stack', {
value: stack,
writable: true,
enumerable: false,
configurable: true
});
return error;
}
function isSharedArrayBuffer(value) {
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
}
function isTrapError(e) {
try {
return e instanceof _WebAssembly.RuntimeError;
}
catch (_) {
return false;
}
}
function createMessage(type, payload) {
return {
__emnapi__: {
type,
payload
}
};
}
const WASI_THREADS_MAX_TID = 0x1FFFFFFF;
function checkSharedWasmMemory(wasmMemory) {
if (wasmMemory) {
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
throw new Error('Multithread features require shared wasm memory. ' +
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
'then create WebAssembly.Memory with `shared: true` option');
}
}
else {
if (typeof SharedArrayBuffer === 'undefined') {
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
}
}
}
function getReuseWorker(value) {
var _a;
if (typeof value === 'boolean') {
return value ? { size: 0, strict: false } : false;
}
if (typeof value === 'number') {
if (!(value >= 0)) {
throw new RangeError('reuseWorker: size must be a non-negative integer');
}
return { size: value, strict: false };
}
if (!value) {
return false;
}
const size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
const strict = Boolean(value.strict);
if (!(size > 0) && strict) {
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
}
return { size, strict };
}
let nextWorkerID = 0;
class ThreadManager {
get nextWorkerID() { return nextWorkerID; }
constructor(options) {
var _a;
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.wasmModule = null;
this.wasmMemory = null;
this.messageEvents = new WeakMap();
if (!options) {
throw new TypeError('ThreadManager(): options is not provided');
}
if ('childThread' in options) {
this._childThread = Boolean(options.childThread);
}
else {
this._childThread = false;
}
if (this._childThread) {
this._onCreateWorker = undefined;
this._reuseWorker = false;
this._beforeLoad = undefined;
}
else {
this._onCreateWorker = options.onCreateWorker;
this._reuseWorker = getReuseWorker(options.reuseWorker);
this._beforeLoad = options.beforeLoad;
}
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
this.threadSpawn = options.threadSpawn;
}
init() {
if (!this._childThread) {
this.initMainThread();
}
}
initMainThread() {
this.preparePool();
}
preparePool() {
if (this._reuseWorker) {
if (this._reuseWorker.size) {
let pthreadPoolSize = this._reuseWorker.size;
while (pthreadPoolSize--) {
const worker = this.allocateUnusedWorker();
if (ENVIRONMENT_IS_NODE) {
worker.once('message', () => { });
worker.unref();
}
}
}
}
}
shouldPreloadWorkers() {
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
}
loadWasmModuleToAllWorkers() {
const promises = Array(this.unusedWorkers.length);
for (let i = 0; i < this.unusedWorkers.length; ++i) {
const worker = this.unusedWorkers[i];
if (ENVIRONMENT_IS_NODE)
worker.ref();
promises[i] = this.loadWasmModuleToWorker(worker).then((w) => {
if (ENVIRONMENT_IS_NODE)
worker.unref();
return w;
}, (e) => {
if (ENVIRONMENT_IS_NODE)
worker.unref();
throw e;
});
}
return Promise.all(promises).catch((err) => {
this.terminateAllThreads();
throw err;
});
}
preloadWorkers() {
if (this.shouldPreloadWorkers()) {
return this.loadWasmModuleToAllWorkers();
}
return Promise.resolve([]);
}
setup(wasmModule, wasmMemory) {
this.wasmModule = wasmModule;
this.wasmMemory = wasmMemory;
}
markId(worker) {
if (worker.__emnapi_tid)
return worker.__emnapi_tid;
const tid = nextWorkerID + 43;
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
this.pthreads[tid] = worker;
worker.__emnapi_tid = tid;
return tid;
}
returnWorkerToPool(worker) {
var tid = worker.__emnapi_tid;
if (tid !== undefined) {
delete this.pthreads[tid];
}
this.unusedWorkers.push(worker);
delete worker.__emnapi_tid;
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
}
loadWasmModuleToWorker(worker, sab) {
if (worker.whenLoaded)
return worker.whenLoaded;
const err = this.printErr;
const beforeLoad = this._beforeLoad;
const _this = this;
worker.whenLoaded = new Promise((resolve, reject) => {
const handleError = function (e) {
let message = 'worker sent an error!';
if (worker.__emnapi_tid !== undefined) {
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
}
if ('message' in e) {
err(message + ' ' + e.message);
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
try {
_this.terminateAllThreads();
}
catch (_) { }
}
}
else {
err(message);
}
reject(e);
throw e;
};
const handleMessage = (data) => {
if (data.__emnapi__) {
const type = data.__emnapi__.type;
const payload = data.__emnapi__.payload;
if (type === 'loaded') {
worker.loaded = true;
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
worker.unref();
}
resolve(worker);
}
else if (type === 'cleanup-thread') {
if (payload.tid in this.pthreads) {
this.cleanThread(worker, payload.tid);
}
}
else if (type === 'spawn-thread') {
this.threadSpawn(payload.startArg, payload.errorOrTid);
}
else if (type === 'terminate-all-threads') {
this.terminateAllThreads();
}
}
};
worker.onmessage = (e) => {
handleMessage(e.data);
this.fireMessageEvent(worker, e);
};
worker.onerror = handleError;
if (ENVIRONMENT_IS_NODE) {
worker.on('message', function (data) {
var _a, _b;
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
data
});
});
worker.on('error', function (e) {
var _a, _b;
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
});
worker.on('detachedExit', function () { });
}
if (typeof beforeLoad === 'function') {
beforeLoad(worker);
}
try {
worker.postMessage(createMessage('load', {
wasmModule: this.wasmModule,
wasmMemory: this.wasmMemory,
sab
}));
}
catch (err) {
checkSharedWasmMemory(this.wasmMemory);
throw err;
}
});
return worker.whenLoaded;
}
allocateUnusedWorker() {
const _onCreateWorker = this._onCreateWorker;
if (typeof _onCreateWorker !== 'function') {
throw new TypeError('`options.onCreateWorker` is not provided');
}
const worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
this.unusedWorkers.push(worker);
return worker;
}
getNewWorker(sab) {
if (this._reuseWorker) {
if (this.unusedWorkers.length === 0) {
if (this._reuseWorker.strict) {
if (!ENVIRONMENT_IS_NODE) {
const err = this.printErr;
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
return;
}
}
const worker = this.allocateUnusedWorker();
this.loadWasmModuleToWorker(worker, sab);
}
return this.unusedWorkers.pop();
}
const worker = this.allocateUnusedWorker();
this.loadWasmModuleToWorker(worker, sab);
return this.unusedWorkers.pop();
}
cleanThread(worker, tid, force) {
if (!force && this._reuseWorker) {
this.returnWorkerToPool(worker);
}
else {
delete this.pthreads[tid];
this.terminateWorker(worker);
delete worker.__emnapi_tid;
}
}
terminateWorker(worker) {
var _a;
const tid = worker.__emnapi_tid;
worker.terminate();
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
this.messageEvents.delete(worker);
worker.onmessage = (e) => {
if (e.data.__emnapi__) {
const err = this.printErr;
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
}
};
}
terminateAllThreads() {
const runningWorkers = Object.values(this.pthreads);
for (let i = 0; i < runningWorkers.length; ++i) {
this.terminateWorker(runningWorkers[i]);
}
for (let i = 0; i < this.unusedWorkers.length; ++i) {
this.terminateWorker(this.unusedWorkers[i]);
}
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.preparePool();
}
addMessageEventListener(worker, onMessage) {
let listeners = this.messageEvents.get(worker);
if (!listeners) {
listeners = new Set();
this.messageEvents.set(worker, listeners);
}
listeners.add(onMessage);
return () => {
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
};
}
fireMessageEvent(worker, e) {
const listeners = this.messageEvents.get(worker);
if (!listeners)
return;
const err = this.printErr;
listeners.forEach((listener) => {
try {
listener(e);
}
catch (e) {
err(e.stack);
}
});
}
}
const kIsProxy = Symbol('kIsProxy');
function createInstanceProxy(instance, memory) {
if (instance[kIsProxy])
return instance;
const originalExports = instance.exports;
const createHandler = function (target) {
const handlers = [
'apply',
'construct',
'defineProperty',
'deleteProperty',
'get',
'getOwnPropertyDescriptor',
'getPrototypeOf',
'has',
'isExtensible',
'ownKeys',
'preventExtensions',
'set',
'setPrototypeOf'
];
const handler = {};
for (let i = 0; i < handlers.length; i++) {
const name = handlers[i];
handler[name] = function () {
const args = Array.prototype.slice.call(arguments, 1);
args.unshift(target);
return Reflect[name].apply(Reflect, args);
};
}
return handler;
};
const handler = createHandler(originalExports);
const _initialize = () => { };
const _start = () => 0;
handler.get = function (_target, p, receiver) {
var _a;
if (p === 'memory') {
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
}
if (p === '_initialize') {
return p in originalExports ? _initialize : undefined;
}
if (p === '_start') {
return p in originalExports ? _start : undefined;
}
return Reflect.get(originalExports, p, receiver);
};
handler.has = function (_target, p) {
if (p === 'memory')
return true;
return Reflect.has(originalExports, p);
};
const exportsProxy = new Proxy(Object.create(null), handler);
return new Proxy(instance, {
get(target, p, receiver) {
if (p === 'exports') {
return exportsProxy;
}
if (p === kIsProxy) {
return true;
}
return Reflect.get(target, p, receiver);
}
});
}
const patchedWasiInstances = new WeakMap();
class WASIThreads {
constructor(options) {
if (!options) {
throw new TypeError('WASIThreads(): options is not provided');
}
if (!options.wasi) {
throw new TypeError('WASIThreads(): options.wasi is not provided');
}
patchedWasiInstances.set(this, new WeakSet());
const wasi = options.wasi;
patchWasiInstance(this, wasi);
this.wasi = wasi;
if ('childThread' in options) {
this.childThread = Boolean(options.childThread);
}
else {
this.childThread = false;
}
this.PThread = undefined;
if ('threadManager' in options) {
if (typeof options.threadManager === 'function') {
this.PThread = options.threadManager();
}
else {
this.PThread = options.threadManager;
}
}
else {
if (!this.childThread) {
this.PThread = new ThreadManager(options);
this.PThread.init();
}
}
let waitThreadStart = false;
if ('waitThreadStart' in options) {
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
}
const postMessage = getPostMessage(options);
if (this.childThread && typeof postMessage !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMessage;
const wasm64 = Boolean(options.wasm64);
const threadSpawn = (startArg, errorOrTid) => {
var _a;
const EAGAIN = 6;
const isNewABI = errorOrTid !== undefined;
try {
checkSharedWasmMemory(this.wasmMemory);
}
catch (err) {
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
if (isNewABI) {
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
return 1;
}
else {
return -EAGAIN;
}
}
if (!isNewABI) {
const malloc = this.wasmInstance.exports.malloc;
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
if (!errorOrTid) {
return -48;
}
}
const _free = this.wasmInstance.exports.free;
const free = wasm64 ? (ptr) => { _free(BigInt(ptr)); } : _free;
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, 0);
if (this.childThread) {
postMessage(createMessage('spawn-thread', {
startArg,
errorOrTid: errorOrTid
}));
Atomics.wait(struct, 1, 0);
const isError = Atomics.load(struct, 0);
const result = Atomics.load(struct, 1);
if (isNewABI) {
return isError;
}
free(errorOrTid);
return isError ? -result : result;
}
const shouldWait = waitThreadStart || (waitThreadStart === 0);
let sab;
if (shouldWait) {
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
Atomics.store(sab, 0, 0);
}
let worker;
let tid;
const PThread = this.PThread;
try {
worker = PThread.getNewWorker(sab);
if (!worker) {
throw new Error('failed to get new worker');
}
tid = PThread.markId(worker);
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
worker.postMessage(createMessage('start', {
tid,
arg: startArg,
sab
}));
if (shouldWait) {
if (typeof waitThreadStart === 'number') {
const waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
if (waitResult === 'timed-out') {
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
}
}
else {
Atomics.wait(sab, 0, 0);
}
const r = Atomics.load(sab, 0);
if (r > 1) {
throw deserizeErrorFromBuffer(sab.buffer);
}
}
}
catch (e) {
if (worker !== undefined && tid !== undefined) {
try {
PThread.cleanThread(worker, tid, true);
}
catch (_) { }
}
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
if (isNewABI) {
return 1;
}
free(errorOrTid);
return -EAGAIN;
}
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, tid);
Atomics.notify(struct, 1);
if (!shouldWait) {
worker.whenLoaded.catch((err) => {
delete worker.whenLoaded;
PThread.cleanThread(worker, tid, true);
throw err;
});
}
if (isNewABI) {
return 0;
}
free(errorOrTid);
return tid;
};
this.threadSpawn = threadSpawn;
if (this.PThread) {
this.PThread.threadSpawn = threadSpawn;
}
}
getImportObject() {
return {
wasi: {
'thread-spawn': this.threadSpawn
}
};
}
setup(wasmInstance, wasmModule, wasmMemory) {
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
this.wasmInstance = wasmInstance;
this.wasmMemory = wasmMemory;
if (this.PThread) {
this.PThread.setup(wasmModule, wasmMemory);
}
}
preloadWorkers() {
if (this.PThread) {
return this.PThread.preloadWorkers();
}
return Promise.resolve([]);
}
initialize(instance, module, memory) {
const exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
const wasi = this.wasi;
if (('_start' in exports) && (typeof exports._start === 'function')) {
if (this.childThread) {
wasi.start(instance);
try {
const kStarted = getWasiSymbol(wasi, 'kStarted');
wasi[kStarted] = false;
}
catch (_) { }
}
else {
setupInstance(wasi, instance);
}
}
else {
wasi.initialize(instance);
}
return instance;
}
start(instance, module, memory) {
const exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
const exitCode = this.wasi.start(instance);
return { exitCode, instance };
}
terminateAllThreads() {
var _a;
if (!this.childThread) {
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
}
else {
this.postMessage(createMessage('terminate-all-threads', {}));
}
}
}
function patchWasiInstance(wasiThreads, wasi) {
const patched = patchedWasiInstances.get(wasiThreads);
if (patched.has(wasi)) {
return;
}
const _this = wasiThreads;
const wasiImport = wasi.wasiImport;
if (wasiImport) {
const proc_exit = wasiImport.proc_exit;
wasiImport.proc_exit = function (code) {
_this.terminateAllThreads();
return proc_exit.call(this, code);
};
}
if (!_this.childThread) {
const start = wasi.start;
if (typeof start === 'function') {
wasi.start = function (instance) {
try {
return start.call(this, instance);
}
catch (err) {
if (isTrapError(err)) {
_this.terminateAllThreads();
}
throw err;
}
};
}
}
patched.add(wasi);
}
function getWasiSymbol(wasi, description) {
const symbols = Object.getOwnPropertySymbols(wasi);
const selectDescription = (description) => (s) => {
if (s.description) {
return s.description === description;
}
return s.toString() === `Symbol(${description})`;
};
if (Array.isArray(description)) {
return description.map(d => symbols.filter(selectDescription(d))[0]);
}
return symbols.filter(selectDescription(description))[0];
}
function setupInstance(wasi, instance) {
const [kInstance, kSetMemory] = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']);
wasi[kInstance] = instance;
wasi[kSetMemory](instance.exports.memory);
}
class ThreadMessageHandler {
constructor(options) {
const postMsg = getPostMessage(options);
if (typeof postMsg !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMsg;
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : (_type, err) => { throw err; };
this.instance = undefined;
this.messagesBeforeLoad = [];
}
instantiate(data) {
if (typeof this.onLoad === 'function') {
return this.onLoad(data);
}
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
}
handle(e) {
var _a;
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
const type = e.data.__emnapi__.type;
const payload = e.data.__emnapi__.payload;
try {
if (type === 'load') {
this._load(payload);
}
else if (type === 'start') {
this.handleAfterLoad(e, () => {
this._start(payload);
});
}
}
catch (err) {
this.onError(err, type);
}
}
}
_load(payload) {
if (this.instance !== undefined)
return;
let source;
try {
source = this.instantiate(payload);
}
catch (err) {
this._loaded(err, null, payload);
return;
}
const then = source && 'then' in source ? source.then : undefined;
if (typeof then === 'function') {
then.call(source, (source) => { this._loaded(null, source, payload); }, (err) => { this._loaded(err, null, payload); });
}
else {
this._loaded(null, source, payload);
}
}
_start(payload) {
const wasi_thread_start = this.instance.exports.wasi_thread_start;
if (typeof wasi_thread_start !== 'function') {
const err = new TypeError('wasi_thread_start is not exported');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
const postMessage = this.postMessage;
const tid = payload.tid;
const startArg = payload.arg;
notifyPthreadCreateResult(payload.sab, 1);
try {
wasi_thread_start(tid, startArg);
}
catch (err) {
if (err !== 'unwind') {
throw err;
}
else {
return;
}
}
postMessage(createMessage('cleanup-thread', { tid }));
}
_loaded(err, source, payload) {
if (err) {
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
if (source == null) {
const err = new TypeError('onLoad should return an object');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
const instance = source.instance;
if (!instance) {
const err = new TypeError('onLoad should return an object which includes "instance"');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
this.instance = instance;
const postMessage = this.postMessage;
postMessage(createMessage('loaded', {}));
const messages = this.messagesBeforeLoad;
this.messagesBeforeLoad = [];
for (let i = 0; i < messages.length; i++) {
const data = messages[i];
this.handle({ data });
}
}
handleAfterLoad(e, f) {
if (this.instance !== undefined) {
f.call(this, e);
}
else {
this.messagesBeforeLoad.push(e.data);
}
}
}
function notifyPthreadCreateResult(sab, result, error) {
if (sab) {
serizeErrorToBuffer(sab.buffer, result, error);
Atomics.notify(sab, 0);
}
}
exports.ThreadManager = ThreadManager;
exports.ThreadMessageHandler = ThreadMessageHandler;
exports.WASIThreads = WASIThreads;
exports.createInstanceProxy = createInstanceProxy;
exports.isSharedArrayBuffer = isSharedArrayBuffer;
exports.isTrapError = isTrapError;
@@ -0,0 +1,271 @@
/// <reference types="node" />
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
File diff suppressed because one or more lines are too long
@@ -0,0 +1,271 @@
/// <reference types="node" />
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
@@ -0,0 +1,273 @@
/// <reference types="node" />
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
export as namespace wasiThreads;
@@ -0,0 +1,933 @@
var _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
var ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
function getPostMessage(options) {
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
? options.postMessage
: typeof postMessage === 'function'
? postMessage
: undefined;
}
function serizeErrorToBuffer(sab, code, error) {
var i32array = new Int32Array(sab);
Atomics.store(i32array, 0, code);
if (code > 1 && error) {
var name_1 = error.name;
var message = error.message;
var stack = error.stack;
var nameBuffer = new TextEncoder().encode(name_1);
var messageBuffer = new TextEncoder().encode(message);
var stackBuffer = new TextEncoder().encode(stack);
Atomics.store(i32array, 1, nameBuffer.length);
Atomics.store(i32array, 2, messageBuffer.length);
Atomics.store(i32array, 3, stackBuffer.length);
var buffer = new Uint8Array(sab);
buffer.set(nameBuffer, 16);
buffer.set(messageBuffer, 16 + nameBuffer.length);
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
}
}
function deserizeErrorFromBuffer(sab) {
var _a, _b;
var i32array = new Int32Array(sab);
var status = Atomics.load(i32array, 0);
if (status <= 1) {
return null;
}
var nameLength = Atomics.load(i32array, 1);
var messageLength = Atomics.load(i32array, 2);
var stackLength = Atomics.load(i32array, 3);
var buffer = new Uint8Array(sab);
var nameBuffer = buffer.slice(16, 16 + nameLength);
var messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
var stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
var name = new TextDecoder().decode(nameBuffer);
var message = new TextDecoder().decode(messageBuffer);
var stack = new TextDecoder().decode(stackBuffer);
var ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
var error = new ErrorConstructor(message);
Object.defineProperty(error, 'stack', {
value: stack,
writable: true,
enumerable: false,
configurable: true
});
return error;
}
/** @public */
function isSharedArrayBuffer(value) {
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
}
/** @public */
function isTrapError(e) {
try {
return e instanceof _WebAssembly.RuntimeError;
}
catch (_) {
return false;
}
}
function createMessage(type, payload) {
return {
__emnapi__: {
type: type,
payload: payload
}
};
}
var WASI_THREADS_MAX_TID = 0x1FFFFFFF;
function checkSharedWasmMemory(wasmMemory) {
if (wasmMemory) {
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
throw new Error('Multithread features require shared wasm memory. ' +
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
'then create WebAssembly.Memory with `shared: true` option');
}
}
else {
if (typeof SharedArrayBuffer === 'undefined') {
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
}
}
}
function getReuseWorker(value) {
var _a;
if (typeof value === 'boolean') {
return value ? { size: 0, strict: false } : false;
}
if (typeof value === 'number') {
if (!(value >= 0)) {
throw new RangeError('reuseWorker: size must be a non-negative integer');
}
return { size: value, strict: false };
}
if (!value) {
return false;
}
var size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
var strict = Boolean(value.strict);
if (!(size > 0) && strict) {
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
}
return { size: size, strict: strict };
}
var nextWorkerID = 0;
/** @public */
var ThreadManager = /*#__PURE__*/ (function () {
function ThreadManager(options) {
var _a;
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.wasmModule = null;
this.wasmMemory = null;
this.messageEvents = new WeakMap();
if (!options) {
throw new TypeError('ThreadManager(): options is not provided');
}
if ('childThread' in options) {
this._childThread = Boolean(options.childThread);
}
else {
this._childThread = false;
}
if (this._childThread) {
this._onCreateWorker = undefined;
this._reuseWorker = false;
this._beforeLoad = undefined;
}
else {
this._onCreateWorker = options.onCreateWorker;
this._reuseWorker = getReuseWorker(options.reuseWorker);
this._beforeLoad = options.beforeLoad;
}
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
this.threadSpawn = options.threadSpawn;
}
Object.defineProperty(ThreadManager.prototype, "nextWorkerID", {
get: function () { return nextWorkerID; },
enumerable: false,
configurable: true
});
ThreadManager.prototype.init = function () {
if (!this._childThread) {
this.initMainThread();
}
};
ThreadManager.prototype.initMainThread = function () {
this.preparePool();
};
ThreadManager.prototype.preparePool = function () {
if (this._reuseWorker) {
if (this._reuseWorker.size) {
var pthreadPoolSize = this._reuseWorker.size;
while (pthreadPoolSize--) {
var worker = this.allocateUnusedWorker();
if (ENVIRONMENT_IS_NODE) {
// https://github.com/nodejs/node/issues/53036
worker.once('message', function () { });
worker.unref();
}
}
}
}
};
ThreadManager.prototype.shouldPreloadWorkers = function () {
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
};
ThreadManager.prototype.loadWasmModuleToAllWorkers = function () {
var _this_1 = this;
var promises = Array(this.unusedWorkers.length);
var _loop_1 = function (i) {
var worker = this_1.unusedWorkers[i];
if (ENVIRONMENT_IS_NODE)
worker.ref();
promises[i] = this_1.loadWasmModuleToWorker(worker).then(function (w) {
if (ENVIRONMENT_IS_NODE)
worker.unref();
return w;
}, function (e) {
if (ENVIRONMENT_IS_NODE)
worker.unref();
throw e;
});
};
var this_1 = this;
for (var i = 0; i < this.unusedWorkers.length; ++i) {
_loop_1(i);
}
return Promise.all(promises).catch(function (err) {
_this_1.terminateAllThreads();
throw err;
});
};
ThreadManager.prototype.preloadWorkers = function () {
if (this.shouldPreloadWorkers()) {
return this.loadWasmModuleToAllWorkers();
}
return Promise.resolve([]);
};
ThreadManager.prototype.setup = function (wasmModule, wasmMemory) {
this.wasmModule = wasmModule;
this.wasmMemory = wasmMemory;
};
ThreadManager.prototype.markId = function (worker) {
if (worker.__emnapi_tid)
return worker.__emnapi_tid;
var tid = nextWorkerID + 43;
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
this.pthreads[tid] = worker;
worker.__emnapi_tid = tid;
return tid;
};
ThreadManager.prototype.returnWorkerToPool = function (worker) {
var tid = worker.__emnapi_tid;
if (tid !== undefined) {
delete this.pthreads[tid];
}
this.unusedWorkers.push(worker);
delete worker.__emnapi_tid;
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
};
ThreadManager.prototype.loadWasmModuleToWorker = function (worker, sab) {
var _this_1 = this;
if (worker.whenLoaded)
return worker.whenLoaded;
var err = this.printErr;
var beforeLoad = this._beforeLoad;
// eslint-disable-next-line @typescript-eslint/no-this-alias
var _this = this;
worker.whenLoaded = new Promise(function (resolve, reject) {
var handleError = function (e) {
var message = 'worker sent an error!';
if (worker.__emnapi_tid !== undefined) {
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
}
if ('message' in e) {
err(message + ' ' + e.message);
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
try {
_this.terminateAllThreads();
}
catch (_) { }
}
}
else {
err(message);
}
reject(e);
throw e;
};
var handleMessage = function (data) {
if (data.__emnapi__) {
var type = data.__emnapi__.type;
var payload = data.__emnapi__.payload;
if (type === 'loaded') {
worker.loaded = true;
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
worker.unref();
}
resolve(worker);
// if (payload.err) {
// err('failed to load in child thread: ' + (payload.err.message || payload.err))
// }
}
else if (type === 'cleanup-thread') {
if (payload.tid in _this_1.pthreads) {
_this_1.cleanThread(worker, payload.tid);
}
}
else if (type === 'spawn-thread') {
_this_1.threadSpawn(payload.startArg, payload.errorOrTid);
}
else if (type === 'terminate-all-threads') {
_this_1.terminateAllThreads();
}
}
};
worker.onmessage = function (e) {
handleMessage(e.data);
_this_1.fireMessageEvent(worker, e);
};
worker.onerror = handleError;
if (ENVIRONMENT_IS_NODE) {
worker.on('message', function (data) {
var _a, _b;
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
data: data
});
});
worker.on('error', function (e) {
var _a, _b;
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
});
worker.on('detachedExit', function () { });
}
if (typeof beforeLoad === 'function') {
beforeLoad(worker);
}
try {
worker.postMessage(createMessage('load', {
wasmModule: _this_1.wasmModule,
wasmMemory: _this_1.wasmMemory,
sab: sab
}));
}
catch (err) {
checkSharedWasmMemory(_this_1.wasmMemory);
throw err;
}
});
return worker.whenLoaded;
};
ThreadManager.prototype.allocateUnusedWorker = function () {
var _onCreateWorker = this._onCreateWorker;
if (typeof _onCreateWorker !== 'function') {
throw new TypeError('`options.onCreateWorker` is not provided');
}
var worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
this.unusedWorkers.push(worker);
return worker;
};
ThreadManager.prototype.getNewWorker = function (sab) {
if (this._reuseWorker) {
if (this.unusedWorkers.length === 0) {
if (this._reuseWorker.strict) {
if (!ENVIRONMENT_IS_NODE) {
var err = this.printErr;
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
return;
}
}
var worker_1 = this.allocateUnusedWorker();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.loadWasmModuleToWorker(worker_1, sab);
}
return this.unusedWorkers.pop();
}
var worker = this.allocateUnusedWorker();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.loadWasmModuleToWorker(worker, sab);
return this.unusedWorkers.pop();
};
ThreadManager.prototype.cleanThread = function (worker, tid, force) {
if (!force && this._reuseWorker) {
this.returnWorkerToPool(worker);
}
else {
delete this.pthreads[tid];
this.terminateWorker(worker);
delete worker.__emnapi_tid;
}
};
ThreadManager.prototype.terminateWorker = function (worker) {
var _this_1 = this;
var _a;
var tid = worker.__emnapi_tid;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
worker.terminate();
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
this.messageEvents.delete(worker);
worker.onmessage = function (e) {
if (e.data.__emnapi__) {
var err = _this_1.printErr;
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
}
};
};
ThreadManager.prototype.terminateAllThreads = function () {
var runningWorkers = Object.values(this.pthreads);
for (var i = 0; i < runningWorkers.length; ++i) {
this.terminateWorker(runningWorkers[i]);
}
for (var i = 0; i < this.unusedWorkers.length; ++i) {
this.terminateWorker(this.unusedWorkers[i]);
}
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.preparePool();
};
ThreadManager.prototype.addMessageEventListener = function (worker, onMessage) {
var listeners = this.messageEvents.get(worker);
if (!listeners) {
listeners = new Set();
this.messageEvents.set(worker, listeners);
}
listeners.add(onMessage);
return function () {
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
};
};
ThreadManager.prototype.fireMessageEvent = function (worker, e) {
var listeners = this.messageEvents.get(worker);
if (!listeners)
return;
var err = this.printErr;
listeners.forEach(function (listener) {
try {
listener(e);
}
catch (e) {
err(e.stack);
}
});
};
return ThreadManager;
}());
var kIsProxy = Symbol('kIsProxy');
/** @public */
function createInstanceProxy(instance, memory) {
if (instance[kIsProxy])
return instance;
// https://github.com/nodejs/help/issues/4102
var originalExports = instance.exports;
var createHandler = function (target) {
var handlers = [
'apply',
'construct',
'defineProperty',
'deleteProperty',
'get',
'getOwnPropertyDescriptor',
'getPrototypeOf',
'has',
'isExtensible',
'ownKeys',
'preventExtensions',
'set',
'setPrototypeOf'
];
var handler = {};
var _loop_1 = function (i) {
var name_1 = handlers[i];
handler[name_1] = function () {
var args = Array.prototype.slice.call(arguments, 1);
args.unshift(target);
return Reflect[name_1].apply(Reflect, args);
};
};
for (var i = 0; i < handlers.length; i++) {
_loop_1(i);
}
return handler;
};
var handler = createHandler(originalExports);
var _initialize = function () { };
var _start = function () { return 0; };
handler.get = function (_target, p, receiver) {
var _a;
if (p === 'memory') {
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
}
if (p === '_initialize') {
return p in originalExports ? _initialize : undefined;
}
if (p === '_start') {
return p in originalExports ? _start : undefined;
}
return Reflect.get(originalExports, p, receiver);
};
handler.has = function (_target, p) {
if (p === 'memory')
return true;
return Reflect.has(originalExports, p);
};
var exportsProxy = new Proxy(Object.create(null), handler);
return new Proxy(instance, {
get: function (target, p, receiver) {
if (p === 'exports') {
return exportsProxy;
}
if (p === kIsProxy) {
return true;
}
return Reflect.get(target, p, receiver);
}
});
}
var patchedWasiInstances = new WeakMap();
/** @public */
var WASIThreads = /*#__PURE__*/ (function () {
function WASIThreads(options) {
var _this_1 = this;
if (!options) {
throw new TypeError('WASIThreads(): options is not provided');
}
if (!options.wasi) {
throw new TypeError('WASIThreads(): options.wasi is not provided');
}
patchedWasiInstances.set(this, new WeakSet());
var wasi = options.wasi;
patchWasiInstance(this, wasi);
this.wasi = wasi;
if ('childThread' in options) {
this.childThread = Boolean(options.childThread);
}
else {
this.childThread = false;
}
this.PThread = undefined;
if ('threadManager' in options) {
if (typeof options.threadManager === 'function') {
this.PThread = options.threadManager();
}
else {
this.PThread = options.threadManager;
}
}
else {
if (!this.childThread) {
this.PThread = new ThreadManager(options);
this.PThread.init();
}
}
var waitThreadStart = false;
if ('waitThreadStart' in options) {
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
}
var postMessage = getPostMessage(options);
if (this.childThread && typeof postMessage !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMessage;
var wasm64 = Boolean(options.wasm64);
var threadSpawn = function (startArg, errorOrTid) {
var _a;
var EAGAIN = 6;
var isNewABI = errorOrTid !== undefined;
try {
checkSharedWasmMemory(_this_1.wasmMemory);
}
catch (err) {
(_a = _this_1.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
if (isNewABI) {
var struct_1 = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct_1, 0, 1);
Atomics.store(struct_1, 1, EAGAIN);
Atomics.notify(struct_1, 1);
return 1;
}
else {
return -EAGAIN;
}
}
if (!isNewABI) {
var malloc = _this_1.wasmInstance.exports.malloc;
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
if (!errorOrTid) {
return -48; /* ENOMEM */
}
}
var _free = _this_1.wasmInstance.exports.free;
var free = wasm64 ? function (ptr) { _free(BigInt(ptr)); } : _free;
var struct = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, 0);
if (_this_1.childThread) {
postMessage(createMessage('spawn-thread', {
startArg: startArg,
errorOrTid: errorOrTid
}));
Atomics.wait(struct, 1, 0);
var isError = Atomics.load(struct, 0);
var result = Atomics.load(struct, 1);
if (isNewABI) {
return isError;
}
free(errorOrTid);
return isError ? -result : result;
}
var shouldWait = waitThreadStart || (waitThreadStart === 0);
var sab;
if (shouldWait) {
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
Atomics.store(sab, 0, 0);
}
var worker;
var tid;
var PThread = _this_1.PThread;
try {
worker = PThread.getNewWorker(sab);
if (!worker) {
throw new Error('failed to get new worker');
}
tid = PThread.markId(worker);
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
worker.postMessage(createMessage('start', {
tid: tid,
arg: startArg,
sab: sab
}));
if (shouldWait) {
if (typeof waitThreadStart === 'number') {
var waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
if (waitResult === 'timed-out') {
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
}
}
else {
Atomics.wait(sab, 0, 0);
}
var r = Atomics.load(sab, 0);
if (r > 1) {
throw deserizeErrorFromBuffer(sab.buffer);
}
}
}
catch (e) {
if (worker !== undefined && tid !== undefined) {
try {
PThread.cleanThread(worker, tid, true);
}
catch (_) { }
}
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
if (isNewABI) {
return 1;
}
free(errorOrTid);
return -EAGAIN;
}
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, tid);
Atomics.notify(struct, 1);
if (!shouldWait) {
worker.whenLoaded.catch(function (err) {
delete worker.whenLoaded;
PThread.cleanThread(worker, tid, true);
throw err;
});
}
if (isNewABI) {
return 0;
}
free(errorOrTid);
return tid;
};
this.threadSpawn = threadSpawn;
if (this.PThread) {
this.PThread.threadSpawn = threadSpawn;
}
}
WASIThreads.prototype.getImportObject = function () {
return {
wasi: {
'thread-spawn': this.threadSpawn
}
};
};
WASIThreads.prototype.setup = function (wasmInstance, wasmModule, wasmMemory) {
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
this.wasmInstance = wasmInstance;
this.wasmMemory = wasmMemory;
if (this.PThread) {
this.PThread.setup(wasmModule, wasmMemory);
}
};
WASIThreads.prototype.preloadWorkers = function () {
if (this.PThread) {
return this.PThread.preloadWorkers();
}
return Promise.resolve([]);
};
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
WASIThreads.prototype.initialize = function (instance, module, memory) {
var exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
var wasi = this.wasi;
if (('_start' in exports) && (typeof exports._start === 'function')) {
if (this.childThread) {
wasi.start(instance);
try {
var kStarted = getWasiSymbol(wasi, 'kStarted');
wasi[kStarted] = false;
}
catch (_) { }
}
else {
setupInstance(wasi, instance);
}
}
else {
wasi.initialize(instance);
}
return instance;
};
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
WASIThreads.prototype.start = function (instance, module, memory) {
var exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
var exitCode = this.wasi.start(instance);
return { exitCode: exitCode, instance: instance };
};
WASIThreads.prototype.terminateAllThreads = function () {
var _a;
if (!this.childThread) {
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
}
else {
this.postMessage(createMessage('terminate-all-threads', {}));
}
};
return WASIThreads;
}());
function patchWasiInstance(wasiThreads, wasi) {
var patched = patchedWasiInstances.get(wasiThreads);
if (patched.has(wasi)) {
return;
}
var _this = wasiThreads;
var wasiImport = wasi.wasiImport;
if (wasiImport) {
var proc_exit_1 = wasiImport.proc_exit;
wasiImport.proc_exit = function (code) {
_this.terminateAllThreads();
return proc_exit_1.call(this, code);
};
}
if (!_this.childThread) {
var start_1 = wasi.start;
if (typeof start_1 === 'function') {
wasi.start = function (instance) {
try {
return start_1.call(this, instance);
}
catch (err) {
if (isTrapError(err)) {
_this.terminateAllThreads();
}
throw err;
}
};
}
}
patched.add(wasi);
}
function getWasiSymbol(wasi, description) {
var symbols = Object.getOwnPropertySymbols(wasi);
var selectDescription = function (description) { return function (s) {
if (s.description) {
return s.description === description;
}
return s.toString() === "Symbol(".concat(description, ")");
}; };
if (Array.isArray(description)) {
return description.map(function (d) { return symbols.filter(selectDescription(d))[0]; });
}
return symbols.filter(selectDescription(description))[0];
}
function setupInstance(wasi, instance) {
var _a = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']), kInstance = _a[0], kSetMemory = _a[1];
wasi[kInstance] = instance;
wasi[kSetMemory](instance.exports.memory);
}
/** @public */
var ThreadMessageHandler = /*#__PURE__*/ (function () {
function ThreadMessageHandler(options) {
var postMsg = getPostMessage(options);
if (typeof postMsg !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMsg;
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : function (_type, err) { throw err; };
this.instance = undefined;
// this.module = undefined
this.messagesBeforeLoad = [];
}
/** @virtual */
ThreadMessageHandler.prototype.instantiate = function (data) {
if (typeof this.onLoad === 'function') {
return this.onLoad(data);
}
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
};
/** @virtual */
ThreadMessageHandler.prototype.handle = function (e) {
var _this = this;
var _a;
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
var type = e.data.__emnapi__.type;
var payload_1 = e.data.__emnapi__.payload;
try {
if (type === 'load') {
this._load(payload_1);
}
else if (type === 'start') {
this.handleAfterLoad(e, function () {
_this._start(payload_1);
});
}
}
catch (err) {
this.onError(err, type);
}
}
};
ThreadMessageHandler.prototype._load = function (payload) {
var _this = this;
if (this.instance !== undefined)
return;
var source;
try {
source = this.instantiate(payload);
}
catch (err) {
this._loaded(err, null, payload);
return;
}
var then = source && 'then' in source ? source.then : undefined;
if (typeof then === 'function') {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
then.call(source, function (source) { _this._loaded(null, source, payload); }, function (err) { _this._loaded(err, null, payload); });
}
else {
this._loaded(null, source, payload);
}
};
ThreadMessageHandler.prototype._start = function (payload) {
var wasi_thread_start = this.instance.exports.wasi_thread_start;
if (typeof wasi_thread_start !== 'function') {
var err = new TypeError('wasi_thread_start is not exported');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
var postMessage = this.postMessage;
var tid = payload.tid;
var startArg = payload.arg;
notifyPthreadCreateResult(payload.sab, 1);
try {
wasi_thread_start(tid, startArg);
}
catch (err) {
if (err !== 'unwind') {
throw err;
}
else {
return;
}
}
postMessage(createMessage('cleanup-thread', { tid: tid }));
};
ThreadMessageHandler.prototype._loaded = function (err, source, payload) {
if (err) {
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
if (source == null) {
var err_1 = new TypeError('onLoad should return an object');
notifyPthreadCreateResult(payload.sab, 2, err_1);
throw err_1;
}
var instance = source.instance;
if (!instance) {
var err_2 = new TypeError('onLoad should return an object which includes "instance"');
notifyPthreadCreateResult(payload.sab, 2, err_2);
throw err_2;
}
this.instance = instance;
var postMessage = this.postMessage;
postMessage(createMessage('loaded', {}));
var messages = this.messagesBeforeLoad;
this.messagesBeforeLoad = [];
for (var i = 0; i < messages.length; i++) {
var data = messages[i];
this.handle({ data: data });
}
};
ThreadMessageHandler.prototype.handleAfterLoad = function (e, f) {
if (this.instance !== undefined) {
f.call(this, e);
}
else {
this.messagesBeforeLoad.push(e.data);
}
};
return ThreadMessageHandler;
}());
function notifyPthreadCreateResult(sab, result, error) {
if (sab) {
serizeErrorToBuffer(sab.buffer, result, error);
Atomics.notify(sab, 0);
}
}
export { ThreadManager, ThreadMessageHandler, WASIThreads, createInstanceProxy, isSharedArrayBuffer, isTrapError };
@@ -0,0 +1,945 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.wasiThreads = {}));
})(this, (function (exports) {
var _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
var ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
function getPostMessage(options) {
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
? options.postMessage
: typeof postMessage === 'function'
? postMessage
: undefined;
}
function serizeErrorToBuffer(sab, code, error) {
var i32array = new Int32Array(sab);
Atomics.store(i32array, 0, code);
if (code > 1 && error) {
var name_1 = error.name;
var message = error.message;
var stack = error.stack;
var nameBuffer = new TextEncoder().encode(name_1);
var messageBuffer = new TextEncoder().encode(message);
var stackBuffer = new TextEncoder().encode(stack);
Atomics.store(i32array, 1, nameBuffer.length);
Atomics.store(i32array, 2, messageBuffer.length);
Atomics.store(i32array, 3, stackBuffer.length);
var buffer = new Uint8Array(sab);
buffer.set(nameBuffer, 16);
buffer.set(messageBuffer, 16 + nameBuffer.length);
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
}
}
function deserizeErrorFromBuffer(sab) {
var _a, _b;
var i32array = new Int32Array(sab);
var status = Atomics.load(i32array, 0);
if (status <= 1) {
return null;
}
var nameLength = Atomics.load(i32array, 1);
var messageLength = Atomics.load(i32array, 2);
var stackLength = Atomics.load(i32array, 3);
var buffer = new Uint8Array(sab);
var nameBuffer = buffer.slice(16, 16 + nameLength);
var messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
var stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
var name = new TextDecoder().decode(nameBuffer);
var message = new TextDecoder().decode(messageBuffer);
var stack = new TextDecoder().decode(stackBuffer);
var ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
var error = new ErrorConstructor(message);
Object.defineProperty(error, 'stack', {
value: stack,
writable: true,
enumerable: false,
configurable: true
});
return error;
}
/** @public */
function isSharedArrayBuffer(value) {
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
}
/** @public */
function isTrapError(e) {
try {
return e instanceof _WebAssembly.RuntimeError;
}
catch (_) {
return false;
}
}
function createMessage(type, payload) {
return {
__emnapi__: {
type: type,
payload: payload
}
};
}
var WASI_THREADS_MAX_TID = 0x1FFFFFFF;
function checkSharedWasmMemory(wasmMemory) {
if (wasmMemory) {
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
throw new Error('Multithread features require shared wasm memory. ' +
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
'then create WebAssembly.Memory with `shared: true` option');
}
}
else {
if (typeof SharedArrayBuffer === 'undefined') {
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
}
}
}
function getReuseWorker(value) {
var _a;
if (typeof value === 'boolean') {
return value ? { size: 0, strict: false } : false;
}
if (typeof value === 'number') {
if (!(value >= 0)) {
throw new RangeError('reuseWorker: size must be a non-negative integer');
}
return { size: value, strict: false };
}
if (!value) {
return false;
}
var size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
var strict = Boolean(value.strict);
if (!(size > 0) && strict) {
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
}
return { size: size, strict: strict };
}
var nextWorkerID = 0;
/** @public */
var ThreadManager = /*#__PURE__*/ (function () {
function ThreadManager(options) {
var _a;
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.wasmModule = null;
this.wasmMemory = null;
this.messageEvents = new WeakMap();
if (!options) {
throw new TypeError('ThreadManager(): options is not provided');
}
if ('childThread' in options) {
this._childThread = Boolean(options.childThread);
}
else {
this._childThread = false;
}
if (this._childThread) {
this._onCreateWorker = undefined;
this._reuseWorker = false;
this._beforeLoad = undefined;
}
else {
this._onCreateWorker = options.onCreateWorker;
this._reuseWorker = getReuseWorker(options.reuseWorker);
this._beforeLoad = options.beforeLoad;
}
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
this.threadSpawn = options.threadSpawn;
}
Object.defineProperty(ThreadManager.prototype, "nextWorkerID", {
get: function () { return nextWorkerID; },
enumerable: false,
configurable: true
});
ThreadManager.prototype.init = function () {
if (!this._childThread) {
this.initMainThread();
}
};
ThreadManager.prototype.initMainThread = function () {
this.preparePool();
};
ThreadManager.prototype.preparePool = function () {
if (this._reuseWorker) {
if (this._reuseWorker.size) {
var pthreadPoolSize = this._reuseWorker.size;
while (pthreadPoolSize--) {
var worker = this.allocateUnusedWorker();
if (ENVIRONMENT_IS_NODE) {
// https://github.com/nodejs/node/issues/53036
worker.once('message', function () { });
worker.unref();
}
}
}
}
};
ThreadManager.prototype.shouldPreloadWorkers = function () {
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
};
ThreadManager.prototype.loadWasmModuleToAllWorkers = function () {
var _this_1 = this;
var promises = Array(this.unusedWorkers.length);
var _loop_1 = function (i) {
var worker = this_1.unusedWorkers[i];
if (ENVIRONMENT_IS_NODE)
worker.ref();
promises[i] = this_1.loadWasmModuleToWorker(worker).then(function (w) {
if (ENVIRONMENT_IS_NODE)
worker.unref();
return w;
}, function (e) {
if (ENVIRONMENT_IS_NODE)
worker.unref();
throw e;
});
};
var this_1 = this;
for (var i = 0; i < this.unusedWorkers.length; ++i) {
_loop_1(i);
}
return Promise.all(promises).catch(function (err) {
_this_1.terminateAllThreads();
throw err;
});
};
ThreadManager.prototype.preloadWorkers = function () {
if (this.shouldPreloadWorkers()) {
return this.loadWasmModuleToAllWorkers();
}
return Promise.resolve([]);
};
ThreadManager.prototype.setup = function (wasmModule, wasmMemory) {
this.wasmModule = wasmModule;
this.wasmMemory = wasmMemory;
};
ThreadManager.prototype.markId = function (worker) {
if (worker.__emnapi_tid)
return worker.__emnapi_tid;
var tid = nextWorkerID + 43;
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
this.pthreads[tid] = worker;
worker.__emnapi_tid = tid;
return tid;
};
ThreadManager.prototype.returnWorkerToPool = function (worker) {
var tid = worker.__emnapi_tid;
if (tid !== undefined) {
delete this.pthreads[tid];
}
this.unusedWorkers.push(worker);
delete worker.__emnapi_tid;
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
};
ThreadManager.prototype.loadWasmModuleToWorker = function (worker, sab) {
var _this_1 = this;
if (worker.whenLoaded)
return worker.whenLoaded;
var err = this.printErr;
var beforeLoad = this._beforeLoad;
// eslint-disable-next-line @typescript-eslint/no-this-alias
var _this = this;
worker.whenLoaded = new Promise(function (resolve, reject) {
var handleError = function (e) {
var message = 'worker sent an error!';
if (worker.__emnapi_tid !== undefined) {
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
}
if ('message' in e) {
err(message + ' ' + e.message);
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
try {
_this.terminateAllThreads();
}
catch (_) { }
}
}
else {
err(message);
}
reject(e);
throw e;
};
var handleMessage = function (data) {
if (data.__emnapi__) {
var type = data.__emnapi__.type;
var payload = data.__emnapi__.payload;
if (type === 'loaded') {
worker.loaded = true;
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
worker.unref();
}
resolve(worker);
// if (payload.err) {
// err('failed to load in child thread: ' + (payload.err.message || payload.err))
// }
}
else if (type === 'cleanup-thread') {
if (payload.tid in _this_1.pthreads) {
_this_1.cleanThread(worker, payload.tid);
}
}
else if (type === 'spawn-thread') {
_this_1.threadSpawn(payload.startArg, payload.errorOrTid);
}
else if (type === 'terminate-all-threads') {
_this_1.terminateAllThreads();
}
}
};
worker.onmessage = function (e) {
handleMessage(e.data);
_this_1.fireMessageEvent(worker, e);
};
worker.onerror = handleError;
if (ENVIRONMENT_IS_NODE) {
worker.on('message', function (data) {
var _a, _b;
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
data: data
});
});
worker.on('error', function (e) {
var _a, _b;
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
});
worker.on('detachedExit', function () { });
}
if (typeof beforeLoad === 'function') {
beforeLoad(worker);
}
try {
worker.postMessage(createMessage('load', {
wasmModule: _this_1.wasmModule,
wasmMemory: _this_1.wasmMemory,
sab: sab
}));
}
catch (err) {
checkSharedWasmMemory(_this_1.wasmMemory);
throw err;
}
});
return worker.whenLoaded;
};
ThreadManager.prototype.allocateUnusedWorker = function () {
var _onCreateWorker = this._onCreateWorker;
if (typeof _onCreateWorker !== 'function') {
throw new TypeError('`options.onCreateWorker` is not provided');
}
var worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
this.unusedWorkers.push(worker);
return worker;
};
ThreadManager.prototype.getNewWorker = function (sab) {
if (this._reuseWorker) {
if (this.unusedWorkers.length === 0) {
if (this._reuseWorker.strict) {
if (!ENVIRONMENT_IS_NODE) {
var err = this.printErr;
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
return;
}
}
var worker_1 = this.allocateUnusedWorker();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.loadWasmModuleToWorker(worker_1, sab);
}
return this.unusedWorkers.pop();
}
var worker = this.allocateUnusedWorker();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.loadWasmModuleToWorker(worker, sab);
return this.unusedWorkers.pop();
};
ThreadManager.prototype.cleanThread = function (worker, tid, force) {
if (!force && this._reuseWorker) {
this.returnWorkerToPool(worker);
}
else {
delete this.pthreads[tid];
this.terminateWorker(worker);
delete worker.__emnapi_tid;
}
};
ThreadManager.prototype.terminateWorker = function (worker) {
var _this_1 = this;
var _a;
var tid = worker.__emnapi_tid;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
worker.terminate();
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
this.messageEvents.delete(worker);
worker.onmessage = function (e) {
if (e.data.__emnapi__) {
var err = _this_1.printErr;
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
}
};
};
ThreadManager.prototype.terminateAllThreads = function () {
var runningWorkers = Object.values(this.pthreads);
for (var i = 0; i < runningWorkers.length; ++i) {
this.terminateWorker(runningWorkers[i]);
}
for (var i = 0; i < this.unusedWorkers.length; ++i) {
this.terminateWorker(this.unusedWorkers[i]);
}
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.preparePool();
};
ThreadManager.prototype.addMessageEventListener = function (worker, onMessage) {
var listeners = this.messageEvents.get(worker);
if (!listeners) {
listeners = new Set();
this.messageEvents.set(worker, listeners);
}
listeners.add(onMessage);
return function () {
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
};
};
ThreadManager.prototype.fireMessageEvent = function (worker, e) {
var listeners = this.messageEvents.get(worker);
if (!listeners)
return;
var err = this.printErr;
listeners.forEach(function (listener) {
try {
listener(e);
}
catch (e) {
err(e.stack);
}
});
};
return ThreadManager;
}());
var kIsProxy = Symbol('kIsProxy');
/** @public */
function createInstanceProxy(instance, memory) {
if (instance[kIsProxy])
return instance;
// https://github.com/nodejs/help/issues/4102
var originalExports = instance.exports;
var createHandler = function (target) {
var handlers = [
'apply',
'construct',
'defineProperty',
'deleteProperty',
'get',
'getOwnPropertyDescriptor',
'getPrototypeOf',
'has',
'isExtensible',
'ownKeys',
'preventExtensions',
'set',
'setPrototypeOf'
];
var handler = {};
var _loop_1 = function (i) {
var name_1 = handlers[i];
handler[name_1] = function () {
var args = Array.prototype.slice.call(arguments, 1);
args.unshift(target);
return Reflect[name_1].apply(Reflect, args);
};
};
for (var i = 0; i < handlers.length; i++) {
_loop_1(i);
}
return handler;
};
var handler = createHandler(originalExports);
var _initialize = function () { };
var _start = function () { return 0; };
handler.get = function (_target, p, receiver) {
var _a;
if (p === 'memory') {
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
}
if (p === '_initialize') {
return p in originalExports ? _initialize : undefined;
}
if (p === '_start') {
return p in originalExports ? _start : undefined;
}
return Reflect.get(originalExports, p, receiver);
};
handler.has = function (_target, p) {
if (p === 'memory')
return true;
return Reflect.has(originalExports, p);
};
var exportsProxy = new Proxy(Object.create(null), handler);
return new Proxy(instance, {
get: function (target, p, receiver) {
if (p === 'exports') {
return exportsProxy;
}
if (p === kIsProxy) {
return true;
}
return Reflect.get(target, p, receiver);
}
});
}
var patchedWasiInstances = new WeakMap();
/** @public */
var WASIThreads = /*#__PURE__*/ (function () {
function WASIThreads(options) {
var _this_1 = this;
if (!options) {
throw new TypeError('WASIThreads(): options is not provided');
}
if (!options.wasi) {
throw new TypeError('WASIThreads(): options.wasi is not provided');
}
patchedWasiInstances.set(this, new WeakSet());
var wasi = options.wasi;
patchWasiInstance(this, wasi);
this.wasi = wasi;
if ('childThread' in options) {
this.childThread = Boolean(options.childThread);
}
else {
this.childThread = false;
}
this.PThread = undefined;
if ('threadManager' in options) {
if (typeof options.threadManager === 'function') {
this.PThread = options.threadManager();
}
else {
this.PThread = options.threadManager;
}
}
else {
if (!this.childThread) {
this.PThread = new ThreadManager(options);
this.PThread.init();
}
}
var waitThreadStart = false;
if ('waitThreadStart' in options) {
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
}
var postMessage = getPostMessage(options);
if (this.childThread && typeof postMessage !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMessage;
var wasm64 = Boolean(options.wasm64);
var threadSpawn = function (startArg, errorOrTid) {
var _a;
var EAGAIN = 6;
var isNewABI = errorOrTid !== undefined;
try {
checkSharedWasmMemory(_this_1.wasmMemory);
}
catch (err) {
(_a = _this_1.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
if (isNewABI) {
var struct_1 = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct_1, 0, 1);
Atomics.store(struct_1, 1, EAGAIN);
Atomics.notify(struct_1, 1);
return 1;
}
else {
return -EAGAIN;
}
}
if (!isNewABI) {
var malloc = _this_1.wasmInstance.exports.malloc;
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
if (!errorOrTid) {
return -48; /* ENOMEM */
}
}
var _free = _this_1.wasmInstance.exports.free;
var free = wasm64 ? function (ptr) { _free(BigInt(ptr)); } : _free;
var struct = new Int32Array(_this_1.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, 0);
if (_this_1.childThread) {
postMessage(createMessage('spawn-thread', {
startArg: startArg,
errorOrTid: errorOrTid
}));
Atomics.wait(struct, 1, 0);
var isError = Atomics.load(struct, 0);
var result = Atomics.load(struct, 1);
if (isNewABI) {
return isError;
}
free(errorOrTid);
return isError ? -result : result;
}
var shouldWait = waitThreadStart || (waitThreadStart === 0);
var sab;
if (shouldWait) {
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
Atomics.store(sab, 0, 0);
}
var worker;
var tid;
var PThread = _this_1.PThread;
try {
worker = PThread.getNewWorker(sab);
if (!worker) {
throw new Error('failed to get new worker');
}
tid = PThread.markId(worker);
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
worker.postMessage(createMessage('start', {
tid: tid,
arg: startArg,
sab: sab
}));
if (shouldWait) {
if (typeof waitThreadStart === 'number') {
var waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
if (waitResult === 'timed-out') {
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
}
}
else {
Atomics.wait(sab, 0, 0);
}
var r = Atomics.load(sab, 0);
if (r > 1) {
throw deserizeErrorFromBuffer(sab.buffer);
}
}
}
catch (e) {
if (worker !== undefined && tid !== undefined) {
try {
PThread.cleanThread(worker, tid, true);
}
catch (_) { }
}
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
if (isNewABI) {
return 1;
}
free(errorOrTid);
return -EAGAIN;
}
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, tid);
Atomics.notify(struct, 1);
if (!shouldWait) {
worker.whenLoaded.catch(function (err) {
delete worker.whenLoaded;
PThread.cleanThread(worker, tid, true);
throw err;
});
}
if (isNewABI) {
return 0;
}
free(errorOrTid);
return tid;
};
this.threadSpawn = threadSpawn;
if (this.PThread) {
this.PThread.threadSpawn = threadSpawn;
}
}
WASIThreads.prototype.getImportObject = function () {
return {
wasi: {
'thread-spawn': this.threadSpawn
}
};
};
WASIThreads.prototype.setup = function (wasmInstance, wasmModule, wasmMemory) {
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
this.wasmInstance = wasmInstance;
this.wasmMemory = wasmMemory;
if (this.PThread) {
this.PThread.setup(wasmModule, wasmMemory);
}
};
WASIThreads.prototype.preloadWorkers = function () {
if (this.PThread) {
return this.PThread.preloadWorkers();
}
return Promise.resolve([]);
};
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
WASIThreads.prototype.initialize = function (instance, module, memory) {
var exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
var wasi = this.wasi;
if (('_start' in exports) && (typeof exports._start === 'function')) {
if (this.childThread) {
wasi.start(instance);
try {
var kStarted = getWasiSymbol(wasi, 'kStarted');
wasi[kStarted] = false;
}
catch (_) { }
}
else {
setupInstance(wasi, instance);
}
}
else {
wasi.initialize(instance);
}
return instance;
};
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
WASIThreads.prototype.start = function (instance, module, memory) {
var exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
var exitCode = this.wasi.start(instance);
return { exitCode: exitCode, instance: instance };
};
WASIThreads.prototype.terminateAllThreads = function () {
var _a;
if (!this.childThread) {
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
}
else {
this.postMessage(createMessage('terminate-all-threads', {}));
}
};
return WASIThreads;
}());
function patchWasiInstance(wasiThreads, wasi) {
var patched = patchedWasiInstances.get(wasiThreads);
if (patched.has(wasi)) {
return;
}
var _this = wasiThreads;
var wasiImport = wasi.wasiImport;
if (wasiImport) {
var proc_exit_1 = wasiImport.proc_exit;
wasiImport.proc_exit = function (code) {
_this.terminateAllThreads();
return proc_exit_1.call(this, code);
};
}
if (!_this.childThread) {
var start_1 = wasi.start;
if (typeof start_1 === 'function') {
wasi.start = function (instance) {
try {
return start_1.call(this, instance);
}
catch (err) {
if (isTrapError(err)) {
_this.terminateAllThreads();
}
throw err;
}
};
}
}
patched.add(wasi);
}
function getWasiSymbol(wasi, description) {
var symbols = Object.getOwnPropertySymbols(wasi);
var selectDescription = function (description) { return function (s) {
if (s.description) {
return s.description === description;
}
return s.toString() === "Symbol(".concat(description, ")");
}; };
if (Array.isArray(description)) {
return description.map(function (d) { return symbols.filter(selectDescription(d))[0]; });
}
return symbols.filter(selectDescription(description))[0];
}
function setupInstance(wasi, instance) {
var _a = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']), kInstance = _a[0], kSetMemory = _a[1];
wasi[kInstance] = instance;
wasi[kSetMemory](instance.exports.memory);
}
/** @public */
var ThreadMessageHandler = /*#__PURE__*/ (function () {
function ThreadMessageHandler(options) {
var postMsg = getPostMessage(options);
if (typeof postMsg !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMsg;
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : function (_type, err) { throw err; };
this.instance = undefined;
// this.module = undefined
this.messagesBeforeLoad = [];
}
/** @virtual */
ThreadMessageHandler.prototype.instantiate = function (data) {
if (typeof this.onLoad === 'function') {
return this.onLoad(data);
}
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
};
/** @virtual */
ThreadMessageHandler.prototype.handle = function (e) {
var _this = this;
var _a;
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
var type = e.data.__emnapi__.type;
var payload_1 = e.data.__emnapi__.payload;
try {
if (type === 'load') {
this._load(payload_1);
}
else if (type === 'start') {
this.handleAfterLoad(e, function () {
_this._start(payload_1);
});
}
}
catch (err) {
this.onError(err, type);
}
}
};
ThreadMessageHandler.prototype._load = function (payload) {
var _this = this;
if (this.instance !== undefined)
return;
var source;
try {
source = this.instantiate(payload);
}
catch (err) {
this._loaded(err, null, payload);
return;
}
var then = source && 'then' in source ? source.then : undefined;
if (typeof then === 'function') {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
then.call(source, function (source) { _this._loaded(null, source, payload); }, function (err) { _this._loaded(err, null, payload); });
}
else {
this._loaded(null, source, payload);
}
};
ThreadMessageHandler.prototype._start = function (payload) {
var wasi_thread_start = this.instance.exports.wasi_thread_start;
if (typeof wasi_thread_start !== 'function') {
var err = new TypeError('wasi_thread_start is not exported');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
var postMessage = this.postMessage;
var tid = payload.tid;
var startArg = payload.arg;
notifyPthreadCreateResult(payload.sab, 1);
try {
wasi_thread_start(tid, startArg);
}
catch (err) {
if (err !== 'unwind') {
throw err;
}
else {
return;
}
}
postMessage(createMessage('cleanup-thread', { tid: tid }));
};
ThreadMessageHandler.prototype._loaded = function (err, source, payload) {
if (err) {
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
if (source == null) {
var err_1 = new TypeError('onLoad should return an object');
notifyPthreadCreateResult(payload.sab, 2, err_1);
throw err_1;
}
var instance = source.instance;
if (!instance) {
var err_2 = new TypeError('onLoad should return an object which includes "instance"');
notifyPthreadCreateResult(payload.sab, 2, err_2);
throw err_2;
}
this.instance = instance;
var postMessage = this.postMessage;
postMessage(createMessage('loaded', {}));
var messages = this.messagesBeforeLoad;
this.messagesBeforeLoad = [];
for (var i = 0; i < messages.length; i++) {
var data = messages[i];
this.handle({ data: data });
}
};
ThreadMessageHandler.prototype.handleAfterLoad = function (e, f) {
if (this.instance !== undefined) {
f.call(this, e);
}
else {
this.messagesBeforeLoad.push(e.data);
}
};
return ThreadMessageHandler;
}());
function notifyPthreadCreateResult(sab, result, error) {
if (sab) {
serizeErrorToBuffer(sab.buffer, result, error);
Atomics.notify(sab, 0);
}
}
exports.ThreadManager = ThreadManager;
exports.ThreadMessageHandler = ThreadMessageHandler;
exports.WASIThreads = WASIThreads;
exports.createInstanceProxy = createInstanceProxy;
exports.isSharedArrayBuffer = isSharedArrayBuffer;
exports.isTrapError = isTrapError;
}));
@@ -0,0 +1,271 @@
/// <reference types="node" />
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
/** @public */
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
/** @public */
export declare interface CleanupThreadPayload {
tid: number;
}
/** @public */
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
/** @public */
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
/** @public */
export declare type CommandType = keyof CommandPayloadMap;
/** @public */
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
/** @public */
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
/** @public */
export declare interface LoadedPayload {
}
/** @public */
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
/** @public */
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
/** @public */
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
/** @public */
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
/** @public */
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
/** @public */
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
/** @public */
export declare interface ReuseWorkerOptions {
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size | PTHREAD_POOL_SIZE}
*/
size: number;
/**
* @see {@link https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size-strict | PTHREAD_POOL_SIZE_STRICT}
*/
strict?: boolean;
}
/** @public */
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
/** @public */
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
/** @public */
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
/** @public */
export declare interface TerminateAllThreadsPayload {
}
/** @public */
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
/* Excluded from this release type: printErr */
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
/** @public */
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
/** @public */
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
/** @public */
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
/** @public */
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
/** @virtual */
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
/** @virtual */
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
/** @public */
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
/** @public */
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
/** @public */
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
/**
* It's ok to call this method to a WASI command module.
*
* in child thread, must call this method instead of {@link WASIThreads.start} even if it's a WASI command module
*
* @returns A proxied WebAssembly instance if in child thread, other wise the original instance
*/
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
/**
* Equivalent to calling {@link WASIThreads.initialize} and then calling {@link WASIInstance.start}
* ```js
* this.initialize(instance, module, memory)
* this.wasi.start(instance)
* ```
*/
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
/** @public */
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
/** @public */
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
/** @public */
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
/** @public */
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
/** @public */
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
/** @public */
export declare type WorkerMessageType = 'load' | 'start';
export { }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,880 @@
const _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
function getPostMessage(options) {
return typeof (options === null || options === void 0 ? void 0 : options.postMessage) === 'function'
? options.postMessage
: typeof postMessage === 'function'
? postMessage
: undefined;
}
function serizeErrorToBuffer(sab, code, error) {
const i32array = new Int32Array(sab);
Atomics.store(i32array, 0, code);
if (code > 1 && error) {
const name = error.name;
const message = error.message;
const stack = error.stack;
const nameBuffer = new TextEncoder().encode(name);
const messageBuffer = new TextEncoder().encode(message);
const stackBuffer = new TextEncoder().encode(stack);
Atomics.store(i32array, 1, nameBuffer.length);
Atomics.store(i32array, 2, messageBuffer.length);
Atomics.store(i32array, 3, stackBuffer.length);
const buffer = new Uint8Array(sab);
buffer.set(nameBuffer, 16);
buffer.set(messageBuffer, 16 + nameBuffer.length);
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
}
}
function deserizeErrorFromBuffer(sab) {
var _a, _b;
const i32array = new Int32Array(sab);
const status = Atomics.load(i32array, 0);
if (status <= 1) {
return null;
}
const nameLength = Atomics.load(i32array, 1);
const messageLength = Atomics.load(i32array, 2);
const stackLength = Atomics.load(i32array, 3);
const buffer = new Uint8Array(sab);
const nameBuffer = buffer.slice(16, 16 + nameLength);
const messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
const stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
const name = new TextDecoder().decode(nameBuffer);
const message = new TextDecoder().decode(messageBuffer);
const stack = new TextDecoder().decode(stackBuffer);
const ErrorConstructor = (_a = globalThis[name]) !== null && _a !== void 0 ? _a : (name === 'RuntimeError' ? ((_b = _WebAssembly.RuntimeError) !== null && _b !== void 0 ? _b : Error) : Error);
const error = new ErrorConstructor(message);
Object.defineProperty(error, 'stack', {
value: stack,
writable: true,
enumerable: false,
configurable: true
});
return error;
}
function isSharedArrayBuffer(value) {
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
}
function isTrapError(e) {
try {
return e instanceof _WebAssembly.RuntimeError;
}
catch (_) {
return false;
}
}
function createMessage(type, payload) {
return {
__emnapi__: {
type,
payload
}
};
}
const WASI_THREADS_MAX_TID = 0x1FFFFFFF;
function checkSharedWasmMemory(wasmMemory) {
if (wasmMemory) {
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
throw new Error('Multithread features require shared wasm memory. ' +
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
'then create WebAssembly.Memory with `shared: true` option');
}
}
else {
if (typeof SharedArrayBuffer === 'undefined') {
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
}
}
}
function getReuseWorker(value) {
var _a;
if (typeof value === 'boolean') {
return value ? { size: 0, strict: false } : false;
}
if (typeof value === 'number') {
if (!(value >= 0)) {
throw new RangeError('reuseWorker: size must be a non-negative integer');
}
return { size: value, strict: false };
}
if (!value) {
return false;
}
const size = (_a = Number(value.size)) !== null && _a !== void 0 ? _a : 0;
const strict = Boolean(value.strict);
if (!(size > 0) && strict) {
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
}
return { size, strict };
}
let nextWorkerID = 0;
class ThreadManager {
get nextWorkerID() { return nextWorkerID; }
constructor(options) {
var _a;
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.wasmModule = null;
this.wasmMemory = null;
this.messageEvents = new WeakMap();
if (!options) {
throw new TypeError('ThreadManager(): options is not provided');
}
if ('childThread' in options) {
this._childThread = Boolean(options.childThread);
}
else {
this._childThread = false;
}
if (this._childThread) {
this._onCreateWorker = undefined;
this._reuseWorker = false;
this._beforeLoad = undefined;
}
else {
this._onCreateWorker = options.onCreateWorker;
this._reuseWorker = getReuseWorker(options.reuseWorker);
this._beforeLoad = options.beforeLoad;
}
this.printErr = (_a = options.printErr) !== null && _a !== void 0 ? _a : console.error.bind(console);
this.threadSpawn = options.threadSpawn;
}
init() {
if (!this._childThread) {
this.initMainThread();
}
}
initMainThread() {
this.preparePool();
}
preparePool() {
if (this._reuseWorker) {
if (this._reuseWorker.size) {
let pthreadPoolSize = this._reuseWorker.size;
while (pthreadPoolSize--) {
const worker = this.allocateUnusedWorker();
if (ENVIRONMENT_IS_NODE) {
worker.once('message', () => { });
worker.unref();
}
}
}
}
}
shouldPreloadWorkers() {
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
}
loadWasmModuleToAllWorkers() {
const promises = Array(this.unusedWorkers.length);
for (let i = 0; i < this.unusedWorkers.length; ++i) {
const worker = this.unusedWorkers[i];
if (ENVIRONMENT_IS_NODE)
worker.ref();
promises[i] = this.loadWasmModuleToWorker(worker).then((w) => {
if (ENVIRONMENT_IS_NODE)
worker.unref();
return w;
}, (e) => {
if (ENVIRONMENT_IS_NODE)
worker.unref();
throw e;
});
}
return Promise.all(promises).catch((err) => {
this.terminateAllThreads();
throw err;
});
}
preloadWorkers() {
if (this.shouldPreloadWorkers()) {
return this.loadWasmModuleToAllWorkers();
}
return Promise.resolve([]);
}
setup(wasmModule, wasmMemory) {
this.wasmModule = wasmModule;
this.wasmMemory = wasmMemory;
}
markId(worker) {
if (worker.__emnapi_tid)
return worker.__emnapi_tid;
const tid = nextWorkerID + 43;
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
this.pthreads[tid] = worker;
worker.__emnapi_tid = tid;
return tid;
}
returnWorkerToPool(worker) {
var tid = worker.__emnapi_tid;
if (tid !== undefined) {
delete this.pthreads[tid];
}
this.unusedWorkers.push(worker);
delete worker.__emnapi_tid;
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
}
loadWasmModuleToWorker(worker, sab) {
if (worker.whenLoaded)
return worker.whenLoaded;
const err = this.printErr;
const beforeLoad = this._beforeLoad;
const _this = this;
worker.whenLoaded = new Promise((resolve, reject) => {
const handleError = function (e) {
let message = 'worker sent an error!';
if (worker.__emnapi_tid !== undefined) {
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
}
if ('message' in e) {
err(message + ' ' + e.message);
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
try {
_this.terminateAllThreads();
}
catch (_) { }
}
}
else {
err(message);
}
reject(e);
throw e;
};
const handleMessage = (data) => {
if (data.__emnapi__) {
const type = data.__emnapi__.type;
const payload = data.__emnapi__.payload;
if (type === 'loaded') {
worker.loaded = true;
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
worker.unref();
}
resolve(worker);
}
else if (type === 'cleanup-thread') {
if (payload.tid in this.pthreads) {
this.cleanThread(worker, payload.tid);
}
}
else if (type === 'spawn-thread') {
this.threadSpawn(payload.startArg, payload.errorOrTid);
}
else if (type === 'terminate-all-threads') {
this.terminateAllThreads();
}
}
};
worker.onmessage = (e) => {
handleMessage(e.data);
this.fireMessageEvent(worker, e);
};
worker.onerror = handleError;
if (ENVIRONMENT_IS_NODE) {
worker.on('message', function (data) {
var _a, _b;
(_b = (_a = worker).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, {
data
});
});
worker.on('error', function (e) {
var _a, _b;
(_b = (_a = worker).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, e);
});
worker.on('detachedExit', function () { });
}
if (typeof beforeLoad === 'function') {
beforeLoad(worker);
}
try {
worker.postMessage(createMessage('load', {
wasmModule: this.wasmModule,
wasmMemory: this.wasmMemory,
sab
}));
}
catch (err) {
checkSharedWasmMemory(this.wasmMemory);
throw err;
}
});
return worker.whenLoaded;
}
allocateUnusedWorker() {
const _onCreateWorker = this._onCreateWorker;
if (typeof _onCreateWorker !== 'function') {
throw new TypeError('`options.onCreateWorker` is not provided');
}
const worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
this.unusedWorkers.push(worker);
return worker;
}
getNewWorker(sab) {
if (this._reuseWorker) {
if (this.unusedWorkers.length === 0) {
if (this._reuseWorker.strict) {
if (!ENVIRONMENT_IS_NODE) {
const err = this.printErr;
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
return;
}
}
const worker = this.allocateUnusedWorker();
this.loadWasmModuleToWorker(worker, sab);
}
return this.unusedWorkers.pop();
}
const worker = this.allocateUnusedWorker();
this.loadWasmModuleToWorker(worker, sab);
return this.unusedWorkers.pop();
}
cleanThread(worker, tid, force) {
if (!force && this._reuseWorker) {
this.returnWorkerToPool(worker);
}
else {
delete this.pthreads[tid];
this.terminateWorker(worker);
delete worker.__emnapi_tid;
}
}
terminateWorker(worker) {
var _a;
const tid = worker.__emnapi_tid;
worker.terminate();
(_a = this.messageEvents.get(worker)) === null || _a === void 0 ? void 0 : _a.clear();
this.messageEvents.delete(worker);
worker.onmessage = (e) => {
if (e.data.__emnapi__) {
const err = this.printErr;
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
}
};
}
terminateAllThreads() {
const runningWorkers = Object.values(this.pthreads);
for (let i = 0; i < runningWorkers.length; ++i) {
this.terminateWorker(runningWorkers[i]);
}
for (let i = 0; i < this.unusedWorkers.length; ++i) {
this.terminateWorker(this.unusedWorkers[i]);
}
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.preparePool();
}
addMessageEventListener(worker, onMessage) {
let listeners = this.messageEvents.get(worker);
if (!listeners) {
listeners = new Set();
this.messageEvents.set(worker, listeners);
}
listeners.add(onMessage);
return () => {
listeners === null || listeners === void 0 ? void 0 : listeners.delete(onMessage);
};
}
fireMessageEvent(worker, e) {
const listeners = this.messageEvents.get(worker);
if (!listeners)
return;
const err = this.printErr;
listeners.forEach((listener) => {
try {
listener(e);
}
catch (e) {
err(e.stack);
}
});
}
}
const kIsProxy = Symbol('kIsProxy');
function createInstanceProxy(instance, memory) {
if (instance[kIsProxy])
return instance;
const originalExports = instance.exports;
const createHandler = function (target) {
const handlers = [
'apply',
'construct',
'defineProperty',
'deleteProperty',
'get',
'getOwnPropertyDescriptor',
'getPrototypeOf',
'has',
'isExtensible',
'ownKeys',
'preventExtensions',
'set',
'setPrototypeOf'
];
const handler = {};
for (let i = 0; i < handlers.length; i++) {
const name = handlers[i];
handler[name] = function () {
const args = Array.prototype.slice.call(arguments, 1);
args.unshift(target);
return Reflect[name].apply(Reflect, args);
};
}
return handler;
};
const handler = createHandler(originalExports);
const _initialize = () => { };
const _start = () => 0;
handler.get = function (_target, p, receiver) {
var _a;
if (p === 'memory') {
return (_a = (typeof memory === 'function' ? memory() : memory)) !== null && _a !== void 0 ? _a : Reflect.get(originalExports, p, receiver);
}
if (p === '_initialize') {
return p in originalExports ? _initialize : undefined;
}
if (p === '_start') {
return p in originalExports ? _start : undefined;
}
return Reflect.get(originalExports, p, receiver);
};
handler.has = function (_target, p) {
if (p === 'memory')
return true;
return Reflect.has(originalExports, p);
};
const exportsProxy = new Proxy(Object.create(null), handler);
return new Proxy(instance, {
get(target, p, receiver) {
if (p === 'exports') {
return exportsProxy;
}
if (p === kIsProxy) {
return true;
}
return Reflect.get(target, p, receiver);
}
});
}
const patchedWasiInstances = new WeakMap();
class WASIThreads {
constructor(options) {
if (!options) {
throw new TypeError('WASIThreads(): options is not provided');
}
if (!options.wasi) {
throw new TypeError('WASIThreads(): options.wasi is not provided');
}
patchedWasiInstances.set(this, new WeakSet());
const wasi = options.wasi;
patchWasiInstance(this, wasi);
this.wasi = wasi;
if ('childThread' in options) {
this.childThread = Boolean(options.childThread);
}
else {
this.childThread = false;
}
this.PThread = undefined;
if ('threadManager' in options) {
if (typeof options.threadManager === 'function') {
this.PThread = options.threadManager();
}
else {
this.PThread = options.threadManager;
}
}
else {
if (!this.childThread) {
this.PThread = new ThreadManager(options);
this.PThread.init();
}
}
let waitThreadStart = false;
if ('waitThreadStart' in options) {
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
}
const postMessage = getPostMessage(options);
if (this.childThread && typeof postMessage !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMessage;
const wasm64 = Boolean(options.wasm64);
const threadSpawn = (startArg, errorOrTid) => {
var _a;
const EAGAIN = 6;
const isNewABI = errorOrTid !== undefined;
try {
checkSharedWasmMemory(this.wasmMemory);
}
catch (err) {
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.printErr(err.stack);
if (isNewABI) {
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
return 1;
}
else {
return -EAGAIN;
}
}
if (!isNewABI) {
const malloc = this.wasmInstance.exports.malloc;
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
if (!errorOrTid) {
return -48;
}
}
const _free = this.wasmInstance.exports.free;
const free = wasm64 ? (ptr) => { _free(BigInt(ptr)); } : _free;
const struct = new Int32Array(this.wasmMemory.buffer, errorOrTid, 2);
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, 0);
if (this.childThread) {
postMessage(createMessage('spawn-thread', {
startArg,
errorOrTid: errorOrTid
}));
Atomics.wait(struct, 1, 0);
const isError = Atomics.load(struct, 0);
const result = Atomics.load(struct, 1);
if (isNewABI) {
return isError;
}
free(errorOrTid);
return isError ? -result : result;
}
const shouldWait = waitThreadStart || (waitThreadStart === 0);
let sab;
if (shouldWait) {
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
Atomics.store(sab, 0, 0);
}
let worker;
let tid;
const PThread = this.PThread;
try {
worker = PThread.getNewWorker(sab);
if (!worker) {
throw new Error('failed to get new worker');
}
tid = PThread.markId(worker);
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
worker.postMessage(createMessage('start', {
tid,
arg: startArg,
sab
}));
if (shouldWait) {
if (typeof waitThreadStart === 'number') {
const waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
if (waitResult === 'timed-out') {
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
}
}
else {
Atomics.wait(sab, 0, 0);
}
const r = Atomics.load(sab, 0);
if (r > 1) {
throw deserizeErrorFromBuffer(sab.buffer);
}
}
}
catch (e) {
if (worker !== undefined && tid !== undefined) {
try {
PThread.cleanThread(worker, tid, true);
}
catch (_) { }
}
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
PThread === null || PThread === void 0 ? void 0 : PThread.printErr(e.stack);
if (isNewABI) {
return 1;
}
free(errorOrTid);
return -EAGAIN;
}
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, tid);
Atomics.notify(struct, 1);
if (!shouldWait) {
worker.whenLoaded.catch((err) => {
delete worker.whenLoaded;
PThread.cleanThread(worker, tid, true);
throw err;
});
}
if (isNewABI) {
return 0;
}
free(errorOrTid);
return tid;
};
this.threadSpawn = threadSpawn;
if (this.PThread) {
this.PThread.threadSpawn = threadSpawn;
}
}
getImportObject() {
return {
wasi: {
'thread-spawn': this.threadSpawn
}
};
}
setup(wasmInstance, wasmModule, wasmMemory) {
wasmMemory !== null && wasmMemory !== void 0 ? wasmMemory : (wasmMemory = wasmInstance.exports.memory);
this.wasmInstance = wasmInstance;
this.wasmMemory = wasmMemory;
if (this.PThread) {
this.PThread.setup(wasmModule, wasmMemory);
}
}
preloadWorkers() {
if (this.PThread) {
return this.PThread.preloadWorkers();
}
return Promise.resolve([]);
}
initialize(instance, module, memory) {
const exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
const wasi = this.wasi;
if (('_start' in exports) && (typeof exports._start === 'function')) {
if (this.childThread) {
wasi.start(instance);
try {
const kStarted = getWasiSymbol(wasi, 'kStarted');
wasi[kStarted] = false;
}
catch (_) { }
}
else {
setupInstance(wasi, instance);
}
}
else {
wasi.initialize(instance);
}
return instance;
}
start(instance, module, memory) {
const exports = instance.exports;
memory !== null && memory !== void 0 ? memory : (memory = exports.memory);
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
const exitCode = this.wasi.start(instance);
return { exitCode, instance };
}
terminateAllThreads() {
var _a;
if (!this.childThread) {
(_a = this.PThread) === null || _a === void 0 ? void 0 : _a.terminateAllThreads();
}
else {
this.postMessage(createMessage('terminate-all-threads', {}));
}
}
}
function patchWasiInstance(wasiThreads, wasi) {
const patched = patchedWasiInstances.get(wasiThreads);
if (patched.has(wasi)) {
return;
}
const _this = wasiThreads;
const wasiImport = wasi.wasiImport;
if (wasiImport) {
const proc_exit = wasiImport.proc_exit;
wasiImport.proc_exit = function (code) {
_this.terminateAllThreads();
return proc_exit.call(this, code);
};
}
if (!_this.childThread) {
const start = wasi.start;
if (typeof start === 'function') {
wasi.start = function (instance) {
try {
return start.call(this, instance);
}
catch (err) {
if (isTrapError(err)) {
_this.terminateAllThreads();
}
throw err;
}
};
}
}
patched.add(wasi);
}
function getWasiSymbol(wasi, description) {
const symbols = Object.getOwnPropertySymbols(wasi);
const selectDescription = (description) => (s) => {
if (s.description) {
return s.description === description;
}
return s.toString() === `Symbol(${description})`;
};
if (Array.isArray(description)) {
return description.map(d => symbols.filter(selectDescription(d))[0]);
}
return symbols.filter(selectDescription(description))[0];
}
function setupInstance(wasi, instance) {
const [kInstance, kSetMemory] = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']);
wasi[kInstance] = instance;
wasi[kSetMemory](instance.exports.memory);
}
class ThreadMessageHandler {
constructor(options) {
const postMsg = getPostMessage(options);
if (typeof postMsg !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMsg;
this.onLoad = options === null || options === void 0 ? void 0 : options.onLoad;
this.onError = typeof (options === null || options === void 0 ? void 0 : options.onError) === 'function' ? options.onError : (_type, err) => { throw err; };
this.instance = undefined;
this.messagesBeforeLoad = [];
}
instantiate(data) {
if (typeof this.onLoad === 'function') {
return this.onLoad(data);
}
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
}
handle(e) {
var _a;
if ((_a = e === null || e === void 0 ? void 0 : e.data) === null || _a === void 0 ? void 0 : _a.__emnapi__) {
const type = e.data.__emnapi__.type;
const payload = e.data.__emnapi__.payload;
try {
if (type === 'load') {
this._load(payload);
}
else if (type === 'start') {
this.handleAfterLoad(e, () => {
this._start(payload);
});
}
}
catch (err) {
this.onError(err, type);
}
}
}
_load(payload) {
if (this.instance !== undefined)
return;
let source;
try {
source = this.instantiate(payload);
}
catch (err) {
this._loaded(err, null, payload);
return;
}
const then = source && 'then' in source ? source.then : undefined;
if (typeof then === 'function') {
then.call(source, (source) => { this._loaded(null, source, payload); }, (err) => { this._loaded(err, null, payload); });
}
else {
this._loaded(null, source, payload);
}
}
_start(payload) {
const wasi_thread_start = this.instance.exports.wasi_thread_start;
if (typeof wasi_thread_start !== 'function') {
const err = new TypeError('wasi_thread_start is not exported');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
const postMessage = this.postMessage;
const tid = payload.tid;
const startArg = payload.arg;
notifyPthreadCreateResult(payload.sab, 1);
try {
wasi_thread_start(tid, startArg);
}
catch (err) {
if (err !== 'unwind') {
throw err;
}
else {
return;
}
}
postMessage(createMessage('cleanup-thread', { tid }));
}
_loaded(err, source, payload) {
if (err) {
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
if (source == null) {
const err = new TypeError('onLoad should return an object');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
const instance = source.instance;
if (!instance) {
const err = new TypeError('onLoad should return an object which includes "instance"');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
this.instance = instance;
const postMessage = this.postMessage;
postMessage(createMessage('loaded', {}));
const messages = this.messagesBeforeLoad;
this.messagesBeforeLoad = [];
for (let i = 0; i < messages.length; i++) {
const data = messages[i];
this.handle({ data });
}
}
handleAfterLoad(e, f) {
if (this.instance !== undefined) {
f.call(this, e);
}
else {
this.messagesBeforeLoad.push(e.data);
}
}
}
function notifyPthreadCreateResult(sab, result, error) {
if (sab) {
serizeErrorToBuffer(sab.buffer, result, error);
Atomics.notify(sab, 0);
}
}
export { ThreadManager, ThreadMessageHandler, WASIThreads, createInstanceProxy, isSharedArrayBuffer, isTrapError };
@@ -0,0 +1,5 @@
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
module.exports = require('./dist/wasi-threads.cjs.min.js')
} else {
module.exports = require('./dist/wasi-threads.cjs.js')
}
@@ -0,0 +1,50 @@
{
"name": "@emnapi/wasi-threads",
"version": "1.2.2",
"description": "WASI threads proposal implementation in JavaScript",
"main": "index.js",
"module": "./dist/wasi-threads.esm-bundler.js",
"types": "./dist/wasi-threads.d.ts",
"sideEffects": false,
"exports": {
".": {
"types": {
"module": "./dist/wasi-threads.d.ts",
"import": "./dist/wasi-threads.d.mts",
"default": "./dist/wasi-threads.d.ts"
},
"module": "./dist/wasi-threads.esm-bundler.js",
"import": "./dist/wasi-threads.mjs",
"default": "./index.js"
},
"./dist/wasi-threads.cjs.min": {
"types": "./dist/wasi-threads.d.ts",
"default": "./dist/wasi-threads.cjs.min.js"
},
"./dist/wasi-threads.min.mjs": {
"types": "./dist/wasi-threads.d.mts",
"default": "./dist/wasi-threads.min.mjs"
}
},
"dependencies": {
"tslib": "^2.4.0"
},
"scripts": {
"build": "node ./script/build.js",
"build:test": "node ./test/build.js",
"test": "node ./test/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/toyobayashi/emnapi.git"
},
"author": "toyobayashi",
"license": "MIT",
"bugs": {
"url": "https://github.com/toyobayashi/emnapi/issues"
},
"homepage": "https://github.com/toyobayashi/emnapi#readme",
"publishConfig": {
"access": "public"
}
}
@@ -0,0 +1,321 @@
'use strict';
// @ts-check
/**
* @param {unknown} value
*/
const getType = (value) => {
if (value === undefined) return 0
if (value === null) return 1
if (isBuffer(value)) return 10
const t = typeof value;
if (t === 'boolean') return 2
if (t === 'number') return 3
if (t === 'string') return 4
if (t === 'object') return 6
if (t === 'bigint') return 9
return -1
};
/**
* @param {unknown} value
* @returns {value is Uint8Array}
*/
const isBuffer = (value) => {
const BufferCtor = globalThis.Buffer;
if (typeof BufferCtor?.isBuffer === 'function') {
return BufferCtor.isBuffer(value)
}
return value instanceof Uint8Array && value.constructor?.name === 'Buffer'
};
const RESPONSE_HEADER_SIZE = 16;
const RESPONSE_PAYLOAD_SIZE = 10240;
const RESPONSE_BUFFER_SIZE = RESPONSE_HEADER_SIZE + RESPONSE_PAYLOAD_SIZE;
/**
* @param {Int32Array} sab
* @param {Uint8Array} payload
*/
const writeResponsePayload = (sab, payload) => {
if (payload.length > RESPONSE_PAYLOAD_SIZE) {
throw new RangeError('payload overflow')
}
new Uint8Array(sab.buffer).set(payload, RESPONSE_HEADER_SIZE);
};
/**
* @param {import('memfs').IFs} memfs
* @param {any} value
* @param {ReturnType<typeof getType>} type
* @returns {Uint8Array}
*/
const encodeValue = (memfs, value, type) => {
switch (type) {
case 0:
case 1:
return new Uint8Array(0)
case 2: {
const view = new Int32Array(1);
view[0] = value ? 1 : 0;
return new Uint8Array(view.buffer)
}
case 3: {
const view = new Float64Array(1);
view[0] = value;
return new Uint8Array(view.buffer)
}
case 4: {
const view = new TextEncoder().encode(value);
return view
}
case 10:
return new Uint8Array(value)
case 6: {
function storeConstructor(obj, memfs, processed = new WeakSet()) {
if (!obj || typeof obj !== 'object') {
return
}
if (processed.has(obj)) {
return
}
processed.add(obj);
const [entry] =
Object.entries(memfs).filter(([_, v]) => v === obj.constructor)[0] ??
[];
if (entry) {
Object.defineProperty(obj, '__constructor__', {
configurable: true,
writable: true,
enumerable: true,
value: entry,
});
}
for (const value of Object.values(obj)) {
storeConstructor(value, memfs, processed);
}
}
storeConstructor(value, memfs);
const json = JSON.stringify(value, (_, value) => {
if (typeof value === 'bigint') {
return `BigInt(${String(value)})`
}
if (value instanceof Error) {
return {
...value,
message: value.message,
stack: value.stack,
__error__: value.constructor.name,
}
}
return value
});
const view = new TextEncoder().encode(json);
return view
}
case 9: {
return new TextEncoder().encode(String(value))
}
case -1:
default:
throw new Error('unsupported data')
}
};
/**
* @param {typeof import('memfs')} memfs
* @param {Uint8Array} payload
* @param {number} type
* @returns {any}
*/
const decodeValue = (memfs, payload, type) => {
if (type === 0) return undefined
if (type === 1) return null
if (type === 2)
return Boolean(new Int32Array(payload.buffer, payload.byteOffset, 1)[0])
if (type === 3)
return new Float64Array(payload.buffer, payload.byteOffset, 1)[0]
if (type === 4) return new TextDecoder().decode(payload.slice())
if (type === 10) {
const BufferCtor = globalThis.Buffer;
if (typeof BufferCtor?.from === 'function') {
return BufferCtor.from(payload)
}
return payload.slice()
}
if (type === 6) {
const obj = JSON.parse(
new TextDecoder().decode(payload.slice()),
(_key, value) => {
if (typeof value === 'string') {
const matched = value.match(/^BigInt\((-?\d+)\)$/);
if (matched && matched[1]) {
return BigInt(matched[1])
}
}
return value
},
);
function loadConstructor(obj, memfs, processed = new WeakSet()) {
if (!obj || typeof obj !== 'object') {
return
}
if (processed.has(obj)) {
return
}
processed.add(obj);
if (obj.__constructor__) {
const ctor = obj.__constructor__;
delete obj.__constructor__;
Object.setPrototypeOf(obj, memfs[ctor].prototype);
}
for (const value of Object.values(obj)) {
loadConstructor(value, memfs, processed);
}
}
loadConstructor(obj, memfs);
if (obj.__error__) {
const name = obj.__error__;
const ErrorConstructor = globalThis[name] || Error;
delete obj.__error__;
const err = new ErrorConstructor(obj.message);
Object.defineProperty(err, 'stack', {
configurable: true,
enumerable: false,
writable: true,
value: err.stack,
});
Object.defineProperty(err, Symbol.toStringTag, {
configurable: true,
enumerable: false,
writable: true,
value: name,
});
for (const [k, v] of Object.entries(obj)) {
if (k === 'message' || k === 'stack') continue
err[k] = v;
}
return err
}
return obj
}
if (type === 9) {
return BigInt(new TextDecoder().decode(payload.slice()))
}
throw new Error('unsupported data')
};
/**
* @param {import('memfs').IFs} fs
* @returns {(e: { data: { __fs__: { sab: Int32Array, type: keyof import('memfs').IFs, payload: any[] } } }) => void}
*/
// oxlint-disable-next-line no-unused-vars -- fixed in an upcoming release
const createOnMessage = (fs) =>
function onMessage(e) {
if (e.data.__fs__) {
/**
* 0..4 status(int32_t): 21(waiting) 0(success) 1(error)
* 5..8 type(napi_valuetype): 0(undefined) 1(null) 2(boolean) 3(number) 4(string) 6(jsonstring) 9(bigint) 10(buffer) -1(unsupported)
* 9..16 payload_size(uint32_t) <= 10240
* 16..16 + payload_size payload_content
*/
const { sab, type, payload } = e.data.__fs__;
const fn = fs[type];
try {
const ret = fn.apply(fs, payload);
const t = getType(ret);
Atomics.store(sab, 1, t);
const v = encodeValue(fs, ret, t);
Atomics.store(sab, 2, v.length);
writeResponsePayload(sab, v);
Atomics.store(sab, 0, 0); // success
} catch (/** @type {any} */ err) {
let t = getType(err);
let v;
try {
if (t === -1) {
throw new Error('unsupported data')
}
v = encodeValue(fs, err, t);
} catch {
const fallback = (() => {
try {
return String(err)
} catch {
return 'Unserializable thrown value'
}
})();
t = getType(fallback);
v = encodeValue(fs, fallback, t);
}
if (v.length > RESPONSE_PAYLOAD_SIZE) {
const overflowErr = new RangeError('payload overflow');
t = getType(overflowErr);
v = encodeValue(fs, overflowErr, t);
}
Atomics.store(sab, 1, t);
Atomics.store(sab, 2, v.length);
writeResponsePayload(sab, v);
Atomics.store(sab, 0, 1); // error
} finally {
Atomics.notify(sab, 0);
}
}
};
/**
* @param {typeof import('memfs')} memfs
*/
const createFsProxy = (memfs) =>
new Proxy(
{},
{
get(_target, p, _receiver) {
/**
* @param {any[]} args
*/
return function (...args) {
const sab = new SharedArrayBuffer(RESPONSE_BUFFER_SIZE);
const i32arr = new Int32Array(sab);
Atomics.store(i32arr, 0, 21);
postMessage({
__fs__: {
sab: i32arr,
type: p,
payload: args,
},
});
Atomics.wait(i32arr, 0, 21);
const status = Atomics.load(i32arr, 0);
const type = Atomics.load(i32arr, 1);
const size = Atomics.load(i32arr, 2);
const content = new Uint8Array(sab, RESPONSE_HEADER_SIZE, size);
const value = decodeValue(memfs, content, type);
if (status === 1) {
throw value
}
return value
}
},
},
);
exports.createFsProxy = createFsProxy;
exports.createOnMessage = createOnMessage;
File diff suppressed because one or more lines are too long
@@ -0,0 +1,316 @@
// @ts-check
/**
* @param {unknown} value
*/
const getType = (value) => {
if (value === undefined) return 0
if (value === null) return 1
if (isBuffer(value)) return 10
const t = typeof value
if (t === 'boolean') return 2
if (t === 'number') return 3
if (t === 'string') return 4
if (t === 'object') return 6
if (t === 'bigint') return 9
return -1
}
/**
* @param {unknown} value
* @returns {value is Uint8Array}
*/
const isBuffer = (value) => {
const BufferCtor = globalThis.Buffer
if (typeof BufferCtor?.isBuffer === 'function') {
return BufferCtor.isBuffer(value)
}
return value instanceof Uint8Array && value.constructor?.name === 'Buffer'
}
const RESPONSE_HEADER_SIZE = 16
const RESPONSE_PAYLOAD_SIZE = 10240
const RESPONSE_BUFFER_SIZE = RESPONSE_HEADER_SIZE + RESPONSE_PAYLOAD_SIZE
/**
* @param {Int32Array} sab
* @param {Uint8Array} payload
*/
const writeResponsePayload = (sab, payload) => {
if (payload.length > RESPONSE_PAYLOAD_SIZE) {
throw new RangeError('payload overflow')
}
new Uint8Array(sab.buffer).set(payload, RESPONSE_HEADER_SIZE)
}
/**
* @param {import('memfs').IFs} memfs
* @param {any} value
* @param {ReturnType<typeof getType>} type
* @returns {Uint8Array}
*/
const encodeValue = (memfs, value, type) => {
switch (type) {
case 0:
case 1:
return new Uint8Array(0)
case 2: {
const view = new Int32Array(1)
view[0] = value ? 1 : 0
return new Uint8Array(view.buffer)
}
case 3: {
const view = new Float64Array(1)
view[0] = value
return new Uint8Array(view.buffer)
}
case 4: {
const view = new TextEncoder().encode(value)
return view
}
case 10:
return new Uint8Array(value)
case 6: {
function storeConstructor(obj, memfs, processed = new WeakSet()) {
if (!obj || typeof obj !== 'object') {
return
}
if (processed.has(obj)) {
return
}
processed.add(obj)
const [entry] =
Object.entries(memfs).filter(([_, v]) => v === obj.constructor)[0] ??
[]
if (entry) {
Object.defineProperty(obj, '__constructor__', {
configurable: true,
writable: true,
enumerable: true,
value: entry,
})
}
for (const value of Object.values(obj)) {
storeConstructor(value, memfs, processed)
}
}
storeConstructor(value, memfs)
const json = JSON.stringify(value, (_, value) => {
if (typeof value === 'bigint') {
return `BigInt(${String(value)})`
}
if (value instanceof Error) {
return {
...value,
message: value.message,
stack: value.stack,
__error__: value.constructor.name,
}
}
return value
})
const view = new TextEncoder().encode(json)
return view
}
case 9: {
return new TextEncoder().encode(String(value))
}
case -1:
default:
throw new Error('unsupported data')
}
}
/**
* @param {typeof import('memfs')} memfs
* @param {Uint8Array} payload
* @param {number} type
* @returns {any}
*/
const decodeValue = (memfs, payload, type) => {
if (type === 0) return undefined
if (type === 1) return null
if (type === 2)
return Boolean(new Int32Array(payload.buffer, payload.byteOffset, 1)[0])
if (type === 3)
return new Float64Array(payload.buffer, payload.byteOffset, 1)[0]
if (type === 4) return new TextDecoder().decode(payload.slice())
if (type === 10) {
const BufferCtor = globalThis.Buffer
if (typeof BufferCtor?.from === 'function') {
return BufferCtor.from(payload)
}
return payload.slice()
}
if (type === 6) {
const obj = JSON.parse(
new TextDecoder().decode(payload.slice()),
(_key, value) => {
if (typeof value === 'string') {
const matched = value.match(/^BigInt\((-?\d+)\)$/)
if (matched && matched[1]) {
return BigInt(matched[1])
}
}
return value
},
)
function loadConstructor(obj, memfs, processed = new WeakSet()) {
if (!obj || typeof obj !== 'object') {
return
}
if (processed.has(obj)) {
return
}
processed.add(obj)
if (obj.__constructor__) {
const ctor = obj.__constructor__
delete obj.__constructor__
Object.setPrototypeOf(obj, memfs[ctor].prototype)
}
for (const value of Object.values(obj)) {
loadConstructor(value, memfs, processed)
}
}
loadConstructor(obj, memfs)
if (obj.__error__) {
const name = obj.__error__
const ErrorConstructor = globalThis[name] || Error
delete obj.__error__
const err = new ErrorConstructor(obj.message)
Object.defineProperty(err, 'stack', {
configurable: true,
enumerable: false,
writable: true,
value: err.stack,
})
Object.defineProperty(err, Symbol.toStringTag, {
configurable: true,
enumerable: false,
writable: true,
value: name,
})
for (const [k, v] of Object.entries(obj)) {
if (k === 'message' || k === 'stack') continue
err[k] = v
}
return err
}
return obj
}
if (type === 9) {
return BigInt(new TextDecoder().decode(payload.slice()))
}
throw new Error('unsupported data')
}
/**
* @param {import('memfs').IFs} fs
* @returns {(e: { data: { __fs__: { sab: Int32Array, type: keyof import('memfs').IFs, payload: any[] } } }) => void}
*/
// oxlint-disable-next-line no-unused-vars -- fixed in an upcoming release
export const createOnMessage = (fs) =>
function onMessage(e) {
if (e.data.__fs__) {
/**
* 0..4 status(int32_t): 21(waiting) 0(success) 1(error)
* 5..8 type(napi_valuetype): 0(undefined) 1(null) 2(boolean) 3(number) 4(string) 6(jsonstring) 9(bigint) 10(buffer) -1(unsupported)
* 9..16 payload_size(uint32_t) <= 10240
* 16..16 + payload_size payload_content
*/
const { sab, type, payload } = e.data.__fs__
const fn = fs[type]
try {
const ret = fn.apply(fs, payload)
const t = getType(ret)
Atomics.store(sab, 1, t)
const v = encodeValue(fs, ret, t)
Atomics.store(sab, 2, v.length)
writeResponsePayload(sab, v)
Atomics.store(sab, 0, 0) // success
} catch (/** @type {any} */ err) {
let t = getType(err)
let v
try {
if (t === -1) {
throw new Error('unsupported data')
}
v = encodeValue(fs, err, t)
} catch {
const fallback = (() => {
try {
return String(err)
} catch {
return 'Unserializable thrown value'
}
})()
t = getType(fallback)
v = encodeValue(fs, fallback, t)
}
if (v.length > RESPONSE_PAYLOAD_SIZE) {
const overflowErr = new RangeError('payload overflow')
t = getType(overflowErr)
v = encodeValue(fs, overflowErr, t)
}
Atomics.store(sab, 1, t)
Atomics.store(sab, 2, v.length)
writeResponsePayload(sab, v)
Atomics.store(sab, 0, 1) // error
} finally {
Atomics.notify(sab, 0)
}
}
}
/**
* @param {typeof import('memfs')} memfs
*/
export const createFsProxy = (memfs) =>
new Proxy(
{},
{
get(_target, p, _receiver) {
/**
* @param {any[]} args
*/
return function (...args) {
const sab = new SharedArrayBuffer(RESPONSE_BUFFER_SIZE)
const i32arr = new Int32Array(sab)
Atomics.store(i32arr, 0, 21)
postMessage({
__fs__: {
sab: i32arr,
type: p,
payload: args,
},
})
Atomics.wait(i32arr, 0, 21)
const status = Atomics.load(i32arr, 0)
const type = Atomics.load(i32arr, 1)
const size = Atomics.load(i32arr, 2)
const content = new Uint8Array(sab, RESPONSE_HEADER_SIZE, size)
const value = decodeValue(memfs, content, type)
if (status === 1) {
throw value
}
return value
}
},
},
)
@@ -0,0 +1,70 @@
{
"name": "@napi-rs/wasm-runtime",
"version": "1.1.6",
"type": "module",
"description": "Runtime and polyfill for wasm targets",
"homepage": "https://napi.rs/",
"author": {
"name": "LongYinan",
"url": "https://github.com/Brooooooklyn"
},
"repository": {
"type": "git",
"url": "git+https://github.com/napi-rs/napi-rs.git",
"directory": "wasm-runtime"
},
"license": "MIT",
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"files": [
"runtime.cjs",
"runtime.js",
"fs-proxy.js",
"dist/*.cjs",
"dist/*.js"
],
"devDependencies": {
"@rollup/plugin-alias": "^6.0.0",
"@rollup/plugin-commonjs": "^29.0.3",
"@rollup/plugin-inject": "^5.0.5",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.3",
"@rollup/plugin-replace": "^6.0.3",
"buffer": "^6.0.3",
"events": "^3.3.0",
"memfs": "^4.57.6",
"node-inspect-extracted": "^3.3.2",
"path-browserify": "^1.0.1",
"process": "^0.11.10",
"readable-stream": "^4.7.0",
"rollup": "^4.61.1",
"rollup-plugin-polyfill-node": "^0.13.0",
"tslib": "^2.8.1"
},
"dependencies": {
"@tybys/wasm-util": "^0.10.3"
},
"peerDependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1"
},
"scripts": {
"build": "rollup -c rollup.config.js",
"test": "node --test"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"exports": {
".": {
"import": "./runtime.js",
"require": "./runtime.cjs"
},
"./fs": {
"import": "./dist/fs.js"
}
}
}
@@ -0,0 +1,15 @@
const { MessageHandler, instantiateNapiModuleSync, instantiateNapiModule } = require('@emnapi/core')
const { getDefaultContext } = require('@emnapi/runtime')
const { WASI } = require('@tybys/wasm-util')
const { createFsProxy, createOnMessage } = require('./dist/fs-proxy.cjs')
module.exports = {
MessageHandler,
instantiateNapiModule,
instantiateNapiModuleSync,
getDefaultContext,
WASI,
createFsProxy,
createOnMessage,
}
@@ -0,0 +1,8 @@
export {
instantiateNapiModuleSync,
instantiateNapiModule,
MessageHandler,
} from '@emnapi/core'
export { getDefaultContext } from '@emnapi/runtime'
export * from '@tybys/wasm-util'
export { createOnMessage, createFsProxy } from './fs-proxy.js'
+193
View File
@@ -0,0 +1,193 @@
# @tybys/wasm-util
WebAssembly related utils for browser environment
**The output code is ES2019**
## Features
All example code below need to be bundled by ES module bundlers like `webpack` / `rollup`, or specify import map in browser native ES module runtime.
### WASI polyfill for browser
The API is similar to the `require('wasi').WASI` in Node.js.
You can use `memfs-browser` to provide filesystem capability.
- Example: [https://github.com/toyobayashi/wasi-wabt](https://github.com/toyobayashi/wasi-wabt)
- Demo: [https://toyobayashi.github.io/wasi-wabt/](https://toyobayashi.github.io/wasi-wabt/)
```js
import { load, WASI } from '@tybys/wasm-util'
import { Volume, createFsFromVolume } from 'memfs-browser'
const fs = createFsFromVolume(Volume.fromJSON({
'/home/wasi': null
}))
const wasi = new WASI({
args: ['chrome', 'file.wasm'],
env: {
NODE_ENV: 'development',
WASI_SDK_PATH: '/opt/wasi-sdk'
},
preopens: {
'/': '/'
},
fs,
// redirect stdout / stderr
// print (text) { console.log(text) },
// printErr (text) { console.error(text) }
})
const imports = {
wasi_snapshot_preview1: wasi.wasiImport
}
const { module, instance } = await load('/path/to/file.wasm', imports)
wasi.start(instance)
// wasi.initialize(instance)
```
Implemented syscalls: [wasi_snapshot_preview1](#wasi_snapshot_preview1)
### `load` / `loadSync`
`loadSync` has 4KB wasm size limit in browser.
```js
// bundler
import { load, loadSync } from '@tybys/wasm-util'
const imports = { /* ... */ }
// using path
const { module, instance } = await load('/path/to/file.wasm', imports)
const { module, instance } = loadSync('/path/to/file.wasm', imports)
// using URL
const { module, instance } = await load(new URL('./file.wasm', import.meta.url), imports)
const { module, instance } = loadSync(new URL('./file.wasm', import.meta.url), imports)
// using Uint8Array
const buffer = new Uint8Array([
0x00, 0x61, 0x73, 0x6d,
0x01, 0x00, 0x00, 0x00
])
const { module, instance } = await load(buffer, imports)
const { module, instance } = loadSync(buffer, imports)
// auto asyncify
const {
module,
instance: asyncifiedInstance
} = await load(buffer, imports, { /* asyncify options */})
asyncifiedInstance.exports.fn() // => return Promise
```
### Extend Memory instance
```js
import { Memory, extendMemory } from '@tybys/wasm-util'
const memory = new WebAssembly.Memory({ initial: 256 })
// const memory = instance.exports.memory
extendMemory(memory)
console.log(memory instanceof Memory)
console.log(memory instanceof WebAssembly.Memory)
// expose memory view getters like Emscripten
const { HEAPU8, HEAPU32, view } = memory
```
### Asyncify wrap
Build the C code using `clang`, `wasm-ld` and `wasm-opt`
```c
void async_sleep(int ms);
int main() {
async_sleep(200);
return 0;
}
```
```js
import { Asyncify } from '@tybys/wasm-util'
const asyncify = new Asyncify()
const imports = {
env: {
async_sleep: asyncify.wrapImportFunction(function (ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
})
}
}
// async_sleep(200)
const bytes = await (await fetch('/asyncfied_by_wasm-opt.wasm')).arrayBuffer()
const { instance } = await WebAssembly.instantiate(bytes, imports)
const asyncifiedInstance = asyncify.init(instance.exports.memory, instance, {
wrapExports: ['_start']
})
const p = asyncifedInstance._start()
console.log(typeof p.then === 'function')
const now = Date.now()
await p
console.log(Date.now() - now >= 200)
```
### wasi_snapshot_preview1
- [x] args_get
- [x] args_sizes_get
- [x] environ_get
- [x] environ_sizes_get
- [x] clock_res_get
- [x] clock_time_get
- [ ] ~~fd_advise~~
- [x] fd_allocate
- [x] fd_close
- [x] fd_datasync
- [x] fd_fdstat_get
- [ ] ~~fd_fdstat_set_flags~~
- [x] fd_fdstat_set_rights
- [x] fd_filestat_get
- [x] fd_filestat_set_size
- [x] fd_filestat_set_times
- [x] fd_pread
- [x] fd_prestat_get
- [x] fd_prestat_dir_name
- [x] fd_pwrite
- [x] fd_read
- [x] fd_readdir
- [x] fd_renumber
- [x] fd_seek
- [x] fd_sync
- [x] fd_tell
- [x] fd_write
- [x] path_create_directory
- [x] path_filestat_get
- [x] path_filestat_set_times
- [x] path_link
- [x] path_open
- [x] path_readlink
- [x] path_remove_directory
- [x] path_rename
- [x] path_symlink
- [x] path_unlink_file
- [x] poll_oneoff (timer only)
- [x] proc_exit
- [ ] ~~proc_raise~~
- [x] sched_yield
- [x] random_get
- [ ] ~~sock_recv~~
- [ ] ~~sock_send~~
- [ ] ~~sock_shutdown~~
@@ -0,0 +1,11 @@
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
// It should be published with your NPM package. It should not be tracked by Git.
{
"tsdocVersion": "0.12",
"toolPackages": [
{
"packageName": "@microsoft/api-extractor",
"packageVersion": "7.34.4"
}
]
}
@@ -0,0 +1,423 @@
/**
* @packageDocumentation
*/
/** @public */
export declare class Asyncify {
private value;
private exports;
private dataPtr;
init<T extends WebAssembly.Exports, U extends Array<Exclude<keyof T, AsyncifyExportName>>>(memory: WebAssembly.Memory, instance: {
readonly exports: T;
}, options: AsyncifyOptions): {
readonly exports: AsyncifyExports<T, U>;
};
private assertState;
wrapImportFunction<T extends Function>(f: T): T;
wrapImports<T extends WebAssembly.Imports>(imports: T): T;
wrapExportFunction<T extends Function>(f: T): AsyncifyExportFunction<T>;
wrapExports<T extends WebAssembly.Exports>(exports: T): AsyncifyExports<T, void>;
wrapExports<T extends WebAssembly.Exports, U extends Array<Exclude<keyof T, AsyncifyExportName>>>(exports: T, needWrap: U): AsyncifyExports<T, U>;
}
/** @public */
export declare type AsyncifyExportFunction<T> = T extends Callable ? (...args: Parameters<T>) => Promise<ReturnType<T>> : T;
/** @public */
export declare type AsyncifyExportName = 'asyncify_get_state' | 'asyncify_start_unwind' | 'asyncify_stop_unwind' | 'asyncify_start_rewind' | 'asyncify_stop_rewind';
/** @public */
export declare type AsyncifyExports<T, U> = T extends Record<string, any> ? {
[P in keyof T]: T[P] extends Callable ? U extends Array<Exclude<keyof T, AsyncifyExportName>> ? P extends U[number] ? AsyncifyExportFunction<T[P]> : T[P] : AsyncifyExportFunction<T[P]> : T[P];
} : T;
/** @public */
export declare function asyncifyLoad(asyncify: AsyncifyOptions, urlOrBuffer: string | URL | BufferSource | WebAssembly.Module, imports?: WebAssembly.Imports): Promise<WebAssembly.WebAssemblyInstantiatedSource>;
/** @public */
export declare function asyncifyLoadSync(asyncify: AsyncifyOptions, buffer: BufferSource | WebAssembly.Module, imports?: WebAssembly.Imports): WebAssembly.WebAssemblyInstantiatedSource;
/** @public */
export declare interface AsyncifyOptions {
wasm64?: boolean;
tryAllocate?: boolean | {
size?: number;
name?: string;
};
wrapExports?: string[];
}
/** @public */
export declare interface AsyncWASIOptions extends WASIOptions {
fs: {
promises: IFsPromises;
};
asyncify?: Asyncify;
}
/** @public */
export declare interface BaseEncodingOptions {
encoding?: BufferEncoding_2;
}
/** @public */
export declare interface BigIntStats extends StatsBase<bigint> {
}
/** @public */
declare type BufferEncoding_2 = 'ascii' | 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2' | 'base64' | 'base64url' | 'latin1' | 'binary' | 'hex';
export { BufferEncoding_2 as BufferEncoding }
/** @public */
export declare type BufferEncodingOption = 'buffer' | {
encoding: 'buffer';
};
/** @public */
export declare type Callable = (...args: any[]) => any;
/** @public */
export declare function createAsyncWASI(options?: AsyncWASIOptions): Promise<WASI>;
/** @public */
export declare function extendMemory(memory: WebAssembly.Memory): Memory;
/** @public */
export declare interface FileHandle {
readonly fd: number;
datasync(): Promise<void>;
sync(): Promise<void>;
read<TBuffer extends Uint8Array>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{
bytesRead: number;
buffer: TBuffer;
}>;
stat(opts?: StatOptions & {
bigint?: false;
}): Promise<Stats>;
stat(opts: StatOptions & {
bigint: true;
}): Promise<BigIntStats>;
stat(opts?: StatOptions): Promise<Stats | BigIntStats>;
truncate(len?: number): Promise<void>;
utimes(atime: string | number | Date, mtime: string | number | Date): Promise<void>;
write<TBuffer extends Uint8Array>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{
bytesWritten: number;
buffer: TBuffer;
}>;
write(data: string | Uint8Array, position?: number, encoding?: BufferEncoding_2): Promise<{
bytesWritten: number;
buffer: string;
}>;
close(): Promise<void>;
}
/** @public */
export declare interface FinalizeBindingsOptions {
memory?: WebAssembly.Memory;
}
/** @public */
export declare interface IDirent {
isFile(): boolean;
isDirectory(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
name: string;
}
/** @public */
export declare interface IFs {
fstatSync(fd: number, options?: StatOptions & {
bigint?: false;
}): Stats;
fstatSync(fd: number, options: StatOptions & {
bigint: true;
}): BigIntStats;
fstatSync(fd: number, options?: StatOptions): Stats | BigIntStats;
statSync(path: PathLike, options?: StatOptions & {
bigint?: false;
}): Stats;
statSync(path: PathLike, options: StatOptions & {
bigint: true;
}): BigIntStats;
statSync(path: PathLike, options?: StatOptions): Stats | BigIntStats;
lstatSync(path: PathLike, options?: StatOptions & {
bigint?: false;
}): Stats;
lstatSync(path: PathLike, options: StatOptions & {
bigint: true;
}): BigIntStats;
lstatSync(path: PathLike, options?: StatOptions): Stats | BigIntStats;
utimesSync(path: PathLike, atime: string | number | Date, mtime: string | number | Date): void;
openSync(path: PathLike, flags: OpenMode, mode?: Mode): number;
readSync(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number | null): number;
readSync(fd: number, buffer: ArrayBufferView, opts?: ReadSyncOptions): number;
writeSync(fd: number, buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
writeSync(fd: number, string: string, position?: number, encoding?: BufferEncoding_2): number;
closeSync(fd: number): void;
readlinkSync(path: PathLike, options?: BaseEncodingOptions | BufferEncoding_2): string;
readlinkSync(path: PathLike, options: BufferEncodingOption): Uint8Array;
readlinkSync(path: PathLike, options?: BaseEncodingOptions | string): string | Uint8Array;
realpathSync(path: PathLike, options?: BaseEncodingOptions | BufferEncoding_2): string;
realpathSync(path: PathLike, options: BufferEncodingOption): Uint8Array;
realpathSync(path: PathLike, options?: BaseEncodingOptions | string): string | Uint8Array;
truncateSync(path: PathLike, len?: number): void;
ftruncateSync(fd: number, len?: number): void;
fdatasyncSync(fd: number): void;
futimesSync(fd: number, atime: string | number | Date, mtime: string | number | Date): void;
readdirSync(path: PathLike, options?: {
encoding: BufferEncoding_2 | null;
withFileTypes?: false;
} | BufferEncoding_2): string[];
readdirSync(path: PathLike, options: {
encoding: 'buffer';
withFileTypes?: false;
} | 'buffer'): Uint8Array[];
readdirSync(path: PathLike, options?: BaseEncodingOptions & {
withFileTypes?: false;
} | BufferEncoding_2): string[] | Uint8Array[];
readdirSync(path: PathLike, options: BaseEncodingOptions & {
withFileTypes: true;
}): IDirent[];
fsyncSync(fd: number): void;
mkdirSync(path: PathLike, options: MakeDirectoryOptions & {
recursive: true;
}): string | undefined;
mkdirSync(path: PathLike, options?: Mode | (MakeDirectoryOptions & {
recursive?: false;
})): void;
mkdirSync(path: PathLike, options?: Mode | MakeDirectoryOptions): string | undefined;
rmdirSync(path: PathLike, options?: RmDirOptions): void;
linkSync(existingPath: PathLike, newPath: PathLike): void;
unlinkSync(path: PathLike): void;
renameSync(oldPath: PathLike, newPath: PathLike): void;
symlinkSync(target: PathLike, path: PathLike, type?: 'dir' | 'file' | 'junction'): void;
}
/** @public */
export declare interface IFsPromises {
stat(path: PathLike, options?: StatOptions & {
bigint?: false;
}): Promise<Stats>;
stat(path: PathLike, options: StatOptions & {
bigint: true;
}): Promise<BigIntStats>;
stat(path: PathLike, options?: StatOptions): Promise<Stats | BigIntStats>;
lstat(path: PathLike, options?: StatOptions & {
bigint?: false;
}): Promise<Stats>;
lstat(path: PathLike, options: StatOptions & {
bigint: true;
}): Promise<BigIntStats>;
lstat(path: PathLike, options?: StatOptions): Promise<Stats | BigIntStats>;
utimes(path: PathLike, atime: string | number | Date, mtime: string | number | Date): Promise<void>;
open(path: PathLike, flags: OpenMode, mode?: Mode): Promise<FileHandle>;
read<TBuffer extends Uint8Array>(handle: FileHandle, buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{
bytesRead: number;
buffer: TBuffer;
}>;
write<TBuffer extends Uint8Array>(handle: FileHandle, buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{
bytesWritten: number;
buffer: TBuffer;
}>;
readlink(path: PathLike, options?: BaseEncodingOptions | BufferEncoding_2): Promise<string>;
readlink(path: PathLike, options: BufferEncodingOption): Promise<Uint8Array>;
readlink(path: PathLike, options?: BaseEncodingOptions | string): Promise<string | Uint8Array>;
realpath(path: PathLike, options?: BaseEncodingOptions | BufferEncoding_2): Promise<string>;
realpath(path: PathLike, options: BufferEncodingOption): Promise<Uint8Array>;
realpath(path: PathLike, options?: BaseEncodingOptions | string): Promise<string | Uint8Array>;
truncate(path: PathLike, len?: number): Promise<void>;
ftruncate(handle: FileHandle, len?: number): Promise<void>;
fdatasync(handle: FileHandle): Promise<void>;
futimes(handle: FileHandle, atime: string | number | Date, mtime: string | number | Date): Promise<void>;
readdir(path: PathLike, options?: {
encoding: BufferEncoding_2 | null;
withFileTypes?: false;
} | BufferEncoding_2): Promise<string[]>;
readdir(path: PathLike, options: {
encoding: 'buffer';
withFileTypes?: false;
} | 'buffer'): Promise<Uint8Array[]>;
readdir(path: PathLike, options?: BaseEncodingOptions & {
withFileTypes?: false;
} | BufferEncoding_2): Promise<string[] | Uint8Array[]>;
readdir(path: PathLike, options: BaseEncodingOptions & {
withFileTypes: true;
}): Promise<IDirent[]>;
fsync(handle: FileHandle): Promise<void>;
mkdir(path: PathLike, options: MakeDirectoryOptions & {
recursive: true;
}): Promise<string | undefined>;
mkdir(path: PathLike, options?: Mode | (MakeDirectoryOptions & {
recursive?: false;
})): Promise<void>;
mkdir(path: PathLike, options?: Mode | MakeDirectoryOptions): Promise<string | undefined>;
rmdir(path: PathLike, options?: RmDirOptions): Promise<void>;
link(existingPath: PathLike, newPath: PathLike): Promise<void>;
unlink(path: PathLike): Promise<void>;
rename(oldPath: PathLike, newPath: PathLike): Promise<void>;
symlink(target: PathLike, path: PathLike, type?: 'dir' | 'file' | 'junction'): Promise<void>;
}
declare const kBindingName: unique symbol;
declare const kExitCode: unique symbol;
declare const kInstance: unique symbol;
declare const kSetMemory: unique symbol;
declare const kStarted: unique symbol;
/** @public */
export declare function load(wasmInput: string | URL | BufferSource | WebAssembly.Module, imports?: WebAssembly.Imports): Promise<WebAssembly.WebAssemblyInstantiatedSource>;
/** @public */
export declare function loadSync(wasmInput: BufferSource | WebAssembly.Module, imports?: WebAssembly.Imports): WebAssembly.WebAssemblyInstantiatedSource;
/** @public */
export declare interface MakeDirectoryOptions {
recursive?: boolean;
mode?: Mode;
}
/** @public */
export declare class Memory extends WebAssemblyMemory {
constructor(descriptor: WebAssembly.MemoryDescriptor);
get HEAP8(): Int8Array;
get HEAPU8(): Uint8Array;
get HEAP16(): Int16Array;
get HEAPU16(): Uint16Array;
get HEAP32(): Int32Array;
get HEAPU32(): Uint32Array;
get HEAP64(): BigInt64Array;
get HEAPU64(): BigUint64Array;
get HEAPF32(): Float32Array;
get HEAPF64(): Float64Array;
get view(): DataView;
}
/** @public */
export declare type Mode = number | string;
/** @public */
export declare type OpenMode = number | string;
/** @public */
export declare type PathLike = string | Uint8Array | URL;
/** @public */
export declare type PromisifyExports<T, U> = T extends Record<string, any> ? {
[P in keyof T]: T[P] extends Callable ? U extends Array<keyof T> ? P extends U[number] ? AsyncifyExportFunction<T[P]> : T[P] : AsyncifyExportFunction<T[P]> : T[P];
} : T;
/** @public */
export declare interface ReadSyncOptions {
offset?: number;
length?: number;
position?: number;
}
/** @public */
export declare interface RmDirOptions {
maxRetries?: number;
recursive?: boolean;
retryDelay?: number;
}
/** @public */
export declare interface StatOptions {
bigint?: boolean;
}
/** @public */
export declare interface Stats extends StatsBase<number> {
}
/** @public */
export declare interface StatsBase<T> {
isFile(): boolean;
isDirectory(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isSymbolicLink(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
dev: T;
ino: T;
mode: T;
nlink: T;
uid: T;
gid: T;
rdev: T;
size: T;
blksize: T;
blocks: T;
atimeMs: T;
mtimeMs: T;
ctimeMs: T;
birthtimeMs: T;
atime: Date;
mtime: Date;
ctime: Date;
birthtime: Date;
}
/** @public */
export declare interface SyncWASIOptions extends WASIOptions {
fs?: IFs;
}
/** @public */
export declare class WASI {
private [kSetMemory];
private [kStarted];
private [kExitCode];
private [kInstance];
private [kBindingName];
readonly wasiImport: Record<string, any>;
constructor(options?: SyncWASIOptions);
finalizeBindings(instance: WebAssembly.Instance, { memory }?: FinalizeBindingsOptions): void;
start(instance: WebAssembly.Instance): number | undefined | Promise<number> | Promise<undefined>;
initialize(instance: WebAssembly.Instance): void | Promise<void>;
getImportObject(): Record<string, Record<string, any>>;
}
/** @public */
export declare interface WASIOptions {
version?: 'unstable' | 'preview1';
args?: string[] | undefined;
env?: Record<string, string> | undefined;
preopens?: Record<string, string> | undefined;
/**
* @defaultValue `false`
*/
returnOnExit?: boolean | undefined;
print?: (str: string) => void;
printErr?: (str: string) => void;
}
/** @public */
export declare const WebAssemblyMemory: {
new (descriptor: WebAssembly.MemoryDescriptor): WebAssembly.Memory;
prototype: WebAssembly.Memory;
};
/** @public */
export declare function wrapAsyncExport<T extends Function = any>(f: Function): T;
/** @public */
export declare function wrapAsyncImport<T extends (...args: any[]) => any>(f: T, parameterType: WebAssembly.ValueType[], returnType: WebAssembly.ValueType[]): (...args: [object, ...Parameters<T>]) => ReturnType<T>;
/** @public */
export declare function wrapExports<T extends WebAssembly.Exports>(exports: T): PromisifyExports<T, void>;
/** @public */
export declare function wrapExports<T extends WebAssembly.Exports, U extends Array<keyof T>>(exports: T, needWrap: U): PromisifyExports<T, U>;
export { }
export as namespace wasmUtil;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,158 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Asyncify = void 0;
const webassembly_1 = require("./webassembly");
const util_1 = require("./wasi/util");
const ignoreNames = [
'asyncify_get_state',
'asyncify_start_rewind',
'asyncify_start_unwind',
'asyncify_stop_rewind',
'asyncify_stop_unwind'
];
// const wrappedExports = new WeakMap<WebAssembly.Exports, WebAssembly.Exports>()
var AsyncifyState;
(function (AsyncifyState) {
AsyncifyState[AsyncifyState["NONE"] = 0] = "NONE";
AsyncifyState[AsyncifyState["UNWINDING"] = 1] = "UNWINDING";
AsyncifyState[AsyncifyState["REWINDING"] = 2] = "REWINDING";
})(AsyncifyState || (AsyncifyState = {}));
function tryAllocate(instance, wasm64, size, mallocName) {
if (typeof instance.exports[mallocName] !== 'function' || size <= 0) {
return {
wasm64,
dataPtr: 16,
start: wasm64 ? 32 : 24,
end: 1024
};
}
const malloc = instance.exports[mallocName];
const dataPtr = wasm64 ? Number(malloc(BigInt(16) + BigInt(size))) : malloc(8 + size);
if (dataPtr === 0) {
throw new Error('Allocate asyncify data failed');
}
return wasm64
? { wasm64, dataPtr, start: dataPtr + 16, end: dataPtr + 16 + size }
: { wasm64, dataPtr, start: dataPtr + 8, end: dataPtr + 8 + size };
}
/** @public */
class Asyncify {
constructor() {
this.value = undefined;
this.exports = undefined;
this.dataPtr = 0;
}
init(memory, instance, options) {
var _a, _b;
if (this.exports) {
throw new Error('Asyncify has been initialized');
}
if (!(memory instanceof webassembly_1._WebAssembly.Memory)) {
throw new TypeError('Require WebAssembly.Memory object');
}
const exports = instance.exports;
for (let i = 0; i < ignoreNames.length; ++i) {
if (typeof exports[ignoreNames[i]] !== 'function') {
throw new TypeError('Invalid asyncify wasm');
}
}
let address;
const wasm64 = Boolean(options.wasm64);
if (!options.tryAllocate) {
address = {
wasm64,
dataPtr: 16,
start: wasm64 ? 32 : 24,
end: 1024
};
}
else {
if (options.tryAllocate === true) {
address = tryAllocate(instance, wasm64, 4096, 'malloc');
}
else {
address = tryAllocate(instance, wasm64, (_a = options.tryAllocate.size) !== null && _a !== void 0 ? _a : 4096, (_b = options.tryAllocate.name) !== null && _b !== void 0 ? _b : 'malloc');
}
}
this.dataPtr = address.dataPtr;
if (wasm64) {
new BigInt64Array(memory.buffer, this.dataPtr).set([BigInt(address.start), BigInt(address.end)]);
}
else {
new Int32Array(memory.buffer, this.dataPtr).set([address.start, address.end]);
}
this.exports = this.wrapExports(exports, options.wrapExports);
const asyncifiedInstance = Object.create(webassembly_1._WebAssembly.Instance.prototype);
Object.defineProperty(asyncifiedInstance, 'exports', { value: this.exports });
// Object.setPrototypeOf(instance, Instance.prototype)
return asyncifiedInstance;
}
assertState() {
if (this.exports.asyncify_get_state() !== AsyncifyState.NONE) {
throw new Error('Asyncify state error');
}
}
wrapImportFunction(f) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this = this;
return (function () {
// eslint-disable-next-line no-unreachable-loop
while (_this.exports.asyncify_get_state() === AsyncifyState.REWINDING) {
_this.exports.asyncify_stop_rewind();
return _this.value;
}
_this.assertState();
const v = f.apply(this, arguments);
if (!(0, util_1.isPromiseLike)(v))
return v;
_this.exports.asyncify_start_unwind(_this.dataPtr);
_this.value = v;
});
}
wrapImports(imports) {
const importObject = {};
Object.keys(imports).forEach(k => {
const mod = imports[k];
const newModule = {};
Object.keys(mod).forEach(name => {
const importValue = mod[name];
if (typeof importValue === 'function') {
newModule[name] = this.wrapImportFunction(importValue);
}
else {
newModule[name] = importValue;
}
});
importObject[k] = newModule;
});
return importObject;
}
wrapExportFunction(f) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this = this;
return (async function () {
_this.assertState();
let ret = f.apply(this, arguments);
while (_this.exports.asyncify_get_state() === AsyncifyState.UNWINDING) {
_this.exports.asyncify_stop_unwind();
_this.value = await _this.value;
_this.assertState();
_this.exports.asyncify_start_rewind(_this.dataPtr);
ret = f.call(this);
}
_this.assertState();
return ret;
});
}
wrapExports(exports, needWrap) {
return (0, util_1.wrapInstanceExports)(exports, (exportValue, name) => {
let ignore = ignoreNames.indexOf(name) !== -1 || typeof exportValue !== 'function';
if (Array.isArray(needWrap)) {
ignore = ignore || (needWrap.indexOf(name) === -1);
}
return ignore ? exportValue : this.wrapExportFunction(exportValue);
});
}
}
exports.Asyncify = Asyncify;
//# sourceMappingURL=asyncify.js.map
@@ -0,0 +1,13 @@
"use strict";
/**
* @packageDocumentation
*/
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./asyncify"), exports);
tslib_1.__exportStar(require("./load"), exports);
tslib_1.__exportStar(require("./wasi/index"), exports);
tslib_1.__exportStar(require("./memory"), exports);
tslib_1.__exportStar(require("./jspi"), exports);
tslib_1.__exportStar(require("./wasi/fs"), exports);
//# sourceMappingURL=index.js.map
@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapExports = exports.wrapAsyncExport = exports.wrapAsyncImport = void 0;
const util_1 = require("./wasi/util");
const webassembly_1 = require("./webassembly");
function checkWebAssemblyFunction() {
const WebAssemblyFunction = webassembly_1._WebAssembly.Function;
if (typeof WebAssemblyFunction !== 'function') {
throw new Error('WebAssembly.Function is not supported in this environment.' +
' If you are using V8 based browser like Chrome, try to specify' +
' --js-flags="--wasm-staging --experimental-wasm-stack-switching"');
}
return WebAssemblyFunction;
}
/** @public */
function wrapAsyncImport(f, parameterType, returnType) {
const WebAssemblyFunction = checkWebAssemblyFunction();
if (typeof f !== 'function') {
throw new TypeError('Function required');
}
const parameters = parameterType.slice(0);
parameters.unshift('externref');
return new WebAssemblyFunction({ parameters, results: returnType }, f, { suspending: 'first' });
}
exports.wrapAsyncImport = wrapAsyncImport;
/** @public */
function wrapAsyncExport(f) {
const WebAssemblyFunction = checkWebAssemblyFunction();
if (typeof f !== 'function') {
throw new TypeError('Function required');
}
return new WebAssemblyFunction({ parameters: [...WebAssemblyFunction.type(f).parameters.slice(1)], results: ['externref'] }, f, { promising: 'first' });
}
exports.wrapAsyncExport = wrapAsyncExport;
/** @public */
function wrapExports(exports, needWrap) {
return (0, util_1.wrapInstanceExports)(exports, (exportValue, name) => {
let ignore = typeof exportValue !== 'function';
if (Array.isArray(needWrap)) {
ignore = ignore || (needWrap.indexOf(name) === -1);
}
return ignore ? exportValue : wrapAsyncExport(exportValue);
});
}
exports.wrapExports = wrapExports;
//# sourceMappingURL=jspi.js.map
@@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.asyncifyLoadSync = exports.loadSync = exports.asyncifyLoad = exports.load = void 0;
const webassembly_1 = require("./webassembly");
const asyncify_1 = require("./asyncify");
function validateImports(imports) {
if (imports && typeof imports !== 'object') {
throw new TypeError('imports must be an object or undefined');
}
}
function fetchWasm(urlOrBuffer, imports) {
if (typeof wx !== 'undefined' && typeof __wxConfig !== 'undefined') {
return webassembly_1._WebAssembly.instantiate(urlOrBuffer, imports);
}
return fetch(urlOrBuffer)
.then(response => response.arrayBuffer())
.then(buffer => webassembly_1._WebAssembly.instantiate(buffer, imports));
}
/** @public */
function load(wasmInput, imports) {
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
let source;
if (wasmInput instanceof ArrayBuffer || ArrayBuffer.isView(wasmInput)) {
return webassembly_1._WebAssembly.instantiate(wasmInput, imports);
}
if (wasmInput instanceof webassembly_1._WebAssembly.Module) {
return webassembly_1._WebAssembly.instantiate(wasmInput, imports).then((instance) => {
return { instance, module: wasmInput };
});
}
if (typeof wasmInput !== 'string' && !(wasmInput instanceof URL)) {
throw new TypeError('Invalid source');
}
if (typeof webassembly_1._WebAssembly.instantiateStreaming === 'function') {
let responsePromise;
try {
responsePromise = fetch(wasmInput);
source = webassembly_1._WebAssembly.instantiateStreaming(responsePromise, imports).catch(() => {
return fetchWasm(wasmInput, imports);
});
}
catch (_) {
source = fetchWasm(wasmInput, imports);
}
}
else {
source = fetchWasm(wasmInput, imports);
}
return source;
}
exports.load = load;
/** @public */
function asyncifyLoad(asyncify, urlOrBuffer, imports) {
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
const asyncifyHelper = new asyncify_1.Asyncify();
imports = asyncifyHelper.wrapImports(imports);
return load(urlOrBuffer, imports).then(source => {
var _a;
const memory = source.instance.exports.memory || ((_a = imports.env) === null || _a === void 0 ? void 0 : _a.memory);
return { module: source.module, instance: asyncifyHelper.init(memory, source.instance, asyncify) };
});
}
exports.asyncifyLoad = asyncifyLoad;
/** @public */
function loadSync(wasmInput, imports) {
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
let module;
if ((wasmInput instanceof ArrayBuffer) || ArrayBuffer.isView(wasmInput)) {
module = new webassembly_1._WebAssembly.Module(wasmInput);
}
else if (wasmInput instanceof WebAssembly.Module) {
module = wasmInput;
}
else {
throw new TypeError('Invalid source');
}
const instance = new webassembly_1._WebAssembly.Instance(module, imports);
const source = { instance, module };
return source;
}
exports.loadSync = loadSync;
/** @public */
function asyncifyLoadSync(asyncify, buffer, imports) {
var _a;
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
const asyncifyHelper = new asyncify_1.Asyncify();
imports = asyncifyHelper.wrapImports(imports);
const source = loadSync(buffer, imports);
const memory = source.instance.exports.memory || ((_a = imports.env) === null || _a === void 0 ? void 0 : _a.memory);
return { module: source.module, instance: asyncifyHelper.init(memory, source.instance, asyncify) };
}
exports.asyncifyLoadSync = asyncifyLoadSync;
//# sourceMappingURL=load.js.map
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extendMemory = exports.Memory = exports.WebAssemblyMemory = void 0;
/* eslint-disable spaced-comment */
const webassembly_1 = require("./webassembly");
/** @public */
exports.WebAssemblyMemory = (function () { return webassembly_1._WebAssembly.Memory; })();
/** @public */
class Memory extends exports.WebAssemblyMemory {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(descriptor) {
super(descriptor);
}
get HEAP8() { return new Int8Array(super.buffer); }
get HEAPU8() { return new Uint8Array(super.buffer); }
get HEAP16() { return new Int16Array(super.buffer); }
get HEAPU16() { return new Uint16Array(super.buffer); }
get HEAP32() { return new Int32Array(super.buffer); }
get HEAPU32() { return new Uint32Array(super.buffer); }
get HEAP64() { return new BigInt64Array(super.buffer); }
get HEAPU64() { return new BigUint64Array(super.buffer); }
get HEAPF32() { return new Float32Array(super.buffer); }
get HEAPF64() { return new Float64Array(super.buffer); }
get view() { return new DataView(super.buffer); }
}
exports.Memory = Memory;
/** @public */
function extendMemory(memory) {
if (Object.getPrototypeOf(memory) === webassembly_1._WebAssembly.Memory.prototype) {
Object.setPrototypeOf(memory, Memory.prototype);
}
return memory;
}
exports.extendMemory = extendMemory;
//# sourceMappingURL=memory.js.map
@@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WasiError = exports.strerror = void 0;
const types_1 = require("./types");
function strerror(errno) {
switch (errno) {
case types_1.WasiErrno.ESUCCESS: return 'Success';
case types_1.WasiErrno.E2BIG: return 'Argument list too long';
case types_1.WasiErrno.EACCES: return 'Permission denied';
case types_1.WasiErrno.EADDRINUSE: return 'Address in use';
case types_1.WasiErrno.EADDRNOTAVAIL: return 'Address not available';
case types_1.WasiErrno.EAFNOSUPPORT: return 'Address family not supported by protocol';
case types_1.WasiErrno.EAGAIN: return 'Resource temporarily unavailable';
case types_1.WasiErrno.EALREADY: return 'Operation already in progress';
case types_1.WasiErrno.EBADF: return 'Bad file descriptor';
case types_1.WasiErrno.EBADMSG: return 'Bad message';
case types_1.WasiErrno.EBUSY: return 'Resource busy';
case types_1.WasiErrno.ECANCELED: return 'Operation canceled';
case types_1.WasiErrno.ECHILD: return 'No child process';
case types_1.WasiErrno.ECONNABORTED: return 'Connection aborted';
case types_1.WasiErrno.ECONNREFUSED: return 'Connection refused';
case types_1.WasiErrno.ECONNRESET: return 'Connection reset by peer';
case types_1.WasiErrno.EDEADLK: return 'Resource deadlock would occur';
case types_1.WasiErrno.EDESTADDRREQ: return 'Destination address required';
case types_1.WasiErrno.EDOM: return 'Domain error';
case types_1.WasiErrno.EDQUOT: return 'Quota exceeded';
case types_1.WasiErrno.EEXIST: return 'File exists';
case types_1.WasiErrno.EFAULT: return 'Bad address';
case types_1.WasiErrno.EFBIG: return 'File too large';
case types_1.WasiErrno.EHOSTUNREACH: return 'Host is unreachable';
case types_1.WasiErrno.EIDRM: return 'Identifier removed';
case types_1.WasiErrno.EILSEQ: return 'Illegal byte sequence';
case types_1.WasiErrno.EINPROGRESS: return 'Operation in progress';
case types_1.WasiErrno.EINTR: return 'Interrupted system call';
case types_1.WasiErrno.EINVAL: return 'Invalid argument';
case types_1.WasiErrno.EIO: return 'I/O error';
case types_1.WasiErrno.EISCONN: return 'Socket is connected';
case types_1.WasiErrno.EISDIR: return 'Is a directory';
case types_1.WasiErrno.ELOOP: return 'Symbolic link loop';
case types_1.WasiErrno.EMFILE: return 'No file descriptors available';
case types_1.WasiErrno.EMLINK: return 'Too many links';
case types_1.WasiErrno.EMSGSIZE: return 'Message too large';
case types_1.WasiErrno.EMULTIHOP: return 'Multihop attempted';
case types_1.WasiErrno.ENAMETOOLONG: return 'Filename too long';
case types_1.WasiErrno.ENETDOWN: return 'Network is down';
case types_1.WasiErrno.ENETRESET: return 'Connection reset by network';
case types_1.WasiErrno.ENETUNREACH: return 'Network unreachable';
case types_1.WasiErrno.ENFILE: return 'Too many files open in system';
case types_1.WasiErrno.ENOBUFS: return 'No buffer space available';
case types_1.WasiErrno.ENODEV: return 'No such device';
case types_1.WasiErrno.ENOENT: return 'No such file or directory';
case types_1.WasiErrno.ENOEXEC: return 'Exec format error';
case types_1.WasiErrno.ENOLCK: return 'No locks available';
case types_1.WasiErrno.ENOLINK: return 'Link has been severed';
case types_1.WasiErrno.ENOMEM: return 'Out of memory';
case types_1.WasiErrno.ENOMSG: return 'No message of the desired type';
case types_1.WasiErrno.ENOPROTOOPT: return 'Protocol not available';
case types_1.WasiErrno.ENOSPC: return 'No space left on device';
case types_1.WasiErrno.ENOSYS: return 'Function not implemented';
case types_1.WasiErrno.ENOTCONN: return 'Socket not connected';
case types_1.WasiErrno.ENOTDIR: return 'Not a directory';
case types_1.WasiErrno.ENOTEMPTY: return 'Directory not empty';
case types_1.WasiErrno.ENOTRECOVERABLE: return 'State not recoverable';
case types_1.WasiErrno.ENOTSOCK: return 'Not a socket';
case types_1.WasiErrno.ENOTSUP: return 'Not supported';
case types_1.WasiErrno.ENOTTY: return 'Not a tty';
case types_1.WasiErrno.ENXIO: return 'No such device or address';
case types_1.WasiErrno.EOVERFLOW: return 'Value too large for data type';
case types_1.WasiErrno.EOWNERDEAD: return 'Previous owner died';
case types_1.WasiErrno.EPERM: return 'Operation not permitted';
case types_1.WasiErrno.EPIPE: return 'Broken pipe';
case types_1.WasiErrno.EPROTO: return 'Protocol error';
case types_1.WasiErrno.EPROTONOSUPPORT: return 'Protocol not supported';
case types_1.WasiErrno.EPROTOTYPE: return 'Protocol wrong type for socket';
case types_1.WasiErrno.ERANGE: return 'Result not representable';
case types_1.WasiErrno.EROFS: return 'Read-only file system';
case types_1.WasiErrno.ESPIPE: return 'Invalid seek';
case types_1.WasiErrno.ESRCH: return 'No such process';
case types_1.WasiErrno.ESTALE: return 'Stale file handle';
case types_1.WasiErrno.ETIMEDOUT: return 'Operation timed out';
case types_1.WasiErrno.ETXTBSY: return 'Text file busy';
case types_1.WasiErrno.EXDEV: return 'Cross-device link';
case types_1.WasiErrno.ENOTCAPABLE: return 'Capabilities insufficient';
default: return 'Unknown error';
}
}
exports.strerror = strerror;
class WasiError extends Error {
constructor(message, errno) {
super(message);
this.errno = errno;
}
getErrorMessage() {
return strerror(this.errno);
}
}
exports.WasiError = WasiError;
Object.defineProperty(WasiError.prototype, 'name', {
configurable: true,
writable: true,
value: 'WasiError'
});
//# sourceMappingURL=error.js.map
@@ -0,0 +1,268 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncTable = exports.SyncTable = exports.FileDescriptorTable = exports.toFileStat = exports.toFileType = exports.StandardOutput = exports.FileDescriptor = exports.concatBuffer = void 0;
const types_1 = require("./types");
const rights_1 = require("./rights");
const error_1 = require("./error");
function concatBuffer(buffers, size) {
let total = 0;
if (typeof size === 'number' && size >= 0) {
total = size;
}
else {
for (let i = 0; i < buffers.length; i++) {
const buffer = buffers[i];
total += buffer.length;
}
}
let pos = 0;
const ret = new Uint8Array(total);
for (let i = 0; i < buffers.length; i++) {
const buffer = buffers[i];
ret.set(buffer, pos);
pos += buffer.length;
}
return ret;
}
exports.concatBuffer = concatBuffer;
class FileDescriptor {
constructor(id, fd, path, realPath, type, rightsBase, rightsInheriting, preopen) {
this.id = id;
this.fd = fd;
this.path = path;
this.realPath = realPath;
this.type = type;
this.rightsBase = rightsBase;
this.rightsInheriting = rightsInheriting;
this.preopen = preopen;
this.pos = BigInt(0);
this.size = BigInt(0);
}
seek(offset, whence) {
if (whence === types_1.WasiWhence.SET) {
this.pos = BigInt(offset);
}
else if (whence === types_1.WasiWhence.CUR) {
this.pos += BigInt(offset);
}
else if (whence === types_1.WasiWhence.END) {
this.pos = BigInt(this.size) - BigInt(offset);
}
else {
throw new error_1.WasiError('Unknown whence', types_1.WasiErrno.EIO);
}
return this.pos;
}
}
exports.FileDescriptor = FileDescriptor;
class StandardOutput extends FileDescriptor {
constructor(log, id, fd, path, realPath, type, rightsBase, rightsInheriting, preopen) {
super(id, fd, path, realPath, type, rightsBase, rightsInheriting, preopen);
this._log = log;
this._buf = null;
}
write(buffer) {
const originalBuffer = buffer;
if (this._buf) {
buffer = concatBuffer([this._buf, buffer]);
this._buf = null;
}
if (buffer.indexOf(10) === -1) {
this._buf = buffer;
return originalBuffer.byteLength;
}
let written = 0;
let lastBegin = 0;
let index;
while ((index = buffer.indexOf(10, written)) !== -1) {
const str = new TextDecoder().decode(buffer.subarray(lastBegin, index));
this._log(str);
written += index - lastBegin + 1;
lastBegin = index + 1;
}
if (written < buffer.length) {
this._buf = buffer.slice(written);
}
return originalBuffer.byteLength;
}
}
exports.StandardOutput = StandardOutput;
function toFileType(stat) {
if (stat.isBlockDevice())
return types_1.WasiFileType.BLOCK_DEVICE;
if (stat.isCharacterDevice())
return types_1.WasiFileType.CHARACTER_DEVICE;
if (stat.isDirectory())
return types_1.WasiFileType.DIRECTORY;
if (stat.isSocket())
return types_1.WasiFileType.SOCKET_STREAM;
if (stat.isFile())
return types_1.WasiFileType.REGULAR_FILE;
if (stat.isSymbolicLink())
return types_1.WasiFileType.SYMBOLIC_LINK;
return types_1.WasiFileType.UNKNOWN;
}
exports.toFileType = toFileType;
function toFileStat(view, buf, stat) {
view.setBigUint64(buf, stat.dev, true);
view.setBigUint64(buf + 8, stat.ino, true);
view.setBigUint64(buf + 16, BigInt(toFileType(stat)), true);
view.setBigUint64(buf + 24, stat.nlink, true);
view.setBigUint64(buf + 32, stat.size, true);
view.setBigUint64(buf + 40, stat.atimeMs * BigInt(1000000), true);
view.setBigUint64(buf + 48, stat.mtimeMs * BigInt(1000000), true);
view.setBigUint64(buf + 56, stat.ctimeMs * BigInt(1000000), true);
}
exports.toFileStat = toFileStat;
class FileDescriptorTable {
constructor(options) {
this.used = 0;
this.size = options.size;
this.fds = Array(options.size);
this.stdio = [options.in, options.out, options.err];
this.print = options.print;
this.printErr = options.printErr;
this.insertStdio(options.in, 0, '<stdin>');
this.insertStdio(options.out, 1, '<stdout>');
this.insertStdio(options.err, 2, '<stderr>');
}
insertStdio(fd, expected, name) {
const type = types_1.WasiFileType.CHARACTER_DEVICE;
const { base, inheriting } = (0, rights_1.getRights)(this.stdio, fd, types_1.FileControlFlag.O_RDWR, type);
const wrap = this.insert(fd, name, name, type, base, inheriting, 0);
if (wrap.id !== expected) {
throw new error_1.WasiError(`id: ${wrap.id} !== expected: ${expected}`, types_1.WasiErrno.EBADF);
}
return wrap;
}
insert(fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen) {
var _a, _b;
let index = -1;
if (this.used >= this.size) {
const newSize = this.size * 2;
this.fds.length = newSize;
index = this.size;
this.size = newSize;
}
else {
for (let i = 0; i < this.size; ++i) {
if (this.fds[i] == null) {
index = i;
break;
}
}
}
let entry;
if (mappedPath === '<stdout>') {
entry = new StandardOutput((_a = this.print) !== null && _a !== void 0 ? _a : console.log, index, fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen);
}
else if (mappedPath === '<stderr>') {
entry = new StandardOutput((_b = this.printErr) !== null && _b !== void 0 ? _b : console.error, index, fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen);
}
else {
entry = new FileDescriptor(index, fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen);
}
this.fds[index] = entry;
this.used++;
return entry;
}
get(id, base, inheriting) {
if (id >= this.size) {
throw new error_1.WasiError('Invalid fd', types_1.WasiErrno.EBADF);
}
const entry = this.fds[id];
if (!entry || entry.id !== id) {
throw new error_1.WasiError('Bad file descriptor', types_1.WasiErrno.EBADF);
}
/* Validate that the fd has the necessary rights. */
if ((~entry.rightsBase & base) !== BigInt(0) || (~entry.rightsInheriting & inheriting) !== BigInt(0)) {
throw new error_1.WasiError('Capabilities insufficient', types_1.WasiErrno.ENOTCAPABLE);
}
return entry;
}
remove(id) {
if (id >= this.size) {
throw new error_1.WasiError('Invalid fd', types_1.WasiErrno.EBADF);
}
const entry = this.fds[id];
if (!entry || entry.id !== id) {
throw new error_1.WasiError('Bad file descriptor', types_1.WasiErrno.EBADF);
}
this.fds[id] = undefined;
this.used--;
}
}
exports.FileDescriptorTable = FileDescriptorTable;
class SyncTable extends FileDescriptorTable {
constructor(options) {
super(options);
this.fs = options.fs;
}
getFileTypeByFd(fd) {
const stats = this.fs.fstatSync(fd, { bigint: true });
return toFileType(stats);
}
insertPreopen(fd, mappedPath, realPath) {
const type = this.getFileTypeByFd(fd);
if (type !== types_1.WasiFileType.DIRECTORY) {
throw new error_1.WasiError(`Preopen not dir: ["${mappedPath}", "${realPath}"]`, types_1.WasiErrno.ENOTDIR);
}
const result = (0, rights_1.getRights)(this.stdio, fd, 0, type);
return this.insert(fd, mappedPath, realPath, type, result.base, result.inheriting, 1);
}
renumber(dst, src) {
if (dst === src)
return;
if (dst >= this.size || src >= this.size) {
throw new error_1.WasiError('Invalid fd', types_1.WasiErrno.EBADF);
}
const dstEntry = this.fds[dst];
const srcEntry = this.fds[src];
if (!dstEntry || !srcEntry || dstEntry.id !== dst || srcEntry.id !== src) {
throw new error_1.WasiError('Invalid fd', types_1.WasiErrno.EBADF);
}
this.fs.closeSync(dstEntry.fd);
this.fds[dst] = this.fds[src];
this.fds[dst].id = dst;
this.fds[src] = undefined;
this.used--;
}
}
exports.SyncTable = SyncTable;
class AsyncTable extends FileDescriptorTable {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(options) {
super(options);
}
async getFileTypeByFd(fd) {
const stats = await fd.stat({ bigint: true });
return toFileType(stats);
}
async insertPreopen(fd, mappedPath, realPath) {
const type = await this.getFileTypeByFd(fd);
if (type !== types_1.WasiFileType.DIRECTORY) {
throw new error_1.WasiError(`Preopen not dir: ["${mappedPath}", "${realPath}"]`, types_1.WasiErrno.ENOTDIR);
}
const result = (0, rights_1.getRights)(this.stdio, fd.fd, 0, type);
return this.insert(fd, mappedPath, realPath, type, result.base, result.inheriting, 1);
}
async renumber(dst, src) {
if (dst === src)
return;
if (dst >= this.size || src >= this.size) {
throw new error_1.WasiError('Invalid fd', types_1.WasiErrno.EBADF);
}
const dstEntry = this.fds[dst];
const srcEntry = this.fds[src];
if (!dstEntry || !srcEntry || dstEntry.id !== dst || srcEntry.id !== src) {
throw new error_1.WasiError('Invalid fd', types_1.WasiErrno.EBADF);
}
await dstEntry.fd.close();
this.fds[dst] = this.fds[src];
this.fds[dst].id = dst;
this.fds[src] = undefined;
this.used--;
}
}
exports.AsyncTable = AsyncTable;
//# sourceMappingURL=fd.js.map
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=fs.js.map
@@ -0,0 +1,192 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAsyncWASI = exports.WASI = void 0;
const preview1_1 = require("./preview1");
const util_1 = require("./util");
// eslint-disable-next-line spaced-comment
const kEmptyObject = /*#__PURE__*/ Object.freeze(/*#__PURE__*/ Object.create(null));
const kExitCode = Symbol('kExitCode');
const kSetMemory = Symbol('kSetMemory');
const kStarted = Symbol('kStarted');
const kInstance = Symbol('kInstance');
const kBindingName = Symbol('kBindingName');
function validateOptions(options) {
var _a;
(0, util_1.validateObject)(options, 'options');
let _WASI;
if (options.version !== undefined) {
(0, util_1.validateString)(options.version, 'options.version');
switch (options.version) {
case 'unstable':
_WASI = preview1_1.WASI;
this[kBindingName] = 'wasi_unstable';
break;
case 'preview1':
_WASI = preview1_1.WASI;
this[kBindingName] = 'wasi_snapshot_preview1';
break;
default:
throw new TypeError(`unsupported WASI version "${options.version}"`);
}
}
else {
_WASI = preview1_1.WASI;
this[kBindingName] = 'wasi_snapshot_preview1';
}
if (options.args !== undefined) {
(0, util_1.validateArray)(options.args, 'options.args');
}
const args = ((_a = options.args) !== null && _a !== void 0 ? _a : []).map(String);
const env = [];
if (options.env !== undefined) {
(0, util_1.validateObject)(options.env, 'options.env');
Object.entries(options.env).forEach(({ 0: key, 1: value }) => {
if (value !== undefined) {
env.push(`${key}=${value}`);
}
});
}
const preopens = [];
if (options.preopens !== undefined) {
(0, util_1.validateObject)(options.preopens, 'options.preopens');
Object.entries(options.preopens).forEach(({ 0: key, 1: value }) => preopens.push({ mappedPath: String(key), realPath: String(value) }));
}
if (preopens.length > 0) {
if (options.fs === undefined) {
throw new Error('filesystem is disabled, can not preopen directory');
}
try {
(0, util_1.validateObject)(options.fs, 'options.fs');
}
catch (_) {
throw new TypeError('Node.js fs like implementation is not provided');
}
}
// if (options.filesystem !== undefined) {
// validateObject(options.filesystem, 'options.filesystem')
// validateString(options.filesystem.type, 'options.filesystem.type')
// if (options.filesystem.type !== 'memfs' && options.filesystem.type !== 'file-system-access-api') {
// throw new Error(`Filesystem type ${(options.filesystem as any).type as string} is not supported, only "memfs" and "file-system-access-api" is supported currently`)
// }
// try {
// validateObject(options.filesystem.fs, 'options.filesystem.fs')
// } catch (_) {
// throw new Error('Node.js fs like implementation is not provided')
// }
// }
if (options.print !== undefined)
(0, util_1.validateFunction)(options.print, 'options.print');
if (options.printErr !== undefined)
(0, util_1.validateFunction)(options.printErr, 'options.printErr');
if (options.returnOnExit !== undefined) {
(0, util_1.validateBoolean)(options.returnOnExit, 'options.returnOnExit');
}
// const { stdin = 0, stdout = 1, stderr = 2 } = options
// validateInt32(stdin, 'options.stdin', 0)
// validateInt32(stdout, 'options.stdout', 0)
// validateInt32(stderr, 'options.stderr', 0)
// const stdio = [stdin, stdout, stderr] as const
const stdio = [0, 1, 2];
return {
args,
env,
preopens,
stdio,
_WASI
};
}
function initWASI(setMemory, wrap) {
this[kSetMemory] = setMemory;
this.wasiImport = wrap;
this[kStarted] = false;
this[kExitCode] = 0;
this[kInstance] = undefined;
}
/** @public */
class WASI {
constructor(options = kEmptyObject) {
const { args, env, preopens, stdio, _WASI } = validateOptions.call(this, options);
const wrap = _WASI.createSync(args, env, preopens, stdio, options.fs, options.print, options.printErr);
const setMemory = wrap._setMemory;
delete wrap._setMemory;
initWASI.call(this, setMemory, wrap);
if (options.returnOnExit) {
wrap.proc_exit = wasiReturnOnProcExit.bind(this);
}
}
finalizeBindings(instance, _a) {
var _b;
var { memory = (_b = instance === null || instance === void 0 ? void 0 : instance.exports) === null || _b === void 0 ? void 0 : _b.memory } = _a === void 0 ? {} : _a;
if (this[kStarted]) {
throw new Error('WASI instance has already started');
}
(0, util_1.validateObject)(instance, 'instance');
(0, util_1.validateObject)(instance.exports, 'instance.exports');
this[kSetMemory](memory);
this[kInstance] = instance;
this[kStarted] = true;
}
// Must not export _initialize, must export _start
start(instance) {
this.finalizeBindings(instance);
const { _start, _initialize } = this[kInstance].exports;
(0, util_1.validateFunction)(_start, 'instance.exports._start');
(0, util_1.validateUndefined)(_initialize, 'instance.exports._initialize');
let ret;
try {
ret = _start();
}
catch (err) {
if (err !== kExitCode) {
throw err;
}
}
if (ret instanceof Promise) {
return ret.then(() => this[kExitCode], (err) => {
if (err !== kExitCode) {
throw err;
}
return this[kExitCode];
});
}
return this[kExitCode];
}
// Must not export _start, may optionally export _initialize
initialize(instance) {
this.finalizeBindings(instance);
const { _start, _initialize } = this[kInstance].exports;
(0, util_1.validateUndefined)(_start, 'instance.exports._start');
if (_initialize !== undefined) {
(0, util_1.validateFunction)(_initialize, 'instance.exports._initialize');
return _initialize();
}
}
getImportObject() {
return { [this[kBindingName]]: this.wasiImport };
}
}
exports.WASI = WASI;
function wasiReturnOnProcExit(rval) {
this[kExitCode] = rval;
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw kExitCode;
}
/** @public */
async function createAsyncWASI(options = kEmptyObject) {
const _this = Object.create(WASI.prototype);
const { args, env, preopens, stdio, _WASI } = validateOptions.call(_this, options);
if (options.asyncify !== undefined) {
(0, util_1.validateObject)(options.asyncify, 'options.asyncify');
(0, util_1.validateFunction)(options.asyncify.wrapImportFunction, 'options.asyncify.wrapImportFunction');
}
const wrap = await _WASI.createAsync(args, env, preopens, stdio, options.fs, options.print, options.printErr, options.asyncify);
const setMemory = wrap._setMemory;
delete wrap._setMemory;
initWASI.call(_this, setMemory, wrap);
if (options.returnOnExit) {
wrap.proc_exit = wasiReturnOnProcExit.bind(_this);
}
return _this;
}
exports.createAsyncWASI = createAsyncWASI;
//# sourceMappingURL=index.js.map
@@ -0,0 +1,316 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.relative = exports.resolve = void 0;
const util_1 = require("./util");
const CHAR_DOT = 46; /* . */
const CHAR_FORWARD_SLASH = 47; /* / */
const CHAR_BACKWARD_SLASH = 92; /* \ */
const CHAR_COLON = 58; /* : */
const CHAR_UPPERCASE_A = 65; /* A */
const CHAR_UPPERCASE_Z = 90; /* Z */
const CHAR_LOWERCASE_A = 97; /* a */
const CHAR_LOWERCASE_Z = 122; /* z */
function isPathSeparatorWin(code) {
return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
}
function isWindowsDeviceRoot(code) {
return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
(code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z);
}
const _isWin32 = typeof process !== 'undefined' && process.platform === 'win32';
/**
* Windows variant of `resolve()`. Mirrors Node's `path.win32.resolve`
* semantics enough for the WASI shim's needs (drive-letter absolutes
* + UNC paths + per-drive cwd lookups via `process.env`/`process.cwd`).
*
* Why this is needed: on Windows, `FileDescriptor.realPath` is the
* host realpath returned by `fs.realpathSync(realPath, 'utf8')` — the
* backslash form `D:\…`. The POSIX-only `resolveImpl` below only
* treats `/` as a separator, reads `D` as non-`/`, decides realPath
* is "relative", and produces a garbage joined path. Downstream
* `fs.openSync(garbage)` then returns `EINVAL` and the WASI caller
* sees a permanent failure. This function gives us the correct
* Windows-style resolution without taking a Node-only `path` import
* (which would break browser bundles of this package).
*
* Cribbed from Node's `lib/path.js` `win32.resolve()` (MIT-licensed),
* trimmed to what WASI realpath resolution actually exercises.
*/
function resolveWin32(args) {
let resolvedDevice = '';
let resolvedTail = '';
let resolvedAbsolute = false;
for (let i = args.length - 1; i >= -1; i--) {
let path;
if (i >= 0) {
path = args[i];
(0, util_1.validateString)(path, 'path');
if (path.length === 0)
continue;
}
else if (resolvedDevice.length === 0) {
path = (typeof process !== 'undefined' && typeof process.cwd === 'function')
? process.cwd()
: '';
}
else {
// Look up per-drive cwd via the `=X:` env var convention; fall back
// to the global cwd if absent.
const envKey = `=${resolvedDevice}`;
const env = (typeof process !== 'undefined') ? process.env : undefined;
path = (env && typeof env[envKey] === 'string')
? env[envKey]
: (typeof process !== 'undefined' && typeof process.cwd === 'function')
? process.cwd()
: '';
if (path === undefined ||
(path.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() &&
path.charCodeAt(2) === CHAR_BACKWARD_SLASH)) {
path = `${resolvedDevice}\\`;
}
}
const len = path.length;
let rootEnd = 0;
let device = '';
let isAbsolute = false;
const code = path.charCodeAt(0);
if (len === 1) {
if (isPathSeparatorWin(code)) {
rootEnd = 1;
isAbsolute = true;
}
}
else if (isPathSeparatorWin(code)) {
isAbsolute = true;
if (isPathSeparatorWin(path.charCodeAt(1))) {
// UNC path: `\\server\share\…`
let j = 2;
let last = j;
while (j < len && !isPathSeparatorWin(path.charCodeAt(j)))
j++;
if (j < len && j !== last) {
const firstPart = path.slice(last, j);
last = j;
while (j < len && isPathSeparatorWin(path.charCodeAt(j)))
j++;
if (j < len && j !== last) {
last = j;
while (j < len && !isPathSeparatorWin(path.charCodeAt(j)))
j++;
if (j === len || j !== last) {
device = `\\\\${firstPart}\\${path.slice(last, j)}`;
rootEnd = j;
}
}
}
}
else {
rootEnd = 1;
}
}
else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {
device = path.slice(0, 2);
rootEnd = 2;
if (len > 2 && isPathSeparatorWin(path.charCodeAt(2))) {
isAbsolute = true;
rootEnd = 3;
}
}
if (device.length > 0) {
if (resolvedDevice.length > 0) {
if (device.toLowerCase() !== resolvedDevice.toLowerCase())
continue;
}
else {
resolvedDevice = device;
}
}
if (resolvedAbsolute) {
if (resolvedDevice.length > 0)
break;
}
else {
resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`;
resolvedAbsolute = isAbsolute;
if (isAbsolute && resolvedDevice.length > 0)
break;
}
}
resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isPathSeparatorWin);
return resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail || '.';
}
function isPosixPathSeparator(code) {
return code === CHAR_FORWARD_SLASH;
}
function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
let res = '';
let lastSegmentLength = 0;
let lastSlash = -1;
let dots = 0;
let code = 0;
for (let i = 0; i <= path.length; ++i) {
if (i < path.length) {
code = path.charCodeAt(i);
}
else if (isPathSeparator(code)) {
break;
}
else {
code = CHAR_FORWARD_SLASH;
}
if (isPathSeparator(code)) {
if (lastSlash === i - 1 || dots === 1) {
// NOOP
}
else if (dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 ||
res.charCodeAt(res.length - 1) !== CHAR_DOT ||
res.charCodeAt(res.length - 2) !== CHAR_DOT) {
if (res.length > 2) {
const lastSlashIndex = res.indexOf(separator);
if (lastSlashIndex === -1) {
res = '';
lastSegmentLength = 0;
}
else {
res = res.slice(0, lastSlashIndex);
lastSegmentLength =
res.length - 1 - res.indexOf(separator);
}
lastSlash = i;
dots = 0;
continue;
}
else if (res.length !== 0) {
res = '';
lastSegmentLength = 0;
lastSlash = i;
dots = 0;
continue;
}
}
if (allowAboveRoot) {
res += res.length > 0 ? `${separator}..` : '..';
lastSegmentLength = 2;
}
}
else {
if (res.length > 0) {
res += `${separator}${path.slice(lastSlash + 1, i)}`;
}
else {
res = path.slice(lastSlash + 1, i);
}
lastSegmentLength = i - lastSlash - 1;
}
lastSlash = i;
dots = 0;
}
else if (code === CHAR_DOT && dots !== -1) {
++dots;
}
else {
dots = -1;
}
}
return res;
}
function resolve(...args) {
// On Windows, host paths are `D:\…` style. The POSIX-only resolver
// below treats `D` as a non-`/` character and produces garbage; route
// to the Windows-aware variant. POSIX hosts (Linux/macOS/browser)
// run the original code path unchanged — `_isWin32` is constant-folded
// away on those targets.
if (_isWin32)
return resolveWin32(args);
let resolvedPath = '';
let resolvedAbsolute = false;
for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
const path = i >= 0 ? args[i] : '/';
(0, util_1.validateString)(path, 'path');
// Skip empty entries
if (path.length === 0) {
continue;
}
resolvedPath = `${path}/${resolvedPath}`;
resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator);
if (resolvedAbsolute) {
return `/${resolvedPath}`;
}
return resolvedPath.length > 0 ? resolvedPath : '.';
}
exports.resolve = resolve;
function relative(from, to) {
(0, util_1.validateString)(from, 'from');
(0, util_1.validateString)(to, 'to');
if (from === to)
return '';
// Trim leading forward slashes.
from = resolve(from);
to = resolve(to);
if (from === to)
return '';
const fromStart = 1;
const fromEnd = from.length;
const fromLen = fromEnd - fromStart;
const toStart = 1;
const toLen = to.length - toStart;
// Compare paths to find the longest common path from root
const length = (fromLen < toLen ? fromLen : toLen);
let lastCommonSep = -1;
let i = 0;
for (; i < length; i++) {
const fromCode = from.charCodeAt(fromStart + i);
if (fromCode !== to.charCodeAt(toStart + i)) {
break;
}
else if (fromCode === CHAR_FORWARD_SLASH) {
lastCommonSep = i;
}
}
if (i === length) {
if (toLen > length) {
if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {
// We get here if `from` is the exact base path for `to`.
// For example: from='/foo/bar'; to='/foo/bar/baz'
return to.slice(toStart + i + 1);
}
if (i === 0) {
// We get here if `from` is the root
// For example: from='/'; to='/foo'
return to.slice(toStart + i);
}
}
else if (fromLen > length) {
if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) {
// We get here if `to` is the exact base path for `from`.
// For example: from='/foo/bar/baz'; to='/foo/bar'
lastCommonSep = i;
}
else if (i === 0) {
// We get here if `to` is the root.
// For example: from='/foo/bar'; to='/'
lastCommonSep = 0;
}
}
}
let out = '';
// Generate the relative path based on the path difference between `to`
// and `from`.
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
if (i === fromEnd ||
from.charCodeAt(i) === CHAR_FORWARD_SLASH) {
out += out.length === 0 ? '..' : '/..';
}
}
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts.
return `${out}${to.slice(toStart + lastCommonSep)}`;
}
exports.relative = relative;
//# sourceMappingURL=path.js.map
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,141 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRights = exports.TTY_INHERITING = exports.TTY_BASE = exports.SOCKET_INHERITING = exports.SOCKET_BASE = exports.DIRECTORY_INHERITING = exports.DIRECTORY_BASE = exports.REGULAR_FILE_INHERITING = exports.REGULAR_FILE_BASE = exports.CHARACTER_DEVICE_INHERITING = exports.CHARACTER_DEVICE_BASE = exports.BLOCK_DEVICE_INHERITING = exports.BLOCK_DEVICE_BASE = exports.RIGHTS_ALL = void 0;
/* eslint-disable spaced-comment */
const error_1 = require("./error");
const types_1 = require("./types");
exports.RIGHTS_ALL = types_1.WasiRights.FD_DATASYNC |
types_1.WasiRights.FD_READ |
types_1.WasiRights.FD_SEEK |
types_1.WasiRights.FD_FDSTAT_SET_FLAGS |
types_1.WasiRights.FD_SYNC |
types_1.WasiRights.FD_TELL |
types_1.WasiRights.FD_WRITE |
types_1.WasiRights.FD_ADVISE |
types_1.WasiRights.FD_ALLOCATE |
types_1.WasiRights.PATH_CREATE_DIRECTORY |
types_1.WasiRights.PATH_CREATE_FILE |
types_1.WasiRights.PATH_LINK_SOURCE |
types_1.WasiRights.PATH_LINK_TARGET |
types_1.WasiRights.PATH_OPEN |
types_1.WasiRights.FD_READDIR |
types_1.WasiRights.PATH_READLINK |
types_1.WasiRights.PATH_RENAME_SOURCE |
types_1.WasiRights.PATH_RENAME_TARGET |
types_1.WasiRights.PATH_FILESTAT_GET |
types_1.WasiRights.PATH_FILESTAT_SET_SIZE |
types_1.WasiRights.PATH_FILESTAT_SET_TIMES |
types_1.WasiRights.FD_FILESTAT_GET |
types_1.WasiRights.FD_FILESTAT_SET_TIMES |
types_1.WasiRights.FD_FILESTAT_SET_SIZE |
types_1.WasiRights.PATH_SYMLINK |
types_1.WasiRights.PATH_UNLINK_FILE |
types_1.WasiRights.PATH_REMOVE_DIRECTORY |
types_1.WasiRights.POLL_FD_READWRITE |
types_1.WasiRights.SOCK_SHUTDOWN |
types_1.WasiRights.SOCK_ACCEPT;
exports.BLOCK_DEVICE_BASE = exports.RIGHTS_ALL;
exports.BLOCK_DEVICE_INHERITING = exports.RIGHTS_ALL;
exports.CHARACTER_DEVICE_BASE = exports.RIGHTS_ALL;
exports.CHARACTER_DEVICE_INHERITING = exports.RIGHTS_ALL;
exports.REGULAR_FILE_BASE = types_1.WasiRights.FD_DATASYNC |
types_1.WasiRights.FD_READ |
types_1.WasiRights.FD_SEEK |
types_1.WasiRights.FD_FDSTAT_SET_FLAGS |
types_1.WasiRights.FD_SYNC |
types_1.WasiRights.FD_TELL |
types_1.WasiRights.FD_WRITE |
types_1.WasiRights.FD_ADVISE |
types_1.WasiRights.FD_ALLOCATE |
types_1.WasiRights.FD_FILESTAT_GET |
types_1.WasiRights.FD_FILESTAT_SET_SIZE |
types_1.WasiRights.FD_FILESTAT_SET_TIMES |
types_1.WasiRights.POLL_FD_READWRITE;
exports.REGULAR_FILE_INHERITING = BigInt(0);
exports.DIRECTORY_BASE = types_1.WasiRights.FD_FDSTAT_SET_FLAGS |
types_1.WasiRights.FD_SYNC |
types_1.WasiRights.FD_ADVISE |
types_1.WasiRights.PATH_CREATE_DIRECTORY |
types_1.WasiRights.PATH_CREATE_FILE |
types_1.WasiRights.PATH_LINK_SOURCE |
types_1.WasiRights.PATH_LINK_TARGET |
types_1.WasiRights.PATH_OPEN |
types_1.WasiRights.FD_READDIR |
types_1.WasiRights.PATH_READLINK |
types_1.WasiRights.PATH_RENAME_SOURCE |
types_1.WasiRights.PATH_RENAME_TARGET |
types_1.WasiRights.PATH_FILESTAT_GET |
types_1.WasiRights.PATH_FILESTAT_SET_SIZE |
types_1.WasiRights.PATH_FILESTAT_SET_TIMES |
types_1.WasiRights.FD_FILESTAT_GET |
types_1.WasiRights.FD_FILESTAT_SET_TIMES |
types_1.WasiRights.PATH_SYMLINK |
types_1.WasiRights.PATH_UNLINK_FILE |
types_1.WasiRights.PATH_REMOVE_DIRECTORY |
types_1.WasiRights.POLL_FD_READWRITE;
exports.DIRECTORY_INHERITING = exports.DIRECTORY_BASE | exports.REGULAR_FILE_BASE;
exports.SOCKET_BASE = (types_1.WasiRights.FD_READ |
types_1.WasiRights.FD_FDSTAT_SET_FLAGS |
types_1.WasiRights.FD_WRITE |
types_1.WasiRights.FD_FILESTAT_GET |
types_1.WasiRights.POLL_FD_READWRITE |
types_1.WasiRights.SOCK_SHUTDOWN);
exports.SOCKET_INHERITING = exports.RIGHTS_ALL;
exports.TTY_BASE = types_1.WasiRights.FD_READ |
types_1.WasiRights.FD_FDSTAT_SET_FLAGS |
types_1.WasiRights.FD_WRITE |
types_1.WasiRights.FD_FILESTAT_GET |
types_1.WasiRights.POLL_FD_READWRITE;
exports.TTY_INHERITING = BigInt(0);
function getRights(stdio, fd, flags, type) {
const ret = {
base: BigInt(0),
inheriting: BigInt(0)
};
if (type === types_1.WasiFileType.UNKNOWN) {
throw new error_1.WasiError('Unknown file type', types_1.WasiErrno.EINVAL);
}
switch (type) {
case types_1.WasiFileType.REGULAR_FILE:
ret.base = exports.REGULAR_FILE_BASE;
ret.inheriting = exports.REGULAR_FILE_INHERITING;
break;
case types_1.WasiFileType.DIRECTORY:
ret.base = exports.DIRECTORY_BASE;
ret.inheriting = exports.DIRECTORY_INHERITING;
break;
case types_1.WasiFileType.SOCKET_STREAM:
case types_1.WasiFileType.SOCKET_DGRAM:
ret.base = exports.SOCKET_BASE;
ret.inheriting = exports.SOCKET_INHERITING;
break;
case types_1.WasiFileType.CHARACTER_DEVICE:
if (stdio.indexOf(fd) !== -1) {
ret.base = exports.TTY_BASE;
ret.inheriting = exports.TTY_INHERITING;
}
else {
ret.base = exports.CHARACTER_DEVICE_BASE;
ret.inheriting = exports.CHARACTER_DEVICE_INHERITING;
}
break;
case types_1.WasiFileType.BLOCK_DEVICE:
ret.base = exports.BLOCK_DEVICE_BASE;
ret.inheriting = exports.BLOCK_DEVICE_INHERITING;
break;
default:
ret.base = BigInt(0);
ret.inheriting = BigInt(0);
}
/* Disable read/write bits depending on access mode. */
const read_or_write_only = flags & (0 | 1 | 2);
if (read_or_write_only === 0) {
ret.base &= ~types_1.WasiRights.FD_WRITE;
}
else if (read_or_write_only === 1) {
ret.base &= ~types_1.WasiRights.FD_READ;
}
return ret;
}
exports.getRights = getRights;
//# sourceMappingURL=rights.js.map
@@ -0,0 +1,220 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WasiSubclockflags = exports.WasiEventType = exports.WasiFstFlag = exports.WasiClockid = exports.WasiFdFlag = exports.WasiFileControlFlag = exports.FileControlFlag = exports.WasiWhence = exports.WasiRights = exports.WasiFileType = exports.WasiErrno = void 0;
/* eslint-disable spaced-comment */
var WasiErrno;
(function (WasiErrno) {
WasiErrno[WasiErrno["ESUCCESS"] = 0] = "ESUCCESS";
WasiErrno[WasiErrno["E2BIG"] = 1] = "E2BIG";
WasiErrno[WasiErrno["EACCES"] = 2] = "EACCES";
WasiErrno[WasiErrno["EADDRINUSE"] = 3] = "EADDRINUSE";
WasiErrno[WasiErrno["EADDRNOTAVAIL"] = 4] = "EADDRNOTAVAIL";
WasiErrno[WasiErrno["EAFNOSUPPORT"] = 5] = "EAFNOSUPPORT";
WasiErrno[WasiErrno["EAGAIN"] = 6] = "EAGAIN";
WasiErrno[WasiErrno["EALREADY"] = 7] = "EALREADY";
WasiErrno[WasiErrno["EBADF"] = 8] = "EBADF";
WasiErrno[WasiErrno["EBADMSG"] = 9] = "EBADMSG";
WasiErrno[WasiErrno["EBUSY"] = 10] = "EBUSY";
WasiErrno[WasiErrno["ECANCELED"] = 11] = "ECANCELED";
WasiErrno[WasiErrno["ECHILD"] = 12] = "ECHILD";
WasiErrno[WasiErrno["ECONNABORTED"] = 13] = "ECONNABORTED";
WasiErrno[WasiErrno["ECONNREFUSED"] = 14] = "ECONNREFUSED";
WasiErrno[WasiErrno["ECONNRESET"] = 15] = "ECONNRESET";
WasiErrno[WasiErrno["EDEADLK"] = 16] = "EDEADLK";
WasiErrno[WasiErrno["EDESTADDRREQ"] = 17] = "EDESTADDRREQ";
WasiErrno[WasiErrno["EDOM"] = 18] = "EDOM";
WasiErrno[WasiErrno["EDQUOT"] = 19] = "EDQUOT";
WasiErrno[WasiErrno["EEXIST"] = 20] = "EEXIST";
WasiErrno[WasiErrno["EFAULT"] = 21] = "EFAULT";
WasiErrno[WasiErrno["EFBIG"] = 22] = "EFBIG";
WasiErrno[WasiErrno["EHOSTUNREACH"] = 23] = "EHOSTUNREACH";
WasiErrno[WasiErrno["EIDRM"] = 24] = "EIDRM";
WasiErrno[WasiErrno["EILSEQ"] = 25] = "EILSEQ";
WasiErrno[WasiErrno["EINPROGRESS"] = 26] = "EINPROGRESS";
WasiErrno[WasiErrno["EINTR"] = 27] = "EINTR";
WasiErrno[WasiErrno["EINVAL"] = 28] = "EINVAL";
WasiErrno[WasiErrno["EIO"] = 29] = "EIO";
WasiErrno[WasiErrno["EISCONN"] = 30] = "EISCONN";
WasiErrno[WasiErrno["EISDIR"] = 31] = "EISDIR";
WasiErrno[WasiErrno["ELOOP"] = 32] = "ELOOP";
WasiErrno[WasiErrno["EMFILE"] = 33] = "EMFILE";
WasiErrno[WasiErrno["EMLINK"] = 34] = "EMLINK";
WasiErrno[WasiErrno["EMSGSIZE"] = 35] = "EMSGSIZE";
WasiErrno[WasiErrno["EMULTIHOP"] = 36] = "EMULTIHOP";
WasiErrno[WasiErrno["ENAMETOOLONG"] = 37] = "ENAMETOOLONG";
WasiErrno[WasiErrno["ENETDOWN"] = 38] = "ENETDOWN";
WasiErrno[WasiErrno["ENETRESET"] = 39] = "ENETRESET";
WasiErrno[WasiErrno["ENETUNREACH"] = 40] = "ENETUNREACH";
WasiErrno[WasiErrno["ENFILE"] = 41] = "ENFILE";
WasiErrno[WasiErrno["ENOBUFS"] = 42] = "ENOBUFS";
WasiErrno[WasiErrno["ENODEV"] = 43] = "ENODEV";
WasiErrno[WasiErrno["ENOENT"] = 44] = "ENOENT";
WasiErrno[WasiErrno["ENOEXEC"] = 45] = "ENOEXEC";
WasiErrno[WasiErrno["ENOLCK"] = 46] = "ENOLCK";
WasiErrno[WasiErrno["ENOLINK"] = 47] = "ENOLINK";
WasiErrno[WasiErrno["ENOMEM"] = 48] = "ENOMEM";
WasiErrno[WasiErrno["ENOMSG"] = 49] = "ENOMSG";
WasiErrno[WasiErrno["ENOPROTOOPT"] = 50] = "ENOPROTOOPT";
WasiErrno[WasiErrno["ENOSPC"] = 51] = "ENOSPC";
WasiErrno[WasiErrno["ENOSYS"] = 52] = "ENOSYS";
WasiErrno[WasiErrno["ENOTCONN"] = 53] = "ENOTCONN";
WasiErrno[WasiErrno["ENOTDIR"] = 54] = "ENOTDIR";
WasiErrno[WasiErrno["ENOTEMPTY"] = 55] = "ENOTEMPTY";
WasiErrno[WasiErrno["ENOTRECOVERABLE"] = 56] = "ENOTRECOVERABLE";
WasiErrno[WasiErrno["ENOTSOCK"] = 57] = "ENOTSOCK";
WasiErrno[WasiErrno["ENOTSUP"] = 58] = "ENOTSUP";
WasiErrno[WasiErrno["ENOTTY"] = 59] = "ENOTTY";
WasiErrno[WasiErrno["ENXIO"] = 60] = "ENXIO";
WasiErrno[WasiErrno["EOVERFLOW"] = 61] = "EOVERFLOW";
WasiErrno[WasiErrno["EOWNERDEAD"] = 62] = "EOWNERDEAD";
WasiErrno[WasiErrno["EPERM"] = 63] = "EPERM";
WasiErrno[WasiErrno["EPIPE"] = 64] = "EPIPE";
WasiErrno[WasiErrno["EPROTO"] = 65] = "EPROTO";
WasiErrno[WasiErrno["EPROTONOSUPPORT"] = 66] = "EPROTONOSUPPORT";
WasiErrno[WasiErrno["EPROTOTYPE"] = 67] = "EPROTOTYPE";
WasiErrno[WasiErrno["ERANGE"] = 68] = "ERANGE";
WasiErrno[WasiErrno["EROFS"] = 69] = "EROFS";
WasiErrno[WasiErrno["ESPIPE"] = 70] = "ESPIPE";
WasiErrno[WasiErrno["ESRCH"] = 71] = "ESRCH";
WasiErrno[WasiErrno["ESTALE"] = 72] = "ESTALE";
WasiErrno[WasiErrno["ETIMEDOUT"] = 73] = "ETIMEDOUT";
WasiErrno[WasiErrno["ETXTBSY"] = 74] = "ETXTBSY";
WasiErrno[WasiErrno["EXDEV"] = 75] = "EXDEV";
WasiErrno[WasiErrno["ENOTCAPABLE"] = 76] = "ENOTCAPABLE";
})(WasiErrno = exports.WasiErrno || (exports.WasiErrno = {}));
var WasiFileType;
(function (WasiFileType) {
WasiFileType[WasiFileType["UNKNOWN"] = 0] = "UNKNOWN";
WasiFileType[WasiFileType["BLOCK_DEVICE"] = 1] = "BLOCK_DEVICE";
WasiFileType[WasiFileType["CHARACTER_DEVICE"] = 2] = "CHARACTER_DEVICE";
WasiFileType[WasiFileType["DIRECTORY"] = 3] = "DIRECTORY";
WasiFileType[WasiFileType["REGULAR_FILE"] = 4] = "REGULAR_FILE";
WasiFileType[WasiFileType["SOCKET_DGRAM"] = 5] = "SOCKET_DGRAM";
WasiFileType[WasiFileType["SOCKET_STREAM"] = 6] = "SOCKET_STREAM";
WasiFileType[WasiFileType["SYMBOLIC_LINK"] = 7] = "SYMBOLIC_LINK";
})(WasiFileType = exports.WasiFileType || (exports.WasiFileType = {}));
const FD_DATASYNC = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(0));
const FD_READ = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(1));
const FD_SEEK = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(2));
const FD_FDSTAT_SET_FLAGS = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(3));
const FD_SYNC = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(4));
const FD_TELL = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(5));
const FD_WRITE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(6));
const FD_ADVISE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(7));
const FD_ALLOCATE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(8));
const PATH_CREATE_DIRECTORY = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(9));
const PATH_CREATE_FILE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(10));
const PATH_LINK_SOURCE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(11));
const PATH_LINK_TARGET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(12));
const PATH_OPEN = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(13));
const FD_READDIR = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(14));
const PATH_READLINK = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(15));
const PATH_RENAME_SOURCE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(16));
const PATH_RENAME_TARGET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(17));
const PATH_FILESTAT_GET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(18));
const PATH_FILESTAT_SET_SIZE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(19));
const PATH_FILESTAT_SET_TIMES = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(20));
const FD_FILESTAT_GET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(21));
const FD_FILESTAT_SET_SIZE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(22));
const FD_FILESTAT_SET_TIMES = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(23));
const PATH_SYMLINK = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(24));
const PATH_REMOVE_DIRECTORY = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(25));
const PATH_UNLINK_FILE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(26));
const POLL_FD_READWRITE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(27));
const SOCK_SHUTDOWN = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(28));
const SOCK_ACCEPT = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(29));
exports.WasiRights = {
FD_DATASYNC,
FD_READ,
FD_SEEK,
FD_FDSTAT_SET_FLAGS,
FD_SYNC,
FD_TELL,
FD_WRITE,
FD_ADVISE,
FD_ALLOCATE,
PATH_CREATE_DIRECTORY,
PATH_CREATE_FILE,
PATH_LINK_SOURCE,
PATH_LINK_TARGET,
PATH_OPEN,
FD_READDIR,
PATH_READLINK,
PATH_RENAME_SOURCE,
PATH_RENAME_TARGET,
PATH_FILESTAT_GET,
PATH_FILESTAT_SET_SIZE,
PATH_FILESTAT_SET_TIMES,
FD_FILESTAT_GET,
FD_FILESTAT_SET_SIZE,
FD_FILESTAT_SET_TIMES,
PATH_SYMLINK,
PATH_REMOVE_DIRECTORY,
PATH_UNLINK_FILE,
POLL_FD_READWRITE,
SOCK_SHUTDOWN,
SOCK_ACCEPT
};
var WasiWhence;
(function (WasiWhence) {
WasiWhence[WasiWhence["SET"] = 0] = "SET";
WasiWhence[WasiWhence["CUR"] = 1] = "CUR";
WasiWhence[WasiWhence["END"] = 2] = "END";
})(WasiWhence = exports.WasiWhence || (exports.WasiWhence = {}));
var FileControlFlag;
(function (FileControlFlag) {
FileControlFlag[FileControlFlag["O_RDONLY"] = 0] = "O_RDONLY";
FileControlFlag[FileControlFlag["O_WRONLY"] = 1] = "O_WRONLY";
FileControlFlag[FileControlFlag["O_RDWR"] = 2] = "O_RDWR";
FileControlFlag[FileControlFlag["O_CREAT"] = 64] = "O_CREAT";
FileControlFlag[FileControlFlag["O_EXCL"] = 128] = "O_EXCL";
FileControlFlag[FileControlFlag["O_NOCTTY"] = 256] = "O_NOCTTY";
FileControlFlag[FileControlFlag["O_TRUNC"] = 512] = "O_TRUNC";
FileControlFlag[FileControlFlag["O_APPEND"] = 1024] = "O_APPEND";
FileControlFlag[FileControlFlag["O_DIRECTORY"] = 65536] = "O_DIRECTORY";
FileControlFlag[FileControlFlag["O_NOATIME"] = 262144] = "O_NOATIME";
FileControlFlag[FileControlFlag["O_NOFOLLOW"] = 131072] = "O_NOFOLLOW";
FileControlFlag[FileControlFlag["O_SYNC"] = 1052672] = "O_SYNC";
FileControlFlag[FileControlFlag["O_DIRECT"] = 16384] = "O_DIRECT";
FileControlFlag[FileControlFlag["O_NONBLOCK"] = 2048] = "O_NONBLOCK";
})(FileControlFlag = exports.FileControlFlag || (exports.FileControlFlag = {}));
var WasiFileControlFlag;
(function (WasiFileControlFlag) {
WasiFileControlFlag[WasiFileControlFlag["O_CREAT"] = 1] = "O_CREAT";
WasiFileControlFlag[WasiFileControlFlag["O_DIRECTORY"] = 2] = "O_DIRECTORY";
WasiFileControlFlag[WasiFileControlFlag["O_EXCL"] = 4] = "O_EXCL";
WasiFileControlFlag[WasiFileControlFlag["O_TRUNC"] = 8] = "O_TRUNC";
})(WasiFileControlFlag = exports.WasiFileControlFlag || (exports.WasiFileControlFlag = {}));
var WasiFdFlag;
(function (WasiFdFlag) {
WasiFdFlag[WasiFdFlag["APPEND"] = 1] = "APPEND";
WasiFdFlag[WasiFdFlag["DSYNC"] = 2] = "DSYNC";
WasiFdFlag[WasiFdFlag["NONBLOCK"] = 4] = "NONBLOCK";
WasiFdFlag[WasiFdFlag["RSYNC"] = 8] = "RSYNC";
WasiFdFlag[WasiFdFlag["SYNC"] = 16] = "SYNC";
})(WasiFdFlag = exports.WasiFdFlag || (exports.WasiFdFlag = {}));
var WasiClockid;
(function (WasiClockid) {
WasiClockid[WasiClockid["REALTIME"] = 0] = "REALTIME";
WasiClockid[WasiClockid["MONOTONIC"] = 1] = "MONOTONIC";
WasiClockid[WasiClockid["PROCESS_CPUTIME_ID"] = 2] = "PROCESS_CPUTIME_ID";
WasiClockid[WasiClockid["THREAD_CPUTIME_ID"] = 3] = "THREAD_CPUTIME_ID";
})(WasiClockid = exports.WasiClockid || (exports.WasiClockid = {}));
var WasiFstFlag;
(function (WasiFstFlag) {
WasiFstFlag[WasiFstFlag["SET_ATIM"] = 1] = "SET_ATIM";
WasiFstFlag[WasiFstFlag["SET_ATIM_NOW"] = 2] = "SET_ATIM_NOW";
WasiFstFlag[WasiFstFlag["SET_MTIM"] = 4] = "SET_MTIM";
WasiFstFlag[WasiFstFlag["SET_MTIM_NOW"] = 8] = "SET_MTIM_NOW";
})(WasiFstFlag = exports.WasiFstFlag || (exports.WasiFstFlag = {}));
var WasiEventType;
(function (WasiEventType) {
WasiEventType[WasiEventType["CLOCK"] = 0] = "CLOCK";
WasiEventType[WasiEventType["FD_READ"] = 1] = "FD_READ";
WasiEventType[WasiEventType["FD_WRITE"] = 2] = "FD_WRITE";
})(WasiEventType = exports.WasiEventType || (exports.WasiEventType = {}));
var WasiSubclockflags;
(function (WasiSubclockflags) {
WasiSubclockflags[WasiSubclockflags["ABSTIME"] = 1] = "ABSTIME";
})(WasiSubclockflags = exports.WasiSubclockflags || (exports.WasiSubclockflags = {}));
//# sourceMappingURL=types.js.map
@@ -0,0 +1,128 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unsharedSlice = exports.sleepBreakIf = exports.postMsg = exports.isMainThread = exports.wrapInstanceExports = exports.isPromiseLike = exports.validateInt32 = exports.validateUndefined = exports.validateFunction = exports.validateString = exports.validateBoolean = exports.validateArray = exports.validateObject = void 0;
/* eslint-disable spaced-comment */
function validateObject(value, name) {
if (value === null || typeof value !== 'object') {
throw new TypeError(`${name} must be an object. Received ${value === null ? 'null' : typeof value}`);
}
}
exports.validateObject = validateObject;
function validateArray(value, name) {
if (!Array.isArray(value)) {
throw new TypeError(`${name} must be an array. Received ${value === null ? 'null' : typeof value}`);
}
}
exports.validateArray = validateArray;
function validateBoolean(value, name) {
if (typeof value !== 'boolean') {
throw new TypeError(`${name} must be a boolean. Received ${value === null ? 'null' : typeof value}`);
}
}
exports.validateBoolean = validateBoolean;
function validateString(value, name) {
if (typeof value !== 'string') {
throw new TypeError(`${name} must be a string. Received ${value === null ? 'null' : typeof value}`);
}
}
exports.validateString = validateString;
function validateFunction(value, name) {
if (typeof value !== 'function') {
throw new TypeError(`${name} must be a function. Received ${value === null ? 'null' : typeof value}`);
}
}
exports.validateFunction = validateFunction;
function validateUndefined(value, name) {
if (value !== undefined) {
throw new TypeError(`${name} must be undefined. Received ${value === null ? 'null' : typeof value}`);
}
}
exports.validateUndefined = validateUndefined;
function validateInt32(value, name, min = -2147483648, max = 2147483647) {
if (typeof value !== 'number') {
throw new TypeError(`${name} must be a number. Received ${value === null ? 'null' : typeof value}`);
}
if (!Number.isInteger(value)) {
throw new RangeError(`${name} must be a integer.`);
}
if (value < min || value > max) {
throw new RangeError(`${name} must be >= ${min} && <= ${max}. Received ${value}`);
}
}
exports.validateInt32 = validateInt32;
function isPromiseLike(obj) {
return !!(obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function');
}
exports.isPromiseLike = isPromiseLike;
function wrapInstanceExports(exports, mapFn) {
const newExports = Object.create(null);
Object.keys(exports).forEach(name => {
const exportValue = exports[name];
Object.defineProperty(newExports, name, {
enumerable: true,
value: mapFn(exportValue, name)
});
});
return newExports;
}
exports.wrapInstanceExports = wrapInstanceExports;
const _require = /*#__PURE__*/ (function () {
let nativeRequire;
if (typeof __webpack_public_path__ !== 'undefined') {
nativeRequire = (function () {
return typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : undefined;
})();
}
else {
nativeRequire = (function () {
return typeof __webpack_public_path__ !== 'undefined' ? (typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : undefined) : (typeof require !== 'undefined' ? require : undefined);
})();
}
return nativeRequire;
})();
exports.isMainThread = (function () {
let worker_threads;
try {
worker_threads = _require('worker_threads');
}
catch (_) { }
if (!worker_threads) {
return typeof importScripts === 'undefined';
}
return worker_threads.isMainThread;
})();
exports.postMsg = exports.isMainThread
? () => { }
: /*#__PURE__*/ (function () {
let worker_threads;
try {
worker_threads = _require('worker_threads');
}
catch (_) { }
if (!worker_threads) {
return postMessage;
}
return function postMessage(data) {
worker_threads.parentPort.postMessage({ data });
};
})();
function sleepBreakIf(delay, breakIf) {
const start = Date.now();
const end = start + delay;
let ret = false;
while (Date.now() < end) {
if (breakIf()) {
ret = true;
break;
}
}
return ret;
}
exports.sleepBreakIf = sleepBreakIf;
function unsharedSlice(view, start, end) {
return ((typeof SharedArrayBuffer === 'function' && view.buffer instanceof SharedArrayBuffer) || (Object.prototype.toString.call(view.buffer.constructor) === '[object SharedArrayBuffer]'))
? view.slice(start, end)
: view.subarray(start, end);
}
exports.unsharedSlice = unsharedSlice;
//# sourceMappingURL=util.js.map
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._WebAssembly = void 0;
const _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
exports._WebAssembly = _WebAssembly;
if (!_WebAssembly) {
throw new Error('WebAssembly is not supported in this environment');
}
//# sourceMappingURL=webassembly.js.map
@@ -0,0 +1,153 @@
import { _WebAssembly } from "./webassembly.mjs";
import { isPromiseLike, wrapInstanceExports } from "./wasi/util.mjs";
const ignoreNames = [
'asyncify_get_state',
'asyncify_start_rewind',
'asyncify_start_unwind',
'asyncify_stop_rewind',
'asyncify_stop_unwind'
];
// const wrappedExports = new WeakMap<WebAssembly.Exports, WebAssembly.Exports>()
var AsyncifyState;
(function (AsyncifyState) {
AsyncifyState[AsyncifyState["NONE"] = 0] = "NONE";
AsyncifyState[AsyncifyState["UNWINDING"] = 1] = "UNWINDING";
AsyncifyState[AsyncifyState["REWINDING"] = 2] = "REWINDING";
})(AsyncifyState || (AsyncifyState = {}));
function tryAllocate(instance, wasm64, size, mallocName) {
if (typeof instance.exports[mallocName] !== 'function' || size <= 0) {
return {
wasm64,
dataPtr: 16,
start: wasm64 ? 32 : 24,
end: 1024
};
}
const malloc = instance.exports[mallocName];
const dataPtr = wasm64 ? Number(malloc(BigInt(16) + BigInt(size))) : malloc(8 + size);
if (dataPtr === 0) {
throw new Error('Allocate asyncify data failed');
}
return wasm64
? { wasm64, dataPtr, start: dataPtr + 16, end: dataPtr + 16 + size }
: { wasm64, dataPtr, start: dataPtr + 8, end: dataPtr + 8 + size };
}
/** @public */
export class Asyncify {
constructor() {
this.value = undefined;
this.exports = undefined;
this.dataPtr = 0;
}
init(memory, instance, options) {
var _a, _b;
if (this.exports) {
throw new Error('Asyncify has been initialized');
}
if (!(memory instanceof _WebAssembly.Memory)) {
throw new TypeError('Require WebAssembly.Memory object');
}
const exports = instance.exports;
for (let i = 0; i < ignoreNames.length; ++i) {
if (typeof exports[ignoreNames[i]] !== 'function') {
throw new TypeError('Invalid asyncify wasm');
}
}
let address;
const wasm64 = Boolean(options.wasm64);
if (!options.tryAllocate) {
address = {
wasm64,
dataPtr: 16,
start: wasm64 ? 32 : 24,
end: 1024
};
}
else {
if (options.tryAllocate === true) {
address = tryAllocate(instance, wasm64, 4096, 'malloc');
}
else {
address = tryAllocate(instance, wasm64, (_a = options.tryAllocate.size) !== null && _a !== void 0 ? _a : 4096, (_b = options.tryAllocate.name) !== null && _b !== void 0 ? _b : 'malloc');
}
}
this.dataPtr = address.dataPtr;
if (wasm64) {
new BigInt64Array(memory.buffer, this.dataPtr).set([BigInt(address.start), BigInt(address.end)]);
}
else {
new Int32Array(memory.buffer, this.dataPtr).set([address.start, address.end]);
}
this.exports = this.wrapExports(exports, options.wrapExports);
const asyncifiedInstance = Object.create(_WebAssembly.Instance.prototype);
Object.defineProperty(asyncifiedInstance, 'exports', { value: this.exports });
// Object.setPrototypeOf(instance, Instance.prototype)
return asyncifiedInstance;
}
assertState() {
if (this.exports.asyncify_get_state() !== AsyncifyState.NONE) {
throw new Error('Asyncify state error');
}
}
wrapImportFunction(f) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this = this;
return (function () {
// eslint-disable-next-line no-unreachable-loop
while (_this.exports.asyncify_get_state() === AsyncifyState.REWINDING) {
_this.exports.asyncify_stop_rewind();
return _this.value;
}
_this.assertState();
const v = f.apply(this, arguments);
if (!isPromiseLike(v))
return v;
_this.exports.asyncify_start_unwind(_this.dataPtr);
_this.value = v;
});
}
wrapImports(imports) {
const importObject = {};
Object.keys(imports).forEach(k => {
const mod = imports[k];
const newModule = {};
Object.keys(mod).forEach(name => {
const importValue = mod[name];
if (typeof importValue === 'function') {
newModule[name] = this.wrapImportFunction(importValue);
}
else {
newModule[name] = importValue;
}
});
importObject[k] = newModule;
});
return importObject;
}
wrapExportFunction(f) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _this = this;
return (async function () {
_this.assertState();
let ret = f.apply(this, arguments);
while (_this.exports.asyncify_get_state() === AsyncifyState.UNWINDING) {
_this.exports.asyncify_stop_unwind();
_this.value = await _this.value;
_this.assertState();
_this.exports.asyncify_start_rewind(_this.dataPtr);
ret = f.call(this);
}
_this.assertState();
return ret;
});
}
wrapExports(exports, needWrap) {
return wrapInstanceExports(exports, (exportValue, name) => {
let ignore = ignoreNames.indexOf(name) !== -1 || typeof exportValue !== 'function';
if (Array.isArray(needWrap)) {
ignore = ignore || (needWrap.indexOf(name) === -1);
}
return ignore ? exportValue : this.wrapExportFunction(exportValue);
});
}
}
@@ -0,0 +1,9 @@
/**
* @packageDocumentation
*/
export * from "./asyncify.mjs";
export * from "./load.mjs";
export * from "./wasi/index.mjs";
export * from "./memory.mjs";
export * from "./jspi.mjs";
export * from "./wasi/fs.mjs";
@@ -0,0 +1,39 @@
import { wrapInstanceExports } from "./wasi/util.mjs";
import { _WebAssembly } from "./webassembly.mjs";
function checkWebAssemblyFunction() {
const WebAssemblyFunction = _WebAssembly.Function;
if (typeof WebAssemblyFunction !== 'function') {
throw new Error('WebAssembly.Function is not supported in this environment.' +
' If you are using V8 based browser like Chrome, try to specify' +
' --js-flags="--wasm-staging --experimental-wasm-stack-switching"');
}
return WebAssemblyFunction;
}
/** @public */
export function wrapAsyncImport(f, parameterType, returnType) {
const WebAssemblyFunction = checkWebAssemblyFunction();
if (typeof f !== 'function') {
throw new TypeError('Function required');
}
const parameters = parameterType.slice(0);
parameters.unshift('externref');
return new WebAssemblyFunction({ parameters, results: returnType }, f, { suspending: 'first' });
}
/** @public */
export function wrapAsyncExport(f) {
const WebAssemblyFunction = checkWebAssemblyFunction();
if (typeof f !== 'function') {
throw new TypeError('Function required');
}
return new WebAssemblyFunction({ parameters: [...WebAssemblyFunction.type(f).parameters.slice(1)], results: ['externref'] }, f, { promising: 'first' });
}
/** @public */
export function wrapExports(exports, needWrap) {
return wrapInstanceExports(exports, (exportValue, name) => {
let ignore = typeof exportValue !== 'function';
if (Array.isArray(needWrap)) {
ignore = ignore || (needWrap.indexOf(name) === -1);
}
return ignore ? exportValue : wrapAsyncExport(exportValue);
});
}
@@ -0,0 +1,89 @@
import { _WebAssembly } from "./webassembly.mjs";
import { Asyncify } from "./asyncify.mjs";
function validateImports(imports) {
if (imports && typeof imports !== 'object') {
throw new TypeError('imports must be an object or undefined');
}
}
function fetchWasm(urlOrBuffer, imports) {
if (typeof wx !== 'undefined' && typeof __wxConfig !== 'undefined') {
return _WebAssembly.instantiate(urlOrBuffer, imports);
}
return fetch(urlOrBuffer)
.then(response => response.arrayBuffer())
.then(buffer => _WebAssembly.instantiate(buffer, imports));
}
/** @public */
export function load(wasmInput, imports) {
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
let source;
if (wasmInput instanceof ArrayBuffer || ArrayBuffer.isView(wasmInput)) {
return _WebAssembly.instantiate(wasmInput, imports);
}
if (wasmInput instanceof _WebAssembly.Module) {
return _WebAssembly.instantiate(wasmInput, imports).then((instance) => {
return { instance, module: wasmInput };
});
}
if (typeof wasmInput !== 'string' && !(wasmInput instanceof URL)) {
throw new TypeError('Invalid source');
}
if (typeof _WebAssembly.instantiateStreaming === 'function') {
let responsePromise;
try {
responsePromise = fetch(wasmInput);
source = _WebAssembly.instantiateStreaming(responsePromise, imports).catch(() => {
return fetchWasm(wasmInput, imports);
});
}
catch (_) {
source = fetchWasm(wasmInput, imports);
}
}
else {
source = fetchWasm(wasmInput, imports);
}
return source;
}
/** @public */
export function asyncifyLoad(asyncify, urlOrBuffer, imports) {
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
const asyncifyHelper = new Asyncify();
imports = asyncifyHelper.wrapImports(imports);
return load(urlOrBuffer, imports).then(source => {
var _a;
const memory = source.instance.exports.memory || ((_a = imports.env) === null || _a === void 0 ? void 0 : _a.memory);
return { module: source.module, instance: asyncifyHelper.init(memory, source.instance, asyncify) };
});
}
/** @public */
export function loadSync(wasmInput, imports) {
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
let module;
if ((wasmInput instanceof ArrayBuffer) || ArrayBuffer.isView(wasmInput)) {
module = new _WebAssembly.Module(wasmInput);
}
else if (wasmInput instanceof WebAssembly.Module) {
module = wasmInput;
}
else {
throw new TypeError('Invalid source');
}
const instance = new _WebAssembly.Instance(module, imports);
const source = { instance, module };
return source;
}
/** @public */
export function asyncifyLoadSync(asyncify, buffer, imports) {
var _a;
validateImports(imports);
imports = imports !== null && imports !== void 0 ? imports : {};
const asyncifyHelper = new Asyncify();
imports = asyncifyHelper.wrapImports(imports);
const source = loadSync(buffer, imports);
const memory = source.instance.exports.memory || ((_a = imports.env) === null || _a === void 0 ? void 0 : _a.memory);
return { module: source.module, instance: asyncifyHelper.init(memory, source.instance, asyncify) };
}
@@ -0,0 +1,28 @@
import { _WebAssembly } from "./webassembly.mjs";
/** @public */
export const WebAssemblyMemory = /*#__PURE__*/ (function () { return _WebAssembly.Memory; })();
/** @public */
export class Memory extends WebAssemblyMemory {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(descriptor) {
super(descriptor);
}
get HEAP8() { return new Int8Array(super.buffer); }
get HEAPU8() { return new Uint8Array(super.buffer); }
get HEAP16() { return new Int16Array(super.buffer); }
get HEAPU16() { return new Uint16Array(super.buffer); }
get HEAP32() { return new Int32Array(super.buffer); }
get HEAPU32() { return new Uint32Array(super.buffer); }
get HEAP64() { return new BigInt64Array(super.buffer); }
get HEAPU64() { return new BigUint64Array(super.buffer); }
get HEAPF32() { return new Float32Array(super.buffer); }
get HEAPF64() { return new Float64Array(super.buffer); }
get view() { return new DataView(super.buffer); }
}
/** @public */
export function extendMemory(memory) {
if (Object.getPrototypeOf(memory) === _WebAssembly.Memory.prototype) {
Object.setPrototypeOf(memory, Memory.prototype);
}
return memory;
}
@@ -0,0 +1,97 @@
import { WasiErrno } from "./types.mjs";
export function strerror(errno) {
switch (errno) {
case WasiErrno.ESUCCESS: return 'Success';
case WasiErrno.E2BIG: return 'Argument list too long';
case WasiErrno.EACCES: return 'Permission denied';
case WasiErrno.EADDRINUSE: return 'Address in use';
case WasiErrno.EADDRNOTAVAIL: return 'Address not available';
case WasiErrno.EAFNOSUPPORT: return 'Address family not supported by protocol';
case WasiErrno.EAGAIN: return 'Resource temporarily unavailable';
case WasiErrno.EALREADY: return 'Operation already in progress';
case WasiErrno.EBADF: return 'Bad file descriptor';
case WasiErrno.EBADMSG: return 'Bad message';
case WasiErrno.EBUSY: return 'Resource busy';
case WasiErrno.ECANCELED: return 'Operation canceled';
case WasiErrno.ECHILD: return 'No child process';
case WasiErrno.ECONNABORTED: return 'Connection aborted';
case WasiErrno.ECONNREFUSED: return 'Connection refused';
case WasiErrno.ECONNRESET: return 'Connection reset by peer';
case WasiErrno.EDEADLK: return 'Resource deadlock would occur';
case WasiErrno.EDESTADDRREQ: return 'Destination address required';
case WasiErrno.EDOM: return 'Domain error';
case WasiErrno.EDQUOT: return 'Quota exceeded';
case WasiErrno.EEXIST: return 'File exists';
case WasiErrno.EFAULT: return 'Bad address';
case WasiErrno.EFBIG: return 'File too large';
case WasiErrno.EHOSTUNREACH: return 'Host is unreachable';
case WasiErrno.EIDRM: return 'Identifier removed';
case WasiErrno.EILSEQ: return 'Illegal byte sequence';
case WasiErrno.EINPROGRESS: return 'Operation in progress';
case WasiErrno.EINTR: return 'Interrupted system call';
case WasiErrno.EINVAL: return 'Invalid argument';
case WasiErrno.EIO: return 'I/O error';
case WasiErrno.EISCONN: return 'Socket is connected';
case WasiErrno.EISDIR: return 'Is a directory';
case WasiErrno.ELOOP: return 'Symbolic link loop';
case WasiErrno.EMFILE: return 'No file descriptors available';
case WasiErrno.EMLINK: return 'Too many links';
case WasiErrno.EMSGSIZE: return 'Message too large';
case WasiErrno.EMULTIHOP: return 'Multihop attempted';
case WasiErrno.ENAMETOOLONG: return 'Filename too long';
case WasiErrno.ENETDOWN: return 'Network is down';
case WasiErrno.ENETRESET: return 'Connection reset by network';
case WasiErrno.ENETUNREACH: return 'Network unreachable';
case WasiErrno.ENFILE: return 'Too many files open in system';
case WasiErrno.ENOBUFS: return 'No buffer space available';
case WasiErrno.ENODEV: return 'No such device';
case WasiErrno.ENOENT: return 'No such file or directory';
case WasiErrno.ENOEXEC: return 'Exec format error';
case WasiErrno.ENOLCK: return 'No locks available';
case WasiErrno.ENOLINK: return 'Link has been severed';
case WasiErrno.ENOMEM: return 'Out of memory';
case WasiErrno.ENOMSG: return 'No message of the desired type';
case WasiErrno.ENOPROTOOPT: return 'Protocol not available';
case WasiErrno.ENOSPC: return 'No space left on device';
case WasiErrno.ENOSYS: return 'Function not implemented';
case WasiErrno.ENOTCONN: return 'Socket not connected';
case WasiErrno.ENOTDIR: return 'Not a directory';
case WasiErrno.ENOTEMPTY: return 'Directory not empty';
case WasiErrno.ENOTRECOVERABLE: return 'State not recoverable';
case WasiErrno.ENOTSOCK: return 'Not a socket';
case WasiErrno.ENOTSUP: return 'Not supported';
case WasiErrno.ENOTTY: return 'Not a tty';
case WasiErrno.ENXIO: return 'No such device or address';
case WasiErrno.EOVERFLOW: return 'Value too large for data type';
case WasiErrno.EOWNERDEAD: return 'Previous owner died';
case WasiErrno.EPERM: return 'Operation not permitted';
case WasiErrno.EPIPE: return 'Broken pipe';
case WasiErrno.EPROTO: return 'Protocol error';
case WasiErrno.EPROTONOSUPPORT: return 'Protocol not supported';
case WasiErrno.EPROTOTYPE: return 'Protocol wrong type for socket';
case WasiErrno.ERANGE: return 'Result not representable';
case WasiErrno.EROFS: return 'Read-only file system';
case WasiErrno.ESPIPE: return 'Invalid seek';
case WasiErrno.ESRCH: return 'No such process';
case WasiErrno.ESTALE: return 'Stale file handle';
case WasiErrno.ETIMEDOUT: return 'Operation timed out';
case WasiErrno.ETXTBSY: return 'Text file busy';
case WasiErrno.EXDEV: return 'Cross-device link';
case WasiErrno.ENOTCAPABLE: return 'Capabilities insufficient';
default: return 'Unknown error';
}
}
export class WasiError extends Error {
constructor(message, errno) {
super(message);
this.errno = errno;
}
getErrorMessage() {
return strerror(this.errno);
}
}
Object.defineProperty(WasiError.prototype, 'name', {
configurable: true,
writable: true,
value: 'WasiError'
});
@@ -0,0 +1,256 @@
import { WasiErrno, FileControlFlag, WasiFileType, WasiWhence } from "./types.mjs";
import { getRights } from "./rights.mjs";
import { WasiError } from "./error.mjs";
export function concatBuffer(buffers, size) {
let total = 0;
if (typeof size === 'number' && size >= 0) {
total = size;
}
else {
for (let i = 0; i < buffers.length; i++) {
const buffer = buffers[i];
total += buffer.length;
}
}
let pos = 0;
const ret = new Uint8Array(total);
for (let i = 0; i < buffers.length; i++) {
const buffer = buffers[i];
ret.set(buffer, pos);
pos += buffer.length;
}
return ret;
}
export class FileDescriptor {
constructor(id, fd, path, realPath, type, rightsBase, rightsInheriting, preopen) {
this.id = id;
this.fd = fd;
this.path = path;
this.realPath = realPath;
this.type = type;
this.rightsBase = rightsBase;
this.rightsInheriting = rightsInheriting;
this.preopen = preopen;
this.pos = BigInt(0);
this.size = BigInt(0);
}
seek(offset, whence) {
if (whence === WasiWhence.SET) {
this.pos = BigInt(offset);
}
else if (whence === WasiWhence.CUR) {
this.pos += BigInt(offset);
}
else if (whence === WasiWhence.END) {
this.pos = BigInt(this.size) - BigInt(offset);
}
else {
throw new WasiError('Unknown whence', WasiErrno.EIO);
}
return this.pos;
}
}
export class StandardOutput extends FileDescriptor {
constructor(log, id, fd, path, realPath, type, rightsBase, rightsInheriting, preopen) {
super(id, fd, path, realPath, type, rightsBase, rightsInheriting, preopen);
this._log = log;
this._buf = null;
}
write(buffer) {
const originalBuffer = buffer;
if (this._buf) {
buffer = concatBuffer([this._buf, buffer]);
this._buf = null;
}
if (buffer.indexOf(10) === -1) {
this._buf = buffer;
return originalBuffer.byteLength;
}
let written = 0;
let lastBegin = 0;
let index;
while ((index = buffer.indexOf(10, written)) !== -1) {
const str = new TextDecoder().decode(buffer.subarray(lastBegin, index));
this._log(str);
written += index - lastBegin + 1;
lastBegin = index + 1;
}
if (written < buffer.length) {
this._buf = buffer.slice(written);
}
return originalBuffer.byteLength;
}
}
export function toFileType(stat) {
if (stat.isBlockDevice())
return WasiFileType.BLOCK_DEVICE;
if (stat.isCharacterDevice())
return WasiFileType.CHARACTER_DEVICE;
if (stat.isDirectory())
return WasiFileType.DIRECTORY;
if (stat.isSocket())
return WasiFileType.SOCKET_STREAM;
if (stat.isFile())
return WasiFileType.REGULAR_FILE;
if (stat.isSymbolicLink())
return WasiFileType.SYMBOLIC_LINK;
return WasiFileType.UNKNOWN;
}
export function toFileStat(view, buf, stat) {
view.setBigUint64(buf, stat.dev, true);
view.setBigUint64(buf + 8, stat.ino, true);
view.setBigUint64(buf + 16, BigInt(toFileType(stat)), true);
view.setBigUint64(buf + 24, stat.nlink, true);
view.setBigUint64(buf + 32, stat.size, true);
view.setBigUint64(buf + 40, stat.atimeMs * BigInt(1000000), true);
view.setBigUint64(buf + 48, stat.mtimeMs * BigInt(1000000), true);
view.setBigUint64(buf + 56, stat.ctimeMs * BigInt(1000000), true);
}
export class FileDescriptorTable {
constructor(options) {
this.used = 0;
this.size = options.size;
this.fds = Array(options.size);
this.stdio = [options.in, options.out, options.err];
this.print = options.print;
this.printErr = options.printErr;
this.insertStdio(options.in, 0, '<stdin>');
this.insertStdio(options.out, 1, '<stdout>');
this.insertStdio(options.err, 2, '<stderr>');
}
insertStdio(fd, expected, name) {
const type = WasiFileType.CHARACTER_DEVICE;
const { base, inheriting } = getRights(this.stdio, fd, FileControlFlag.O_RDWR, type);
const wrap = this.insert(fd, name, name, type, base, inheriting, 0);
if (wrap.id !== expected) {
throw new WasiError(`id: ${wrap.id} !== expected: ${expected}`, WasiErrno.EBADF);
}
return wrap;
}
insert(fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen) {
var _a, _b;
let index = -1;
if (this.used >= this.size) {
const newSize = this.size * 2;
this.fds.length = newSize;
index = this.size;
this.size = newSize;
}
else {
for (let i = 0; i < this.size; ++i) {
if (this.fds[i] == null) {
index = i;
break;
}
}
}
let entry;
if (mappedPath === '<stdout>') {
entry = new StandardOutput((_a = this.print) !== null && _a !== void 0 ? _a : console.log, index, fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen);
}
else if (mappedPath === '<stderr>') {
entry = new StandardOutput((_b = this.printErr) !== null && _b !== void 0 ? _b : console.error, index, fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen);
}
else {
entry = new FileDescriptor(index, fd, mappedPath, realPath, type, rightsBase, rightsInheriting, preopen);
}
this.fds[index] = entry;
this.used++;
return entry;
}
get(id, base, inheriting) {
if (id >= this.size) {
throw new WasiError('Invalid fd', WasiErrno.EBADF);
}
const entry = this.fds[id];
if (!entry || entry.id !== id) {
throw new WasiError('Bad file descriptor', WasiErrno.EBADF);
}
/* Validate that the fd has the necessary rights. */
if ((~entry.rightsBase & base) !== BigInt(0) || (~entry.rightsInheriting & inheriting) !== BigInt(0)) {
throw new WasiError('Capabilities insufficient', WasiErrno.ENOTCAPABLE);
}
return entry;
}
remove(id) {
if (id >= this.size) {
throw new WasiError('Invalid fd', WasiErrno.EBADF);
}
const entry = this.fds[id];
if (!entry || entry.id !== id) {
throw new WasiError('Bad file descriptor', WasiErrno.EBADF);
}
this.fds[id] = undefined;
this.used--;
}
}
export class SyncTable extends FileDescriptorTable {
constructor(options) {
super(options);
this.fs = options.fs;
}
getFileTypeByFd(fd) {
const stats = this.fs.fstatSync(fd, { bigint: true });
return toFileType(stats);
}
insertPreopen(fd, mappedPath, realPath) {
const type = this.getFileTypeByFd(fd);
if (type !== WasiFileType.DIRECTORY) {
throw new WasiError(`Preopen not dir: ["${mappedPath}", "${realPath}"]`, WasiErrno.ENOTDIR);
}
const result = getRights(this.stdio, fd, 0, type);
return this.insert(fd, mappedPath, realPath, type, result.base, result.inheriting, 1);
}
renumber(dst, src) {
if (dst === src)
return;
if (dst >= this.size || src >= this.size) {
throw new WasiError('Invalid fd', WasiErrno.EBADF);
}
const dstEntry = this.fds[dst];
const srcEntry = this.fds[src];
if (!dstEntry || !srcEntry || dstEntry.id !== dst || srcEntry.id !== src) {
throw new WasiError('Invalid fd', WasiErrno.EBADF);
}
this.fs.closeSync(dstEntry.fd);
this.fds[dst] = this.fds[src];
this.fds[dst].id = dst;
this.fds[src] = undefined;
this.used--;
}
}
export class AsyncTable extends FileDescriptorTable {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(options) {
super(options);
}
async getFileTypeByFd(fd) {
const stats = await fd.stat({ bigint: true });
return toFileType(stats);
}
async insertPreopen(fd, mappedPath, realPath) {
const type = await this.getFileTypeByFd(fd);
if (type !== WasiFileType.DIRECTORY) {
throw new WasiError(`Preopen not dir: ["${mappedPath}", "${realPath}"]`, WasiErrno.ENOTDIR);
}
const result = getRights(this.stdio, fd.fd, 0, type);
return this.insert(fd, mappedPath, realPath, type, result.base, result.inheriting, 1);
}
async renumber(dst, src) {
if (dst === src)
return;
if (dst >= this.size || src >= this.size) {
throw new WasiError('Invalid fd', WasiErrno.EBADF);
}
const dstEntry = this.fds[dst];
const srcEntry = this.fds[src];
if (!dstEntry || !srcEntry || dstEntry.id !== dst || srcEntry.id !== src) {
throw new WasiError('Invalid fd', WasiErrno.EBADF);
}
await dstEntry.fd.close();
this.fds[dst] = this.fds[src];
this.fds[dst].id = dst;
this.fds[src] = undefined;
this.used--;
}
}
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,186 @@
import { WASI as WASIPreview1 } from "./preview1.mjs";
import { validateObject, validateArray, validateBoolean, validateFunction, validateUndefined, validateString } from "./util.mjs";
// eslint-disable-next-line spaced-comment
const kEmptyObject = /*#__PURE__*/ Object.freeze(/*#__PURE__*/ Object.create(null));
const kExitCode = Symbol('kExitCode');
const kSetMemory = Symbol('kSetMemory');
const kStarted = Symbol('kStarted');
const kInstance = Symbol('kInstance');
const kBindingName = Symbol('kBindingName');
function validateOptions(options) {
var _a;
validateObject(options, 'options');
let _WASI;
if (options.version !== undefined) {
validateString(options.version, 'options.version');
switch (options.version) {
case 'unstable':
_WASI = WASIPreview1;
this[kBindingName] = 'wasi_unstable';
break;
case 'preview1':
_WASI = WASIPreview1;
this[kBindingName] = 'wasi_snapshot_preview1';
break;
default:
throw new TypeError(`unsupported WASI version "${options.version}"`);
}
}
else {
_WASI = WASIPreview1;
this[kBindingName] = 'wasi_snapshot_preview1';
}
if (options.args !== undefined) {
validateArray(options.args, 'options.args');
}
const args = ((_a = options.args) !== null && _a !== void 0 ? _a : []).map(String);
const env = [];
if (options.env !== undefined) {
validateObject(options.env, 'options.env');
Object.entries(options.env).forEach(({ 0: key, 1: value }) => {
if (value !== undefined) {
env.push(`${key}=${value}`);
}
});
}
const preopens = [];
if (options.preopens !== undefined) {
validateObject(options.preopens, 'options.preopens');
Object.entries(options.preopens).forEach(({ 0: key, 1: value }) => preopens.push({ mappedPath: String(key), realPath: String(value) }));
}
if (preopens.length > 0) {
if (options.fs === undefined) {
throw new Error('filesystem is disabled, can not preopen directory');
}
try {
validateObject(options.fs, 'options.fs');
}
catch (_) {
throw new TypeError('Node.js fs like implementation is not provided');
}
}
// if (options.filesystem !== undefined) {
// validateObject(options.filesystem, 'options.filesystem')
// validateString(options.filesystem.type, 'options.filesystem.type')
// if (options.filesystem.type !== 'memfs' && options.filesystem.type !== 'file-system-access-api') {
// throw new Error(`Filesystem type ${(options.filesystem as any).type as string} is not supported, only "memfs" and "file-system-access-api" is supported currently`)
// }
// try {
// validateObject(options.filesystem.fs, 'options.filesystem.fs')
// } catch (_) {
// throw new Error('Node.js fs like implementation is not provided')
// }
// }
if (options.print !== undefined)
validateFunction(options.print, 'options.print');
if (options.printErr !== undefined)
validateFunction(options.printErr, 'options.printErr');
if (options.returnOnExit !== undefined) {
validateBoolean(options.returnOnExit, 'options.returnOnExit');
}
// const { stdin = 0, stdout = 1, stderr = 2 } = options
// validateInt32(stdin, 'options.stdin', 0)
// validateInt32(stdout, 'options.stdout', 0)
// validateInt32(stderr, 'options.stderr', 0)
// const stdio = [stdin, stdout, stderr] as const
const stdio = [0, 1, 2];
return {
args,
env,
preopens,
stdio,
_WASI
};
}
function initWASI(setMemory, wrap) {
this[kSetMemory] = setMemory;
this.wasiImport = wrap;
this[kStarted] = false;
this[kExitCode] = 0;
this[kInstance] = undefined;
}
/** @public */
export class WASI {
constructor(options = kEmptyObject) {
const { args, env, preopens, stdio, _WASI } = validateOptions.call(this, options);
const wrap = _WASI.createSync(args, env, preopens, stdio, options.fs, options.print, options.printErr);
const setMemory = wrap._setMemory;
delete wrap._setMemory;
initWASI.call(this, setMemory, wrap);
if (options.returnOnExit) {
wrap.proc_exit = wasiReturnOnProcExit.bind(this);
}
}
finalizeBindings(instance, _a) {
var _b;
var { memory = (_b = instance === null || instance === void 0 ? void 0 : instance.exports) === null || _b === void 0 ? void 0 : _b.memory } = _a === void 0 ? {} : _a;
if (this[kStarted]) {
throw new Error('WASI instance has already started');
}
validateObject(instance, 'instance');
validateObject(instance.exports, 'instance.exports');
this[kSetMemory](memory);
this[kInstance] = instance;
this[kStarted] = true;
}
// Must not export _initialize, must export _start
start(instance) {
this.finalizeBindings(instance);
const { _start, _initialize } = this[kInstance].exports;
validateFunction(_start, 'instance.exports._start');
validateUndefined(_initialize, 'instance.exports._initialize');
let ret;
try {
ret = _start();
}
catch (err) {
if (err !== kExitCode) {
throw err;
}
}
if (ret instanceof Promise) {
return ret.then(() => this[kExitCode], (err) => {
if (err !== kExitCode) {
throw err;
}
return this[kExitCode];
});
}
return this[kExitCode];
}
// Must not export _start, may optionally export _initialize
initialize(instance) {
this.finalizeBindings(instance);
const { _start, _initialize } = this[kInstance].exports;
validateUndefined(_start, 'instance.exports._start');
if (_initialize !== undefined) {
validateFunction(_initialize, 'instance.exports._initialize');
return _initialize();
}
}
getImportObject() {
return { [this[kBindingName]]: this.wasiImport };
}
}
function wasiReturnOnProcExit(rval) {
this[kExitCode] = rval;
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw kExitCode;
}
/** @public */
export async function createAsyncWASI(options = kEmptyObject) {
const _this = Object.create(WASI.prototype);
const { args, env, preopens, stdio, _WASI } = validateOptions.call(_this, options);
if (options.asyncify !== undefined) {
validateObject(options.asyncify, 'options.asyncify');
validateFunction(options.asyncify.wrapImportFunction, 'options.asyncify.wrapImportFunction');
}
const wrap = await _WASI.createAsync(args, env, preopens, stdio, options.fs, options.print, options.printErr, options.asyncify);
const setMemory = wrap._setMemory;
delete wrap._setMemory;
initWASI.call(_this, setMemory, wrap);
if (options.returnOnExit) {
wrap.proc_exit = wasiReturnOnProcExit.bind(_this);
}
return _this;
}
@@ -0,0 +1,310 @@
import { validateString } from "./util.mjs";
const CHAR_DOT = 46; /* . */
const CHAR_FORWARD_SLASH = 47; /* / */
const CHAR_BACKWARD_SLASH = 92; /* \ */
const CHAR_COLON = 58; /* : */
const CHAR_UPPERCASE_A = 65; /* A */
const CHAR_UPPERCASE_Z = 90; /* Z */
const CHAR_LOWERCASE_A = 97; /* a */
const CHAR_LOWERCASE_Z = 122; /* z */
function isPathSeparatorWin(code) {
return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
}
function isWindowsDeviceRoot(code) {
return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
(code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z);
}
const _isWin32 = typeof process !== 'undefined' && process.platform === 'win32';
/**
* Windows variant of `resolve()`. Mirrors Node's `path.win32.resolve`
* semantics enough for the WASI shim's needs (drive-letter absolutes
* + UNC paths + per-drive cwd lookups via `process.env`/`process.cwd`).
*
* Why this is needed: on Windows, `FileDescriptor.realPath` is the
* host realpath returned by `fs.realpathSync(realPath, 'utf8')` — the
* backslash form `D:\…`. The POSIX-only `resolveImpl` below only
* treats `/` as a separator, reads `D` as non-`/`, decides realPath
* is "relative", and produces a garbage joined path. Downstream
* `fs.openSync(garbage)` then returns `EINVAL` and the WASI caller
* sees a permanent failure. This function gives us the correct
* Windows-style resolution without taking a Node-only `path` import
* (which would break browser bundles of this package).
*
* Cribbed from Node's `lib/path.js` `win32.resolve()` (MIT-licensed),
* trimmed to what WASI realpath resolution actually exercises.
*/
function resolveWin32(args) {
let resolvedDevice = '';
let resolvedTail = '';
let resolvedAbsolute = false;
for (let i = args.length - 1; i >= -1; i--) {
let path;
if (i >= 0) {
path = args[i];
validateString(path, 'path');
if (path.length === 0)
continue;
}
else if (resolvedDevice.length === 0) {
path = (typeof process !== 'undefined' && typeof process.cwd === 'function')
? process.cwd()
: '';
}
else {
// Look up per-drive cwd via the `=X:` env var convention; fall back
// to the global cwd if absent.
const envKey = `=${resolvedDevice}`;
const env = (typeof process !== 'undefined') ? process.env : undefined;
path = (env && typeof env[envKey] === 'string')
? env[envKey]
: (typeof process !== 'undefined' && typeof process.cwd === 'function')
? process.cwd()
: '';
if (path === undefined ||
(path.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() &&
path.charCodeAt(2) === CHAR_BACKWARD_SLASH)) {
path = `${resolvedDevice}\\`;
}
}
const len = path.length;
let rootEnd = 0;
let device = '';
let isAbsolute = false;
const code = path.charCodeAt(0);
if (len === 1) {
if (isPathSeparatorWin(code)) {
rootEnd = 1;
isAbsolute = true;
}
}
else if (isPathSeparatorWin(code)) {
isAbsolute = true;
if (isPathSeparatorWin(path.charCodeAt(1))) {
// UNC path: `\\server\share\…`
let j = 2;
let last = j;
while (j < len && !isPathSeparatorWin(path.charCodeAt(j)))
j++;
if (j < len && j !== last) {
const firstPart = path.slice(last, j);
last = j;
while (j < len && isPathSeparatorWin(path.charCodeAt(j)))
j++;
if (j < len && j !== last) {
last = j;
while (j < len && !isPathSeparatorWin(path.charCodeAt(j)))
j++;
if (j === len || j !== last) {
device = `\\\\${firstPart}\\${path.slice(last, j)}`;
rootEnd = j;
}
}
}
}
else {
rootEnd = 1;
}
}
else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {
device = path.slice(0, 2);
rootEnd = 2;
if (len > 2 && isPathSeparatorWin(path.charCodeAt(2))) {
isAbsolute = true;
rootEnd = 3;
}
}
if (device.length > 0) {
if (resolvedDevice.length > 0) {
if (device.toLowerCase() !== resolvedDevice.toLowerCase())
continue;
}
else {
resolvedDevice = device;
}
}
if (resolvedAbsolute) {
if (resolvedDevice.length > 0)
break;
}
else {
resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`;
resolvedAbsolute = isAbsolute;
if (isAbsolute && resolvedDevice.length > 0)
break;
}
}
resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isPathSeparatorWin);
return resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail || '.';
}
function isPosixPathSeparator(code) {
return code === CHAR_FORWARD_SLASH;
}
function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
let res = '';
let lastSegmentLength = 0;
let lastSlash = -1;
let dots = 0;
let code = 0;
for (let i = 0; i <= path.length; ++i) {
if (i < path.length) {
code = path.charCodeAt(i);
}
else if (isPathSeparator(code)) {
break;
}
else {
code = CHAR_FORWARD_SLASH;
}
if (isPathSeparator(code)) {
if (lastSlash === i - 1 || dots === 1) {
// NOOP
}
else if (dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 ||
res.charCodeAt(res.length - 1) !== CHAR_DOT ||
res.charCodeAt(res.length - 2) !== CHAR_DOT) {
if (res.length > 2) {
const lastSlashIndex = res.indexOf(separator);
if (lastSlashIndex === -1) {
res = '';
lastSegmentLength = 0;
}
else {
res = res.slice(0, lastSlashIndex);
lastSegmentLength =
res.length - 1 - res.indexOf(separator);
}
lastSlash = i;
dots = 0;
continue;
}
else if (res.length !== 0) {
res = '';
lastSegmentLength = 0;
lastSlash = i;
dots = 0;
continue;
}
}
if (allowAboveRoot) {
res += res.length > 0 ? `${separator}..` : '..';
lastSegmentLength = 2;
}
}
else {
if (res.length > 0) {
res += `${separator}${path.slice(lastSlash + 1, i)}`;
}
else {
res = path.slice(lastSlash + 1, i);
}
lastSegmentLength = i - lastSlash - 1;
}
lastSlash = i;
dots = 0;
}
else if (code === CHAR_DOT && dots !== -1) {
++dots;
}
else {
dots = -1;
}
}
return res;
}
export function resolve(...args) {
// On Windows, host paths are `D:\…` style. The POSIX-only resolver
// below treats `D` as a non-`/` character and produces garbage; route
// to the Windows-aware variant. POSIX hosts (Linux/macOS/browser)
// run the original code path unchanged — `_isWin32` is constant-folded
// away on those targets.
if (_isWin32)
return resolveWin32(args);
let resolvedPath = '';
let resolvedAbsolute = false;
for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
const path = i >= 0 ? args[i] : '/';
validateString(path, 'path');
// Skip empty entries
if (path.length === 0) {
continue;
}
resolvedPath = `${path}/${resolvedPath}`;
resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator);
if (resolvedAbsolute) {
return `/${resolvedPath}`;
}
return resolvedPath.length > 0 ? resolvedPath : '.';
}
export function relative(from, to) {
validateString(from, 'from');
validateString(to, 'to');
if (from === to)
return '';
// Trim leading forward slashes.
from = resolve(from);
to = resolve(to);
if (from === to)
return '';
const fromStart = 1;
const fromEnd = from.length;
const fromLen = fromEnd - fromStart;
const toStart = 1;
const toLen = to.length - toStart;
// Compare paths to find the longest common path from root
const length = (fromLen < toLen ? fromLen : toLen);
let lastCommonSep = -1;
let i = 0;
for (; i < length; i++) {
const fromCode = from.charCodeAt(fromStart + i);
if (fromCode !== to.charCodeAt(toStart + i)) {
break;
}
else if (fromCode === CHAR_FORWARD_SLASH) {
lastCommonSep = i;
}
}
if (i === length) {
if (toLen > length) {
if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {
// We get here if `from` is the exact base path for `to`.
// For example: from='/foo/bar'; to='/foo/bar/baz'
return to.slice(toStart + i + 1);
}
if (i === 0) {
// We get here if `from` is the root
// For example: from='/'; to='/foo'
return to.slice(toStart + i);
}
}
else if (fromLen > length) {
if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) {
// We get here if `to` is the exact base path for `from`.
// For example: from='/foo/bar/baz'; to='/foo/bar'
lastCommonSep = i;
}
else if (i === 0) {
// We get here if `to` is the root.
// For example: from='/foo/bar'; to='/'
lastCommonSep = 0;
}
}
}
let out = '';
// Generate the relative path based on the path difference between `to`
// and `from`.
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
if (i === fromEnd ||
from.charCodeAt(i) === CHAR_FORWARD_SLASH) {
out += out.length === 0 ? '..' : '/..';
}
}
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts.
return `${out}${to.slice(toStart + lastCommonSep)}`;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,135 @@
import { WasiError } from "./error.mjs";
import { WasiErrno, WasiRights, WasiFileType } from "./types.mjs";
export const RIGHTS_ALL = WasiRights.FD_DATASYNC |
WasiRights.FD_READ |
WasiRights.FD_SEEK |
WasiRights.FD_FDSTAT_SET_FLAGS |
WasiRights.FD_SYNC |
WasiRights.FD_TELL |
WasiRights.FD_WRITE |
WasiRights.FD_ADVISE |
WasiRights.FD_ALLOCATE |
WasiRights.PATH_CREATE_DIRECTORY |
WasiRights.PATH_CREATE_FILE |
WasiRights.PATH_LINK_SOURCE |
WasiRights.PATH_LINK_TARGET |
WasiRights.PATH_OPEN |
WasiRights.FD_READDIR |
WasiRights.PATH_READLINK |
WasiRights.PATH_RENAME_SOURCE |
WasiRights.PATH_RENAME_TARGET |
WasiRights.PATH_FILESTAT_GET |
WasiRights.PATH_FILESTAT_SET_SIZE |
WasiRights.PATH_FILESTAT_SET_TIMES |
WasiRights.FD_FILESTAT_GET |
WasiRights.FD_FILESTAT_SET_TIMES |
WasiRights.FD_FILESTAT_SET_SIZE |
WasiRights.PATH_SYMLINK |
WasiRights.PATH_UNLINK_FILE |
WasiRights.PATH_REMOVE_DIRECTORY |
WasiRights.POLL_FD_READWRITE |
WasiRights.SOCK_SHUTDOWN |
WasiRights.SOCK_ACCEPT;
export const BLOCK_DEVICE_BASE = RIGHTS_ALL;
export const BLOCK_DEVICE_INHERITING = RIGHTS_ALL;
export const CHARACTER_DEVICE_BASE = RIGHTS_ALL;
export const CHARACTER_DEVICE_INHERITING = RIGHTS_ALL;
export const REGULAR_FILE_BASE = WasiRights.FD_DATASYNC |
WasiRights.FD_READ |
WasiRights.FD_SEEK |
WasiRights.FD_FDSTAT_SET_FLAGS |
WasiRights.FD_SYNC |
WasiRights.FD_TELL |
WasiRights.FD_WRITE |
WasiRights.FD_ADVISE |
WasiRights.FD_ALLOCATE |
WasiRights.FD_FILESTAT_GET |
WasiRights.FD_FILESTAT_SET_SIZE |
WasiRights.FD_FILESTAT_SET_TIMES |
WasiRights.POLL_FD_READWRITE;
export const REGULAR_FILE_INHERITING = /*#__PURE__*/ BigInt(0);
export const DIRECTORY_BASE = WasiRights.FD_FDSTAT_SET_FLAGS |
WasiRights.FD_SYNC |
WasiRights.FD_ADVISE |
WasiRights.PATH_CREATE_DIRECTORY |
WasiRights.PATH_CREATE_FILE |
WasiRights.PATH_LINK_SOURCE |
WasiRights.PATH_LINK_TARGET |
WasiRights.PATH_OPEN |
WasiRights.FD_READDIR |
WasiRights.PATH_READLINK |
WasiRights.PATH_RENAME_SOURCE |
WasiRights.PATH_RENAME_TARGET |
WasiRights.PATH_FILESTAT_GET |
WasiRights.PATH_FILESTAT_SET_SIZE |
WasiRights.PATH_FILESTAT_SET_TIMES |
WasiRights.FD_FILESTAT_GET |
WasiRights.FD_FILESTAT_SET_TIMES |
WasiRights.PATH_SYMLINK |
WasiRights.PATH_UNLINK_FILE |
WasiRights.PATH_REMOVE_DIRECTORY |
WasiRights.POLL_FD_READWRITE;
export const DIRECTORY_INHERITING = DIRECTORY_BASE | REGULAR_FILE_BASE;
export const SOCKET_BASE = (WasiRights.FD_READ |
WasiRights.FD_FDSTAT_SET_FLAGS |
WasiRights.FD_WRITE |
WasiRights.FD_FILESTAT_GET |
WasiRights.POLL_FD_READWRITE |
WasiRights.SOCK_SHUTDOWN);
export const SOCKET_INHERITING = RIGHTS_ALL;
export const TTY_BASE = WasiRights.FD_READ |
WasiRights.FD_FDSTAT_SET_FLAGS |
WasiRights.FD_WRITE |
WasiRights.FD_FILESTAT_GET |
WasiRights.POLL_FD_READWRITE;
export const TTY_INHERITING = /*#__PURE__*/ BigInt(0);
export function getRights(stdio, fd, flags, type) {
const ret = {
base: BigInt(0),
inheriting: BigInt(0)
};
if (type === WasiFileType.UNKNOWN) {
throw new WasiError('Unknown file type', WasiErrno.EINVAL);
}
switch (type) {
case WasiFileType.REGULAR_FILE:
ret.base = REGULAR_FILE_BASE;
ret.inheriting = REGULAR_FILE_INHERITING;
break;
case WasiFileType.DIRECTORY:
ret.base = DIRECTORY_BASE;
ret.inheriting = DIRECTORY_INHERITING;
break;
case WasiFileType.SOCKET_STREAM:
case WasiFileType.SOCKET_DGRAM:
ret.base = SOCKET_BASE;
ret.inheriting = SOCKET_INHERITING;
break;
case WasiFileType.CHARACTER_DEVICE:
if (stdio.indexOf(fd) !== -1) {
ret.base = TTY_BASE;
ret.inheriting = TTY_INHERITING;
}
else {
ret.base = CHARACTER_DEVICE_BASE;
ret.inheriting = CHARACTER_DEVICE_INHERITING;
}
break;
case WasiFileType.BLOCK_DEVICE:
ret.base = BLOCK_DEVICE_BASE;
ret.inheriting = BLOCK_DEVICE_INHERITING;
break;
default:
ret.base = BigInt(0);
ret.inheriting = BigInt(0);
}
/* Disable read/write bits depending on access mode. */
const read_or_write_only = flags & (0 | 1 | 2);
if (read_or_write_only === 0) {
ret.base &= ~WasiRights.FD_WRITE;
}
else if (read_or_write_only === 1) {
ret.base &= ~WasiRights.FD_READ;
}
return ret;
}
@@ -0,0 +1,216 @@
/* eslint-disable spaced-comment */
export var WasiErrno;
(function (WasiErrno) {
WasiErrno[WasiErrno["ESUCCESS"] = 0] = "ESUCCESS";
WasiErrno[WasiErrno["E2BIG"] = 1] = "E2BIG";
WasiErrno[WasiErrno["EACCES"] = 2] = "EACCES";
WasiErrno[WasiErrno["EADDRINUSE"] = 3] = "EADDRINUSE";
WasiErrno[WasiErrno["EADDRNOTAVAIL"] = 4] = "EADDRNOTAVAIL";
WasiErrno[WasiErrno["EAFNOSUPPORT"] = 5] = "EAFNOSUPPORT";
WasiErrno[WasiErrno["EAGAIN"] = 6] = "EAGAIN";
WasiErrno[WasiErrno["EALREADY"] = 7] = "EALREADY";
WasiErrno[WasiErrno["EBADF"] = 8] = "EBADF";
WasiErrno[WasiErrno["EBADMSG"] = 9] = "EBADMSG";
WasiErrno[WasiErrno["EBUSY"] = 10] = "EBUSY";
WasiErrno[WasiErrno["ECANCELED"] = 11] = "ECANCELED";
WasiErrno[WasiErrno["ECHILD"] = 12] = "ECHILD";
WasiErrno[WasiErrno["ECONNABORTED"] = 13] = "ECONNABORTED";
WasiErrno[WasiErrno["ECONNREFUSED"] = 14] = "ECONNREFUSED";
WasiErrno[WasiErrno["ECONNRESET"] = 15] = "ECONNRESET";
WasiErrno[WasiErrno["EDEADLK"] = 16] = "EDEADLK";
WasiErrno[WasiErrno["EDESTADDRREQ"] = 17] = "EDESTADDRREQ";
WasiErrno[WasiErrno["EDOM"] = 18] = "EDOM";
WasiErrno[WasiErrno["EDQUOT"] = 19] = "EDQUOT";
WasiErrno[WasiErrno["EEXIST"] = 20] = "EEXIST";
WasiErrno[WasiErrno["EFAULT"] = 21] = "EFAULT";
WasiErrno[WasiErrno["EFBIG"] = 22] = "EFBIG";
WasiErrno[WasiErrno["EHOSTUNREACH"] = 23] = "EHOSTUNREACH";
WasiErrno[WasiErrno["EIDRM"] = 24] = "EIDRM";
WasiErrno[WasiErrno["EILSEQ"] = 25] = "EILSEQ";
WasiErrno[WasiErrno["EINPROGRESS"] = 26] = "EINPROGRESS";
WasiErrno[WasiErrno["EINTR"] = 27] = "EINTR";
WasiErrno[WasiErrno["EINVAL"] = 28] = "EINVAL";
WasiErrno[WasiErrno["EIO"] = 29] = "EIO";
WasiErrno[WasiErrno["EISCONN"] = 30] = "EISCONN";
WasiErrno[WasiErrno["EISDIR"] = 31] = "EISDIR";
WasiErrno[WasiErrno["ELOOP"] = 32] = "ELOOP";
WasiErrno[WasiErrno["EMFILE"] = 33] = "EMFILE";
WasiErrno[WasiErrno["EMLINK"] = 34] = "EMLINK";
WasiErrno[WasiErrno["EMSGSIZE"] = 35] = "EMSGSIZE";
WasiErrno[WasiErrno["EMULTIHOP"] = 36] = "EMULTIHOP";
WasiErrno[WasiErrno["ENAMETOOLONG"] = 37] = "ENAMETOOLONG";
WasiErrno[WasiErrno["ENETDOWN"] = 38] = "ENETDOWN";
WasiErrno[WasiErrno["ENETRESET"] = 39] = "ENETRESET";
WasiErrno[WasiErrno["ENETUNREACH"] = 40] = "ENETUNREACH";
WasiErrno[WasiErrno["ENFILE"] = 41] = "ENFILE";
WasiErrno[WasiErrno["ENOBUFS"] = 42] = "ENOBUFS";
WasiErrno[WasiErrno["ENODEV"] = 43] = "ENODEV";
WasiErrno[WasiErrno["ENOENT"] = 44] = "ENOENT";
WasiErrno[WasiErrno["ENOEXEC"] = 45] = "ENOEXEC";
WasiErrno[WasiErrno["ENOLCK"] = 46] = "ENOLCK";
WasiErrno[WasiErrno["ENOLINK"] = 47] = "ENOLINK";
WasiErrno[WasiErrno["ENOMEM"] = 48] = "ENOMEM";
WasiErrno[WasiErrno["ENOMSG"] = 49] = "ENOMSG";
WasiErrno[WasiErrno["ENOPROTOOPT"] = 50] = "ENOPROTOOPT";
WasiErrno[WasiErrno["ENOSPC"] = 51] = "ENOSPC";
WasiErrno[WasiErrno["ENOSYS"] = 52] = "ENOSYS";
WasiErrno[WasiErrno["ENOTCONN"] = 53] = "ENOTCONN";
WasiErrno[WasiErrno["ENOTDIR"] = 54] = "ENOTDIR";
WasiErrno[WasiErrno["ENOTEMPTY"] = 55] = "ENOTEMPTY";
WasiErrno[WasiErrno["ENOTRECOVERABLE"] = 56] = "ENOTRECOVERABLE";
WasiErrno[WasiErrno["ENOTSOCK"] = 57] = "ENOTSOCK";
WasiErrno[WasiErrno["ENOTSUP"] = 58] = "ENOTSUP";
WasiErrno[WasiErrno["ENOTTY"] = 59] = "ENOTTY";
WasiErrno[WasiErrno["ENXIO"] = 60] = "ENXIO";
WasiErrno[WasiErrno["EOVERFLOW"] = 61] = "EOVERFLOW";
WasiErrno[WasiErrno["EOWNERDEAD"] = 62] = "EOWNERDEAD";
WasiErrno[WasiErrno["EPERM"] = 63] = "EPERM";
WasiErrno[WasiErrno["EPIPE"] = 64] = "EPIPE";
WasiErrno[WasiErrno["EPROTO"] = 65] = "EPROTO";
WasiErrno[WasiErrno["EPROTONOSUPPORT"] = 66] = "EPROTONOSUPPORT";
WasiErrno[WasiErrno["EPROTOTYPE"] = 67] = "EPROTOTYPE";
WasiErrno[WasiErrno["ERANGE"] = 68] = "ERANGE";
WasiErrno[WasiErrno["EROFS"] = 69] = "EROFS";
WasiErrno[WasiErrno["ESPIPE"] = 70] = "ESPIPE";
WasiErrno[WasiErrno["ESRCH"] = 71] = "ESRCH";
WasiErrno[WasiErrno["ESTALE"] = 72] = "ESTALE";
WasiErrno[WasiErrno["ETIMEDOUT"] = 73] = "ETIMEDOUT";
WasiErrno[WasiErrno["ETXTBSY"] = 74] = "ETXTBSY";
WasiErrno[WasiErrno["EXDEV"] = 75] = "EXDEV";
WasiErrno[WasiErrno["ENOTCAPABLE"] = 76] = "ENOTCAPABLE";
})(WasiErrno || (WasiErrno = {}));
export var WasiFileType;
(function (WasiFileType) {
WasiFileType[WasiFileType["UNKNOWN"] = 0] = "UNKNOWN";
WasiFileType[WasiFileType["BLOCK_DEVICE"] = 1] = "BLOCK_DEVICE";
WasiFileType[WasiFileType["CHARACTER_DEVICE"] = 2] = "CHARACTER_DEVICE";
WasiFileType[WasiFileType["DIRECTORY"] = 3] = "DIRECTORY";
WasiFileType[WasiFileType["REGULAR_FILE"] = 4] = "REGULAR_FILE";
WasiFileType[WasiFileType["SOCKET_DGRAM"] = 5] = "SOCKET_DGRAM";
WasiFileType[WasiFileType["SOCKET_STREAM"] = 6] = "SOCKET_STREAM";
WasiFileType[WasiFileType["SYMBOLIC_LINK"] = 7] = "SYMBOLIC_LINK";
})(WasiFileType || (WasiFileType = {}));
const FD_DATASYNC = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(0));
const FD_READ = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(1));
const FD_SEEK = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(2));
const FD_FDSTAT_SET_FLAGS = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(3));
const FD_SYNC = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(4));
const FD_TELL = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(5));
const FD_WRITE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(6));
const FD_ADVISE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(7));
const FD_ALLOCATE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(8));
const PATH_CREATE_DIRECTORY = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(9));
const PATH_CREATE_FILE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(10));
const PATH_LINK_SOURCE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(11));
const PATH_LINK_TARGET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(12));
const PATH_OPEN = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(13));
const FD_READDIR = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(14));
const PATH_READLINK = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(15));
const PATH_RENAME_SOURCE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(16));
const PATH_RENAME_TARGET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(17));
const PATH_FILESTAT_GET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(18));
const PATH_FILESTAT_SET_SIZE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(19));
const PATH_FILESTAT_SET_TIMES = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(20));
const FD_FILESTAT_GET = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(21));
const FD_FILESTAT_SET_SIZE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(22));
const FD_FILESTAT_SET_TIMES = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(23));
const PATH_SYMLINK = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(24));
const PATH_REMOVE_DIRECTORY = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(25));
const PATH_UNLINK_FILE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(26));
const POLL_FD_READWRITE = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(27));
const SOCK_SHUTDOWN = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(28));
const SOCK_ACCEPT = ( /*#__PURE__*/BigInt(1) << /*#__PURE__*/ BigInt(29));
export const WasiRights = {
FD_DATASYNC,
FD_READ,
FD_SEEK,
FD_FDSTAT_SET_FLAGS,
FD_SYNC,
FD_TELL,
FD_WRITE,
FD_ADVISE,
FD_ALLOCATE,
PATH_CREATE_DIRECTORY,
PATH_CREATE_FILE,
PATH_LINK_SOURCE,
PATH_LINK_TARGET,
PATH_OPEN,
FD_READDIR,
PATH_READLINK,
PATH_RENAME_SOURCE,
PATH_RENAME_TARGET,
PATH_FILESTAT_GET,
PATH_FILESTAT_SET_SIZE,
PATH_FILESTAT_SET_TIMES,
FD_FILESTAT_GET,
FD_FILESTAT_SET_SIZE,
FD_FILESTAT_SET_TIMES,
PATH_SYMLINK,
PATH_REMOVE_DIRECTORY,
PATH_UNLINK_FILE,
POLL_FD_READWRITE,
SOCK_SHUTDOWN,
SOCK_ACCEPT
};
export var WasiWhence;
(function (WasiWhence) {
WasiWhence[WasiWhence["SET"] = 0] = "SET";
WasiWhence[WasiWhence["CUR"] = 1] = "CUR";
WasiWhence[WasiWhence["END"] = 2] = "END";
})(WasiWhence || (WasiWhence = {}));
export var FileControlFlag;
(function (FileControlFlag) {
FileControlFlag[FileControlFlag["O_RDONLY"] = 0] = "O_RDONLY";
FileControlFlag[FileControlFlag["O_WRONLY"] = 1] = "O_WRONLY";
FileControlFlag[FileControlFlag["O_RDWR"] = 2] = "O_RDWR";
FileControlFlag[FileControlFlag["O_CREAT"] = 64] = "O_CREAT";
FileControlFlag[FileControlFlag["O_EXCL"] = 128] = "O_EXCL";
FileControlFlag[FileControlFlag["O_NOCTTY"] = 256] = "O_NOCTTY";
FileControlFlag[FileControlFlag["O_TRUNC"] = 512] = "O_TRUNC";
FileControlFlag[FileControlFlag["O_APPEND"] = 1024] = "O_APPEND";
FileControlFlag[FileControlFlag["O_DIRECTORY"] = 65536] = "O_DIRECTORY";
FileControlFlag[FileControlFlag["O_NOATIME"] = 262144] = "O_NOATIME";
FileControlFlag[FileControlFlag["O_NOFOLLOW"] = 131072] = "O_NOFOLLOW";
FileControlFlag[FileControlFlag["O_SYNC"] = 1052672] = "O_SYNC";
FileControlFlag[FileControlFlag["O_DIRECT"] = 16384] = "O_DIRECT";
FileControlFlag[FileControlFlag["O_NONBLOCK"] = 2048] = "O_NONBLOCK";
})(FileControlFlag || (FileControlFlag = {}));
export var WasiFileControlFlag;
(function (WasiFileControlFlag) {
WasiFileControlFlag[WasiFileControlFlag["O_CREAT"] = 1] = "O_CREAT";
WasiFileControlFlag[WasiFileControlFlag["O_DIRECTORY"] = 2] = "O_DIRECTORY";
WasiFileControlFlag[WasiFileControlFlag["O_EXCL"] = 4] = "O_EXCL";
WasiFileControlFlag[WasiFileControlFlag["O_TRUNC"] = 8] = "O_TRUNC";
})(WasiFileControlFlag || (WasiFileControlFlag = {}));
export var WasiFdFlag;
(function (WasiFdFlag) {
WasiFdFlag[WasiFdFlag["APPEND"] = 1] = "APPEND";
WasiFdFlag[WasiFdFlag["DSYNC"] = 2] = "DSYNC";
WasiFdFlag[WasiFdFlag["NONBLOCK"] = 4] = "NONBLOCK";
WasiFdFlag[WasiFdFlag["RSYNC"] = 8] = "RSYNC";
WasiFdFlag[WasiFdFlag["SYNC"] = 16] = "SYNC";
})(WasiFdFlag || (WasiFdFlag = {}));
export var WasiClockid;
(function (WasiClockid) {
WasiClockid[WasiClockid["REALTIME"] = 0] = "REALTIME";
WasiClockid[WasiClockid["MONOTONIC"] = 1] = "MONOTONIC";
WasiClockid[WasiClockid["PROCESS_CPUTIME_ID"] = 2] = "PROCESS_CPUTIME_ID";
WasiClockid[WasiClockid["THREAD_CPUTIME_ID"] = 3] = "THREAD_CPUTIME_ID";
})(WasiClockid || (WasiClockid = {}));
export var WasiFstFlag;
(function (WasiFstFlag) {
WasiFstFlag[WasiFstFlag["SET_ATIM"] = 1] = "SET_ATIM";
WasiFstFlag[WasiFstFlag["SET_ATIM_NOW"] = 2] = "SET_ATIM_NOW";
WasiFstFlag[WasiFstFlag["SET_MTIM"] = 4] = "SET_MTIM";
WasiFstFlag[WasiFstFlag["SET_MTIM_NOW"] = 8] = "SET_MTIM_NOW";
})(WasiFstFlag || (WasiFstFlag = {}));
export var WasiEventType;
(function (WasiEventType) {
WasiEventType[WasiEventType["CLOCK"] = 0] = "CLOCK";
WasiEventType[WasiEventType["FD_READ"] = 1] = "FD_READ";
WasiEventType[WasiEventType["FD_WRITE"] = 2] = "FD_WRITE";
})(WasiEventType || (WasiEventType = {}));
export var WasiSubclockflags;
(function (WasiSubclockflags) {
WasiSubclockflags[WasiSubclockflags["ABSTIME"] = 1] = "ABSTIME";
})(WasiSubclockflags || (WasiSubclockflags = {}));
@@ -0,0 +1,113 @@
/* eslint-disable spaced-comment */
export function validateObject(value, name) {
if (value === null || typeof value !== 'object') {
throw new TypeError(`${name} must be an object. Received ${value === null ? 'null' : typeof value}`);
}
}
export function validateArray(value, name) {
if (!Array.isArray(value)) {
throw new TypeError(`${name} must be an array. Received ${value === null ? 'null' : typeof value}`);
}
}
export function validateBoolean(value, name) {
if (typeof value !== 'boolean') {
throw new TypeError(`${name} must be a boolean. Received ${value === null ? 'null' : typeof value}`);
}
}
export function validateString(value, name) {
if (typeof value !== 'string') {
throw new TypeError(`${name} must be a string. Received ${value === null ? 'null' : typeof value}`);
}
}
export function validateFunction(value, name) {
if (typeof value !== 'function') {
throw new TypeError(`${name} must be a function. Received ${value === null ? 'null' : typeof value}`);
}
}
export function validateUndefined(value, name) {
if (value !== undefined) {
throw new TypeError(`${name} must be undefined. Received ${value === null ? 'null' : typeof value}`);
}
}
export function validateInt32(value, name, min = -2147483648, max = 2147483647) {
if (typeof value !== 'number') {
throw new TypeError(`${name} must be a number. Received ${value === null ? 'null' : typeof value}`);
}
if (!Number.isInteger(value)) {
throw new RangeError(`${name} must be a integer.`);
}
if (value < min || value > max) {
throw new RangeError(`${name} must be >= ${min} && <= ${max}. Received ${value}`);
}
}
export function isPromiseLike(obj) {
return !!(obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function');
}
export function wrapInstanceExports(exports, mapFn) {
const newExports = Object.create(null);
Object.keys(exports).forEach(name => {
const exportValue = exports[name];
Object.defineProperty(newExports, name, {
enumerable: true,
value: mapFn(exportValue, name)
});
});
return newExports;
}
const _require = /*#__PURE__*/ (function () {
let nativeRequire;
if (typeof __webpack_public_path__ !== 'undefined') {
nativeRequire = (function () {
return typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : undefined;
})();
}
else {
nativeRequire = (function () {
return typeof __webpack_public_path__ !== 'undefined' ? (typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : undefined) : (typeof require !== 'undefined' ? require : undefined);
})();
}
return nativeRequire;
})();
export const isMainThread = /*#__PURE__*/ (function () {
let worker_threads;
try {
worker_threads = _require('worker_threads');
}
catch (_) { }
if (!worker_threads) {
return typeof importScripts === 'undefined';
}
return worker_threads.isMainThread;
})();
export const postMsg = isMainThread
? () => { }
: /*#__PURE__*/ (function () {
let worker_threads;
try {
worker_threads = _require('worker_threads');
}
catch (_) { }
if (!worker_threads) {
return postMessage;
}
return function postMessage(data) {
worker_threads.parentPort.postMessage({ data });
};
})();
export function sleepBreakIf(delay, breakIf) {
const start = Date.now();
const end = start + delay;
let ret = false;
while (Date.now() < end) {
if (breakIf()) {
ret = true;
break;
}
}
return ret;
}
export function unsharedSlice(view, start, end) {
return ((typeof SharedArrayBuffer === 'function' && view.buffer instanceof SharedArrayBuffer) || (Object.prototype.toString.call(view.buffer.constructor) === '[object SharedArrayBuffer]'))
? view.slice(start, end)
: view.subarray(start, end);
}
@@ -0,0 +1,9 @@
const _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
if (!_WebAssembly) {
throw new Error('WebAssembly is not supported in this environment');
}
export { _WebAssembly };
@@ -0,0 +1,58 @@
{
"name": "@tybys/wasm-util",
"version": "0.10.3",
"description": "WASI polyfill for browser and some wasm util",
"main": "./lib/cjs/index.js",
"module": "./dist/wasm-util.esm-bundler.js",
"types": "./dist/wasm-util.d.ts",
"exports": {
".": {
"module": "./dist/wasm-util.esm-bundler.js",
"import": "./lib/mjs/index.mjs",
"require": "./lib/cjs/index.js",
"types": "./dist/wasm-util.d.ts"
}
},
"scripts": {
"build": "tsgo build",
"watch": "tsgo watch",
"test": "jest",
"lint": "eslint ./src/**/*.{ts,js} --fix",
"prepare": "npm run build"
},
"publishConfig": {
"access": "public"
},
"keywords": [
"wasm",
"webassembly",
"wasi",
"polyfill"
],
"repository": {
"type": "git",
"url": "https://github.com/toyobayashi/wasm-util.git"
},
"author": "toyobayashi",
"license": "MIT",
"dependencies": {
"tslib": "^2.4.0"
},
"devDependencies": {
"@tybys/ts-transform-module-specifier": "^0.0.2",
"@tybys/ts-transform-pure-class": "^0.1.1",
"@tybys/tsgo": "^1.1.0",
"@types/node": "^14.14.31",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1",
"eslint": "^8.25.0",
"eslint-config-standard-with-typescript": "^23.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.3.0",
"eslint-plugin-promise": "^6.1.0",
"memfs-browser": "^3.4.13000",
"mocha": "^10.1.0",
"ts-node": "^10.9.1",
"typescript": "~4.8.3"
}
}
+15
View File
@@ -0,0 +1,15 @@
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
+12
View File
@@ -0,0 +1,12 @@
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
+164
View File
@@ -0,0 +1,164 @@
# tslib
This is a runtime library for [TypeScript](https://www.typescriptlang.org/) that contains all of the TypeScript helper functions.
This library is primarily used by the `--importHelpers` flag in TypeScript.
When using `--importHelpers`, a module that uses helper functions like `__extends` and `__assign` in the following emitted file:
```ts
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
exports.x = {};
exports.y = __assign({}, exports.x);
```
will instead be emitted as something like the following:
```ts
var tslib_1 = require("tslib");
exports.x = {};
exports.y = tslib_1.__assign({}, exports.x);
```
Because this can avoid duplicate declarations of things like `__extends`, `__assign`, etc., this means delivering users smaller files on average, as well as less runtime overhead.
For optimized bundles with TypeScript, you should absolutely consider using `tslib` and `--importHelpers`.
# Installing
For the latest stable version, run:
## npm
```sh
# TypeScript 3.9.2 or later
npm install tslib
# TypeScript 3.8.4 or earlier
npm install tslib@^1
# TypeScript 2.3.2 or earlier
npm install tslib@1.6.1
```
## yarn
```sh
# TypeScript 3.9.2 or later
yarn add tslib
# TypeScript 3.8.4 or earlier
yarn add tslib@^1
# TypeScript 2.3.2 or earlier
yarn add tslib@1.6.1
```
## bower
```sh
# TypeScript 3.9.2 or later
bower install tslib
# TypeScript 3.8.4 or earlier
bower install tslib@^1
# TypeScript 2.3.2 or earlier
bower install tslib@1.6.1
```
## JSPM
```sh
# TypeScript 3.9.2 or later
jspm install tslib
# TypeScript 3.8.4 or earlier
jspm install tslib@^1
# TypeScript 2.3.2 or earlier
jspm install tslib@1.6.1
```
# Usage
Set the `importHelpers` compiler option on the command line:
```
tsc --importHelpers file.ts
```
or in your tsconfig.json:
```json
{
"compilerOptions": {
"importHelpers": true
}
}
```
#### For bower and JSPM users
You will need to add a `paths` mapping for `tslib`, e.g. For Bower users:
```json
{
"compilerOptions": {
"module": "amd",
"importHelpers": true,
"baseUrl": "./",
"paths": {
"tslib" : ["bower_components/tslib/tslib.d.ts"]
}
}
}
```
For JSPM users:
```json
{
"compilerOptions": {
"module": "system",
"importHelpers": true,
"baseUrl": "./",
"paths": {
"tslib" : ["jspm_packages/npm/tslib@2.x.y/tslib.d.ts"]
}
}
}
```
## Deployment
- Choose your new version number
- Set it in `package.json` and `bower.json`
- Create a tag: `git tag [version]`
- Push the tag: `git push --tags`
- Create a [release in GitHub](https://github.com/microsoft/tslib/releases)
- Run the [publish to npm](https://github.com/microsoft/tslib/actions?query=workflow%3A%22Publish+to+NPM%22) workflow
Done.
# Contribute
There are many ways to [contribute](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md) to TypeScript.
* [Submit bugs](https://github.com/Microsoft/TypeScript/issues) and help us verify fixes as they are checked in.
* Review the [source code changes](https://github.com/Microsoft/TypeScript/pulls).
* Engage with other TypeScript users and developers on [StackOverflow](http://stackoverflow.com/questions/tagged/typescript).
* Join the [#typescript](http://twitter.com/#!/search/realtime/%23typescript) discussion on Twitter.
* [Contribute bug fixes](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md).
# Documentation
* [Quick tutorial](http://www.typescriptlang.org/Tutorial)
* [Programming handbook](http://www.typescriptlang.org/Handbook)
* [Homepage](http://www.typescriptlang.org/)
+41
View File
@@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->
+38
View File
@@ -0,0 +1,38 @@
// Note: named reexports are used instead of `export *` because
// TypeScript itself doesn't resolve the `export *` when checking
// if a particular helper exists.
export {
__extends,
__assign,
__rest,
__decorate,
__param,
__esDecorate,
__runInitializers,
__propKey,
__setFunctionName,
__metadata,
__awaiter,
__generator,
__exportStar,
__values,
__read,
__spread,
__spreadArrays,
__spreadArray,
__await,
__asyncGenerator,
__asyncDelegator,
__asyncValues,
__makeTemplateObject,
__importStar,
__importDefault,
__classPrivateFieldGet,
__classPrivateFieldSet,
__classPrivateFieldIn,
__createBinding,
__addDisposableResource,
__disposeResources,
__rewriteRelativeImportExtension,
} from '../tslib.js';
export * as default from '../tslib.js';
+70
View File
@@ -0,0 +1,70 @@
import tslib from '../tslib.js';
const {
__extends,
__assign,
__rest,
__decorate,
__param,
__esDecorate,
__runInitializers,
__propKey,
__setFunctionName,
__metadata,
__awaiter,
__generator,
__exportStar,
__createBinding,
__values,
__read,
__spread,
__spreadArrays,
__spreadArray,
__await,
__asyncGenerator,
__asyncDelegator,
__asyncValues,
__makeTemplateObject,
__importStar,
__importDefault,
__classPrivateFieldGet,
__classPrivateFieldSet,
__classPrivateFieldIn,
__addDisposableResource,
__disposeResources,
__rewriteRelativeImportExtension,
} = tslib;
export {
__extends,
__assign,
__rest,
__decorate,
__param,
__esDecorate,
__runInitializers,
__propKey,
__setFunctionName,
__metadata,
__awaiter,
__generator,
__exportStar,
__createBinding,
__values,
__read,
__spread,
__spreadArrays,
__spreadArray,
__await,
__asyncGenerator,
__asyncDelegator,
__asyncValues,
__makeTemplateObject,
__importStar,
__importDefault,
__classPrivateFieldGet,
__classPrivateFieldSet,
__classPrivateFieldIn,
__addDisposableResource,
__disposeResources,
__rewriteRelativeImportExtension,
};
export default tslib;
@@ -0,0 +1,3 @@
{
"type": "module"
}
+47
View File
@@ -0,0 +1,47 @@
{
"name": "tslib",
"author": "Microsoft Corp.",
"homepage": "https://www.typescriptlang.org/",
"version": "2.8.1",
"license": "0BSD",
"description": "Runtime library for TypeScript helper functions",
"keywords": [
"TypeScript",
"Microsoft",
"compiler",
"language",
"javascript",
"tslib",
"runtime"
],
"bugs": {
"url": "https://github.com/Microsoft/TypeScript/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/tslib.git"
},
"main": "tslib.js",
"module": "tslib.es6.js",
"jsnext:main": "tslib.es6.js",
"typings": "tslib.d.ts",
"sideEffects": false,
"exports": {
".": {
"module": {
"types": "./modules/index.d.ts",
"default": "./tslib.es6.mjs"
},
"import": {
"node": "./modules/index.js",
"default": {
"types": "./modules/index.d.ts",
"default": "./tslib.es6.mjs"
}
},
"default": "./tslib.js"
},
"./*": "./*",
"./": "./"
}
}

Some files were not shown because too many files have changed in this diff Show More