/** * Ajv-backed JSON Schema validation runtime for ggui contracts. * * Owns layers B (inner JSON Schema meta-validation) and C (runtime * data validation across propsSpec / actionSpec / streamSpec / * contextSpec) of the six-layer model. The outer A-layers — protocol * wrappers (DataContract envelope, PropsSpec, PropEntry, ActionEntry, * etc.) — stay on zod where TS inference + structural strict-mode * already do their job. * * Why Ajv: * - Canonical JSON Schema validator (303M weekly downloads). * - Single source of truth: same compiled validator powers all four * runtime spec surfaces, so closed-shape semantics never diverge * between props vs action vs stream vs context. * - Compile-time meta-validation: `strict: true` rejects malformed * JSON Schemas at `compile()` — agents discover bugs at * handshake/render, not at first data flow. * * Closed-shape (load-bearing): * JSON Schema's default is `additionalProperties: true` (extras * allowed). Our "propsSpec IS the contract" promise needs * closed-shape at EVERY depth. Rather than tax agents with * `additionalProperties: false` at every object node, we inject it * recursively via {@link injectClosedShape} before Ajv compiles. * An author who explicitly sets `additionalProperties` (boolean or * schema) keeps that intent — escape hatch for the rare case where * open extension is intentional. * * Tolerated metadata keywords: * - `example` (singular, OpenAPI-ish; JSON Schema standard is * `examples` array). Registered by us as a genuine no-op keyword * (informational only) so strict mode doesn't reject it. * - `nullable` (OpenAPI 3.0 shorthand). NOT a no-op: Ajv 8 * pre-registers `nullable` itself with WIDENING semantics — * `{type:'string', nullable:true}` accepts `null` (empirically * verified 2026-08-19; the `getKeyword` guard below never fires * for it). Behaviorally equivalent to the canonical * `type: [, 'null']` union, which is what the enforced * props schema emission (`buildEnforcedPropsSchema`) rewrites it * to — the wire artifact carries the widening explicitly so a * strict reader of the emitted schema sees the same acceptance * the validator enforces. */ import type { ErrorObject, ValidateFunction } from 'ajv'; /** * Re-export of Ajv's compiled-validator function type. Consumers * (e.g. the renderer iframe loading precompiled validator modules) * import it from `@ggui-ai/protocol` so they need no direct `ajv` * dependency — TS resolves the type transitively through this package. */ export type { ValidateFunction } from 'ajv'; import type { JsonSchema } from '../types/data-contract.js'; import type { ContractViolation } from './contract-validator.js'; /** * Recursively walk a JSON Schema and inject * `additionalProperties: false` at every object node. Authors who * explicitly set `additionalProperties` keep that intent (boolean * preserved; schema recursed into). * * Walks: * - `properties` (each entry) * - `items` (array element schema) * - `additionalProperties` (when it's a schema) * - `oneOf` / `anyOf` (each branch) * * Returns a new schema tree; never mutates the input. */ export declare function injectClosedShape(schema: JsonSchema): JsonSchema; /** * Compile a JSON Schema into an Ajv {@link ValidateFunction}, with * closed-shape injected at every object node. Throws if the schema * is malformed under Ajv strict mode — this is layer B meta- * validation as a free side effect. Dedicated meta-validation call * sites (handshake / render) wrap this in a structured error. * * Not cached. Compilation is fast and contracts are small; caching * adds a memory cost without a measured win. Revisit if profiling * shows compile dominating. */ export declare function compileForValidation(schema: JsonSchema): ValidateFunction; /** * Compile a JSON Schema into a standalone, **fully self-contained ESM * validator module** — source text, never a live function. Closed-shape * is injected first, exactly as {@link compileForValidation} does, so * the emitted validator enforces the same semantics. * * Why this exists: the renderer iframe runs under a strict CSP with no * `'unsafe-eval'`, so `ajv.compile()` (which builds the validator via * `new Function`) throws `EvalError` there. Codegen has to happen * where `eval` is legal — the server, at render time, where the contract * schema is already fixed. The iframe then loads this module source * via a `blob:` dynamic import (governed by `script-src`, not * `unsafe-eval`) and only ever *runs* the validator. * * The returned module `export default`s the validator function (and * also names it `validate`). Ajv standalone references its runtime * helpers by bare specifier (`ajv/dist/runtime/*`) — the * CSP-sandboxed iframe has no bundler to resolve those, so this * function **inlines** every helper a closed-contract validator can * reach (in practice only `equal` / fast-deep-equal, for `uniqueItems` * and object-valued `enum`/`const`). The result has zero imports. A * survivor check throws if any un-inlined bare import remains, so a new * Ajv helper surfaces as a loud server-side failure, never as silent * iframe breakage. * * Throws if the schema is malformed under Ajv strict mode — same * layer-B meta-validation side effect as {@link compileForValidation}. */ export declare function compileValidatorModule(schema: JsonSchema): string; /** * Compile a JSON Schema into a standalone validator as a JS * **EXPRESSION** — an IIFE over the CJS standalone emission, runtime * helpers inlined, evaluating to the validate function. * * The expression form is what makes the eval-free EXECUTABLE contract * bundle possible (ggui#522 slice 2): N validators concatenate into * ONE plain ES module (`v.actions["submit"] = ;`) that a * strict-CSP iframe imports directly — no per-validator `blob:` * import, no `new Function`, the browser just parses code. Closed * shape + strict-mode meta-validation semantics are identical to * {@link compileValidatorModule} (same options, same injection). */ export declare function compileValidatorFunctionExpr(schema: JsonSchema): string; /** * Convert Ajv error objects into our {@link ContractViolation} shape. * * Path translation: Ajv `instancePath: '/todos/0/done'` → * `field: 'todos[0].done'`. Numeric segments become bracket indices, * named segments become dot-separated. Empty instancePath collapses * to `''` (root-level error). * * Per-keyword mapping (see {@link mapOne}): * - `additionalProperties` — extra-key violation; `field` includes * the offending key, `expected: ''`. * - `required` — missing-key violation; `field` includes the * missing key, `expected: 'present'`, `received: 'undefined'`. * - `type` — type mismatch; `expected` is the JSON Schema type, * `received` reads from the violating value. * - `enum` / `const` — `expected` is the allowed value(s); * `received` is the offending value. * - `pattern` — `expected` is the regex; `received` is the * offending string. * - other keywords — fall through to Ajv's message verbatim. */ export declare function mapAjvErrorsToViolations(errors: ErrorObject[] | null | undefined, data: unknown): ContractViolation[]; /** * Re-anchor a list of Ajv-mapped violations under a stable field * prefix. Used by the four spec validators to lift Ajv's root- * relative paths into the caller's namespace: * - propsSpec: no prefix (paths already prop-relative). * - actionSpec: `.data`. * - streamSpec: `.payload`. * - contextSpec: `.value`. * * Empty `field` (root-level violation) collapses to the prefix * itself; sub-fields dot-join. */ export declare function prefixViolations(violations: ContractViolation[], prefix: string): ContractViolation[]; //# sourceMappingURL=ajv-runtime.d.ts.map