import type Device from "./device/Device.js"; import { StateBuilder } from "./messages/StateBuilder.js"; import type { Publisher, PublishResult } from "./transport.js"; /** A directive as Alex2MQTT publishes it: the directive of Alexa without endpoint.scope, the token of the user. */ export interface RawDirective { header: { namespace: string; name: string; instance?: string; messageId?: string; correlationToken?: string; payloadVersion?: string; }; endpoint?: { endpointId?: string; cookie?: Record; }; payload?: unknown; } /** Sets the properties of a message. */ export type Fill = (state: StateBuilder) => void; /** One directive, and the ways to answer it. Each method resolves with what became of the publish, none rejects. */ export interface DirectiveContext { readonly endpointId: string; readonly namespace: string; readonly name: string; /** The instance of a generic controller, "" without one. */ readonly instance: string; /** "" when the directive came without one; it can then not be answered. */ readonly correlationToken: string; /** The payload, checked by the descriptor of the interface. As it arrived for an interface the library only names. */ readonly payload: T; readonly raw: RawDirective; /** Date.now() when the directive arrived. */ readonly receivedAt: number; /** A Response, a StateReport or an ErrorResponse was sent. */ readonly answered: boolean; /** A DeferredResponse was sent: the answer goes to //deferredResponse. */ readonly deferred: boolean; /** * Answer with a Response, or with the response the interface has of its own. The context is the state of * device.state(), and what fill sets replaces the same property of it. */ respond(fill?: Fill, options?: { payload?: Record; }): Promise; /** Answer ReportState with a StateReport, its properties as for respond(). */ report(fill?: Fill): Promise; /** Send a DeferredResponse now, when the answer takes longer than the 7 s Alex2MQTT waits for it. */ defer(estimatedDeferralInSeconds?: number): Promise; /** Answer with an ErrorResponse. An error that is not an AlexaError is sent as INTERNAL_ERROR. */ error(type: string, message: string, extra?: Record): Promise; error(err: Error): Promise; } /** What a handler returns is awaited and otherwise ignored; what it throws answers the directive. */ export type DirectiveHandler = (ctx: DirectiveContext) => unknown; /** The clock of the watchdog, replaced in tests. */ export interface Timers { setTimeout(run: () => void, ms: number): unknown; clearTimeout(timer: unknown): void; } /** What the dispatcher needs of its bridge. */ export interface DispatcherOptions { rootTopic: string; /** Where the answers go. */ publisher: Publisher; getDevice(endpointId: string): Device | undefined; log(message: string, detail?: unknown): void; /** Reports an error: the "error" event of the bridge. */ fail(err: Error): void; emit(event: string, ...args: unknown[]): void; answerWithinMs?: number; answerUnknownEndpoints?: boolean; timers?: Timers; } /** Alex2MQTT gives up on a directive after DIRECTIVE_BUDGET_MS: the answer of the watchdog has to be there before. */ export declare const ANSWER_WITHIN_MS: number; export declare class Dispatcher { private readonly options; readonly rootTopic: string; /** * What the devices of the bridge publish through. An answer to a directive that waits is let through once, and a * DeferredResponse once before it; everything else passes. */ readonly publisher: Publisher; private readonly answerWithinMs; private readonly timers; private readonly exchanges; private readonly arrived; private readonly deferralNoted; constructor(options: DispatcherOptions); /** Publish an answer; one that is not published is reported to the bridge. */ send(topic: string, message: object): Promise; /** defer() for an interface Amazon documents no DeferredResponse for: said once, the DeferredResponse is sent. */ noteDeferral(namespace: string): void; /** The text of a message on the directive topic of endpointId. Resolves when the handlers are done. */ dispatch(endpointId: string, text: string): Promise; private route; private isolated; private watch; private publish; private forget; }