import { MessagePriority, type TXReport, type TransactionProgress, type TransactionProgressListener, type ZWaveError } from "@zwave-js/core"; import type { Message } from "@zwave-js/serial"; import { type Comparable, type CompareResult } from "alcalzone-shared/comparable"; import type { DeferredPromise } from "alcalzone-shared/deferred-promise"; import type { Driver } from "./Driver.js"; export interface MessageGenerator { parent: Transaction; /** Start a new copy of this message generator */ start: () => AsyncGenerator; /** Resets this message generator so it can be started anew */ reset: () => void; /** A reference to the currently running message generator if it was already started */ self?: ReturnType; /** A reference to the last generated message, or undefined if the generator wasn't started or has finished */ current?: Message; } export interface TransactionOptions { /** The "primary" message this transaction contains, e.g. the un-encapsulated version of a SendData request */ message: Message; /** * The actual messages that will be sent when handling this transaction, * defined as a message generator to dynamically create the messages. */ parts: MessageGenerator; /** The priority of this transaction */ priority: MessagePriority; /** * Ensures this command is transmitted: it will not share another command's * physical transmission and a newer command cannot supersede it. */ preventDeduplication?: boolean; /** Reports the physical outcome exactly once, no matter how many deduplicated transactions are attached. */ onSettled?: (result: TransactionResult) => void; } /** * A caller waiting for the result of a transaction: the promise to settle, * plus optional callbacks for progress updates and TX reports. Multiple * callers can wait for the same transaction when commands are deduplicated. */ interface TransactionCaller { promise: DeferredPromise; listener?: TransactionProgressListener; onTXReport?: (report: TXReport) => void; /** The lifecycle this caller is currently attached to */ lifecycle: TransactionLifecycle; } /** The physical outcome of a transaction */ export type TransactionResult = { status: "fulfilled"; value: Message | void; } | { status: "rejected"; reason: unknown; }; /** Lets a single caller manage its attachment to a transaction */ export interface TransactionAttachmentHandle { /** * Rejects this caller's promise and stops its progress updates. * Returns `true` when no other callers are waiting for the transmission. */ detach(error: ZWaveError): boolean; /** * Whether this caller gets its result from the given transaction. * Also works after detaching. */ sharesLifecycleWith(transaction: Transaction): boolean; } /** * Tracks the state of one physical transmission and distributes progress * updates, TX reports and the final result to all attached callers. * Requeued clones of a transaction share its lifecycle. When commands are * deduplicated, callers move between lifecycles. */ declare class TransactionLifecycle { constructor(onSettled?: (result: TransactionResult) => void); private readonly onSettled?; private readonly callers; private settled; private progress; /** * Adds a caller. It immediately receives the current progress and, if the * transaction is already settled, the result. */ attach(caller: TransactionCaller): void; /** * Rejects the given caller's promise and stops its progress updates. * Returns `true` when this removed the last attached caller. */ detach(caller: TransactionCaller, error: ZWaveError): boolean; /** Whether any callers are waiting for the result */ get hasCallers(): boolean; /** Whether the physical outcome is already known */ get isSettled(): boolean; /** * Reports the physical outcome. The first call wins, emits the terminal * progress update and settles all attached callers. */ settle(result: TransactionResult): void; /** * Moves all callers waiting for another lifecycle over to this one, * e.g. when a newer command replaces or joins an older one. */ adoptCallersFrom(source: TransactionLifecycle): void; /** Forwards a TX report to all attached callers */ reportTXReport(report: TXReport): void; /** * Notifies all attached callers of a progress update. * Duplicate updates and updates after Completed/Failed are ignored. */ setProgress(progress: TransactionProgress): void; /** Passes an already-known result on to a single caller */ private replaySettlement; } /** * Transactions are used to track and correlate messages with their responses. */ export declare class Transaction implements Comparable { readonly driver: Driver; private readonly options; constructor(driver: Driver, options: TransactionOptions, lifecycle?: TransactionLifecycle); /** Creates a copy of this transaction that shares its lifecycle. */ clone(): Transaction; /** The "primary" message this transaction contains, e.g. the un-encapsulated version of a SendData request */ readonly message: Message; /** The message generator to create the actual messages for this transaction */ readonly parts: MessageGenerator; private readonly lifecycle; /** * Adds a caller that waits for this transaction's result. * @param promise Settled with the result of the transaction * @param listener Called with each progress update * @param onTXReport Called when a TX report for the transmission is received */ attach(promise: DeferredPromise, listener?: TransactionProgressListener, onTXReport?: (report: TXReport) => void): TransactionAttachmentHandle; /** Whether any callers are waiting for this transaction's result */ get hasAttachments(): boolean; /** Whether the physical outcome of this transaction is already known */ get isSettled(): boolean; /** Moves all callers waiting for the given transaction over to this one */ adoptCallersFrom(other: Transaction): void; /** Forwards a TX report to all attached callers */ reportTXReport(report: TXReport): void; /** Notifies all attached callers of a progress update */ setProgress(progress: TransactionProgress): void; /** * Returns the current message of this transaction. This is either the currently active partial message * or the primary message if the generator hasn't been started yet. */ getCurrentMessage(): Message | undefined; /** * Starts the transaction's message generator if it hasn't been started yet. * Returns `true` when the generator was started, `false` if it was already started before. */ start(): boolean; /** * Resets this transaction's message generator */ reset(): void; generateNextMessage(prevResult: Message | undefined): Promise; /** * Forcefully aborts the message generator by throwing the given result. * Errors will be treated as a rejection of the transaction, everything else as success */ abort(result: Message | ZWaveError | undefined): void; /** The priority of this transaction */ priority: MessagePriority; /** * Ensures this command is transmitted: it will not share another command's * physical transmission and a newer command cannot supersede it. */ readonly preventDeduplication: boolean; /** The timestamp at which the transaction was created */ creationTimestamp: number; /** Whether the node status should be updated when this transaction times out */ changeNodeStatusOnTimeout: boolean; /** Whether the send thread MUST be paused after this transaction was handled */ pauseSendThread: boolean; /** If a Wake Up On Demand should be requested for the target node. */ requestWakeUpOnDemand: boolean; /** Whether follow-up Supervision status updates are requested. */ requestStatusUpdates: boolean; /** Internal information used to identify or mark this transaction */ tag?: any; /** The stack trace where the transaction was created */ private _stack; get stack(): string; /** Compares two transactions in order to plan their transmission sequence */ compareTo(other: Transaction): CompareResult; } export {}; //# sourceMappingURL=Transaction.d.ts.map