JavaScript APIs / oro:async

oro:async

oro:async exposes async context propagation, deferred values, and resource tracking primitives.

Examples#

Propagate request-scoped state across async boundaries:

import { AsyncLocalStorage } from 'oro:async'

const store = new AsyncLocalStorage()

await store.run({ requestId: 'req-42' }, async () => {
  await Promise.resolve()
  console.log(store.getStore().requestId)
})

API reference#

Module specifiers#

oro:async
oro:async/context
oro:async/deferred
oro:async/hooks
oro:async/resource
oro:async/storage
oro:async/wrap

TypeScript declarations#

These declarations are generated from the runtime's published TypeScript surface.

oro:async#

declare module "oro:async" {
    export default exports;
    import AsyncLocalStorage from "oro:async/storage";
    import AsyncResource from "oro:async/resource";
    import AsyncContext from "oro:async/context";
    import Deferred from "oro:async/deferred";
    import { executionAsyncResource } from "oro:async/hooks";
    import { executionAsyncId } from "oro:async/hooks";
    import { triggerAsyncId } from "oro:async/hooks";
    import { createHook } from "oro:async/hooks";
    import { AsyncHook } from "oro:async/hooks";
    import * as exports from "oro:async";

    export { AsyncLocalStorage, AsyncResource, AsyncContext, Deferred, executionAsyncResource, executionAsyncId, triggerAsyncId, createHook, AsyncHook };
}

oro:async/context#

declare module "oro:async/context" {
    /**
     * @module async.context
     *
     * Async Context for JavaScript based on the TC39 proposal.
     *
     * Example usage:
     * ```js
     * // `AsyncContext` is also globally available as `globalThis.AsyncContext`
     * import AsyncContext from 'oro:async/context'
     *
     * const var = new AsyncContext.Variable()
     * var.run('top', () => {
     *   console.log(var.get()) // 'top'
     *   queueMicrotask(() => {
     *     var.run('nested', () => {
     *       console.log(var.get()) // 'nested'
     *     })
     *   })
     * })
     * ```
     *
     * @see {@link https://tc39.es/proposal-async-context}
     * @see {@link https://github.com/tc39/proposal-async-context}
     */
    /**
     * @template T
     * @typedef {{
     *   name?: string,
     *   defaultValue?: T
     * }} VariableOptions
     */
    /**
     * @callback AnyFunc
     * @template T
     * @this T
     * @param {...any} args
     * @returns {any}
     */
    /**
     * `FrozenRevert` holds a frozen Mapping that will be simply restored
     * when the revert is run.
     * @see {@link https://github.com/tc39/proposal-async-context/blob/master/src/fork.ts}
     */
    export class FrozenRevert {
        /**
         * `FrozenRevert` class constructor.
         * @param {Mapping} mapping
         */
        constructor(mapping: Mapping);
        /**
         * Restores (unchaged) mapping from this `FrozenRevert`. This function is
         * called by `AsyncContext.Storage` when it reverts a current mapping to the
         * previous state before a "fork".
         * @param {Mapping=} [unused]
         * @return {Mapping}
         */
        restore(unused?: Mapping | undefined): Mapping;
        #private;
    }
    /**
     * Revert holds the state on how to revert a change to the
     * `AsyncContext.Storage` current `Mapping`
     * @see {@link https://github.com/tc39/proposal-async-context/blob/master/src/fork.ts}
     * @template T
     */
    export class Revert<T> {
        /**
         * `Revert` class constructor.
         * @param {Mapping} mapping
         * @param {Variable<T>} key
         */
        constructor(mapping: Mapping, key: Variable<T>);
        /**
         * @type {T|undefined}
         */
        get previousVariable(): T | undefined;
        /**
         * Restores a mapping from this `Revert`. This function is called by
         * `AsyncContext.Storage` when it reverts a current mapping to the
         * previous state before a "fork".
         * @param {Mapping} current
         * @return {Mapping}
         */
        restore(current: Mapping): Mapping;
        #private;
    }
    /**
     * A container for all `AsyncContext.Variable` instances and snapshot state.
     * @see {@link https://github.com/tc39/proposal-async-context/blob/master/src/mapping.ts}
     */
    export class Mapping {
        /**
         * `Mapping` class constructor.
         * @param {Map<Variable<any>, any>} data
         */
        constructor(data: Map<Variable<any>, any>);
        /**
         * Freezes the `Mapping` preventing `AsyncContext.Variable` modifications with
         * `set()` and `delete()`.
         */
        freeze(): void;
        /**
         * Returns `true` if the `Mapping` is frozen, otherwise `false`.
         * @return {boolean}
         */
        isFrozen(): boolean;
        /**
         * Optionally returns a new `Mapping` if the current one is "frozen",
         * otherwise it just returns the current instance.
         * @return {Mapping}
         */
        fork(): Mapping;
        /**
         * Returns `true` if the `Mapping` has a `AsyncContext.Variable` at `key`,
         * otherwise `false.
         * @template T
         * @param {Variable<T>} key
         * @return {boolean}
         */
        has<T>(key: Variable<T>): boolean;
        /**
         * Gets an `AsyncContext.Variable` value at `key`. If not set, this function
         * returns `undefined`.
         * @template T
         * @param {Variable<T>} key
         * @return {boolean}
         */
        get<T>(key: Variable<T>): boolean;
        /**
         * Sets an `AsyncContext.Variable` value at `key`. If the `Mapping` is frozen,
         * then a "forked" (new) instance with the value set on it is returned,
         * otherwise the current instance.
         * @template T
         * @param {Variable<T>} key
         * @param {T} value
         * @return {Mapping}
         */
        set<T>(key: Variable<T>, value: T): Mapping;
        /**
         * Delete  an `AsyncContext.Variable` value at `key`.
         * If the `Mapping` is frozen, then a "forked" (new) instance is returned,
         * otherwise the current instance.
         * @template T
         * @param {Variable<T>} key
         * @param {T} value
         * @return {Mapping}
         */
        delete<T>(key: Variable<T>): Mapping;
        #private;
    }
    /**
     * A container of all `AsyncContext.Variable` data.
     * @ignore
     * @see {@link https://github.com/tc39/proposal-async-context/blob/master/src/storage.ts}
     */
    export class Storage {
        /**
         * The current `Mapping` for this `AsyncContext`.
         * @type {Mapping}
         */
        static "__#private@#current": Mapping;
        /**
         * Returns `true` if the current `Mapping` has a
         * `AsyncContext.Variable` at `key`,
         * otherwise `false.
         * @template T
         * @param {Variable<T>} key
         * @return {boolean}
         */
        static has<T>(key: Variable<T>): boolean;
        /**
         * Gets an `AsyncContext.Variable` value at `key` for the current `Mapping`.
         * If not set, this function returns `undefined`.
         * @template T
         * @param {Variable<T>} key
         * @return {T|undefined}
         */
        static get<T>(key: Variable<T>): T | undefined;
        /**
         * Set updates the `AsyncContext.Variable` with a new value and returns a
         * revert action that allows the modification to be reversed in the future.
         * @template T
         * @param {Variable<T>} key
         * @param {T} value
         * @return {Revert<T>|FrozenRevert}
         */
        static set<T>(key: Variable<T>, value: T): Revert<T> | FrozenRevert;
        /**
         * "Freezes" the current storage `Mapping`, and returns a new `FrozenRevert`
         * or `Revert` which can restore the storage state to the state at
         * the time of the snapshot.
         * @return {FrozenRevert}
         */
        static snapshot(): FrozenRevert;
        /**
         * Restores the storage `Mapping` state to state at the time the
         * "revert" (`FrozenRevert` or `Revert`) was created.
         * @template T
         * @param {Revert<T>|FrozenRevert} revert
         */
        static restore<T>(revert: Revert<T> | FrozenRevert): void;
        /**
         * Switches storage `Mapping` state to the state at the time of a
         * "snapshot".
         * @param {FrozenRevert} snapshot
         * @return {FrozenRevert}
         */
        static switch(snapshot: FrozenRevert): FrozenRevert;
    }
    /**
     * `AsyncContext.Variable` is a container for a value that is associated with
     * the current execution flow. The value is propagated through async execution
     * flows, and can be snapshot and restored with Snapshot.
     * @template T
     * @see {@link https://github.com/tc39/proposal-async-context/blob/master/README.md#asynccontextvariable}
     */
    export class Variable<T> {
        /**
         * `Variable` class constructor.
         * @param {VariableOptions<T>=} [options]
         */
        constructor(options?: VariableOptions<T> | undefined);
        set defaultValue(defaultValue: T);
        /**
         * @ignore
         */
        get defaultValue(): T;
        /**
         * @ignore
         */
        get revert(): FrozenRevert | Revert<T>;
        /**
         * The name of this async context variable.
         * @type {string}
         */
        get name(): string;
        /**
         * Executes a function `fn` with specified arguments,
         * setting a new value to the current context before the call,
         * and ensuring the environment is reverted back afterwards.
         * The function allows for the modification of a specific context's
         * state in a controlled manner, ensuring that any changes can be undone.
         * @template T, F extends AnyFunc<null>
         * @param {T} value
         * @param {F} fn
         * @param {...Parameters<F>} args
         * @returns {ReturnType<F>}
         */
        run<T_1, F>(value: T_1, fn: F, ...args: Parameters<F>[]): ReturnType<F>;
        /**
         * Get the `AsyncContext.Variable` value.
         * @template T
         * @return {T|undefined}
         */
        get<T_1>(): T_1 | undefined;
        #private;
    }
    /**
     * `AsyncContext.Snapshot` allows you to opaquely capture the current values of
     * all `AsyncContext.Variable` instances and execute a function at a later time
     * as if those values were still the current values (a snapshot and restore).
     * @see {@link https://github.com/tc39/proposal-async-context/blob/master/README.md#asynccontextsnapshot}
     */
    export class Snapshot {
        /**
         * Wraps a given function `fn` with additional logic to take a snapshot of
         * `Storage` before invoking `fn`. Returns a new function with the same
         * signature as `fn` that when called, will invoke `fn` with the current
         * `this` context and provided arguments, after restoring the `Storage`
         * snapshot.
         *
         * `AsyncContext.Snapshot.wrap` is a helper which captures the current values
         * of all Variables and returns a wrapped function. When invoked, this
         * wrapped function restores the state of all Variables and executes the
         * inner function.
         *
         * @see {@link https://github.com/tc39/proposal-async-context/blob/master/README.md#asynccontextsnapshotwrap}
         *
         * @template F
         * @param {F} fn
         * @returns {F}
         */
        static wrap<F>(fn: F): F;
        /**
         * Runs the given function `fn` with arguments `args`, using a `null`
         * context and the current snapshot.
         *
         * @template F extends AnyFunc<null>
         * @param {F} fn
         * @param {...Parameters<F>} args
         * @returns {ReturnType<F>}
         */
        run<F>(fn: F, ...args: Parameters<F>[]): ReturnType<F>;
        #private;
    }
    /**
     * `AsyncContext` container.
     */
    export class AsyncContext {
        /**
         * `AsyncContext.Variable` is a container for a value that is associated with
         * the current execution flow. The value is propagated through async execution
         * flows, and can be snapshot and restored with Snapshot.
         * @see {@link https://github.com/tc39/proposal-async-context/blob/master/README.md#asynccontextvariable}
         * @type {typeof Variable}
         */
        static Variable: typeof Variable;
        /**
         * `AsyncContext.Snapshot` allows you to opaquely capture the current values of
         * all `AsyncContext.Variable` instances and execute a function at a later time
         * as if those values were still the current values (a snapshot and restore).
         * @see {@link https://github.com/tc39/proposal-async-context/blob/master/README.md#asynccontextsnapshot}
         * @type {typeof Snapshot}
         */
        static Snapshot: typeof Snapshot;
    }
    export default AsyncContext;
    export type VariableOptions<T> = {
        name?: string;
        defaultValue?: T;
    };
    export type AnyFunc = () => any;
}

oro:async/deferred#

declare module "oro:async/deferred" {
    /**
     * Dispatched when a `Deferred` internal promise is resolved.
     */
    export class DeferredResolveEvent extends Event {
        /**
         * `DeferredResolveEvent` class constructor
         * @ignore
         * @param {string=} [type]
         * @param {any=} [result]
         */
        constructor(type?: string | undefined, result?: any | undefined);
        /**
         * The `Deferred` promise result value.
         * @type {any?}
         */
        result: any | null;
    }
    /**
     * Dispatched when a `Deferred` internal promise is rejected.
     */
    export class DeferredRejectEvent {
        /**
         * `DeferredRejectEvent` class constructor
         * @ignore
         * @param {string=} [type]
         * @param {Error=} [error]
         */
        constructor(type?: string | undefined, error?: Error | undefined);
    }
    /**
     * A utility class for creating deferred promises.
     */
    export class Deferred extends EventTarget {
        /**
         * `Deferred` class constructor.
         * @param {Deferred|Promise?} [promise]
         */
        constructor(promise?: Deferred | (Promise<any> | null));
        /**
         * Function to resolve the associated promise.
         * @type {function}
         */
        resolve: Function;
        /**
         * Function to reject the associated promise.
         * @type {function}
         */
        reject: Function;
        /**
         * Attaches a fulfillment callback and a rejection callback to the promise,
         * and returns a new promise resolving to the return value of the called
         * callback.
         * @param {function(any)=} [resolve]
         * @param {function(Error)=} [reject]
         */
        then(resolve?: ((arg0: any) => any) | undefined, reject?: ((arg0: Error) => any) | undefined): Promise<any>;
        /**
         * Attaches a rejection callback to the promise, and returns a new promise
         * resolving to the return value of the callback if it is called, or to its
         * original fulfillment value if the promise is instead fulfilled.
         * @param {function(Error)=} [callback]
         */
        catch(callback?: ((arg0: Error) => any) | undefined): Promise<any>;
        /**
         * Attaches a callback for when the promise is settled (fulfilled or rejected).
         * @param {function(any?)} [callback]
         */
        finally(callback?: (arg0: any | null) => any): Promise<any>;
        /**
         * The promise associated with this Deferred instance.
         * @type {Promise<any>}
         */
        get promise(): Promise<any>;
        /**
         * A string representation of this Deferred instance.
         * @type {string}
         * @ignore
         */
        get [Symbol.toStringTag](): string;
        #private;
    }
    export default Deferred;
}

oro:async/hooks#

declare module "oro:async/hooks" {
    /**
     * Factory for creating a `AsyncHook` instance.
     * @param {AsyncHookCallbackOptions|AsyncHookCallbacks=} [callbacks]
     * @return {AsyncHook}
     */
    export function createHook(callbacks?: (AsyncHookCallbackOptions | AsyncHookCallbacks) | undefined): AsyncHook;
    /**
     * A container for `AsyncHooks` callbacks.
     * @ignore
     */
    export class AsyncHookCallbacks {
        /**
         * `AsyncHookCallbacks` class constructor.
         * @ignore
         * @param {AsyncHookCallbacks} [options]
         */
        constructor(options?: AsyncHookCallbacks);
        init(_asyncId: any, _type: any, _triggerAsyncId: any, _resource: any): void;
        before(_asyncId: any): void;
        after(_asyncId: any): void;
        destroy(_asyncId: any): void;
        promiseResolve(_asyncId: any): void;
    }
    /**
     * A container for registering various callbacks for async resource hooks.
     */
    export class AsyncHook {
        /**
         * @param {AsyncHookCallbacks=} [options]
         */
        constructor(callbacks?: any);
        /**
         * @type {boolean}
         */
        get enabled(): boolean;
        /**
         * Enable the async hook.
         * @return {AsyncHook}
         */
        enable(): AsyncHook;
        /**
         * Disables the async hook
         * @return {AsyncHook}
         */
        disable(): AsyncHook;
        #private;
    }
    export default createHook;
    import { executionAsyncResource } from "oro:internal/async/hooks";
    import { executionAsyncId } from "oro:internal/async/hooks";
    import { triggerAsyncId } from "oro:internal/async/hooks";
    export { executionAsyncResource, executionAsyncId, triggerAsyncId };
}

oro:async/resource#

declare module "oro:async/resource" {
    /**
     * @typedef {{
     *   triggerAsyncId?: number,
     *   requireManualDestroy?: boolean
     * }} AsyncResourceOptions
     */
    /**
     * A container that should be extended that represents a resource with
     * an asynchronous execution context.
     */
    export class AsyncResource extends CoreAsyncResource {
        /**
         * Binds function `fn` with an optional this `thisArg` binding to run
         * in the execution context of an anonymous `AsyncResource`.
         * @param {function} fn
         * @param {object|string=} [type]
         * @param {object=} [thisArg]
         * @return {function}
         */
        static bind(fn: Function, type?: (object | string) | undefined, thisArg?: object | undefined): Function;
        /**
         * `AsyncResource` class constructor.
         * @param {string} type
         * @param {AsyncResourceOptions|number=} [options]
         */
        constructor(type: string, options?: (AsyncResourceOptions | number) | undefined);
    }
    export default AsyncResource;
    export type AsyncResourceOptions = {
        triggerAsyncId?: number;
        requireManualDestroy?: boolean;
    };
    import { executionAsyncResource } from "oro:internal/async/hooks";
    import { executionAsyncId } from "oro:internal/async/hooks";
    import { triggerAsyncId } from "oro:internal/async/hooks";
    import { CoreAsyncResource } from "oro:internal/async/hooks";
    export { executionAsyncResource, executionAsyncId, triggerAsyncId };
}

oro:async/storage#

declare module "oro:async/storage" {
    /**
     * A container for storing values that remain present during
     * asynchronous operations.
     */
    export class AsyncLocalStorage {
        /**
         * Binds function `fn` to run in the execution context of an
         * anonymous `AsyncResource`.
         * @param {function} fn
         * @return {function}
         */
        static bind(fn: Function): Function;
        /**
         * Captures the current async context and returns a function that runs
         * a function in that execution context.
         * @return {function}
         */
        static snapshot(): Function;
        /**
         * @type {boolean}
         */
        get enabled(): boolean;
        /**
         * Disables the `AsyncLocalStorage` instance. When disabled,
         * `getStore()` will always return `undefined`.
         */
        disable(): void;
        /**
         * Enables the `AsyncLocalStorage` instance.
         */
        enable(): void;
        /**
         * Enables and sets the `AsyncLocalStorage` instance default store value.
         * @param {any} store
         */
        enterWith(store: any): void;
        /**
         * Runs function `fn` in the current asynchronous execution context with
         * a given `store` value and arguments given to `fn`.
         * @param {any} store
         * @param {function} fn
         * @param {...any} args
         * @return {any}
         */
        run(store: any, fn: Function, ...args: any[]): any;
        exit(fn: any, ...args: any[]): any;
        /**
         * If the `AsyncLocalStorage` instance is enabled, it returns the current
         * store value for this asynchronous execution context.
         * @return {any|undefined}
         */
        getStore(): any | undefined;
        #private;
    }
    export default AsyncLocalStorage;
}

oro:async/wrap#

declare module "oro:async/wrap" {
    /**
     * Returns `true` if a given function `fn` has the "async" wrapped tag,
     * meaning it was "tagged" in a `wrap(fn)` call before, otherwise this
     * function will return `false`.
     * @ignore
     * @param {function} fn
     * @param {boolean}
     */
    export function isTagged(fn: Function): boolean;
    /**
     * Tags a function `fn` as being "async wrapped" so subsequent calls to
     * `wrap(fn)` do not wrap an already wrapped function.
     * @ignore
     * @param {function} fn
     * @return {function}
     */
    export function tag(fn: Function): Function;
    /**
     * Wraps a function `fn` that captures a snapshot of the current async
     * context. This function is idempotent and will not wrap a function more
     * than once.
     * @ignore
     * @param {function} fn
     * @return {function}
     */
    export function wrap(fn: Function): Function;
    export const symbol: unique symbol;
    export default wrap;
}

See also#

Source repository · Edit this page · View Markdown