{"version":3,"file":"protocol.mjs","names":[],"sources":["../../../../src/batteries/generation/local_diffusion/protocol.ts"],"sourcesContent":["/**\n * Pure protocol constants, frame parsing, and byte-safe line framing for local diffusion backends.\n *\n * @remarks\n * The line framer is **byte-oriented**: it retains raw bytes (never a decoded string), enforces the\n * `maxLineBytes` cap while consuming input (so an unbounded no-newline write cannot balloon memory),\n * discards the remainder of an over-sized physical line up to its next newline before resuming, and\n * decodes each bounded, complete line with a fatal UTF-8 decoder (invalid encoding → a `malformed`\n * frame, never a silent mis-parse). {@link parseFrame} is total — it classifies every line as a typed\n * frame and never throws.\n *\n * @module @nhtio/adk/batteries/generation/local_diffusion/protocol\n */\n\nimport { isObject } from '@nhtio/adk/guards'\n\n/** The configurable wire tags used by a local diffusion backend. */\nexport type ProtocolConfig = {\n  /** Leading tag on every host→backend command line (DiffusionBee: `b2py`). */\n  commandPrefix: string\n  /** Leading tag on every backend→host event line (DiffusionBee: `sdbk`). */\n  eventPrefix: string\n  /** Operation sub-tags for the two request commands. */\n  ops: {\n    /** text→image generate op sub-tag (DiffusionBee: `t2im`). */\n    generate: string\n    /** image+text→image edit op sub-tag (DiffusionBee: `im2im`). */\n    edit: string\n  }\n  /** Control-command sub-tags (no request payload). */\n  control: {\n    /** Advisory cancel of the current request (DiffusionBee: `__stop__`). */\n    stop: string\n    /** Graceful backend shutdown request (DiffusionBee: `__shutdown__`). */\n    shutdown: string\n  }\n  /** Backend→host event sub-tags. */\n  events: {\n    /** Startup model-load progress event (DiffusionBee: `mdld`). */\n    modelLoad: string\n    /** Backend-ready event that resolves preload (DiffusionBee: `rdy`). */\n    ready: string\n    /** Per-step generation progress event (DiffusionBee: `dnpr`). */\n    progress: string\n    /** One finished image result event (DiffusionBee: `nwim`). */\n    image: string\n    /** Request-complete terminal event (DiffusionBee: `done`). */\n    done: string\n    /** Request-error terminal event (DiffusionBee: `err`). */\n    error: string\n  }\n}\n\n/** The DiffusionBee-compatible default local diffusion protocol configuration. */\nexport const DEFAULT_PROTOCOL: ProtocolConfig = {\n  commandPrefix: 'b2py',\n  eventPrefix: 'sdbk',\n  ops: { generate: 't2im', edit: 'im2im' },\n  control: { stop: '__stop__', shutdown: '__shutdown__' },\n  events: {\n    modelLoad: 'mdld',\n    ready: 'rdy',\n    progress: 'dnpr',\n    image: 'nwim',\n    done: 'done',\n    error: 'err',\n  },\n}\n\n/** A parsed startup model-loading progress frame. */\nexport type ModelLoadFrame = {\n  /** Discriminant. */\n  kind: 'modelLoad'\n  /** Normalized model-load progress in `0..1`. */\n  progress: number\n}\n/** A parsed backend-ready frame. */\nexport type ReadyFrame = {\n  /** Discriminant. */\n  kind: 'ready'\n}\n/** A parsed request progress frame. */\nexport type ProgressFrame = {\n  /** Discriminant. */\n  kind: 'progress'\n  /** The request id this progress belongs to. */\n  rid: number\n  /** Normalized per-step generation progress in `0..1`. */\n  progress: number\n}\n/** A parsed image result frame. */\nexport type ImageFrame = {\n  /** Discriminant. */\n  kind: 'image'\n  /** The request id this image belongs to. */\n  rid: number\n  /** The image payload: either an inline base64 blob or a backend-written file path, plus its MIME. */\n  payload: {\n    /** Backend-written output file path (mutually exclusive with `b64`). */\n    path?: string\n    /** Inline base64-encoded image bytes (mutually exclusive with `path`). */\n    b64?: string\n    /** Concrete image MIME type, e.g. `image/png`. */\n    mimeType: string\n  }\n}\n/** A parsed request completion frame. */\nexport type DoneFrame = {\n  /** Discriminant. */\n  kind: 'done'\n  /** The request id that completed. */\n  rid: number\n}\n/** A parsed request error frame. */\nexport type ErrorFrame = {\n  /** Discriminant. */\n  kind: 'error'\n  /** The request id that errored. */\n  rid: number\n  /** The backend-reported error message. */\n  message: string\n}\n/** A frame with a tag this protocol version does not understand. */\nexport type UnknownFrame = {\n  /** Discriminant. */\n  kind: 'unknown'\n  /** The original, unrecognized line. */\n  raw: string\n}\n/** A prefix-matched frame whose fields or JSON do not satisfy the protocol. */\nexport type MalformedFrame = {\n  /** Discriminant. */\n  kind: 'malformed'\n  /** The original line that failed validation (best-effort, lossy decode for invalid UTF-8). */\n  raw: string\n  /** Why the line was rejected. */\n  detail: string\n}\n/** A stream-level protocol problem, such as an over-sized line. */\nexport type ProtocolErrorFrame = {\n  /** Discriminant. */\n  kind: 'protocolError'\n  /** Why the stream framing failed. */\n  detail: string\n}\n\n/** The total, discriminated result of parsing one backend stdout line. */\nexport type ParsedFrame =\n  | ModelLoadFrame\n  | ReadyFrame\n  | ProgressFrame\n  | ImageFrame\n  | DoneFrame\n  | ErrorFrame\n  | UnknownFrame\n  | MalformedFrame\n  | ProtocolErrorFrame\n\nconst malformed = (raw: string, detail: string): MalformedFrame => ({\n  kind: 'malformed',\n  raw,\n  detail,\n})\n\nconst validRid = (value: string | undefined): number | undefined => {\n  if (value === undefined || !/^\\d+$/.test(value)) return undefined\n  const rid = Number(value)\n  return Number.isSafeInteger(rid) && rid >= 0 ? rid : undefined\n}\n\n/**\n * Strictly parse a normalized-unit-interval token (`0..1`). Rejects `undefined`, empty/whitespace-only\n * strings, and anything that is not a plain non-negative decimal — closing the `Number('')===0`\n * coercion hole (a blank progress field would otherwise be accepted as zero) AND the negative-signed\n * `-0` spelling, which contradicts the non-negative wire representation. Scientific/hex notation is\n * likewise rejected; only plain decimals (optionally `+`-signed) are accepted.\n */\nconst parseUnitInterval = (value: string | undefined): number | undefined => {\n  if (value === undefined) return undefined\n  const trimmed = value.trim()\n  if (trimmed === '' || !/^\\+?(?:\\d+\\.?\\d*|\\.\\d+)$/.test(trimmed)) return undefined\n  const n = Number(trimmed)\n  return Number.isFinite(n) && n >= 0 && n <= 1 ? n : undefined\n}\n\nconst json = (raw: string): unknown => JSON.parse(raw) as unknown\n\n/**\n * Structural check that a runtime-supplied `config` carries the string tags this parser dereferences:\n * `eventPrefix` plus all six `events` members must be strings. `parseFrame` promises to never throw;\n * a JS caller passing `null`, `{events:null}`, or a partial `{events:{}}` must get a typed frame, not\n * a `TypeError` (terra v2 #5 / v3 #5). A hostile accessor/proxy that throws on read is caught by the\n * top-level `try/catch` in {@link parseFrame} — this guard is the fast structural gate, the wrapper is\n * the belt.\n */\nconst isUsableConfig = (config: ProtocolConfig): boolean => {\n  if (!isObject(config) || typeof config.eventPrefix !== 'string' || !isObject(config.events)) {\n    return false\n  }\n  const { events } = config\n  return (\n    typeof events.modelLoad === 'string' &&\n    typeof events.ready === 'string' &&\n    typeof events.progress === 'string' &&\n    typeof events.image === 'string' &&\n    typeof events.done === 'string' &&\n    typeof events.error === 'string'\n  )\n}\n\n/**\n * Parse one already-split backend stdout line into a typed {@link ParsedFrame}. Total by contract —\n * it never throws: malformed input yields a `malformed`/`unknown` frame, and a runtime-invalid or\n * hostile `config` (null, partial, or a throwing accessor) is caught and reported as `malformed`.\n *\n * @param line - One already-newline-split backend stdout line.\n * @param config - Protocol tag configuration; defaults to {@link DEFAULT_PROTOCOL}.\n * @returns The discriminated parse result.\n */\nexport const parseFrame = (\n  line: string,\n  config: ProtocolConfig = DEFAULT_PROTOCOL\n): ParsedFrame => {\n  try {\n    return parseFrameChecked(line, config)\n  } catch {\n    // A hostile config (throwing getter/proxy) or any unforeseen runtime error must not escape:\n    // parseFrame is total by contract.\n    return malformed(line, 'invalid protocol config')\n  }\n}\n\nconst parseFrameChecked = (line: string, config: ProtocolConfig): ParsedFrame => {\n  const raw = line\n  if (!isUsableConfig(config)) return malformed(raw, 'invalid protocol config')\n  const match = /^(\\S+)(?:\\s+(\\S+))?(?:\\s+([\\s\\S]*))?$/.exec(line)\n  if (!match || match[1] !== config.eventPrefix) return { kind: 'unknown', raw }\n  const tag = match[2]\n  if (!tag) return malformed(raw, 'missing event tag')\n  const { events } = config\n  if (tag === events.modelLoad) {\n    const progress = parseUnitInterval(match[3])\n    return progress !== undefined\n      ? { kind: 'modelLoad', progress }\n      : malformed(raw, 'progress must be a finite number in 0..1')\n  }\n  if (tag === events.ready) {\n    // The wire contract is `<EVT> rdy` with no payload; a trailing token means a corrupt line.\n    return match[3] === undefined ? { kind: 'ready' } : malformed(raw, 'ready has no payload')\n  }\n  if (\n    tag === events.progress ||\n    tag === events.image ||\n    tag === events.done ||\n    tag === events.error\n  ) {\n    const parts = match[3]?.match(/^(\\S+)(?:\\s+([\\s\\S]*))?$/)\n    const rid = validRid(parts?.[1])\n    if (rid === undefined) return malformed(raw, 'rid must be a non-negative integer')\n    const remainder = parts?.[2]\n    if (tag === events.progress) {\n      const progress = parseUnitInterval(remainder)\n      return progress !== undefined\n        ? { kind: 'progress', rid, progress }\n        : malformed(raw, 'progress must be a finite number in 0..1')\n    }\n    if (tag === events.done)\n      return remainder === undefined ? { kind: 'done', rid } : malformed(raw, 'done has no payload')\n    if (remainder === undefined) return malformed(raw, 'missing JSON payload')\n    try {\n      const value = json(remainder)\n      if (tag === events.error) {\n        if (\n          typeof value !== 'object' ||\n          value === null ||\n          typeof (value as { message?: unknown }).message !== 'string'\n        ) {\n          return malformed(raw, 'error payload requires a message string')\n        }\n        return { kind: 'error', rid, message: (value as { message: string }).message }\n      }\n      if (typeof value !== 'object' || value === null)\n        return malformed(raw, 'image payload must be an object')\n      const obj = value as Record<string, unknown>\n      const mimeType = obj.mimeType\n      // Exactly one of the `path`/`b64` KEYS may be present (regardless of value type), and the\n      // selected field must be a string — an object carrying both keys, or a non-string in the\n      // present key, is malformed even if the other key holds a valid string (terra v2 #1).\n      const pathPresent = 'path' in obj\n      const b64Present = 'b64' in obj\n      if (typeof mimeType !== 'string' || pathPresent === b64Present)\n        return malformed(raw, 'image requires mimeType and exactly one of path or b64')\n      if (pathPresent) {\n        if (typeof obj.path !== 'string') return malformed(raw, 'image path must be a string')\n        return { kind: 'image', rid, payload: { mimeType, path: obj.path } }\n      }\n      if (typeof obj.b64 !== 'string') return malformed(raw, 'image b64 must be a string')\n      return { kind: 'image', rid, payload: { mimeType, b64: obj.b64 } }\n    } catch {\n      return malformed(raw, 'invalid JSON payload')\n    }\n  }\n  return { kind: 'unknown', raw }\n}\n\n/** Assert a request id satisfies the parser's rid contract (a non-negative safe integer). */\nconst assertRid = (rid: number): void => {\n  if (!Number.isSafeInteger(rid) || rid < 0)\n    throw new RangeError(`request id must be a non-negative safe integer, received ${String(rid)}`)\n}\n\n/** Serialize command arguments, rejecting values JSON cannot represent (which would emit `undefined`). */\nconst encodeArgs = (args: Record<string, unknown>): string => {\n  const encoded = JSON.stringify(args)\n  if (encoded === undefined) throw new TypeError('command arguments must be JSON-serializable')\n  return encoded\n}\n\n/** Build a generate command frame, including its terminating newline. */\nexport const buildGenerateCommand = (\n  rid: number,\n  args: Record<string, unknown>,\n  config: ProtocolConfig = DEFAULT_PROTOCOL\n): string => {\n  assertRid(rid)\n  return `${config.commandPrefix} ${config.ops.generate} ${rid} ${encodeArgs(args)}\\n`\n}\n/** Build an edit command frame, including its terminating newline. */\nexport const buildEditCommand = (\n  rid: number,\n  args: Record<string, unknown>,\n  config: ProtocolConfig = DEFAULT_PROTOCOL\n): string => {\n  assertRid(rid)\n  return `${config.commandPrefix} ${config.ops.edit} ${rid} ${encodeArgs(args)}\\n`\n}\n/** Build a best-effort stop command frame, including its terminating newline. */\nexport const buildStopCommand = (\n  rid: number,\n  config: ProtocolConfig = DEFAULT_PROTOCOL\n): string => {\n  assertRid(rid)\n  return `${config.commandPrefix} ${config.control.stop} ${rid}\\n`\n}\n/** Build a backend shutdown command frame, including its terminating newline. */\nexport const buildShutdownCommand = (config: ProtocolConfig = DEFAULT_PROTOCOL): string =>\n  `${config.commandPrefix} ${config.control.shutdown}\\n`\n\nconst LF = 0x0a\nconst CR = 0x0d\n\n/**\n * Create an incremental, **byte-oriented** line reader. Raw bytes are retained (never a decoded\n * string), the `maxLineBytes` cap is enforced while consuming so an unbounded no-newline write cannot\n * balloon memory, an over-sized physical line reports exactly one `protocolError` and is then discarded\n * through its next newline (its continuation is NOT re-parsed as a fresh frame), and each bounded,\n * complete line is decoded with a fatal UTF-8 decoder — invalid encoding yields a `malformed` frame.\n * Malformed protocol lines are reported as `malformed` rather than thrown.\n *\n * Pending bytes of an in-progress line are held as a queue of chunk SEGMENTS with a running byte\n * count, and concatenated exactly once when the line's terminator arrives — so many small fragments of\n * one line cost O(line length) total, not O(line length²) (terra v2 #4).\n *\n * @throws RangeError if `maxLineBytes` is provided but is not a positive, finite, safe integer — an\n *   unvalidated `Infinity`/`NaN`/negative would silently defeat the bounded-memory guarantee (terra v2 #3).\n */\nexport const createFrameReader = (opts: {\n  onFrame(frame: ParsedFrame): void\n  config?: ProtocolConfig\n  maxLineBytes?: number\n}): { push(chunk: Uint8Array): void; end(): void } => {\n  const config = opts.config ?? DEFAULT_PROTOCOL\n  if (\n    opts.maxLineBytes !== undefined &&\n    (!Number.isSafeInteger(opts.maxLineBytes) || opts.maxLineBytes < 1)\n  ) {\n    throw new RangeError(\n      `maxLineBytes must be a positive safe integer, received ${String(opts.maxLineBytes)}`\n    )\n  }\n  const cap = opts.maxLineBytes ?? 1_048_576\n  const segments: Uint8Array[] = [] // retained segments of the current, not-yet-terminated line\n  let pending = 0 // total retained bytes across `segments`\n  let discarding = false // dropping bytes until the next newline (recovering from an over-sized line)\n  let ended = false\n\n  const resetLine = (): void => {\n    segments.length = 0\n    pending = 0\n  }\n\n  /** Assemble the retained segments plus `chunk[start..end]` into one contiguous line buffer. */\n  const assemble = (chunk: Uint8Array, start: number, end: number): Uint8Array => {\n    const tail = end - start\n    if (segments.length === 0) return chunk.subarray(start, end)\n    const line = new Uint8Array(pending + tail)\n    let at = 0\n    for (const seg of segments) {\n      line.set(seg, at)\n      at += seg.length\n    }\n    if (tail > 0) line.set(chunk.subarray(start, end), at)\n    return line\n  }\n\n  const decodeLine = (bytes: Uint8Array): void => {\n    let end = bytes.length\n    if (end > 0 && bytes[end - 1] === CR) end -= 1 // strip a CRLF's CR\n    if (end === 0) return // blank line — skip\n    const slice = bytes.subarray(0, end)\n    try {\n      // Each complete line is a whole UTF-8 byte sequence (a newline can't split a code point), so a\n      // fresh non-streaming fatal decode is correct and immune to any reuse-after-throw state.\n      opts.onFrame(parseFrame(new TextDecoder('utf-8', { fatal: true }).decode(slice), config))\n    } catch {\n      opts.onFrame(malformed(new TextDecoder().decode(slice), 'invalid UTF-8 in line'))\n    }\n  }\n\n  const consume = (chunk: Uint8Array): void => {\n    let pos = 0\n    if (discarding) {\n      const nl = chunk.indexOf(LF, pos)\n      if (nl === -1) return // still inside the over-sized line — drop the whole chunk\n      discarding = false\n      pos = nl + 1\n    }\n    while (pos < chunk.length) {\n      const nl = chunk.indexOf(LF, pos)\n      if (nl === -1) {\n        // No terminator in the remainder: retain it, but only if it keeps the line within the cap.\n        if (pending + (chunk.length - pos) > cap) {\n          opts.onFrame({ kind: 'protocolError', detail: 'line exceeded maxLineBytes' })\n          resetLine()\n          discarding = true\n        } else if (chunk.length > pos) {\n          const seg = chunk.subarray(pos, chunk.length)\n          segments.push(seg)\n          pending += seg.length\n        }\n        return\n      }\n      // A complete line spans the retained segments + chunk[pos..nl]; its terminator is this newline.\n      if (pending + (nl - pos) > cap) {\n        opts.onFrame({ kind: 'protocolError', detail: 'line exceeded maxLineBytes' })\n        resetLine() // the line is already terminated here — no discard state needed\n      } else {\n        const line = assemble(chunk, pos, nl)\n        resetLine()\n        decodeLine(line)\n      }\n      pos = nl + 1\n    }\n  }\n\n  return {\n    push(chunk) {\n      if (!ended) consume(chunk)\n    },\n    end() {\n      if (ended) return\n      ended = true\n      if (!discarding && pending > 0) {\n        opts.onFrame({\n          kind: 'malformed',\n          raw: new TextDecoder().decode(assemble(new Uint8Array(0), 0, 0)),\n          detail: 'unterminated line at EOF',\n        })\n      }\n      resetLine()\n      discarding = false\n    },\n  }\n}\n"],"mappings":"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"}