/** * The engine registry: capability-filtered, middleware-arbitrated, ordered dispatch over the * pipeline's engine array. * * @remarks * Internal sibling of the `@nhtio/adk/batteries/media` entry (re-exported through the barrel). * One selection rule everywhere: gather every engine whose declarations match the request * (capability filter), run the consumer's selection onion (stages may exclude or reorder * candidates, never add), then the first survivor in supply order wins. * * Convert dispatch additionally computes multi-hop paths: when no single engine declares a * direct edge for the requested (input, target) pair, a breadth-first search over the format * graph finds the shortest chain of hops (capped at {@link MAX_HOPS}), with supply order * breaking ties at equal length. Pathfinding explores capability declarations only — cheap * and synchronous; the selection onion runs once per executed hop with real bytes in hand. */ import type { NextFn } from '@nhtio/middleware'; import type { CapabilityProbe } from "./validate"; import type { MediaEngine, ConvertRequest, ConvertResult, MutateRequest, EditRequest, EditResult, EngineBytesResult } from "./contracts"; /** * The request summary a selection stage sees: enough to implement content- and * format-dependent rules without exposing dispatch internals. */ export interface EngineSelectionContext { /** Which capability is being dispatched. */ kind: 'convert' | 'mutate' | 'edit'; /** The dispatch request (for convert under multi-hop, the CURRENT hop's input/target). */ request: { /** The input MIME type. */ mimeType: string; /** The input filename. */ filename: string; /** The input bytes — content-dependent rules (e.g. workbook complexity) need them. */ bytes: Uint8Array; /** The convert target token, or the mutate `format.to` when a re-encode was requested. */ to?: string; /** The requested mutate operations. */ ops?: readonly string[]; }; /** * The capable engines, in supply order. Stages may exclude or reorder (mutate in place or * reassign); survivors are re-filtered against the original capable set, so a stage can * never add an engine the capability filter rejected. */ candidates: MediaEngine[]; } /** * A selection-middleware stage — the seam for quality heuristics and implementor overrides * when several engines can perform the same transform (e.g. route complex workbooks past a * pure-JS converter to LibreOffice). Same onion shape as the battery's `use` interceptors; * a fresh runner is minted per dispatch. Keep stages cheap or memoized: they run with bytes * in hand on every dispatch. */ export type EngineSelectionMiddlewareFn = (ctx: EngineSelectionContext, next: NextFn) => void | Promise; /** Ordered capability-filtered dispatch over the pipeline's engines. */ export interface EngineRegistry extends CapabilityProbe { /** The resolved engines, in supply order (inspection/debugging). */ readonly engines: readonly MediaEngine[]; /** * Every format token reachable from `fromMime` — directly or through a computed path of up * to three hops. Drives "supported targets" error messages. * * @param fromMime - The input MIME type. */ convertTargets(fromMime: string): readonly string[]; /** * Convert via the shortest capable path (direct edge = one hop). The selection rule picks * the engine for each executed hop; options are forwarded to every hop (engines ignore * keys they don't understand). * * @param request - The input bytes, target token, and options. * @returns The final hop's outputs. */ convert(request: ConvertRequest): Promise; /** * Apply a fused same-format transform. Candidates are engines whose `over` matches the * input, whose `ops` cover the requested operations, and — when a re-encode is requested — * whose `encodes` include the target. * * @param request - The fused operations and input bytes. * @returns The transformed bytes. */ mutate(request: MutateRequest): Promise; /** * Apply one structural document operation. Candidates are engines whose `over` matches the * input and whose `ops` include the requested op; the selection rule arbitrates between * engines of differing fidelity (supply order wins by default). * * @param request - The op, its args, and the input bytes. * @returns The restructured bytes plus optional change counts. */ edit(request: EditRequest): Promise; } /** * Build the registry over a resolved, validated engine array. * * @param engines - The engines, in supply (priority) order. * @param selection - Optional selection-middleware stages arbitrating multi-candidate dispatches. * @returns The registry. */ export declare const buildEngineRegistry: (engines: readonly MediaEngine[], selection?: readonly EngineSelectionMiddlewareFn[]) => EngineRegistry;