/** * Length-prefixed frames between the browser tool host and the image worker. * * A frame is a big-endian payload length followed by the payload, and the * payload is a big-endian header length followed by the UTF-8 header JSON and * the raw body bytes: * * ```text * frame := u32be payloadLength | payload * payload := u32be headerLength | headerJson(utf8) | body * payloadLength = 4 + headerJson.length + body.length * ``` * * Image bytes always travel in the body; nothing is ever base64-encoded here. */ import { Buffer } from "node:buffer"; import type { EncodeJob } from "./image-encode.js"; /** Largest accepted frame payload; one frame carries at most one screenshot plus its facts. */ export declare const MAX_FRAME_BYTES: number; /** Facts identifying one recompression request; the source bytes travel in the frame body. */ export interface WorkerRequestHeader { /** Request id the reply echoes back. */ id: number; /** Operation this frame asks the worker to run. */ op: "encodeBest"; /** Recompression facts; the source image itself is the frame body. */ job: Omit; } /** Worker reply to one {@link WorkerRequestHeader}; a successful reply carries encoded bytes in the body. */ export interface WorkerReplyHeader { /** Id of the request this reply answers. */ id: number; /** Whether the operation succeeded. */ ok: boolean; /** Media type of the encoded body, present when `ok` is true. */ mimeType?: string; /** Failure detail, present when `ok` is false. */ message?: string; } /** * Encode one frame. * @param header - JSON-serializable header; carries the request or reply facts. * @param body - optional raw bytes; the image itself, empty for replies that carry none. * @returns one frame ready to write to the channel. * @throws when the header or the assembled payload exceeds {@link MAX_FRAME_BYTES}. */ export declare function encodeFrame(header: object, body?: Uint8Array): Buffer; /** * Incremental frame parser for one channel. * * Each payload is copied once into a buffer sized from its declared length, so * arriving chunks never re-copy a frame body and a declared length above * {@link MAX_FRAME_BYTES} fails the channel instead of allocating. Any split * point works, including one byte at a time, and one chunk may carry many frames. */ export declare class FrameDecoder { private readonly onFrame; private readonly onError; private stage; private readonly lengthPrefix; private lengthPrefixBytes; private payload; private payloadLength; private payloadBytes; private failed; /** * @param onFrame - receives one complete frame's header JSON text and body bytes. * @param onError - receives the first protocol failure; the decoder is unusable afterwards. */ constructor(onFrame: (headerText: string, body: Buffer) => void, onError: (error: Error) => void); /** * Consume one chunk of the frame stream. * @param chunk - arriving bytes, at any split point. */ push(chunk: Buffer): void; /** Hand one fully received payload to the frame callback, or fail the channel. */ private completePayload; }