/** * The A2UI processor: incremental, whitelist-only, fail-loud validation that * turns a stream of Server→Client envelopes into per-surface component maps and * data models. Pure TS, no Svelte — deliberately NOT reactive (the house * pattern of the streaming-markdown engine: plain Maps mutated in place; the * Svelte layer bumps a version counter to re-derive the render tree). * * Security posture (untrusted-payload path): * - Whitelist-only: only registry-declared props reach the render layer, so * handler injection (`onclick`, …) and prop smuggling are structurally * impossible — there is no payload spread. * - `__proto__`/`constructor`/`prototype` are rejected as component ids, prop * keys, pointer segments and action-context keys. * - Never merges or spreads payload objects; everything flows through `Map`s. * - `collectGraphIssues` bounds traversal (depth 32, nodes 512) to cap DoS. * * Issue routing: envelope-level faults (bad version, unknown envelope type, * op-before-createSurface) land in `globalIssues`; everything scoped to a known * surface lands in that surface's `issues`. Graph-level faults (cycle, depth, * node count, dangling refs) are computed on demand by `collectGraphIssues`, * because "dangling" is a warning mid-stream and an error once settled. */ import { type A2uiValidationIssue } from './a2ui.types.js'; import { type A2uiCatalogSpec } from './a2ui-catalog.js'; import { type A2uiDataSchema } from './a2ui-schema.js'; export interface A2uiComponentInstance { id: string; component: string; /** Only registry-declared props; the raw payload values (dynamics resolved at render). */ props: ReadonlyMap; /** Index of the envelope that last defined this component. */ sourceIndex: number; } export interface A2uiSurfaceState { surfaceId: string; components: Map; /** Root of the surface data model (mutated in place by two-way edits). */ dataModel: unknown; issues: A2uiValidationIssue[]; /** * The catalog resolved from `createSurface.catalogId` (or the default when the * id names no configured catalog). Every downstream check — registry lookup, * icon set, flex containers, per-component checks — reads it, so surfaces on * different catalogs validate and render independently. */ catalog: A2uiCatalogSpec; /** * `createSurface.sendDataModel` — when true, every action dispatched from this * surface carries the full data model (see `A2uiActionEvent.dataModel`), so * the agent sees the user's input even for fields it left out of `context`. */ sendDataModel: boolean; } export interface A2uiProcessor { surfaces: Map; globalIssues: A2uiValidationIssue[]; /** Validate + apply one envelope. `index` positions it as `/messages/` in issue paths. */ apply(envelope: unknown, index: number): void; } /** Options for {@link createA2uiProcessor}. Omitting them yields the Basic-only default. */ export interface A2uiProcessorOptions { /** * The catalogs this processor understands, in priority order. `catalogs[0]` * is the default/fallback. Defaults to `[basicA2uiCatalogSpec]` — a * single-catalog processor accepts any `catalogId` string silently * (back-compat); an unknown id only warns once there are ≥ 2 catalogs. */ catalogs?: readonly A2uiCatalogSpec[]; /** * Optional data schema. When set, every `updateDataModel` write is validated * against it — a type mismatch on a declared pointer is a `SCHEMA_TYPE_MISMATCH` * error, a write to an undeclared top-level branch a `SCHEMA_UNDECLARED_PATH` * warning. Omitting it disables schema validation entirely (back-compat). */ dataSchema?: A2uiDataSchema; } export declare function createA2uiProcessor(options?: A2uiProcessorOptions): A2uiProcessor; /** * Normalize a render payload into an envelope list. Accepts an envelope array, * a single envelope, or the golden-file `{ messages: [...] }` wrapper. Returns * an `issue` (and no envelopes) only for wholly unusable input. */ export declare function normalizeA2uiPayload(payload: unknown): { envelopes: unknown[]; issue?: A2uiValidationIssue; }; export interface GraphIssueOptions { /** When true, dangling refs are warnings (still streaming); when false, errors. @default false */ streaming?: boolean; /** @default 32 */ maxDepth?: number; /** @default 512 */ maxNodes?: number; } /** * Walk the component graph from `root` and collect structural faults that only * exist once components are assembled: cycles, excessive depth/nodes, dangling * child references, non-array template paths, and mis-placed `weight`. * * NOTE — contract extension. The design's published `a2ui-validate.ts` surface * is `createA2uiProcessor` + `normalizeA2uiPayload`. This function is an * additive export (no existing signature changed): the renderer (WP-B) needs * render-time graph faults whose severity depends on the `streaming` flag, and * the test suite exercises them here. Traversal is bounded by `maxNodes` so a * template over a huge array cannot DoS the walk itself. */ export declare function collectGraphIssues(surface: A2uiSurfaceState, options?: GraphIssueOptions): A2uiValidationIssue[];