/** * @fileoverview Streaming types for AFD commands * // afd-override: max-lines=600 * Justification: Streaming chunk types, helpers, guards, and utilities are intentionally grouped * here as a single public surface; this small parity addition does not justify a module split yet. * * Streaming enables incremental delivery of large results with real-time * progress feedback. Commands can emit progress updates, data chunks, * and completion/error signals. */ import type { CommandError } from './errors.js'; import type { ResultMetadata } from './result.js'; /** * Progress update chunk. * * Emitted during long-running operations to show progress. * * @example * ```typescript * const chunk: ProgressChunk = { * type: 'progress', * progress: 0.45, * message: 'Processing item 45 of 100...', * itemsProcessed: 45, * itemsTotal: 100 * }; * ``` */ export interface ProgressChunk { /** * Discriminator for chunk type. */ type: 'progress'; /** * Progress percentage (0-1). */ progress: number; /** * Human-readable progress message. */ message?: string; /** * Current step number when tracking a multi-step workflow. */ currentStep?: number; /** * Total number of steps when tracking a multi-step workflow. */ totalSteps?: number; /** * Number of items processed so far. */ itemsProcessed?: number; /** * Total number of items to process. */ itemsTotal?: number; /** * Estimated time remaining in milliseconds. */ estimatedTimeRemainingMs?: number; /** * Current phase or stage of the operation. */ phase?: string; } /** * Data chunk containing partial results. * * Emitted as data becomes available, allowing incremental UI updates. * * @template T - The type of data in this chunk * * @example * ```typescript * const chunk: DataChunk = { * type: 'data', * data: { id: 'todo-1', title: 'Buy groceries' }, * index: 0, * isLast: false * }; * ``` */ export interface DataChunk { /** * Discriminator for chunk type. */ type: 'data'; /** * The data payload for this chunk. */ data: T; /** * Index of this chunk in the sequence (0-based). */ index: number; /** * Whether this is the last data chunk. */ isLast: boolean; /** * Optional chunk ID for deduplication. */ chunkId?: string; } /** * Completion chunk signaling successful stream end. * * Contains final summary and aggregated metadata. * * @template T - The type of the complete result data * * @example * ```typescript * const chunk: CompleteChunk = { * type: 'complete', * data: { exportedCount: 100, filename: 'export.csv' }, * totalChunks: 100, * totalDurationMs: 5000, * confidence: 0.95 * }; * ``` */ export interface CompleteChunk { /** * Discriminator for chunk type. */ type: 'complete'; /** * Final result data (summary or complete result). */ data?: T; /** * Total number of data chunks emitted. */ totalChunks: number; /** * Total duration of the stream in milliseconds. */ totalDurationMs: number; /** * Confidence in the overall result (0-1). */ confidence?: number; /** * Human-readable summary of what was accomplished. */ reasoning?: string; /** * Execution metadata. */ metadata?: ResultMetadata; } /** * Error chunk signaling stream failure. * * May be emitted mid-stream if an error occurs after some data has been sent. * * @example * ```typescript * const chunk: ErrorChunk = { * type: 'error', * error: { * code: 'EXPORT_FAILED', * message: 'Failed to export item 45', * suggestion: 'Check the item data and try again' * }, * chunksBeforeError: 44, * recoverable: false * }; * ``` */ export interface ErrorChunk { /** * Discriminator for chunk type. */ type: 'error'; /** * Error details. */ error: CommandError; /** * Number of chunks successfully emitted before the error. */ chunksBeforeError: number; /** * Whether the stream can be resumed or retried. */ recoverable: boolean; /** * If recoverable, the position to resume from. */ resumeFrom?: number; } /** * Union type for all possible stream chunks. * * Use discriminated union on `type` field to handle each chunk type. * * @template T - The type of data in data/complete chunks * * @example * ```typescript * function handleChunk(chunk: StreamChunk) { * switch (chunk.type) { * case 'progress': * updateProgressBar(chunk.progress); * break; * case 'data': * appendToList(chunk.data); * break; * case 'complete': * showCompletion(chunk.totalChunks); * break; * case 'error': * showError(chunk.error); * break; * } * } * ``` */ export type StreamChunk = ProgressChunk | DataChunk | CompleteChunk | ErrorChunk; /** * Options for stream execution. */ export interface StreamOptions { /** * AbortSignal for cancellation support. * When aborted, the stream will emit an error chunk and terminate. */ signal?: AbortSignal; /** Deadline in ms for the whole stream; past it the stream ends with `STREAM_TIMEOUT`. */ timeout?: number; /** * Minimum interval between progress updates in milliseconds. * Prevents UI thrashing from too-frequent updates. * @default 100 */ progressThrottleMs?: number; /** * Maximum number of data chunks to buffer before backpressure. * @default 100 */ bufferSize?: number; } /** * Callbacks for stream consumption. * * @template T - The type of data in data/complete chunks */ export interface StreamCallbacks { /** * Called for each progress update. */ onProgress?: (chunk: ProgressChunk) => void; /** * Called for each data chunk. */ onData?: (chunk: DataChunk) => void; /** * Called when the stream completes successfully. */ onComplete?: (chunk: CompleteChunk) => void; /** * Called if the stream encounters an error. */ onError?: (chunk: ErrorChunk) => void; } /** * Marker interface for commands that support streaming. * * Extends the standard CommandDefinition with streaming metadata. It is * metadata only: handlers still return one `CommandResult`, and the executors * (`executeStream()`, the server's `/stream`) produce chunks from that result * after the handler completes. */ export interface StreamableCommand { /** * Indicates this command supports streaming responses. */ streamable: true; /** * Type of data emitted in stream chunks. */ streamDataType?: string; /** * Whether progress updates are emitted. */ emitsProgress?: boolean; /** * Estimated items per second throughput (for progress estimation). */ estimatedThroughput?: number; } /** * Create a progress chunk. */ export declare function createProgressChunk(progress: number, options?: Omit): ProgressChunk; /** * Create a progress chunk with explicit step tracking. */ export declare function createProgressChunkWithSteps(progress: number, currentStep: number, totalSteps: number, options?: Omit): ProgressChunk; /** * Create a data chunk. */ export declare function createDataChunk(data: T, index: number, isLast: boolean, chunkId?: string): DataChunk; /** * Create a completion chunk. */ export declare function createCompleteChunk(totalChunks: number, totalDurationMs: number, options?: Omit, 'type' | 'totalChunks' | 'totalDurationMs'>): CompleteChunk; /** * Create an error chunk. */ export declare function createErrorChunk(error: CommandError, chunksBeforeError: number, recoverable?: boolean, resumeFrom?: number): ErrorChunk; /** * Type guard for ProgressChunk. */ export declare function isProgressChunk(chunk: StreamChunk): chunk is ProgressChunk; /** * Type guard for DataChunk. */ export declare function isDataChunk(chunk: StreamChunk): chunk is DataChunk; /** * Type guard for CompleteChunk. */ export declare function isCompleteChunk(chunk: StreamChunk): chunk is CompleteChunk; /** * Type guard for ErrorChunk. */ export declare function isErrorChunk(chunk: StreamChunk): chunk is ErrorChunk; /** * Type guard to check if any value is a StreamChunk. */ export declare function isStreamChunk(value: unknown): value is StreamChunk; /** * Type guard to check if a command definition is streamable. */ export declare function isStreamableCommand(command: unknown): command is StreamableCommand; /** * Consume a stream with callbacks. * * @param stream - AsyncGenerator yielding StreamChunks * @param callbacks - Handlers for each chunk type * @returns Promise that resolves when stream completes */ export declare function consumeStream(stream: AsyncGenerator, void, unknown>, callbacks: StreamCallbacks): Promise | ErrorChunk>; /** * Collect all data from a stream into an array. * * @param stream - AsyncGenerator yielding StreamChunks * @returns Promise resolving to array of all data items */ export declare function collectStreamData(stream: AsyncGenerator, void, unknown>): Promise; /** An AbortController whose pending timeout can be cancelled with `dispose()`. */ export interface TimeoutController extends AbortController { /** Cancel the pending timeout without aborting. Idempotent; safe after an abort. */ dispose(): void; } /** * Create an AbortController that aborts after a timeout. * * The timer is `unref()`'d in Node, so it never keeps the process alive, and is * cleared on abort or `dispose()`. Call `dispose()` in a `finally` once the * work completes; otherwise the signal still aborts when the timeout elapses. * * @param timeoutMs - Timeout in milliseconds * @returns A controller that aborts after `timeoutMs`, with `dispose()` to cancel the timeout */ export declare function createTimeoutController(timeoutMs: number): TimeoutController; //# sourceMappingURL=streaming.d.ts.map