/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { Duration } from "#time/Duration.js";
import "../polyfills/disposable.js";
import { MaybePromise } from "./Promises.js";
/**
 * A callback function for observables.
 *
 * The observer return value effects how an {@link Observable} emits:
 *
 *   - If an observer returns undefined the {@link Observable} invokes the next observer immediately.
 *
 *   - If an observer returns a {@link Promise}, the {@link Observable} awaits the return value then continues as
 *     described here.  The emitter must then await the {@link Promise} returned by {@link Observable.emit}.
 *
 *   - Any other return value is returned by {@link Observable.emit} and subsequent observers do not see emission.
 *
 * @param payload a list of arguments to be emitted
 */
export interface Observer<T extends any[] = any[], R = void> {
    (...payload: T): R | undefined;
    [observant]?: boolean;
}
export interface AsyncObserver<T extends any[] = any[], R = void> extends Observer<T, MaybePromise<R>> {
}
/**
 * A discrete event that may be monitored via callback.  Could call it "event" but that could be confused with Matter
 * cluster events and/or DOM events.
 *
 * @param T arguments, should be a named tuple
 */
export interface Observable<T extends any[] = any[], R = void> extends AsyncIterable<T>, PromiseLike<T> {
    /**
     * Notify observers.
     */
    emit(...args: T): R | undefined;
    /**
     * Add an observer.
     */
    on(observer: Observer<T, R>): void;
    /**
     * Add an observer that may be released via disposal.
     */
    use(observer: Observer<T, R>): Disposable;
    /**
     * Add a "once" observer that may be released via disposal.
     */
    useOnce(observer: Observer<T, R>): Disposable;
    /**
     * Remove an observer.
     */
    off(observer: Observer<T, R>): void;
    /**
     * Add an observer that emits once then is unregistered.
     */
    once(observer: Observer<T, R>): void;
    /**
     * True if there is at least one observer registered.
     */
    isObserved: boolean;
    /**
     * Determine whether an observer is registered.
     */
    isObservedBy(observer: Observer<T, R>): boolean;
    /**
     * Errors throw by observers will interrupt emitters unless an error handler is installed here and the handler does
     * not rethrow.
     *
     * The only exception to this is if {@link handlePromise} is false and an observer is asynchronous.  In this case
     * the emitter cannot be made aware of the exception.
     */
    handleError: ObserverErrorHandler;
    /**
     * We allow emitters to be async, but we do not want to overburden either the emitter or the observer with promise
     * tracking if the lifetime of the observer is not relevant to the emitter.
     *
     * To facilitate this we allow observables to be configured in one of three promise handling modes:
     *
     * * If you set handlePromise, isAsync is true; the handler is invoked for any observer promise
     *
     * * If isAsync is true but you do not set handlePromise, any observer promise is returned to the emitter which must
     *   handle the promise
     *
     * * If isAsync is false, we log observer promise errors but the promise is otherwise untracked
     *
     * If the promiseHandler returns a promise or is true and the emitter returns a promise, the observable will emit to
     * successive observers only after the promise resolves.
     */
    isAsync: boolean;
    /**
     * A promise handler.
     *
     * If you set {@link isAsync} (either true or false) the promise handler is set by the Observable.
     */
    handlePromise: ObserverPromiseHandler | boolean;
    /**
     * Creates a promise that resolves when next emitted.
     */
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T[0]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
    /**
     * A diagnostic aid; set this to produce detailed logs of emission.
     */
    traceAs: string | undefined;
    /**
     * Observable supports standard "for await (const value of observable").
     *
     * Using an observer in this manner limits your listener to the first parameter normally emitted and your observer
     * cannot return a value.
     */
    [Symbol.asyncIterator](): AsyncIterator<T[0]>;
    /**
     * Release resources associated with the observable.
     */
    [Symbol.dispose](): void;
}
/**
 * An observable value.
 *
 * This is a stateful observable that remembers its last emitted value and maps to standard Promise semantics.
 *
 * Unlike a normal {@link Observable}, awaiting an {@link ObservableValue} will result in immediate resolution if the
 * value is truthy, and immediately upon updating to a truthy value otherwise.
 *
 * Also unlike a normal {@link Observable}, an {@link ObservableValue} may be placed into an error state which will
 * result in rejection if awaited.
 */
export interface ObservableValue<T extends [any, ...any[]] = [boolean], R extends MaybePromise<void> = void> extends Observable<T, R>, Promise<T[0]> {
    /**
     * The current value.
     *
     * Setting the value will resolve the promise interface but you must use {@link emit} to also emit an event.
     */
    value: T[0] | undefined;
    error?: Error;
    /**
     * Place the observable into an error state.
     *
     * The error is cleared on next emit.
     */
    reject(cause: unknown): void;
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T[0]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<T[0] | TResult>;
    onError(handler: (cause: Error) => void): void;
    offError(handler: (cause: Error) => void): void;
    useError(handler: (cause: Error) => void): Disposable;
}
/**
 * An observer may designate itself as "not observant" for the purposes of {@link Observable.isObserved} by returning
 * false from this field.
 */
export declare const observant: unique symbol;
/**
 * An {@link Observable} that explicitly supports asynchronous observers.
 */
export interface AsyncObservable<T extends any[] = any[], R = void> extends Observable<T, MaybePromise<R>> {
}
/**
 * An {@link ObservableValue} that explicitly supports asynchronous observers.
 */
export interface AsyncObservableValue<T extends [any, ...any[]] = [boolean]> extends ObservableValue<T, MaybePromise> {
}
export type ObserverErrorHandler = (error: Error, observer: Observer<any[], any>) => void;
export type ObserverPromiseHandler = (promise: Promise<unknown>, observer: Observer<any[], any>) => unknown;
/**
 * A concrete {@link Observable} implementation.
 */
export declare class BasicObservable<T extends any[] = any[], R = void> implements Observable<T, R> {
    #private;
    constructor(handleError?: ObserverErrorHandler, asyncConfig?: ObserverPromiseHandler | boolean);
    set traceAs(name: string | undefined);
    [Symbol.dispose](): void;
    set handleError(handleError: ObserverErrorHandler);
    get handleError(): ObserverErrorHandler;
    set isAsync(isAsync: boolean);
    get isAsync(): boolean;
    set handlePromise(handlePromise: ObserverPromiseHandler);
    get handlePromise(): ObserverPromiseHandler;
    get isObserved(): boolean;
    isObservedBy(observer: Observer<T, R>): boolean;
    emit(...payload: T): R | undefined;
    on(observer: Observer<T, R>): void;
    use(observer: Observer<T, R>): {
        [Symbol.dispose]: () => void;
    };
    useOnce(observer: Observer<T, R>): {
        [Symbol.dispose]: () => void;
    };
    off(observer: Observer<T, R>): void;
    once(observer: Observer<T, R>): void;
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T[0]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
    [Symbol.asyncIterator](): AsyncIterator<T[0]>;
    detachObservers(): DetachedObservers<T, R> | undefined;
    attachObservers(detached: DetachedObservers<T, R>): void;
}
/**
 * Create an {@link Observable}.
 */
export declare const Observable: {
    new <T extends any[], R = void>(errorHandler?: ObserverErrorHandler): Observable<T, R>;
    <T extends any[], R = void>(errorHandler?: ObserverErrorHandler): Observable<T, R>;
};
/**
 * Create an {@link AsyncObservable} that explicitly supports asynchronous results
 */
export declare const AsyncObservable: {
    new <T extends any[], R = void>(handleError?: ObserverErrorHandler): AsyncObservable<T, R>;
    <T extends any[], R = void>(handleError?: ObserverErrorHandler): AsyncObservable<T, R>;
};
/**
 * A concrete {@link ObservableValue} implementation.
 */
export declare class BasicObservableValue<T extends [any, ...any[]] = [boolean], R extends MaybePromise<void> = void> extends BasicObservable<T, R> implements ObservableValue<T, R> {
    #private;
    constructor(value?: T[0], handleError?: ObserverErrorHandler, asyncConfig?: ObserverPromiseHandler | boolean);
    get value(): T[0] | undefined;
    set value(value: T[0] | undefined);
    get error(): Error | undefined;
    reject(cause: unknown): void;
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<T | TResult>;
    onError(handler: (cause: Error) => void): void;
    offError(handler: (cause: Error) => void): void;
    useError(handler: (cause: Error) => void): {
        [Symbol.dispose]: () => void;
    };
    finally(onfinally?: (() => void) | null): Promise<T>;
    [Symbol.toStringTag]: string;
}
/**
 * Create an {@link ObservableValue}.
 */
export declare const ObservableValue: {
    new <T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): ObservableValue<T>;
    <T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): ObservableValue<T>;
};
/**
 * Create an {@link AsyncObservableValue}.
 */
export declare const AsyncObservableValue: {
    new <T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): AsyncObservableValue<T>;
    <T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): AsyncObservableValue<T>;
};
/**
 * A set of observables.  You can bind events using individual observables or the methods emulating a subset Node's
 * EventEmitter.
 *
 * To maintain type safety, implementers define events as observable child properties.
 */
export declare class EventEmitter {
    private events?;
    emit<This, N extends EventEmitter.NamesOf<This>>(this: This, name: N, ...payload: EventEmitter.PayloadOf<This, N>): void;
    addListener<This, N extends EventEmitter.NamesOf<This>>(this: This, name: N, handler: EventEmitter.ObserverOf<This, N>): void;
    removeListener<This, N extends EventEmitter.NamesOf<This>>(this: This, name: N, handler: EventEmitter.ObserverOf<This, N>): void;
    addEvent(name: string, event?: AsyncObservable): void;
    getEvent(name: string): AsyncObservable<any[], void>;
    hasEvent(name: string, onlyIfInitialized?: boolean): boolean | AsyncObservable<any[], void> | undefined;
    get eventNames(): string[];
    [Symbol.dispose](): void;
}
export declare namespace EventEmitter {
    /**
     * Legal event names.  If there are no events defined, assume this is an
     * untyped instance and allow any argument.
     */
    type NamesOf<This> = [EventNames<This>] extends [never] ? string : EventNames<This>;
    type EventNames<This> = string & keyof {
        [K in keyof This as This[K] extends Observable ? K : never]: true;
    };
    /**
     * Arguments for an event.  If there are no events defined, assume this is
     * an untyped emitter and allow any argument.
     */
    type PayloadOf<This, E extends string> = [EventPayload<This, E>] extends [never] ? any[] : EventPayload<This, E>;
    type EventPayload<This, E extends string> = This extends {
        [K in E]: Observable<infer T extends any[]>;
    } ? T : never;
    type ObserverOf<This, E extends string> = Observable<PayloadOf<This, E>>;
}
/**
 * An {@link Observable} that proxies to another {@link Observable}.
 *
 * Events emitted here instead emit on the target {@link Observable}.  Events emitted on the target emit locally via
 * a listener installed by the proxy.
 *
 * This is useful for managing a subset of {@link Observer}s for an {@link Observable}.
 *
 * Note that this "proxy" acts as a proxy but is not a JS {@link Proxy}.
 */
export declare class ObservableProxy extends BasicObservable {
    #private;
    constructor(target: Observable);
    [Symbol.dispose](): void;
    get isObserved(): boolean;
    emit: (...payload: any) => any | undefined;
    protected get target(): Observable<any[], void>;
}
/**
 * A collection of observers managed as a unit.  This makes it convenient to deregister multiple observers when an
 * object closes.
 */
export declare class ObserverGroup {
    #private;
    constructor(target?: {});
    on<T extends any[], R>(observable: Observable<T, R>, observer: Observer<ObserverGroup.VarArgs<NoInfer<T>>, NoInfer<R>>, target?: {}): void;
    on<T extends any[], R>(observable: AsyncObservable<T, R>, observer: AsyncObserver<ObserverGroup.VarArgs<NoInfer<T>>, NoInfer<R>>, target?: {}): void;
    /**
     * Remove a single observer.
     *
     * @param observable the observable to observe
     * @param observer the observer function
     * @param target if the observer was bound in {@link on} this must match the bound target
     */
    off<T extends any[]>(observable: Observable<T> | AsyncObservable<T>, observer: Observer<NoInfer<T>>, target?: {} | undefined): void;
    /**
     * Checks if there are any observers currently subscribed to the given observable.
     *
     * @param observable the observable to observe
     */
    observes(observable: Observable<any[], any> | AsyncObservable<any>): number | boolean;
    /**
     * Checks if the given observer is subscribed to the given observable.
     *
     * @param observable the observable to observe
     * @param observer the observer function
     */
    has(observable: Observable<any[], any> | AsyncObservable<any>, observer: Observer<any[], any>): boolean;
    /**
     * Remove all observers. The instance can be reused afterward to add new observers.
     */
    close(): void;
    [Symbol.dispose](): void;
}
/**
 * {@link Observer}s detached from an {@link Observable}.
 */
export interface DetachedObservers<T extends any[] = any[], R = void> {
    observers?: Set<Observer<T, R>>;
    once?: Set<Observer<T, R>>;
}
export declare namespace ObserverGroup {
    /**
     * This is a workaround for a TS bug, without this the observer must provide a full argument set even if it does not
     * use all arguments.
     */
    type VarArgs<T extends any[]> = T extends [...infer R, infer A] ? [...R, A] : T extends [infer A] ? A : [];
}
/**
 * An {@link Observable} that emits an algorithmically-reduced number of events.
 */
export declare class QuietObservable<T extends any[] = any[], R extends MaybePromise<void> = void> extends BasicObservable<T, R> implements QuietObservable.State<T, R> {
    #private;
    constructor(config?: QuietObservable.Configuration<T, R>);
    get config(): QuietObservable.Configuration<T, R>;
    set config(config: QuietObservable.Configuration<T, R>);
    get emitAutomatically(): boolean;
    set emitAutomatically(value: boolean);
    get suppressionEnabled(): boolean;
    set suppressionEnabled(value: boolean);
    get minimumEmitInterval(): Duration;
    set minimumEmitInterval(value: Duration);
    get source(): Observable<T, R> | undefined;
    set source(source: Observable<T, R> | undefined);
    get sink(): Observable<T, R> | undefined;
    set sink(sink: Observable<T, R> | undefined);
    get shouldEmit(): QuietObservable.EmitPredicate<T> | undefined;
    set shouldEmit(shouldEmit: QuietObservable.EmitPredicate<T> | undefined);
    get isObserved(): boolean;
    isObservedBy(observer: Observer<T, R>): boolean;
    emit(...payload: T): R | undefined;
    /**
     * Emit immediately, regardless of suppression configuration.
     */
    emitNow(): void;
    /**
     * Emit as soon as allowed by suppression.
     */
    emitSoon(): void;
    [Symbol.dispose](): void;
}
export declare namespace QuietObservable {
    interface State<T extends any[] = any[], R extends MaybePromise<void> = void> {
        /**
         * If true this observable will emit within the suppression constraints.  If false it will only emit after calls
         * to {@link emitSoon} or {@link emitNow}.
         */
        emitAutomatically: boolean;
        /**
         * If true then emit rate is constrained.  If false emits will occur immediately.
         */
        suppressionEnabled: boolean;
        /**
         * The minimum time between emits in milliseconds.
         */
        minimumEmitInterval: Duration;
        /**
         * An input observable this observable will automatically observe to produce events.
         */
        source?: Observable<T, R>;
        /**
         * An output observable this observable will automatically emit to whenever it emits.
         */
        sink?: Observable<T, R>;
        /**
         * A predicate that determine whether a payload should emit.
         */
        shouldEmit?: EmitPredicate<T>;
        /**
         * Handler for errors returned by observers.
         */
        handleError?: ObserverErrorHandler;
        /**
         * Designates async support (overridden if you supply {@link handlePromise}).
         */
        isAsync?: boolean;
        /**
         * Handler for promises returned by observers.
         */
        handlePromise?: ObserverPromiseHandler;
        /**
         * If true, skips emission when rate limited rather than delaying.
         */
        skipSuppressedEmits?: boolean;
    }
    /**
     * An emit predicate may emit this value to force immediate emit.
     */
    const now = "now";
    /**
     * The return value of an emit predicate.  "true" allows the event to emit as normal, "false" prevents the event
     * from emitting, and {@link now} forces immediate emit regardless of interval configuration.
     */
    type EmitDirective = true | false | typeof now;
    /**
     * A predicate that may filter emits manually.
     */
    interface EmitPredicate<T extends any[] = any[]> {
        (...payload: T): EmitDirective;
    }
    interface Configuration<T extends any[] = any[], R extends MaybePromise<void> = void> extends Partial<State<T, R>> {
    }
    const defaults: State;
}
//# sourceMappingURL=Observable.d.ts.map