diff --git a/app/electron.vite.config.ts b/app/electron.vite.config.ts index 68f16f5..2388830 100644 --- a/app/electron.vite.config.ts +++ b/app/electron.vite.config.ts @@ -1,16 +1,43 @@ -import { defineConfig } from 'electron-vite'; +import { defineConfig, externalizeDepsPlugin } from 'electron-vite'; import react from '@vitejs/plugin-react'; import { fileURLToPath } from 'node:url'; +import { realpathSync } from 'node:fs'; // The renderer imports the protocol schemas from ../docs/protocol/schema — // outside the renderer root, so the dev server needs the repo root allowed. const repoRoot = fileURLToPath(new URL('..', import.meta.url)); +// Allow the REAL node_modules location too: in a normal checkout this is inside +// repoRoot (a no-op), but when node_modules is a symlink (monorepo / git +// worktree dev), assets like @fontsource woff2 resolve to the link target and +// would otherwise fall outside the fs allow list. +const nodeModulesReal = (() => { + try { + return realpathSync(fileURLToPath(new URL('./node_modules', import.meta.url))); + } catch { + return null; + } +})(); +const fsAllow = nodeModulesReal ? [repoRoot, nodeModulesReal] : [repoRoot]; + +// `ws` lazily require()s the optional native addons bufferutil / utf-8-validate. +// If `ws` is bundled into the main process, the bundler tries to resolve those +// addons at build time and the main process crashes at launch ("bufferutil"). +// Keep `ws` (and the optional addons) external so they load from node_modules +// at runtime, where ws's try/catch falls back to its pure-JS path cleanly. +const wsExternals = ['ws', 'bufferutil', 'utf-8-validate']; + export default defineConfig({ - main: {}, - preload: {}, + main: { + plugins: [externalizeDepsPlugin()], + build: { rollupOptions: { external: wsExternals } }, + }, + preload: { + plugins: [externalizeDepsPlugin()], + build: { rollupOptions: { external: wsExternals } }, + }, renderer: { plugins: [react()], - server: { fs: { allow: [repoRoot] } }, + server: { fs: { allow: fsAllow } }, }, }); diff --git a/app/src/renderer/src/lx/index.ts b/app/src/renderer/src/lx/index.ts new file mode 100644 index 0000000..88f5c5f --- /dev/null +++ b/app/src/renderer/src/lx/index.ts @@ -0,0 +1,5 @@ +// VENDORED MIRROR of @omadia/canvas-core src/lx/index.ts — single source of +// truth is byte5ai/omadia middleware/packages/canvas-core. Keep in sync. +export * from './types.js'; +export { evaluate, runTransition } from './interpreter.js'; +export { validateLumenSemantics, type SemanticResult } from './validate.js'; diff --git a/app/src/renderer/src/lx/interpreter.ts b/app/src/renderer/src/lx/interpreter.ts new file mode 100644 index 0000000..2f72a9d --- /dev/null +++ b/app/src/renderer/src/lx/interpreter.ts @@ -0,0 +1,406 @@ +// VENDORED MIRROR of @omadia/canvas-core src/lx/interpreter.ts — single source of +// truth is byte5ai/omadia middleware/packages/canvas-core. Keep in sync. +/** + * omadia-canvas-protocol/1.1 — the Tier-1 LX interpreter (lumens-spec.md §2). + * + * Pure, total, deterministic AST evaluator. No `eval`/`Function` (CSP stays + * `default-src 'self'`). Every node costs gas; iteration is bounded; `random` + * and `now` are host-seeded. Given identical (state, event, seed, now) the + * result is byte-identical on every machine — the basis for replay, undo, + * sharing and v2 multi-user (§0.3). Any structural surprise throws LxError and + * the host halts that Lumen with surface_error (never the canvas, §0.2). + */ +import { + DEFAULT_GAS, + LxError, + MAX_DEPTH, + MAX_ITERATIONS, + MAX_RANGE, + MAX_VALUE_SIZE, + type EvalOptions, + type LxNode, + type LxValue, + type StateValue, +} from './types.js'; + +interface Ctx { + state: StateValue; + event: Record; + env: Record; // lexical bindings (let / it / idx / acc) + now: number; + gas: { n: number }; + depth: number; + rng: () => number; +} + +/** Deterministic PRNG (mulberry32) — pure arithmetic, fully replayable. */ +function mulberry32(seed: number): () => number { + let a = seed >>> 0; + return () => { + a |= 0; + a = (a + 0x6d2b79f5) | 0; + let t = Math.imul(a ^ (a >>> 15), 1 | a); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +const isRecord = (v: unknown): v is { [k: string]: LxValue } => + typeof v === 'object' && v !== null && !Array.isArray(v); + +/** Prototype-pollution guard. LX is data, but a `set`/`record`/`state` path + * segment of `__proto__`/`prototype`/`constructor` would let declarative data + * reach the JS object graph — reject it hard (defence in depth, independent of + * the semantic validator). */ +const FORBIDDEN_KEYS = new Set(['__proto__', 'prototype', 'constructor']); +function safeKey(key: string): string { + if (FORBIDDEN_KEYS.has(key)) throw new LxError('bad-path', `forbidden key '${key}'`); + return key; +} + +function burn(ctx: Ctx, amount = 1): void { + ctx.gas.n -= amount; + if (ctx.gas.n < 0) throw new LxError('gas', 'gas budget exhausted'); +} + +/** Charge gas proportional to a produced value's size AND cap it — so a + * size-amplifying op (concat-doubling, pad, map-over-range) cannot explode + * memory while staying under the per-node gas budget (F1). */ +function chargeSize(ctx: Ctx, size: number): void { + if (size > MAX_VALUE_SIZE) throw new LxError('bounds', `produced value size ${size} exceeds the ${MAX_VALUE_SIZE} cap`); + burn(ctx, size); +} + +/** Guard a numeric result against NaN / ±Infinity / -0 divergence: non-finite + * numbers serialise lossily (JSON → null) and would break replay determinism + * (F8). A non-finite arithmetic result halts the Lumen instead. */ +function fin(n: number): number { + if (!Number.isFinite(n)) throw new LxError('bounds', 'non-finite numeric result'); + return n === 0 ? 0 : n; // normalise -0 → 0 +} + +/** Per-stdlib argument arity (F7). undefined max ⇒ variadic ≥ min. */ +const ARITY: Record = { + map: [2, 2], filter: [2, 2], fold: [3, 3], range: [1, 1], len: [1, 1], + min: [1, Infinity], max: [1, Infinity], clamp: [3, 3], + abs: [1, 1], floor: [1, 1], ceil: [1, 1], round: [1, 1], sqrt: [1, 1], sign: [1, 1], pow: [2, 2], + concat: [1, Infinity], slice: [2, 3], contains: [2, 2], indexOf: [2, 2], keys: [1, 1], values: [1, 1], + upper: [1, 1], lower: [1, 1], pad: [2, 3], fmt: [1, 1], random: [0, 0], now: [0, 0], +}; + +function asNumber(v: LxValue): number { + if (typeof v !== 'number') throw new LxError('type', `expected number, got ${typeof v}`); + return v; +} +function asBool(v: LxValue): boolean { + if (typeof v !== 'boolean') throw new LxError('type', `expected bool, got ${typeof v}`); + return v; +} +function asString(v: LxValue): string { + if (typeof v !== 'string') throw new LxError('type', `expected string, got ${typeof v}`); + return v; +} +function asList(v: LxValue): LxValue[] { + if (!Array.isArray(v)) throw new LxError('type', `expected list, got ${typeof v}`); + return v; +} + +/** Structural deep-equality for `==` / `!=` / `contains` (total, gas-free at + * call sites that already burned for their operands). */ +function deepEqual(a: LxValue, b: LxValue, depth = 0): boolean { + if (depth > MAX_DEPTH) throw new LxError('bounds', 'value nesting too deep'); + if (a === b) return true; + if (Array.isArray(a) && Array.isArray(b)) { + return a.length === b.length && a.every((x, i) => deepEqual(x, b[i]!, depth + 1)); + } + if (isRecord(a) && isRecord(b)) { + const ka = Object.keys(a); + const kb = Object.keys(b); + return ka.length === kb.length && ka.every((k) => k in b && deepEqual(a[k]!, b[k]!, depth + 1)); + } + return false; +} + +/** Read a dotted path into a record/list value. */ +function readPath(root: LxValue, path: string): LxValue { + let cur: LxValue = root; + for (const seg of path.split('.')) { + safeKey(seg); + if (isRecord(cur) && Object.prototype.hasOwnProperty.call(cur, seg)) cur = cur[seg]!; + else if (Array.isArray(cur) && /^\d+$/.test(seg) && Number(seg) < cur.length) cur = cur[Number(seg)]!; + else throw new LxError('bad-path', `path '${path}' does not resolve`); + } + return cur; +} + +/** Immutable set of a dotted path; intermediate records are cloned, not mutated. */ +function setPath(root: StateValue, path: string, value: LxValue): StateValue { + const segs = path.split('.'); + segs.forEach(safeKey); + // a Lumen's state is a CLOSED record (§1.1): `set` may update declared paths, + // never invent a new top-level key (F5). + if (!Object.prototype.hasOwnProperty.call(root, segs[0]!)) { + throw new LxError('bad-path', `set target '${path}' is not a declared state key`); + } + const clone: StateValue = { ...root }; + let cur: { [k: string]: LxValue } = clone; + for (let i = 0; i < segs.length - 1; i++) { + const seg = segs[i]!; + const next = cur[seg]; + if (!isRecord(next)) throw new LxError('bad-path', `cannot set into non-record at '${seg}'`); + const copied = { ...next }; + cur[seg] = copied; + cur = copied; + } + cur[segs[segs.length - 1]!] = value; + return clone; +} + +function evalNode(node: LxNode, ctx: Ctx): LxValue { + burn(ctx); + // every node must be an object (F3): a missing child (e.g. an `if` with no + // `else` that slipped past the schema) becomes a typed LxError, never a raw + // TypeError that escapes the host's surface_error channel. + if (node === null || typeof node !== 'object' || Array.isArray(node)) { + throw new LxError('unknown-node', `expected an LX node object, got ${node === null ? 'null' : typeof node}`); + } + // bound AST recursion depth (F4) — deeper would overflow the JS stack with an + // uncatchable RangeError. Cloning with depth+1 (rather than mutating) means + // siblings each see the true nesting depth, not an accumulated count. + if (ctx.depth >= MAX_DEPTH) throw new LxError('bounds', 'expression nesting too deep'); + ctx = { ...ctx, depth: ctx.depth + 1 }; + const n = node as Record; + + if ('lit' in n) return n.lit as LxValue; + if ('var' in n) { + const name = n.var as string; + if (!(name in ctx.env)) throw new LxError('bad-path', `unbound var '${name}'`); + return ctx.env[name]!; + } + if ('state' in n) { + const base = readPath(ctx.state, n.state as string); + if (n.at) { + const [xn, yn] = n.at as [LxNode, LxNode]; + const x = asNumber(evalNode(xn, ctx)); + const y = asNumber(evalNode(yn, ctx)); + const row = asList(base)[y]; + if (row === undefined) throw new LxError('bounds', `grid row ${y} out of range`); + const cell = asList(row)[x]; + if (cell === undefined) throw new LxError('bounds', `grid col ${x} out of range`); + return cell; + } + return base; + } + if ('event' in n) { + const field = n.event as string; + return field in ctx.event ? ctx.event[field]! : 0; + } + if ('let' in n) { + const binding = n.let as Record; + const [name] = Object.keys(binding); + const value = evalNode(binding[name!]!, ctx); + const child: Ctx = { ...ctx, env: { ...ctx.env, [name!]: value } }; + return evalNode(n.in as LxNode, child); + } + + // arithmetic (all results guarded finite — F8) + if ('+' in n) return fin((n['+'] as LxNode[]).reduce((a, e) => a + asNumber(evalNode(e, ctx)), 0)); + if ('*' in n) return fin((n['*'] as LxNode[]).reduce((a, e) => a * asNumber(evalNode(e, ctx)), 1)); + if ('-' in n) { + const xs = (n['-'] as LxNode[]).map((e) => asNumber(evalNode(e, ctx))); + return fin(xs.slice(1).reduce((a, b) => a - b, xs[0]!)); + } + if ('/' in n) { + const [a, b] = (n['/'] as [LxNode, LxNode]).map((e) => asNumber(evalNode(e, ctx))) as [number, number]; + if (b === 0) throw new LxError('div-zero', 'division by zero'); + return fin(a / b); + } + if ('mod' in n) { + const [a, b] = (n.mod as [LxNode, LxNode]).map((e) => asNumber(evalNode(e, ctx))) as [number, number]; + if (b === 0) throw new LxError('div-zero', 'mod by zero'); + return fin(a % b); + } + + // comparison + if ('>' in n) { const [a, b] = binNum(n['>'] as LxNode[], ctx); return a > b; } + if ('>=' in n) { const [a, b] = binNum(n['>='] as LxNode[], ctx); return a >= b; } + if ('<' in n) { const [a, b] = binNum(n['<'] as LxNode[], ctx); return a < b; } + if ('<=' in n) { const [a, b] = binNum(n['<='] as LxNode[], ctx); return a <= b; } + if ('==' in n) { const [a, b] = (n['=='] as LxNode[]).map((e) => evalNode(e, ctx)); return deepEqual(a!, b!); } + if ('!=' in n) { const [a, b] = (n['!='] as LxNode[]).map((e) => evalNode(e, ctx)); return !deepEqual(a!, b!); } + + // logic (short-circuit) + if ('and' in n) { for (const e of n.and as LxNode[]) if (!asBool(evalNode(e, ctx))) return false; return true; } + if ('or' in n) { for (const e of n.or as LxNode[]) if (asBool(evalNode(e, ctx))) return true; return false; } + if ('not' in n) return !asBool(evalNode(n.not as LxNode, ctx)); + + // conditionals (total) + if ('if' in n) return asBool(evalNode(n.if as LxNode, ctx)) ? evalNode(n.then as LxNode, ctx) : evalNode(n.else as LxNode, ctx); + if ('match' in n) { + const subject = evalNode(n.match as LxNode, ctx); + for (const c of n.cases as { when: LxNode; then: LxNode }[]) { + if (deepEqual(subject, evalNode(c.when, ctx))) return evalNode(c.then, ctx); + } + return evalNode(n.else as LxNode, ctx); + } + + // constructors (size-charged — F1) + if ('record' in n) { + const entries = Object.entries(n.record as Record); + chargeSize(ctx, entries.length); + const out: { [k: string]: LxValue } = {}; + for (const [k, e] of entries) out[safeKey(k)] = evalNode(e, ctx); + return out; + } + if ('list' in n) { + const items = n.list as LxNode[]; + chargeSize(ctx, items.length); + return items.map((e) => evalNode(e, ctx)); + } + + // projection: read a field of a record (string key) or element of a list (int index) + if ('get' in n) { + const container = evalNode(n.get as LxNode, ctx); + const key = evalNode(n.key as LxNode, ctx); + if (Array.isArray(container)) { + if (typeof key !== 'number' || !Number.isInteger(key)) throw new LxError('type', 'list index must be an int'); + const el = container[key]; + if (el === undefined) throw new LxError('bounds', `list index ${key} out of range`); + return el; + } + if (isRecord(container)) { + if (typeof key !== 'string') throw new LxError('type', 'record key must be a string'); + if (!Object.prototype.hasOwnProperty.call(container, safeKey(key))) throw new LxError('bad-path', `record has no key '${key}'`); + return container[key]!; + } + throw new LxError('type', 'get expects a record or list'); + } + + // functional state update + if ('set' in n) { + const updates = n.set as Record; + // evaluate all exprs against the ORIGINAL state, then apply (functional). + const evaluated = Object.entries(updates).map(([path, e]) => [path, evalNode(e, ctx)] as const); + let next: StateValue = ctx.state; + for (const [path, value] of evaluated) next = setPath(next, path, value); + return next; + } + + if ('call' in n) return evalCall(n.call as string, n.args as LxNode[], ctx); + + throw new LxError('unknown-node', `unknown LX node: ${JSON.stringify(node).slice(0, 80)}`); +} + +function binNum(args: LxNode[], ctx: Ctx): [number, number] { + return [asNumber(evalNode(args[0]!, ctx)), asNumber(evalNode(args[1]!, ctx))]; +} + +/** Evaluate a body once per element with iteration bindings layered on env. */ +function evalBody(body: LxNode, ctx: Ctx, extra: Record): LxValue { + return evalNode(body, { ...ctx, env: { ...ctx.env, ...extra } }); +} + +function evalCall(name: string, argNodes: LxNode[], ctx: Ctx): LxValue { + const arity = ARITY[name]; + if (!arity) throw new LxError('unknown-call', `unknown std-lib call: ${name}`); + if (argNodes.length < arity[0] || argNodes.length > arity[1]) { + throw new LxError('arity', `${name} expects ${arity[1] === Infinity ? `≥${arity[0]}` : arity[0] === arity[1] ? arity[0] : `${arity[0]}–${arity[1]}`} args, got ${argNodes.length}`); + } + switch (name) { + case 'range': { + const len = asNumber(evalNode(argNodes[0]!, ctx)); + if (!Number.isInteger(len) || len < 0 || len > MAX_RANGE) throw new LxError('bounds', `range(${len}) out of bounds`); + chargeSize(ctx, len); + return Array.from({ length: len }, (_, i) => i); + } + case 'map': { + const coll = asList(evalNode(argNodes[0]!, ctx)); + if (coll.length > MAX_ITERATIONS) throw new LxError('bounds', 'map over too many items'); + chargeSize(ctx, coll.length); + const body = argNodes[1]!; + return coll.map((it, idx) => evalBody(body, ctx, { it, idx })); + } + case 'filter': { + const coll = asList(evalNode(argNodes[0]!, ctx)); + if (coll.length > MAX_ITERATIONS) throw new LxError('bounds', 'filter over too many items'); + chargeSize(ctx, coll.length); + const pred = argNodes[1]!; + return coll.filter((it, idx) => asBool(evalBody(pred, ctx, { it, idx }))); + } + case 'fold': { + const coll = asList(evalNode(argNodes[0]!, ctx)); + if (coll.length > MAX_ITERATIONS) throw new LxError('bounds', 'fold over too many items'); + burn(ctx, coll.length); + let acc = evalNode(argNodes[1]!, ctx); + const body = argNodes[2]!; + coll.forEach((it, idx) => { acc = evalBody(body, ctx, { acc, it, idx }); }); + return acc; + } + case 'len': { + const v = evalNode(argNodes[0]!, ctx); + if (Array.isArray(v)) return v.length; + if (typeof v === 'string') return v.length; + throw new LxError('type', 'len expects list or string'); + } + case 'min': return Math.min(...argNodes.map((a) => asNumber(evalNode(a, ctx)))); + case 'max': return Math.max(...argNodes.map((a) => asNumber(evalNode(a, ctx)))); + case 'clamp': { const [v, lo, hi] = argNodes.map((a) => asNumber(evalNode(a, ctx))) as [number, number, number]; return Math.min(hi, Math.max(lo, v)); } + case 'abs': return Math.abs(asNumber(evalNode(argNodes[0]!, ctx))); + case 'floor': return Math.floor(asNumber(evalNode(argNodes[0]!, ctx))); + case 'ceil': return Math.ceil(asNumber(evalNode(argNodes[0]!, ctx))); + case 'round': return Math.round(asNumber(evalNode(argNodes[0]!, ctx))); + case 'sqrt': { const x = asNumber(evalNode(argNodes[0]!, ctx)); if (x < 0) throw new LxError('bounds', 'sqrt of negative'); return Math.sqrt(x); } + case 'sign': return Math.sign(asNumber(evalNode(argNodes[0]!, ctx))); + case 'pow': { const [b, e] = binNum(argNodes, ctx); return fin(b ** e); } + case 'concat': { + const parts = argNodes.map((a) => evalNode(a, ctx)); + // require homogeneous args — all lists OR all strings (F9: no silent + // list→JSON-text coercion on a mixed call). + if (parts.every((p) => Array.isArray(p))) { + const total = (parts as LxValue[][]).reduce((s, p) => s + p.length, 0); + chargeSize(ctx, total); + return (parts as LxValue[][]).flat(); + } + if (parts.every((p) => typeof p === 'string')) { + const total = (parts as string[]).reduce((s, p) => s + p.length, 0); + chargeSize(ctx, total); + return (parts as string[]).join(''); + } + throw new LxError('type', 'concat expects all lists or all strings'); + } + case 'slice': { const list = asList(evalNode(argNodes[0]!, ctx)); const start = asNumber(evalNode(argNodes[1]!, ctx)); const end = argNodes[2] ? asNumber(evalNode(argNodes[2], ctx)) : list.length; return list.slice(start, end); } + case 'contains': { const list = asList(evalNode(argNodes[0]!, ctx)); const target = evalNode(argNodes[1]!, ctx); return list.some((x) => deepEqual(x, target)); } + case 'indexOf': { const list = asList(evalNode(argNodes[0]!, ctx)); const target = evalNode(argNodes[1]!, ctx); return list.findIndex((x) => deepEqual(x, target)); } + case 'keys': { const v = evalNode(argNodes[0]!, ctx); if (!isRecord(v)) throw new LxError('type', 'keys expects record'); return Object.keys(v); } + case 'values': { const v = evalNode(argNodes[0]!, ctx); if (!isRecord(v)) throw new LxError('type', 'values expects record'); return Object.values(v); } + case 'upper': return asString(evalNode(argNodes[0]!, ctx)).toUpperCase(); + case 'lower': return asString(evalNode(argNodes[0]!, ctx)).toLowerCase(); + case 'pad': { const s = asString(evalNode(argNodes[0]!, ctx)); const width = asNumber(evalNode(argNodes[1]!, ctx)); if (!Number.isInteger(width) || width < 0) throw new LxError('bounds', 'pad width must be a non-negative int'); chargeSize(ctx, width); const fill = argNodes[2] ? asString(evalNode(argNodes[2], ctx)) : ' '; return s.padStart(width, fill); } + case 'fmt': { const v = evalNode(argNodes[0]!, ctx); return typeof v === 'string' ? v : JSON.stringify(v); } + case 'random': return ctx.rng(); + case 'now': return ctx.now; + default: throw new LxError('unknown-call', `unknown std-lib call: ${name}`); + } +} + +/** Evaluate an LX expression to a value (used by `view`). */ +export function evaluate(node: LxNode, opts: EvalOptions): LxValue { + const ctx: Ctx = { + state: opts.state, + event: opts.event ?? {}, + env: {}, + now: opts.now ?? 0, + gas: { n: opts.gas ?? DEFAULT_GAS }, + depth: 0, + rng: mulberry32(opts.seed ?? 0), + }; + return evalNode(node, ctx); +} + +/** Run a transition `(state, event) -> state`. The result MUST be a record + * (the new state); otherwise the transition is invalid (§2.5). */ +export function runTransition(node: LxNode, opts: EvalOptions): StateValue { + const result = evaluate(node, opts); + if (!isRecord(result)) throw new LxError('type', 'a transition must return a state record'); + return result; +} diff --git a/app/src/renderer/src/lx/types.ts b/app/src/renderer/src/lx/types.ts new file mode 100644 index 0000000..5fb8f5f --- /dev/null +++ b/app/src/renderer/src/lx/types.ts @@ -0,0 +1,78 @@ +// VENDORED MIRROR of @omadia/canvas-core src/lx/types.ts — single source of +// truth is byte5ai/omadia middleware/packages/canvas-core. Keep in sync. +/** + * omadia-canvas-protocol/1.1 — Lume Expressions (LX) TypeScript types. + * Mirrors schema/lx-ast.schema.json and schema/lumen.schema.json. Where these + * and the schema disagree, the schema wins (the validator is the contract). + */ + +/** A runtime LX value: number (int|number), bool, string, list, record. */ +export type LxValue = number | boolean | string | LxValue[] | { [k: string]: LxValue }; + +/** The closed, serialisable state record a Lumen carries (§1.1). */ +export type StateValue = { [k: string]: LxValue }; + +/** A JSON AST node (§2.2). Validated structurally by the schema; this is the + * permissive TS shape the interpreter walks. */ +export type LxNode = + | { lit: LxValue } + | { state: string; at?: [LxNode, LxNode] } + | { event: string } + | { var: string } + | { let: Record; in: LxNode } + | { '+': LxNode[] } | { '-': LxNode[] } | { '*': LxNode[] } | { '/': [LxNode, LxNode] } | { mod: [LxNode, LxNode] } + | { '>': [LxNode, LxNode] } | { '>=': [LxNode, LxNode] } | { '<': [LxNode, LxNode] } | { '<=': [LxNode, LxNode] } | { '==': [LxNode, LxNode] } | { '!=': [LxNode, LxNode] } + | { and: LxNode[] } | { or: LxNode[] } | { not: LxNode } + | { if: LxNode; then: LxNode; else: LxNode } + | { match: LxNode; cases: { when: LxNode; then: LxNode }[]; else: LxNode } + | { record: Record } + | { list: LxNode[] } + | { get: LxNode; key: LxNode } + | { set: Record } + | { call: StdlibName; args: LxNode[] }; + +export type StdlibName = + | 'map' | 'filter' | 'fold' | 'range' | 'len' | 'min' | 'max' | 'clamp' + | 'abs' | 'floor' | 'ceil' | 'round' | 'sqrt' | 'sign' | 'pow' + | 'concat' | 'slice' | 'contains' | 'indexOf' | 'keys' | 'values' + | 'upper' | 'lower' | 'pad' | 'fmt' + | 'random' | 'now'; + +/** Host-seeded, bounded evaluation context (§0.3, §2.4). Identical + * (state, event, seed, now) ⇒ byte-identical result on every machine. */ +export interface EvalOptions { + state: StateValue; + event?: Record; + /** host seed for `random()` — same seed ⇒ same sequence (replay/share). */ + seed?: number; + /** host clock value returned by `now()` — fixed per evaluation. */ + now?: number; + /** instruction budget; default DEFAULT_GAS. Over budget ⇒ LxError('gas'). */ + gas?: number; +} + +export type LxErrorCode = 'gas' | 'type' | 'unknown-node' | 'unknown-call' | 'bad-path' | 'bounds' | 'div-zero' | 'arity'; + +export class LxError extends Error { + constructor( + public code: LxErrorCode, + message: string, + ) { + super(message); + this.name = 'LxError'; + } +} + +/** lumens-spec.md §2.4 — spike-tunable initial defaults. */ +export const DEFAULT_GAS = 50_000; +/** §0.2 — bounded iteration: a single collection op may not exceed this. */ +export const MAX_ITERATIONS = 100_000; +/** §2.3 — `range(n)` upper bound (gas also bounds it). */ +export const MAX_RANGE = 100_000; +/** §0.2 — hard ceiling on any single produced value (list length / string + * length / record keys). Stops size-amplifying ops (concat-doubling, pad, + * map-over-range) from exploding memory while gas stays low. */ +export const MAX_VALUE_SIZE = 1_000_000; +/** §0.2 — max AST recursion depth; a deeper tree halts with LxError before it + * can overflow the JS stack (which would be an uncatchable RangeError). */ +export const MAX_DEPTH = 1_024; diff --git a/app/src/renderer/src/lx/validate.ts b/app/src/renderer/src/lx/validate.ts new file mode 100644 index 0000000..e73a50d --- /dev/null +++ b/app/src/renderer/src/lx/validate.ts @@ -0,0 +1,127 @@ +// VENDORED MIRROR of @omadia/canvas-core src/lx/validate.ts — single source of +// truth is byte5ai/omadia middleware/packages/canvas-core. Keep in sync. +/** + * omadia-canvas-protocol/1.1 — LX static semantic validator (lumens-spec.md §2.5). + * + * The structural whitelist lives in the JSON schema (validateLumen). This layer + * adds the semantics JSON Schema cannot express: + * - every EventBinding.run names a declared transition (§4), + * - every `state`/`set` path resolves against the declared state schema (§1.1), + * - every `{var}` read is lexically bound (a `let`, or an iteration binding), + * - tick/timer bindings declare the field their `on` requires. + * A Lumen is accepted only if BOTH layers pass; either failure ⇒ surface_error. + */ +import { MAX_DEPTH, type LxNode } from './types.js'; + +export interface SemanticResult { + ok: boolean; + errors: string[]; +} + +type StateLeaf = { type: string; fields?: Record; of?: StateLeaf }; +type StateSchema = Record; + +interface LumenShape { + state: StateSchema; + transitions: Record; + view: LxNode; + events: { on: string; run: string; rate?: number; everyMs?: number; key?: string }[]; +} + +/** Does a dotted path resolve through the declared state schema? */ +function pathResolves(schema: StateSchema, path: string): boolean { + const segs = path.split('.'); + let leaf: StateLeaf | undefined = schema[segs[0]!]; + for (let i = 1; i < segs.length && leaf; i++) { + if (leaf.type === 'record' && leaf.fields) leaf = leaf.fields[segs[i]!]; + else if ((leaf.type === 'list' || leaf.type === 'grid') && leaf.of) leaf = leaf.of; // index/sub-field + else return false; + } + return leaf !== undefined; +} + +/** Walk an LX node, collecting path + var-scope errors. `scope` is the set of + * lexically-bound names in effect at this node. */ +function walk(node: LxNode, schema: StateSchema, scope: Set, errors: string[], depth = 0): void { + if (node === null || typeof node !== 'object') return; + // bound recursion (F4) — a deeply-nested tree would overflow the stack on the + // validator's own pass before the interpreter ever ran. + if (depth > MAX_DEPTH) { + errors.push('expression nesting too deep'); + return; + } + const d = depth + 1; + const n = node as Record; + + if ('state' in n && typeof n.state === 'string') { + if (!pathResolves(schema, n.state)) errors.push(`state path '${n.state}' does not resolve against the state schema`); + if (Array.isArray(n.at)) for (const e of n.at) walk(e as LxNode, schema, scope, errors, d); + return; + } + if ('var' in n && typeof n.var === 'string') { + if (!scope.has(n.var)) errors.push(`unbound var '${n.var}'`); + return; + } + if ('let' in n && n.let && typeof n.let === 'object') { + const binding = n.let as Record; + const [name] = Object.keys(binding); + walk(binding[name!]!, schema, scope, errors, d); + walk(n.in as LxNode, schema, new Set([...scope, name!]), errors, d); + return; + } + if ('set' in n && n.set && typeof n.set === 'object') { + for (const [path, e] of Object.entries(n.set as Record)) { + if (!pathResolves(schema, path)) errors.push(`set path '${path}' does not resolve against the state schema`); + walk(e, schema, scope, errors, d); + } + return; + } + if ('call' in n && Array.isArray(n.args)) { + const fn = n.call; + // map/filter bind it/idx in arg[1]; fold binds acc/it/idx in arg[2]. The + // interpreter binds `acc` ONLY for fold, so the validator must too (F6) — + // else {var:acc} in a map body passes validation but throws at runtime. + const mapScope = new Set([...scope, 'it', 'idx']); + const foldScope = new Set([...scope, 'it', 'idx', 'acc']); + n.args.forEach((arg, i) => { + const bodyScope = + (fn === 'map' || fn === 'filter') && i === 1 ? mapScope : fn === 'fold' && i === 2 ? foldScope : scope; + walk(arg as LxNode, schema, bodyScope, errors, d); + }); + return; + } + + // generic recursion over any nested node/array values + for (const value of Object.values(n)) { + if (Array.isArray(value)) for (const v of value) walk(v as LxNode, schema, scope, errors, d); + else if (value && typeof value === 'object') walk(value as LxNode, schema, scope, errors, d); + } +} + +/** Validate the semantic layer of an already structurally-valid Lumen. */ +export function validateLumenSemantics(lumen: unknown): SemanticResult { + const errors: string[] = []; + const l = lumen as Partial; + const schema = (l.state ?? {}) as StateSchema; + const transitions = (l.transitions ?? {}) as Record; + const transitionNames = new Set(Object.keys(transitions)); + + for (const [name, body] of Object.entries(transitions)) { + const sub: string[] = []; + walk(body, schema, new Set(), sub); + for (const e of sub) errors.push(`transition '${name}': ${e}`); + } + if (l.view) { + const sub: string[] = []; + walk(l.view, schema, new Set(), sub); + for (const e of sub) errors.push(`view: ${e}`); + } + for (const ev of l.events ?? []) { + if (!transitionNames.has(ev.run)) errors.push(`event '${ev.on}' runs undeclared transition '${ev.run}'`); + if (ev.on === 'tick' && ev.rate === undefined) errors.push(`tick event must declare a 'rate'`); + if (ev.on === 'timer' && ev.everyMs === undefined) errors.push(`timer event must declare 'everyMs'`); + if (ev.on === 'key' && ev.key === undefined) errors.push(`key event must declare a 'key'`); + } + + return { ok: errors.length === 0, errors }; +} diff --git a/app/src/renderer/src/render/PrimitiveNode.tsx b/app/src/renderer/src/render/PrimitiveNode.tsx index 8cc2e00..ba47653 100644 --- a/app/src/renderer/src/render/PrimitiveNode.tsx +++ b/app/src/renderer/src/render/PrimitiveNode.tsx @@ -3,6 +3,8 @@ import { ChoiceNode, InputNode, ToggleNode } from './controlNodes.js'; import { ChartNode, TreePrimitiveNode } from './dataNodes.js'; import { CanvasRegionNode, MediaNode, TimelineNode, VectorPathNode } from './editorNodes.js'; import { CanvasFormContext, createCanvasFormStore, useCanvasForm } from './formContext.js'; +import { SceneNode } from './SceneNode.js'; +import { LumenNode } from './lumen/LumenNode.js'; /** A validated primitive-tree node. The Ajv whitelist runs BEFORE render; * this component trusts the shape but still fails soft on the unexpected. */ @@ -448,6 +450,14 @@ function renderNode(node: PrimitiveJson, ctx: Omit, root case 'divider': return
; + // omadia-canvas-protocol/1.1 — the `scene` primitive (Lumens, §3). + case 'scene': + return ; + + // omadia-canvas-protocol/1.1 — the `lumen` primitive (Live Interactivity, §1). + case 'lumen': + return ; + default: // Unreachable for validated trees — defensive, never throws mid-render. return
unsupported primitive: {node.type}
; diff --git a/app/src/renderer/src/render/SceneNode.tsx b/app/src/renderer/src/render/SceneNode.tsx new file mode 100644 index 0000000..0d2ac9a --- /dev/null +++ b/app/src/renderer/src/render/SceneNode.tsx @@ -0,0 +1,63 @@ +import { useEffect, useRef, type ReactNode } from 'react'; +import type { PrimitiveAction } from './PrimitiveNode.js'; +import { rasterizeScene } from './scene/rasterize.js'; +import { makeTokenResolver } from './scene/tokens.js'; +import { clientToBuffer, hitTestScene } from './scene/hitTest.js'; +import type { Scene } from './scene/types.js'; + +/** + * omadia-canvas-protocol/1.1 — the `scene` primitive renderer (lumens-spec.md §3). + * + * Rasterises the validated draw-list onto a real canvas (Class A — local, up to + * 60 fps, no per-frame server contact) and turns a pointer-down into a + * `scene-hit` action carrying the topmost node id (a TargetRef). The event → + * LX-transition wiring (running the interpreter on the hit) is layered on in + * L3/L4; this component is the seam. + */ +interface SceneProps { + node: { type: string; [key: string]: unknown }; + onAction: (action: PrimitiveAction) => void; +} + +export function SceneNode({ node, onAction }: SceneProps): ReactNode { + const scene = node as unknown as Scene; + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + const ctx = canvas.getContext('2d'); + if (!ctx) return; + const dpr = window.devicePixelRatio || 1; + canvas.width = Math.max(1, Math.round(scene.width * dpr)); + canvas.height = Math.max(1, Math.round(scene.height * dpr)); + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + ctx.clearRect(0, 0, scene.width, scene.height); + rasterizeScene(ctx, scene, makeTokenResolver(canvas)); + }, [node]); + + const handlePointerDown = (e: React.PointerEvent): void => { + const canvas = canvasRef.current; + if (!canvas) return; + const rect = canvas.getBoundingClientRect(); + const buf = clientToBuffer(scene, { x: e.clientX, y: e.clientY }, rect); + const nodeId = hitTestScene(scene, buf.x, buf.y); + if (nodeId === null) return; + onAction({ + type: 'scene-hit', + payload: { sceneId: scene.id, nodeId, x: buf.x, y: buf.y }, + sourceId: typeof scene.id === 'string' ? scene.id : undefined, + }); + }; + + return ( + + ); +} diff --git a/app/src/renderer/src/render/lumen/LumenNode.tsx b/app/src/renderer/src/render/lumen/LumenNode.tsx new file mode 100644 index 0000000..a4a868a --- /dev/null +++ b/app/src/renderer/src/render/lumen/LumenNode.tsx @@ -0,0 +1,90 @@ +import { useEffect, useMemo, useRef, type ReactNode } from 'react'; +import { PrimitiveNode, type PrimitiveAction, type PrimitiveJson } from '../PrimitiveNode.js'; +import { validateLumen } from '../../validate/validator.js'; +import { validateLumenSemantics } from '../../lx/validate.js'; +import { useLumen } from './useLumen.js'; +import { matchTransition, type LumenSpec } from './lumenRuntime.js'; + +/** + * omadia-canvas-protocol/1.1 — the `lumen` primitive renderer (lumens-spec.md §1). + * + * Validates the Lumen (structural whitelist + semantic layer), then runs it on + * Tier 1 via useLumen: the evaluated `view` renders through the ordinary + * PrimitiveNode pipeline (so a Lumen composes scenes + primitives), and child + * actions are translated into Tier-1 events that drive the Lumen's transitions. + * A Lumen that fails validation or halts (gas/bounds) renders an error chip and + * never partially renders (§1) — and never takes down the canvas (§0.2). + */ +interface LumenProps { + node: { type: string; [key: string]: unknown }; + /** escalation hook to the host (Tier 2) for capability events, beams, etc. */ + onAction: (action: PrimitiveAction) => void; +} + +export function LumenNode({ node, onAction }: LumenProps): ReactNode { + const validation = useMemo(() => { + const structural = validateLumen(node); + if (!structural.ok) return { ok: false, error: structural.errors ?? 'invalid Lumen' }; + const semantic = validateLumenSemantics(node); + if (!semantic.ok) return { ok: false, error: semantic.errors.join('; ') }; + return { ok: true, error: null }; + }, [node]); + + if (!validation.ok) { + return ( +
+ invalid Lumen: {validation.error} +
+ ); + } + return ; +} + +function LiveLumen({ lumen, onAction }: { lumen: LumenSpec; onAction: (a: PrimitiveAction) => void }): ReactNode { + const { tree, dispatch, error } = useLumen(lumen); + const rootRef = useRef(null); + + // declared key events → Tier-1 key dispatch (touch equivalents come via taps). + const hasKeyEvent = useMemo(() => lumen.events.some((e) => e.on === 'key'), [lumen]); + useEffect(() => { + if (!hasKeyEvent) return; + const el = rootRef.current; + if (!el) return; + const onKey = (e: KeyboardEvent): void => { + dispatch({ on: 'key', key: e.key, payload: { key: e.key } }); + }; + el.addEventListener('keydown', onKey); + return () => el.removeEventListener('keydown', onKey); + }, [hasKeyEvent, dispatch]); + + // child primitive/scene actions → Tier-1 events that drive transitions. + const handleChildAction = (action: PrimitiveAction): void => { + if (action.type === 'scene-hit') { + const payload = (action.payload ?? {}) as { nodeId?: string; x?: number; y?: number }; + dispatch({ on: 'tap', targetId: payload.nodeId, payload: { id: payload.nodeId ?? '', x: payload.x ?? 0, y: payload.y ?? 0 } }); + return; + } + // a button/choice/etc. inside the Lumen view is a tap on its source id — + // but only if the Lumen declares a matching binding. Anything it does not + // consume bubbles to the host (Tier 2) for capability/host handling (§6). + if (matchTransition(lumen.events, { on: 'tap', targetId: action.sourceId }) !== null) { + dispatch({ on: 'tap', targetId: action.sourceId, payload: { value: (action.payload ?? null) as never } }); + } else { + onAction(action); + } + }; + + if (error !== null) { + return ( +
+ Lumen halted: {error} +
+ ); + } + + return ( +
+ {tree !== null && } +
+ ); +} diff --git a/app/src/renderer/src/render/lumen/dirty.ts b/app/src/renderer/src/render/lumen/dirty.ts new file mode 100644 index 0000000..3fa6cbc --- /dev/null +++ b/app/src/renderer/src/render/lumen/dirty.ts @@ -0,0 +1,79 @@ +/** + * omadia-canvas-protocol/1.1 — per-region dirty-tracking (lumens-spec.md §5). + * + * The runtime dirty-tracks changed state slices and re-evaluates only the view + * branches that depend on them (retained-mode + memoisation). At rest a Lumen + * costs ~0% CPU. Pure (no DOM): collect the state paths a view branch reads, + * diff old→new state, and re-evaluate a region only when its reads intersect the + * change set. Conservative (top-level diff + prefix match) ⇒ never stale. + */ +import type { LxNode, LxValue, StateValue } from '../../lx/index.js'; + +/** All state paths an LX expression reads (the `{state:path}` leaves). */ +export function collectStateReads(node: LxNode, acc: Set = new Set()): Set { + if (node === null || typeof node !== 'object') return acc; + const n = node as Record; + if (typeof n.state === 'string') { + acc.add(n.state); + if (Array.isArray(n.at)) for (const e of n.at) collectStateReads(e as LxNode, acc); + return acc; + } + for (const v of Object.values(n)) { + if (Array.isArray(v)) for (const e of v) collectStateReads(e as LxNode, acc); + else if (v && typeof v === 'object') collectStateReads(v as LxNode, acc); + } + return acc; +} + +const eq = (a: LxValue, b: LxValue): boolean => JSON.stringify(a) === JSON.stringify(b); + +/** Top-level state keys whose value changed between two states. Conservative: + * a changed record key marks the whole key dirty (prefix-covers its fields). */ +export function changedStatePaths(prev: StateValue, next: StateValue): Set { + const changed = new Set(); + for (const k of new Set([...Object.keys(prev), ...Object.keys(next)])) { + if (!eq(prev[k] as LxValue, next[k] as LxValue)) changed.add(k); + } + return changed; +} + +const pathsOverlap = (read: string, changed: string): boolean => + read === changed || read.startsWith(`${changed}.`) || changed.startsWith(`${read}.`); + +/** Does a region (its set of reads) need re-evaluation given the change set? */ +export function isDirty(reads: Set, changed: Set): boolean { + for (const r of reads) for (const c of changed) if (pathsOverlap(r, c)) return true; + return false; +} + +interface MemoEntry { + reads: Set; + value: LxValue; +} + +/** Memoises evaluated view regions by stable id; re-evaluates a region only + * when the state it reads changed (§5). `static` regions (no reads) are + * evaluated once and never again. */ +export class RegionMemo { + private readonly cache = new Map(); + + /** Return the region's value, re-evaluating only if its reads are dirty. */ + evaluate(regionId: string, node: LxNode, changed: Set, evalFn: (n: LxNode) => LxValue): LxValue { + const cached = this.cache.get(regionId); + if (cached && !isDirty(cached.reads, changed)) return cached.value; + const reads = collectStateReads(node); + const value = evalFn(node); + this.cache.set(regionId, { reads, value }); + return value; + } + + /** Number of regions currently memoised (for tests/diagnostics). */ + get size(): number { + return this.cache.size; + } + + invalidate(regionId?: string): void { + if (regionId === undefined) this.cache.clear(); + else this.cache.delete(regionId); + } +} diff --git a/app/src/renderer/src/render/lumen/lumenRuntime.ts b/app/src/renderer/src/render/lumen/lumenRuntime.ts new file mode 100644 index 0000000..447997f --- /dev/null +++ b/app/src/renderer/src/render/lumen/lumenRuntime.ts @@ -0,0 +1,135 @@ +/** + * omadia-canvas-protocol/1.1 — Lumen runtime (Tier 1, lumens-spec.md §1,§2,§4,§5). + * + * Pure, React-free core that the useLumen hook drives. Initialises state from + * the declared schema, maps a pointer/key/tick event to its transition, runs it + * through the vendored LX interpreter (deterministic, gas-bounded), and + * evaluates the `view` to a primitive/scene tree. No DOM here — unit-testable. + */ +import { evaluate, runTransition, type LxNode, type LxValue, type StateValue } from '../../lx/index.js'; + +interface StateLeaf { + type: string; + init?: unknown; + values?: string[]; + fields?: Record; + of?: StateLeaf; + w?: number; + h?: number; + // client-checkable bounds (enforced by the schema/validator, not initState) + min?: number; + max?: number; + maxLength?: number; + maxLen?: number; +} + +export interface EventBinding { + on: 'tap' | 'longPress' | 'drag' | 'pinch' | 'swipe' | 'pointerMove' | 'key' | 'tick' | 'timer' | 'wire'; + target?: { kind?: string; elementId?: string }; + key?: string; + rate?: number; + everyMs?: number; + run: string; +} + +export interface LumenSpec { + type: 'lumen'; + id: string; + state: Record; + transitions: Record; + view: LxNode; + events: EventBinding[]; + cadence?: 'static' | 'reactive' | { tick: number }; +} + +/** Build the initial value for one state leaf (§1.1). */ +function initLeaf(leaf: StateLeaf): LxValue { + if (leaf.init !== undefined) return leaf.init as LxValue; + switch (leaf.type) { + case 'int': + case 'number': + return 0; + case 'bool': + return false; + case 'string': + return ''; + case 'enum': + return leaf.values?.[0] ?? ''; + case 'list': + return []; + case 'record': + return leaf.fields ? initState(leaf.fields) : {}; + case 'grid': { + const w = leaf.w ?? 0; + const h = leaf.h ?? 0; + const cell = leaf.of ? initLeaf(leaf.of) : 0; + return Array.from({ length: h }, () => Array.from({ length: w }, () => cell)); + } + case 'dataRef': + default: + return null as unknown as LxValue; + } +} + +/** Initialise the full state record from its schema. */ +export function initState(schema: Record): StateValue { + const out: StateValue = {}; + for (const [key, leaf] of Object.entries(schema)) out[key] = initLeaf(leaf); + return out; +} + +export interface EventInput { + on: EventBinding['on']; + targetId?: string; + key?: string; + payload?: Record; +} + +/** Find the transition an event should run, honouring target/key matching. */ +export function matchTransition(events: EventBinding[], input: EventInput): string | null { + for (const b of events) { + if (b.on !== input.on) continue; + if (b.on === 'key' && b.key !== undefined && b.key !== input.key) continue; + if (b.target?.elementId !== undefined && b.target.elementId !== input.targetId) continue; + return b.run; + } + return null; +} + +export interface RunContext { + now: number; + seed: number; + gas?: number; +} + +/** Apply an event: returns the new state, or the SAME reference if no binding + * matched (lets the caller skip a re-render). Throws LxError on a runaway + * transition (caller surfaces surface_error and halts the Lumen). */ +export function applyEvent(lumen: LumenSpec, state: StateValue, input: EventInput, ctx: RunContext): StateValue { + const run = matchTransition(lumen.events, input); + if (run === null) return state; + const transition = lumen.transitions[run]; + if (!transition) return state; + return runTransition(transition, { state, event: input.payload ?? {}, now: ctx.now, seed: ctx.seed, gas: ctx.gas }); +} + +/** Evaluate the Lumen `view` to a primitive/scene tree. */ +export function evalView(lumen: LumenSpec, state: StateValue, ctx: RunContext): LxValue { + return evaluate(lumen.view, { state, now: ctx.now, seed: ctx.seed, gas: ctx.gas }); +} + +/** Deliver a resolved wire value to an `in` port (§7): dispatches an `on:'wire'` + * event carrying { port, value } so the matched transition can read it via + * {event:'value'} / {event:'port'}. The host computes the value with + * resolveWires (wires.ts); this is how cross-element interaction reaches a + * Lumen's state, deterministically and without a turn. */ +export function applyWireInput(lumen: LumenSpec, state: StateValue, port: string, value: LxValue, ctx: RunContext): StateValue { + return applyEvent(lumen, state, { on: 'wire', payload: { port, value } }, ctx); +} + +/** The tick rate (Hz) if this Lumen has a ticking cadence, else null. */ +export function tickRate(lumen: LumenSpec): number | null { + const c = lumen.cadence; + if (c && typeof c === 'object' && typeof c.tick === 'number') return c.tick; + return null; +} diff --git a/app/src/renderer/src/render/lumen/useLumen.ts b/app/src/renderer/src/render/lumen/useLumen.ts new file mode 100644 index 0000000..83f96df --- /dev/null +++ b/app/src/renderer/src/render/lumen/useLumen.ts @@ -0,0 +1,92 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import type { LxValue, StateValue } from '../../lx/index.js'; +import { LxError } from '../../lx/index.js'; +import { applyEvent, evalView, initState, tickRate, type EventInput, type LumenSpec } from './lumenRuntime.js'; + +/** Stable, deterministic per-Lumen seed (FNV-1a over the id) so `random()` + * replays identically for the same Lumen (§0.3). */ +function seedFromId(id: string): number { + let h = 0x811c9dc5; + for (let i = 0; i < id.length; i++) { + h ^= id.charCodeAt(i); + h = Math.imul(h, 0x01000193); + } + return h >>> 0; +} + +export interface LumenHandle { + /** the current evaluated primitive/scene tree, or null while halted on error. */ + tree: LxValue | null; + /** dispatch a Tier-1 event → runs its transition → re-renders. */ + dispatch: (input: EventInput) => void; + /** surface_error message if the Lumen halted (gas/type/bounds), else null. */ + error: string | null; +} + +/** Drives a Lumen on Tier 1: holds state, evaluates the view reactively, runs + * transitions on events, and schedules a `tick` cadence via rAF (and only + * while ticking — at rest the Lumen costs ~0% CPU, §5). */ +export function useLumen(lumen: LumenSpec): LumenHandle { + const seed = useMemo(() => seedFromId(lumen.id), [lumen.id]); + const [state, setState] = useState(() => initState(lumen.state)); + const [error, setError] = useState(null); + + // re-init when the Lumen identity changes (a different Lumen mounted here). + useEffect(() => { + setState(initState(lumen.state)); + setError(null); + }, [lumen]); + + const now = useCallback(() => (typeof performance !== 'undefined' ? performance.now() : Date.now()), []); + + const dispatch = useCallback( + (input: EventInput) => { + setState((prev) => { + try { + return applyEvent(lumen, prev, input, { now: now(), seed }); + } catch (e) { + setError(e instanceof LxError ? `${e.code}: ${e.message}` : String(e)); + return prev; + } + }); + }, + [lumen, seed, now], + ); + + // tick cadence — rAF loop with a timestamp accumulator to hit the declared Hz. + const rate = tickRate(lumen); + useEffect(() => { + if (rate === null || error !== null) return; + const periodMs = 1000 / rate; + let raf = 0; + let last = now(); + let acc = 0; + const frame = (): void => { + const t = now(); + acc += t - last; + last = t; + // run at most a few catch-up ticks to avoid a death spiral after a stall. + let budget = 4; + while (acc >= periodMs && budget-- > 0) { + acc -= periodMs; + dispatch({ on: 'tick' }); + } + raf = requestAnimationFrame(frame); + }; + raf = requestAnimationFrame(frame); + return () => cancelAnimationFrame(raf); + }, [rate, error, dispatch, now]); + + const tree = useMemo(() => { + if (error !== null) return null; + try { + return evalView(lumen, state, { now: now(), seed }); + } catch (e) { + // a bad view halts the Lumen, never the canvas (§0.2). + queueMicrotask(() => setError(e instanceof LxError ? `${e.code}: ${e.message}` : String(e))); + return null; + } + }, [lumen, state, error, seed, now]); + + return { tree, dispatch, error }; +} diff --git a/app/src/renderer/src/render/lumen/wires.ts b/app/src/renderer/src/render/lumen/wires.ts new file mode 100644 index 0000000..607665b --- /dev/null +++ b/app/src/renderer/src/render/lumen/wires.ts @@ -0,0 +1,118 @@ +/** + * omadia-canvas-protocol/1.1 — ports, expose & wires (lumens-spec.md §7). + * + * Tier-1 cross-element interaction, resolved deterministically by stable id. + * Pure (no DOM/React) so it is unit-testable and replayable: + * - a node's `out` port routes to another's `in` port via a declared `wire`; + * - an element may publish a read-only `expose` interface a neighbour reads + * by name — but ONLY what was exposed (least-privilege; un-exposed state is + * unreadable, so an imported element sees no ambient neighbour state). + * Wires/expose are declared data, whitelist-validated, and resolve by id ⇒ + * deterministic, shared-canvas-safe. The agent owns which wires/interfaces + * exist; the client owns the values flowing through them (authority split). + */ +export type PortType = 'selection' | 'viewport' | 'int' | 'number' | 'bool' | 'string' | 'enum' | 'list' | 'record' | 'grid' | 'dataRef' | 'any'; + +export interface PortSpec { + name: string; + dir: 'in' | 'out'; + type: PortType; +} +export interface ExposeSpec { + name: string; + type: PortType; +} +export interface TargetRef { + kind?: string; + elementId?: string; +} +export interface Wire { + from: { ref: TargetRef; port: string }; + to: { ref: TargetRef; port: string }; +} + +/** What a single canvas element declares for wiring. */ +export interface WireableElement { + ports?: PortSpec[]; + expose?: ExposeSpec[]; +} + +export interface WireValidation { + ok: boolean; + errors: string[]; +} + +const portKey = (elementId: string, port: string): string => `${elementId}.${port}`; + +function typesCompatible(a: PortType, b: PortType): boolean { + return a === b || a === 'any' || b === 'any'; +} + +/** Static validation of a wire graph against the elements' declarations (§7). + * A wire is valid iff: both refs resolve to known elements; the source offers + * the port as an `out` port OR an `expose` field; the target declares it as an + * `in` port; and the types are compatible. */ +export function validateWireGraph(elements: Record, wires: Wire[]): WireValidation { + const errors: string[] = []; + const seenTargets = new Set(); + + for (const wire of wires) { + const fromId = wire.from.ref.elementId; + const toId = wire.to.ref.elementId; + if (!fromId || !elements[fromId]) { errors.push(`wire source element '${fromId ?? '?'}' is unknown`); continue; } + if (!toId || !elements[toId]) { errors.push(`wire target element '${toId ?? '?'}' is unknown`); continue; } + + const src = elements[fromId]!; + const dst = elements[toId]!; + const outPort = src.ports?.find((p) => p.dir === 'out' && p.name === wire.from.port); + const exposed = src.expose?.find((e) => e.name === wire.from.port); + const sourceType = outPort?.type ?? exposed?.type; + if (sourceType === undefined) { + errors.push(`'${fromId}' offers no out-port or expose named '${wire.from.port}'`); + continue; + } + const inPort = dst.ports?.find((p) => p.dir === 'in' && p.name === wire.to.port); + if (!inPort) { + errors.push(`'${toId}' has no in-port named '${wire.to.port}'`); + continue; + } + if (!typesCompatible(sourceType, inPort.type)) { + errors.push(`wire ${portKey(fromId, wire.from.port)} (${sourceType}) → ${portKey(toId, wire.to.port)} (${inPort.type}): incompatible types`); + } + const targetKey = portKey(toId, wire.to.port); + if (seenTargets.has(targetKey)) errors.push(`in-port ${targetKey} is driven by more than one wire`); + seenTargets.add(targetKey); + } + + return { ok: errors.length === 0, errors }; +} + +/** Propagate source out/expose values across the wires to the target in-ports. + * `outValues` is keyed by `${elementId}.${port}`; returns the in-port values + * keyed the same way. Unconnected/absent sources simply don't appear. */ +export function resolveWires(wires: Wire[], outValues: Record): Record { + const inValues: Record = {}; + for (const wire of wires) { + const fromId = wire.from.ref.elementId; + const toId = wire.to.ref.elementId; + if (!fromId || !toId) continue; + const sourceKey = portKey(fromId, wire.from.port); + if (!Object.prototype.hasOwnProperty.call(outValues, sourceKey)) continue; + inValues[portKey(toId, wire.to.port)] = outValues[sourceKey]; + } + return inValues; +} + +/** Least-privilege read of a neighbour's published view-state (§7). Returns the + * value ONLY if `elementId` actually `expose`d a field of that name; otherwise + * undefined — un-exposed state stays private even to a same-id reader. */ +export function readExposed( + elements: Record, + published: Record>, + elementId: string, + name: string, +): unknown { + const declares = elements[elementId]?.expose?.some((e) => e.name === name); + if (!declares) return undefined; + return published[elementId]?.[name]; +} diff --git a/app/src/renderer/src/render/scene/animate.ts b/app/src/renderer/src/render/scene/animate.ts new file mode 100644 index 0000000..1fbc99d --- /dev/null +++ b/app/src/renderer/src/render/scene/animate.ts @@ -0,0 +1,91 @@ +/** + * omadia-canvas-protocol/1.1 — declarative animation layer (lumens-spec.md §5). + * + * Presentation motion (fade, glow-pulse, count-up, camera ease, Ken-Burns, + * parallax) is DECLARATIVE — the host runs it, ZERO LX per frame. Only + * *simulation* (state evolving by rules) is an LX `tick`. Easing/durations come + * from the Lume motion tokens (visual-spec.md §2.11). `prefers-reduced-motion` + * collapses animations to their final value. This module is the pure + * interpolation core (no DOM) so it is unit-testable and deterministic. + */ +export type Easing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'standard' | 'emphasis'; + +export interface Animate { + property: string; // e.g. 'opacity', 'glow', 'scale', 'x', 'camera.zoom' + from: number; + to: number; + durationMs: number; + easing?: Easing; + /** true = loop forever; a number = that many cycles; absent/false = one-shot. */ + repeat?: boolean | number; + delayMs?: number; +} + +/** Pure easing functions on a normalised t ∈ [0,1]. The Lume tokens map onto + * these shapes; the real cubic-beziers live in CSS for the GPU path, but the + * same monotonic shape is used here for headless sampling. */ +const EASINGS: Record number> = { + linear: (t) => t, + 'ease-in': (t) => t * t, + 'ease-out': (t) => 1 - (1 - t) * (1 - t), + 'ease-in-out': (t) => (t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)), + standard: (t) => (t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)), // --lume-ease-standard + emphasis: (t) => 1 - (1 - t) * (1 - t), // --lume-ease-emphasis (decelerate) +}; + +/** The CSS timing-function var for the GPU path (visual-spec §2.11). */ +export function cssTimingFunction(easing: Easing = 'standard'): string { + if (easing === 'standard') return 'var(--lume-ease-standard, ease)'; + if (easing === 'emphasis') return 'var(--lume-ease-emphasis, ease-out)'; + return easing; +} + +const clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t); + +export interface Sample { + value: number; + done: boolean; +} + +/** Sample an animation's property value at `elapsedMs` since it began. + * reduced-motion collapses instantly to the final value (done). */ +export function sampleAnimation(anim: Animate, elapsedMs: number, opts: { reducedMotion?: boolean } = {}): Sample { + if (opts.reducedMotion) return { value: anim.to, done: true }; + const delay = anim.delayMs ?? 0; + if (elapsedMs < delay) return { value: anim.from, done: false }; + + const local = elapsedMs - delay; + const dur = Math.max(1, anim.durationMs); + const ease = EASINGS[anim.easing ?? 'standard']; + + const infinite = anim.repeat === true; + const cycles = typeof anim.repeat === 'number' ? Math.max(1, anim.repeat) : 1; + const totalDur = dur * (infinite ? Infinity : cycles); + + if (!infinite && local >= totalDur) return { value: anim.to, done: true }; + + const phase = clamp01((local % dur) / dur); + const eased = ease(phase); + return { value: anim.from + (anim.to - anim.from) * eased, done: false }; +} + +/** The collapsed value under reduced motion (visual-spec §2.11). */ +export function reducedMotionValue(anim: Animate): number { + return anim.to; +} + +/** Translate an Animate descriptor to a GPU/CSS transition descriptor — the + * production path (zero JS per frame). Under reduced motion the transition is + * dropped and only the final value is applied. */ +export function animateToCss( + anim: Animate, + opts: { reducedMotion?: boolean } = {}, +): { value: number; transition: string | null } { + if (opts.reducedMotion) return { value: anim.to, transition: null }; + const iter = anim.repeat === true ? 'infinite' : typeof anim.repeat === 'number' ? String(anim.repeat) : '1'; + const delay = anim.delayMs ? ` ${anim.delayMs}ms` : ''; + return { + value: anim.to, + transition: `${anim.property} ${anim.durationMs}ms ${cssTimingFunction(anim.easing)}${delay}` + (iter !== '1' ? ` /* x${iter} */` : ''), + }; +} diff --git a/app/src/renderer/src/render/scene/hitTest.ts b/app/src/renderer/src/render/scene/hitTest.ts new file mode 100644 index 0000000..335f3a7 --- /dev/null +++ b/app/src/renderer/src/render/scene/hitTest.ts @@ -0,0 +1,144 @@ +/** + * omadia-canvas-protocol/1.1 — buffer-native scene hit-testing (lumens-spec.md §3, §4). + * + * Maps a buffer-native point → the stable `id` of the topmost drawn node that + * contains it. That id is a TargetRef (`{kind:'element', elementId}`) for beams, + * events (§4) and wires (§7). Pure geometry — no DOM — so it is unit-testable + * and identical on every renderer. Interactive nodes inherit a ≥44pt hit area + * regardless of drawn glyph size (Apple HIG, §4). + */ +import { MIN_HIT_TARGET, type Scene, type SceneNode, type SceneTransform } from './types.js'; + +interface Pt { + x: number; + y: number; +} + +/** Inverse-map a parent-space point into a group's local space. The group + * transform applies translate → scale → rotate to children; we undo in + * reverse: untranslate, unrotate, unscale. */ +function toLocal(p: Pt, t: SceneTransform | undefined): Pt { + if (!t) return p; + let { x, y } = { x: p.x - (t.x ?? 0), y: p.y - (t.y ?? 0) }; + const rot = t.rotate ?? 0; + if (rot) { + const rad = (-rot * Math.PI) / 180; + const cos = Math.cos(rad); + const sin = Math.sin(rad); + [x, y] = [x * cos - y * sin, x * sin + y * cos]; + } + const s = t.scale ?? 1; + if (s !== 1 && s !== 0) { + x /= s; + y /= s; + } + return { x, y }; +} + +function dist(ax: number, ay: number, bx: number, by: number): number { + return Math.hypot(ax - bx, ay - by); +} + +/** Distance from point to segment [a,b]. */ +function distToSegment(p: Pt, ax: number, ay: number, bx: number, by: number): number { + const dx = bx - ax; + const dy = by - ay; + const len2 = dx * dx + dy * dy; + if (len2 === 0) return dist(p.x, p.y, ax, ay); + let t = ((p.x - ax) * dx + (p.y - ay) * dy) / len2; + t = Math.max(0, Math.min(1, t)); + return dist(p.x, p.y, ax + t * dx, ay + t * dy); +} + +/** Inflate a bbox so its smaller side reaches MIN_HIT_TARGET (centred). */ +function withMinTarget(min: Pt, max: Pt): { min: Pt; max: Pt } { + const grow = (lo: number, hi: number) => { + const need = MIN_HIT_TARGET - (hi - lo); + if (need <= 0) return [lo, hi] as const; + const h = need / 2; + return [lo - h, hi + h] as const; + }; + const [x0, x1] = grow(min.x, max.x); + const [y0, y1] = grow(min.y, max.y); + return { min: { x: x0, y: y0 }, max: { x: x1, y: y1 } }; +} + +function pointInBox(p: Pt, min: Pt, max: Pt): boolean { + return p.x >= min.x && p.x <= max.x && p.y >= min.y && p.y <= max.y; +} + +/** Does the (interactive) node contain the local-space point? */ +function nodeHit(node: SceneNode, p: Pt): boolean { + const pad = node.hitPadding ?? 0; + switch (node.kind) { + case 'rect': + case 'sprite': { + const box = withMinTarget({ x: node.x - pad, y: node.y - pad }, { x: node.x + node.w + pad, y: node.y + node.h + pad }); + return pointInBox(p, box.min, box.max); + } + case 'circle': { + if (dist(p.x, p.y, node.cx, node.cy) <= node.r + pad) return true; + const box = withMinTarget({ x: node.cx - node.r, y: node.cy - node.r }, { x: node.cx + node.r, y: node.cy + node.r }); + return pointInBox(p, box.min, box.max); + } + case 'line': + // a thin line gets a modest pick slop (not the full 44pt band, which + // would swallow neighbouring targets); the agent can widen via hitPadding. + return distToSegment(p, node.x1, node.y1, node.x2, node.y2) <= Math.max(pad, (node.strokeW ?? 1) / 2 + 6); + case 'path': { + if (node.points.length === 0) return false; + const xs = node.points.map((q) => q[0]); + const ys = node.points.map((q) => q[1]); + const box = withMinTarget({ x: Math.min(...xs) - pad, y: Math.min(...ys) - pad }, { x: Math.max(...xs) + pad, y: Math.max(...ys) + pad }); + return pointInBox(p, box.min, box.max); + } + case 'text': { + const size = node.size ?? 14; + const w = node.text.length * size * 0.6; + const box = withMinTarget({ x: node.x - pad, y: node.y - size - pad }, { x: node.x + w + pad, y: node.y + pad }); + return pointInBox(p, box.min, box.max); + } + case 'group': + return false; // groups are containers, not targets + } +} + +/** Walk nodes in REVERSE paint order (topmost first); return the first + * id-bearing node that contains the point, descending into groups. */ +function walk(nodes: SceneNode[], p: Pt): string | null { + for (let i = nodes.length - 1; i >= 0; i--) { + const node = nodes[i]!; + if (node.kind === 'group') { + const childHit = walk(node.children, toLocal(p, node.transform)); + if (childHit !== null) return childHit; + continue; + } + if (node.id !== undefined && nodeHit(node, p)) return node.id; + } + return null; +} + +/** Map a buffer-native point to the topmost hit node id (or null). */ +export function hitTestScene(scene: Scene, bufferX: number, bufferY: number): string | null { + return walk(scene.draw, { x: bufferX, y: bufferY }); +} + +/** Convert a pointer position within the canvas element to buffer-native + * coordinates, undoing element-fit scaling and the scene camera. */ +export function clientToBuffer( + scene: Scene, + pointer: Pt, + rect: { left: number; top: number; width: number; height: number }, +): Pt { + const fitX = rect.width === 0 ? 1 : scene.width / rect.width; + const fitY = rect.height === 0 ? 1 : scene.height / rect.height; + let bx = (pointer.x - rect.left) * fitX; + let by = (pointer.y - rect.top) * fitY; + const cam = scene.camera; + if (cam) { + const zoom = cam.zoom ?? 1; + bx = bx / (zoom || 1) + (cam.x ?? 0); + by = by / (zoom || 1) + (cam.y ?? 0); + } + return { x: bx, y: by }; +} diff --git a/app/src/renderer/src/render/scene/rasterize.ts b/app/src/renderer/src/render/scene/rasterize.ts new file mode 100644 index 0000000..39dc56f --- /dev/null +++ b/app/src/renderer/src/render/scene/rasterize.ts @@ -0,0 +1,178 @@ +/** + * omadia-canvas-protocol/1.1 — scene draw-list rasteriser (lumens-spec.md §3). + * + * Walks the closed shape vocabulary and issues canvas2d ops. No agent-supplied + * 2d/webgl script is ever executed (§0.1) — only this shipped interpreter walks + * the validated draw-list. Colours resolve through the Lume token resolver + * (tokens.ts), so a scene is always on-theme. Coordinates are buffer-native; the + * scene camera maps buffer → screen here, the inverse of clientToBuffer. + */ +import { REGISTER_TO_CSSVAR } from './tokenMap.js'; +import type { TokenResolver } from './tokens.js'; +import type { Scene, SceneNode, SceneTransform } from './types.js'; + +/** The canvas2d subset the rasteriser uses — kept minimal so tests can pass a + * recording mock (jsdom has no real 2d context). */ +export interface Ctx2D { + save(): void; + restore(): void; + translate(x: number, y: number): void; + scale(x: number, y: number): void; + rotate(angle: number): void; + beginPath(): void; + moveTo(x: number, y: number): void; + lineTo(x: number, y: number): void; + closePath(): void; + arc(x: number, y: number, r: number, start: number, end: number): void; + rect(x: number, y: number, w: number, h: number): void; + roundRect?(x: number, y: number, w: number, h: number, r: number | DOMPointInit | (number | DOMPointInit)[]): void; + fill(): void; + stroke(): void; + fillText(text: string, x: number, y: number): void; + drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void; + fillStyle: string | CanvasGradient | CanvasPattern; + strokeStyle: string | CanvasGradient | CanvasPattern; + lineWidth: number; + font: string; +} + +export interface RasterizeOptions { + /** content-addressed sprite images, keyed by DataRef id; missing ⇒ placeholder. */ + images?: Map; + /** resolves a text register to a font-family value (defaults to Lume vars). */ + fontFamily?: (register: string | undefined) => string; + /** device pixel ratio already applied to the context, if any (default 1). */ +} + +function applyTransform(ctx: Ctx2D, t: SceneTransform | undefined): void { + if (!t) return; + if (t.x || t.y) ctx.translate(t.x ?? 0, t.y ?? 0); + if (t.rotate) ctx.rotate((t.rotate * Math.PI) / 180); + if (t.scale && t.scale !== 1) ctx.scale(t.scale, t.scale); +} + +function pathRoundRect(ctx: Ctx2D, x: number, y: number, w: number, h: number, r: number): void { + if (typeof ctx.roundRect === 'function') { + ctx.beginPath(); + ctx.roundRect(x, y, w, h, r); + return; + } + const rr = Math.min(r, Math.abs(w) / 2, Math.abs(h) / 2); + ctx.beginPath(); + ctx.moveTo(x + rr, y); + ctx.lineTo(x + w - rr, y); + ctx.arc(x + w - rr, y + rr, rr, -Math.PI / 2, 0); + ctx.lineTo(x + w, y + h - rr); + ctx.arc(x + w - rr, y + h - rr, rr, 0, Math.PI / 2); + ctx.lineTo(x + rr, y + h); + ctx.arc(x + rr, y + h - rr, rr, Math.PI / 2, Math.PI); + ctx.lineTo(x, y + rr); + ctx.arc(x + rr, y + rr, rr, Math.PI, (3 * Math.PI) / 2); + ctx.closePath(); +} + +function fillStroke(ctx: Ctx2D, resolve: TokenResolver, fill?: string, stroke?: string, strokeW?: number): void { + if (fill) { + const c = resolve(fill); + if (c !== 'transparent') { + ctx.fillStyle = c; + ctx.fill(); + } + } + if (stroke) { + const c = resolve(stroke); + if (c !== 'transparent') { + ctx.strokeStyle = c; + ctx.lineWidth = strokeW ?? 1; + ctx.stroke(); + } + } +} + +function drawNode(ctx: Ctx2D, node: SceneNode, resolve: TokenResolver, opts: RasterizeOptions): void { + switch (node.kind) { + case 'rect': { + if (node.r && node.r > 0) pathRoundRect(ctx, node.x, node.y, node.w, node.h, node.r); + else { + ctx.beginPath(); + ctx.rect(node.x, node.y, node.w, node.h); + } + fillStroke(ctx, resolve, node.fill, node.stroke, node.strokeW); + break; + } + case 'circle': { + ctx.beginPath(); + ctx.arc(node.cx, node.cy, node.r, 0, Math.PI * 2); + fillStroke(ctx, resolve, node.fill, node.stroke, node.strokeW); + break; + } + case 'line': { + ctx.beginPath(); + ctx.moveTo(node.x1, node.y1); + ctx.lineTo(node.x2, node.y2); + const c = resolve(node.stroke); + if (c !== 'transparent') { + ctx.strokeStyle = c; + ctx.lineWidth = node.strokeW ?? 1; + ctx.stroke(); + } + break; + } + case 'path': { + if (node.points.length === 0) break; + ctx.beginPath(); + ctx.moveTo(node.points[0]![0], node.points[0]![1]); + for (let i = 1; i < node.points.length; i++) ctx.lineTo(node.points[i]![0], node.points[i]![1]); + if (node.closed) ctx.closePath(); + fillStroke(ctx, resolve, node.fill, node.stroke, node.strokeW); + break; + } + case 'sprite': { + const img = opts.images?.get(node.dataRef.id); + if (img) { + ctx.drawImage(img, node.x, node.y, node.w, node.h); + } else { + // asset not yet resolved (transport is L5) — draw an on-theme placeholder. + ctx.beginPath(); + ctx.rect(node.x, node.y, node.w, node.h); + fillStroke(ctx, resolve, 'surface-sunken', 'text-faint', 1); + } + break; + } + case 'text': { + const size = node.size ?? 14; + const family = (opts.fontFamily ?? defaultFontFamily)(node.register); + ctx.font = `${node.weight ?? 400} ${size}px ${family}`; + const c = resolve(node.fill ?? 'text'); + ctx.fillStyle = c === 'transparent' ? resolve('text') : c; + ctx.fillText(node.text, node.x, node.y); + break; + } + case 'group': { + ctx.save(); + applyTransform(ctx, node.transform); + for (const child of node.children) drawNode(ctx, child, resolve, opts); + ctx.restore(); + break; + } + } +} + +function defaultFontFamily(register: string | undefined): string { + const cssVar = REGISTER_TO_CSSVAR[register ?? 'prose'] ?? '--lume-font-prose'; + return `var(${cssVar}, sans-serif)`; +} + +/** Rasterise a whole scene into the 2d context. Applies the camera, then the + * draw-list in paint order. */ +export function rasterizeScene(ctx: Ctx2D, scene: Scene, resolve: TokenResolver, opts: RasterizeOptions = {}): void { + ctx.save(); + const cam = scene.camera; + if (cam) { + const zoom = cam.zoom ?? 1; + if (zoom !== 1) ctx.scale(zoom, zoom); + if (cam.x || cam.y) ctx.translate(-(cam.x ?? 0), -(cam.y ?? 0)); + } + for (const node of scene.draw) drawNode(ctx, node, resolve, opts); + ctx.restore(); +} diff --git a/app/src/renderer/src/render/scene/tokenMap.ts b/app/src/renderer/src/render/scene/tokenMap.ts new file mode 100644 index 0000000..bc49c66 --- /dev/null +++ b/app/src/renderer/src/render/scene/tokenMap.ts @@ -0,0 +1,31 @@ +/** + * omadia-canvas-protocol/1.1 — scene colour/font token → Lume CSS variable maps. + * Pure constants (no DOM) so they can be parity-checked against the schema in a + * node-env test. The DOM resolver lives in tokens.ts. + */ + +/** scene colorToken → Lume CSS custom property (theme/lume.css). */ +export const TOKEN_TO_CSSVAR: Record = { + accent: '--lume-accent', + 'accent.glow': '--lume-accent-glow', + 'accent.glow-soft': '--lume-accent-subtle', + 'accent.glow-core': '--lume-accent-glow-core', + surface: '--lume-surface', + 'surface-raised': '--lume-surface-raised', + 'surface-sunken': '--lume-sunken-top', + text: '--lume-text', + 'text-muted': '--lume-text-secondary', + 'text-faint': '--lume-text-tertiary', + neutral: '--lume-border', + info: '--lume-accent', + success: '--lume-success-fg', + warning: '--lume-warning-fg', + danger: '--lume-error-fg', +}; + +/** scene text register → Lume font CSS variable (visual-spec.md §2.7). */ +export const REGISTER_TO_CSSVAR: Record = { + display: '--lume-font-structural', + prose: '--lume-font-prose', + mono: '--lume-font-mono', +}; diff --git a/app/src/renderer/src/render/scene/tokens.ts b/app/src/renderer/src/render/scene/tokens.ts new file mode 100644 index 0000000..1c18744 --- /dev/null +++ b/app/src/renderer/src/render/scene/tokens.ts @@ -0,0 +1,27 @@ +/** + * omadia-canvas-protocol/1.1 — scene colour tokens → Lume CSS variables. + * + * A `scene` may only reference theme tokens + the active Lume palette + * (lumens-spec.md §3); the whitelist schema already rejects free-form colours. + * The rasteriser draws to canvas2d, which needs concrete colour values, so we + * resolve each token to its Lume CSS custom property at draw time — a scene + * therefore re-themes for free when the palette is bound (palette.ts). + */ +import { TOKEN_TO_CSSVAR } from './tokenMap.js'; + +export { TOKEN_TO_CSSVAR, REGISTER_TO_CSSVAR } from './tokenMap.js'; + +export type TokenResolver = (token: string | undefined) => string; + +/** Build a resolver that reads computed Lume CSS variables off an element. + * Unknown / absent tokens fall back to a safe on-theme value. */ +export function makeTokenResolver(el: Element): TokenResolver { + const computed = getComputedStyle(el); + return (token) => { + if (!token || token === 'transparent') return 'transparent'; + const cssVar = TOKEN_TO_CSSVAR[token]; + if (!cssVar) return 'transparent'; + const value = computed.getPropertyValue(cssVar).trim(); + return value || 'currentColor'; + }; +} diff --git a/app/src/renderer/src/render/scene/types.ts b/app/src/renderer/src/render/scene/types.ts new file mode 100644 index 0000000..b5d0936 --- /dev/null +++ b/app/src/renderer/src/render/scene/types.ts @@ -0,0 +1,33 @@ +/** omadia-canvas-protocol/1.1 — `scene` primitive TS types (lumens-spec.md §3). + * Mirrors schema/scene.schema.json; the schema is the contract. */ + +export type ColorToken = string; // validated by the schema to the token enum +export type TypeRegister = 'display' | 'prose' | 'mono'; + +export interface SceneTransform { + x?: number; + y?: number; + scale?: number; + rotate?: number; // degrees +} + +export type SceneNode = + | { kind: 'rect'; x: number; y: number; w: number; h: number; r?: number; fill?: ColorToken; stroke?: ColorToken; strokeW?: number; id?: string; hitPadding?: number } + | { kind: 'circle'; cx: number; cy: number; r: number; fill?: ColorToken; stroke?: ColorToken; strokeW?: number; id?: string; hitPadding?: number } + | { kind: 'line'; x1: number; y1: number; x2: number; y2: number; stroke: ColorToken; strokeW?: number; id?: string; hitPadding?: number } + | { kind: 'path'; points: [number, number][]; closed?: boolean; fill?: ColorToken; stroke?: ColorToken; strokeW?: number; id?: string; hitPadding?: number } + | { kind: 'sprite'; x: number; y: number; w: number; h: number; dataRef: { id: string }; id?: string; hitPadding?: number } + | { kind: 'text'; x: number; y: number; text: string; size?: number; weight?: number; register?: TypeRegister; fill?: ColorToken; id?: string; hitPadding?: number } + | { kind: 'group'; transform?: SceneTransform; children: SceneNode[]; id?: string; hitPadding?: number }; + +export interface Scene { + type: 'scene'; + id?: string; + width: number; + height: number; + camera?: { x?: number; y?: number; zoom?: number }; + draw: SceneNode[]; +} + +/** Apple HIG minimum hit-target, in buffer units (§4). */ +export const MIN_HIT_TARGET = 44; diff --git a/app/src/renderer/src/validate/validator.ts b/app/src/renderer/src/validate/validator.ts index 6f684f5..dec06b2 100644 --- a/app/src/renderer/src/validate/validator.ts +++ b/app/src/renderer/src/validate/validator.ts @@ -5,6 +5,9 @@ import { validateSurfaceEvent as surfaceValidate, validateTree as treeValidate, + validateLumen as lumenValidate, + validateScene as sceneValidate, + validateLxNode as lxNodeValidate, type StandaloneValidate, } from './validators.generated.mjs'; @@ -30,3 +33,17 @@ export function validateTree(tree: unknown): ValidationResult { export function validateSurfaceEvent(event: unknown): ValidationResult { return run(surfaceValidate, event); } + +// ── omadia-canvas-protocol/1.1 — Lumens (Live Interactivity) ── +/** Structural whitelist parser for a full Lumen (state/transitions/view/…). */ +export function validateLumen(lumen: unknown): ValidationResult { + return run(lumenValidate, lumen); +} +/** Structural whitelist parser for a `scene` primitive (draw-list). */ +export function validateScene(scene: unknown): ValidationResult { + return run(sceneValidate, scene); +} +/** Structural whitelist parser for a single LX AST node. */ +export function validateLxNode(node: unknown): ValidationResult { + return run(lxNodeValidate, node); +} diff --git a/app/src/renderer/src/validate/validators.generated.d.mts b/app/src/renderer/src/validate/validators.generated.d.mts index 81c5db8..6f7a247 100644 --- a/app/src/renderer/src/validate/validators.generated.d.mts +++ b/app/src/renderer/src/validate/validators.generated.d.mts @@ -8,3 +8,7 @@ export type StandaloneValidate = ((data: unknown) => boolean) & { export declare const validateTree: StandaloneValidate; export declare const validateSurfaceEvent: StandaloneValidate; +// omadia-canvas-protocol/1.1 — Lumens +export declare const validateLumen: StandaloneValidate; +export declare const validateScene: StandaloneValidate; +export declare const validateLxNode: StandaloneValidate; diff --git a/app/src/renderer/src/validate/validators.generated.mjs b/app/src/renderer/src/validate/validators.generated.mjs index 9f8a52e..d2df820 100644 --- a/app/src/renderer/src/validate/validators.generated.mjs +++ b/app/src/renderer/src/validate/validators.generated.mjs @@ -1,4 +1,4 @@ /* eslint-disable */ // GENERATED by tools/gen-validator/genValidator.ts — do not edit. import __ajv_ucs2length from 'ajv/dist/runtime/ucs2length.js'; -"use strict";export const validateTree = validate20;const schema31 = {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://omadia.ai/protocol/1.0/canvas-tree.schema.json","title":"Canvas primitive tree","description":"The omadia-canvas-protocol/1.0 primitive vocabulary: 24 primitives in three groups, rendered by Tier 1 against the single Omadia (Lume) theme. The root is any primitive; `container`/`pane`/`tabs` nest children recursively. Validation is strict: unknown primitive types and unknown props are rejected (the whitelist parser).","$ref":"#/$defs/primitive","$defs":{"dataRef":{"$ref":"https://omadia.ai/protocol/1.0/data-ref.schema.json"},"commonTraits":{"$comment":"Cross-cutting traits every primitive may carry. Merged into each primitive via allOf; `unevaluatedProperties:false` on each primitive then rejects anything outside traits+specific.","type":"object","properties":{"id":{"type":"string","description":"stable reference for patches/actions/selections"},"dataRef":{"$ref":"#/$defs/dataRef"},"selectable":{"enum":["none","single","multi"],"description":"selection MODE only; the selected ids live client-side in viewState.selection"},"loading":{"enum":["none","skeleton","spinner"]},"error":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["message","severity"],"properties":{"message":{"type":"string"},"severity":{"enum":["info","warning","error"]}}}]},"virtualized":{"type":"boolean"},"action":{"type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string"},"payload":{},"effect":{"$ref":"#/$defs/actionEffect"}}},"style":{"type":"array","description":"theme tokens only (clipped by the Tier-1 normaliser). Includes the typographic registers 'prose'/'mono' on text.","items":{"enum":["compact","spacious","accent","no-accent","prose","mono","center-glyph"]}},"tone":{"description":"semantic severity hint the renderer maps to a Lume status colour (e.g. a PASS/WARN/FAIL chip). Purely presentational; default 'neutral'.","enum":["neutral","info","success","warning","danger"]},"continuous-input":{"type":"boolean"},"selection-region":{"type":"object","additionalProperties":false,"required":["kind"],"properties":{"kind":{"enum":["rect","lasso","magic-wand"]},"bbox":{},"points":{},"maskHash":{"type":"string"}}},"realtime-output":{"type":"boolean"},"frame-precise-time":{"type":"object","additionalProperties":false,"required":["unit","value"],"properties":{"unit":{"enum":["frame","sample","ms"]},"value":{"type":"number"}}},"suggestedActions":{"type":"array","items":{"$ref":"#/$defs/suggestedAction"}},"dataClass":{"$ref":"#/$defs/dataClass"}}},"actionEffect":{"enum":["local","internal","external-effect"]},"dataClass":{"description":"Annotation on a data-carrying container so Tier 2 can derive mutability per dataClass. Either one string for the whole container, or per-field overrides for a mixed-source container.","oneOf":[{"type":"string"},{"type":"object","required":["default"],"additionalProperties":false,"properties":{"default":{"type":"string"},"fields":{"type":"object","additionalProperties":{"type":"string"}}}}]},"suggestedAction":{"type":"object","additionalProperties":false,"required":["id","label","effect","target"],"properties":{"id":{"type":"string","description":"stable per (treeRevision, container) for idempotency"},"label":{"type":"string","description":"agent-authored, in the user's language"},"effect":{"$ref":"#/$defs/actionEffect"},"target":{"$ref":"https://omadia.ai/protocol/1.0/target-ref.schema.json"},"validUntilRevision":{"type":"string","description":"opaque RevisionId; dropped client-side when treeRevision moves past it (equality semantics)"},"validWhileDataRefs":{"type":"array","items":{"type":"string"}},"prompt":{"type":"string","description":"pre-filled beam text on click"}}},"editableField":{"$comment":"Per-field mutability declaration (client-checkable constraints only).","type":"object","properties":{"editable":{"type":"boolean"},"type":{"type":"string"},"min":{"type":"number"},"max":{"type":"number"},"pattern":{"type":"string"},"enum":{"type":"array"},"maxLength":{"type":"integer"},"required":{"type":"boolean"}}},"tableColumn":{"type":"object","additionalProperties":false,"required":["fieldKey","label"],"properties":{"fieldKey":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"dataClass":{"type":"string"}}},"tableRow":{"type":"object","required":["rowKey","cells"],"additionalProperties":false,"properties":{"rowKey":{"type":"string","description":"REQUIRED stable id, immutable across patches"},"cells":{"type":"object","description":"fieldKey → value; an editable cell carries the editableField shape","additionalProperties":true}}},"listItem":{"type":"object","required":["itemKey"],"additionalProperties":true,"properties":{"itemKey":{"type":"string","description":"REQUIRED stable id"},"label":{"type":"string"}}},"treeNode":{"type":"object","required":["itemKey"],"additionalProperties":false,"properties":{"itemKey":{"type":"string"},"label":{"type":"string"},"children":{"type":"array","items":{"$ref":"#/$defs/treeNode"}},"layer":{"type":"object","description":"layer-stack trait (visibility/opacity/blend-mode/lock)","additionalProperties":true}}},"chartPoint":{"type":"object","required":["pointKey"],"additionalProperties":true,"properties":{"pointKey":{"type":"string","description":"REQUIRED stable id"}}},"primitive":{"type":"object","required":["type"],"oneOf":[{"$ref":"#/$defs/p_text"},{"$ref":"#/$defs/p_heading"},{"$ref":"#/$defs/p_container"},{"$ref":"#/$defs/p_list"},{"$ref":"#/$defs/p_table"},{"$ref":"#/$defs/p_tree"},{"$ref":"#/$defs/p_button"},{"$ref":"#/$defs/p_input"},{"$ref":"#/$defs/p_choice"},{"$ref":"#/$defs/p_toggle"},{"$ref":"#/$defs/p_image"},{"$ref":"#/$defs/p_chart"},{"$ref":"#/$defs/p_form"},{"$ref":"#/$defs/p_toolbar"},{"$ref":"#/$defs/p_menubar"},{"$ref":"#/$defs/p_tabs"},{"$ref":"#/$defs/p_pane"},{"$ref":"#/$defs/p_status"},{"$ref":"#/$defs/p_progress"},{"$ref":"#/$defs/p_divider"},{"$ref":"#/$defs/p_media"},{"$ref":"#/$defs/p_canvasRegion"},{"$ref":"#/$defs/p_timeline"},{"$ref":"#/$defs/p_vectorPath"}]},"p_text":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"text"},"content":{"type":"string"}}}],"unevaluatedProperties":false},"p_heading":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","content"],"properties":{"type":{"const":"heading"},"content":{"type":"string"},"level":{"type":"integer","minimum":1,"maximum":6}}}],"unevaluatedProperties":false},"p_container":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"container"},"title":{"type":"string"},"layout":{"enum":["stack","split","grid","flow"]},"kind":{"enum":["modal","plain"]},"canAddItems":{"type":"boolean"},"canRemoveItems":{"type":"boolean"},"canReorder":{"type":"boolean"},"children":{"type":"array","items":{"$ref":"#/$defs/primitive"}}}}],"unevaluatedProperties":false},"p_list":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","items"],"properties":{"type":{"const":"list"},"items":{"type":"array","items":{"$ref":"#/$defs/listItem"}},"canAddItems":{"type":"boolean"},"canRemoveItems":{"type":"boolean"},"canReorder":{"type":"boolean"}}}],"unevaluatedProperties":false},"p_table":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","columns","rows"],"properties":{"type":{"const":"table"},"columns":{"type":"array","items":{"$ref":"#/$defs/tableColumn"}},"rows":{"type":"array","items":{"$ref":"#/$defs/tableRow"}},"canAddItems":{"type":"boolean"},"canRemoveItems":{"type":"boolean"},"canReorder":{"type":"boolean"}}}],"unevaluatedProperties":false},"p_tree":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","nodes"],"properties":{"type":{"const":"tree"},"nodes":{"type":"array","items":{"$ref":"#/$defs/treeNode"}}}}],"unevaluatedProperties":false},"p_button":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","label"],"properties":{"type":{"const":"button"},"label":{"type":"string"}}}],"unevaluatedProperties":false},"p_input":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"input"},"label":{"type":"string"},"value":{"type":"string"},"placeholder":{"type":"string"}}}],"unevaluatedProperties":false},"p_choice":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","options"],"properties":{"type":{"const":"choice"},"label":{"type":"string"},"variant":{"enum":["radio","dropdown"]},"value":{"type":"string"},"options":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["value","label"],"properties":{"value":{"type":"string"},"label":{"type":"string"}}}}}}],"unevaluatedProperties":false},"p_toggle":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"toggle"},"label":{"type":"string"},"value":{"type":"boolean"},"variant":{"enum":["checkbox","switch"]}}}],"unevaluatedProperties":false},"p_image":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"image"},"src":{"type":"string"},"altText":{"type":"string"}}}],"unevaluatedProperties":false},"p_chart":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","chartType","points"],"properties":{"type":{"const":"chart"},"chartType":{"enum":["bar","line","pie"]},"points":{"type":"array","items":{"$ref":"#/$defs/chartPoint"}}}}],"unevaluatedProperties":false},"p_form":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"form"},"title":{"type":"string"},"contextBinding":{"$ref":"https://omadia.ai/protocol/1.0/target-ref.schema.json"},"children":{"type":"array","items":{"$ref":"#/$defs/primitive"}}}}],"unevaluatedProperties":false},"p_toolbar":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","children"],"properties":{"type":{"const":"toolbar"},"children":{"type":"array","items":{"$ref":"#/$defs/primitive"}}}}],"unevaluatedProperties":false},"p_menubar":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","items"],"properties":{"type":{"const":"menubar"},"items":{"type":"array"}}}],"unevaluatedProperties":false},"p_tabs":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","tabs"],"properties":{"type":{"const":"tabs"},"activeStep":{"type":"integer"},"tabs":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["label","child"],"properties":{"label":{"type":"string"},"done":{"type":"boolean"},"child":{"$ref":"#/$defs/primitive"}}}}}}],"unevaluatedProperties":false},"p_pane":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"pane"},"kind":{"enum":["plain","modal"]},"title":{"type":"string"},"container":{"$ref":"#/$defs/primitive"},"children":{"type":"array","items":{"$ref":"#/$defs/primitive"}}}}],"unevaluatedProperties":false},"p_status":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"status"},"text":{"type":"string"}}}],"unevaluatedProperties":false},"p_progress":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"progress"},"value":{"type":"number"},"indeterminate":{"type":"boolean"}}}],"unevaluatedProperties":false},"p_divider":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"divider"}}}],"unevaluatedProperties":false},"p_media":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","mediaType","dataRef","duration"],"properties":{"type":{"const":"media"},"mediaType":{"enum":["audio","video"]},"dataRef":{"$ref":"#/$defs/dataRef"},"duration":{"type":"number","description":"ms"},"frameRate":{"type":"number"},"resolution":{},"sampleRate":{"type":"number"},"channels":{"type":"integer"},"poster":{"$ref":"#/$defs/dataRef"}}}],"unevaluatedProperties":false},"p_canvasRegion":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","width","height","pixelFormat"],"properties":{"type":{"const":"canvas-region"},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"pixelFormat":{"enum":["rgba8","rgba16"]},"colorSpace":{"type":"string"},"dpi":{"type":"number"}}}],"unevaluatedProperties":false},"p_timeline":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","tracks","timebase"],"properties":{"type":{"const":"timeline"},"tracks":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","kind"],"properties":{"id":{"type":"string"},"kind":{"enum":["audio","video","marker"]}}}},"timebase":{"type":"object","additionalProperties":false,"properties":{"frameRate":{"type":"number"},"sampleRate":{"type":"number"}}},"duration":{"type":"number"},"playhead":{"type":"number"},"loopRegion":{}}}],"unevaluatedProperties":false},"p_vectorPath":{"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","points"],"properties":{"type":{"const":"vector-path"},"points":{"type":"array","items":{"type":"object","required":["x","y"],"properties":{"x":{"type":"number"},"y":{"type":"number"},"ctrlIn":{},"ctrlOut":{}}}},"closed":{"type":"boolean"},"strokeStyle":{},"fillStyle":{}}}],"unevaluatedProperties":false}}};const schema32 = {"type":"object","required":["type"],"oneOf":[{"$ref":"#/$defs/p_text"},{"$ref":"#/$defs/p_heading"},{"$ref":"#/$defs/p_container"},{"$ref":"#/$defs/p_list"},{"$ref":"#/$defs/p_table"},{"$ref":"#/$defs/p_tree"},{"$ref":"#/$defs/p_button"},{"$ref":"#/$defs/p_input"},{"$ref":"#/$defs/p_choice"},{"$ref":"#/$defs/p_toggle"},{"$ref":"#/$defs/p_image"},{"$ref":"#/$defs/p_chart"},{"$ref":"#/$defs/p_form"},{"$ref":"#/$defs/p_toolbar"},{"$ref":"#/$defs/p_menubar"},{"$ref":"#/$defs/p_tabs"},{"$ref":"#/$defs/p_pane"},{"$ref":"#/$defs/p_status"},{"$ref":"#/$defs/p_progress"},{"$ref":"#/$defs/p_divider"},{"$ref":"#/$defs/p_media"},{"$ref":"#/$defs/p_canvasRegion"},{"$ref":"#/$defs/p_timeline"},{"$ref":"#/$defs/p_vectorPath"}]};const schema33 = {"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"text"},"content":{"type":"string"}}}],"unevaluatedProperties":false};const schema34 = {"$comment":"Cross-cutting traits every primitive may carry. Merged into each primitive via allOf; `unevaluatedProperties:false` on each primitive then rejects anything outside traits+specific.","type":"object","properties":{"id":{"type":"string","description":"stable reference for patches/actions/selections"},"dataRef":{"$ref":"#/$defs/dataRef"},"selectable":{"enum":["none","single","multi"],"description":"selection MODE only; the selected ids live client-side in viewState.selection"},"loading":{"enum":["none","skeleton","spinner"]},"error":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["message","severity"],"properties":{"message":{"type":"string"},"severity":{"enum":["info","warning","error"]}}}]},"virtualized":{"type":"boolean"},"action":{"type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string"},"payload":{},"effect":{"$ref":"#/$defs/actionEffect"}}},"style":{"type":"array","description":"theme tokens only (clipped by the Tier-1 normaliser). Includes the typographic registers 'prose'/'mono' on text.","items":{"enum":["compact","spacious","accent","no-accent","prose","mono","center-glyph"]}},"tone":{"description":"semantic severity hint the renderer maps to a Lume status colour (e.g. a PASS/WARN/FAIL chip). Purely presentational; default 'neutral'.","enum":["neutral","info","success","warning","danger"]},"continuous-input":{"type":"boolean"},"selection-region":{"type":"object","additionalProperties":false,"required":["kind"],"properties":{"kind":{"enum":["rect","lasso","magic-wand"]},"bbox":{},"points":{},"maskHash":{"type":"string"}}},"realtime-output":{"type":"boolean"},"frame-precise-time":{"type":"object","additionalProperties":false,"required":["unit","value"],"properties":{"unit":{"enum":["frame","sample","ms"]},"value":{"type":"number"}}},"suggestedActions":{"type":"array","items":{"$ref":"#/$defs/suggestedAction"}},"dataClass":{"$ref":"#/$defs/dataClass"}}};const schema35 = {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://omadia.ai/protocol/1.0/data-ref.schema.json","title":"DataRef","description":"Canonical reference to bulk data behind a primitive or carried by a surface event. Content-addressed id, HMAC-signed token, expiry. The single shape used everywhere bulk data is referenced (omadia-canvas-protocol/1.0).","type":"object","additionalProperties":false,"required":["id","signedToken","expiresAt"],"properties":{"id":{"type":"string","description":"Content-addressed identifier: \"-\", kind ∈ {pixel,vector,audio,video,struct,...}. Same content → same id (automatic dedup).","pattern":"^[a-z]+-[0-9a-f]{16}$"},"signedToken":{"type":"string","minLength":1,"description":"HMAC signature over tenantId ‖ userId ‖ canvasSessionId ‖ dataRefBody ‖ expiryEpoch (see §Security). Server re-validates signature, scope, expiry on fetch."},"expiresAt":{"type":"string","format":"date-time","description":"ISO 8601 expiry. ≤ the server-secret lifetime."},"refreshable":{"type":"boolean","description":"Protocol 1.1 (issue #5): true → the server holds a refresh recipe and re-resolves this data deterministically; the client may surface an instant-refresh affordance. Absent = unknown (agent-fallback refresh)."},"containerId":{"type":"string","description":"Protocol 1.1: the canvas container (table/chart id) this ref's data feeds."}}};const schema37 = {"enum":["local","internal","external-effect"]};const schema43 = {"description":"Annotation on a data-carrying container so Tier 2 can derive mutability per dataClass. Either one string for the whole container, or per-field overrides for a mixed-source container.","oneOf":[{"type":"string"},{"type":"object","required":["default"],"additionalProperties":false,"properties":{"default":{"type":"string"},"fields":{"type":"object","additionalProperties":{"type":"string"}}}}]};const pattern4 = new RegExp("^[a-z]+-[0-9a-f]{16}$", "u");const func1 = __ajv_ucs2length;const schema38 = {"type":"object","additionalProperties":false,"required":["id","label","effect","target"],"properties":{"id":{"type":"string","description":"stable per (treeRevision, container) for idempotency"},"label":{"type":"string","description":"agent-authored, in the user's language"},"effect":{"$ref":"#/$defs/actionEffect"},"target":{"$ref":"https://omadia.ai/protocol/1.0/target-ref.schema.json"},"validUntilRevision":{"type":"string","description":"opaque RevisionId; dropped client-side when treeRevision moves past it (equality semantics)"},"validWhileDataRefs":{"type":"array","items":{"type":"string"}},"prompt":{"type":"string","description":"pre-filled beam text on click"}}};const schema40 = {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://omadia.ai/protocol/1.0/target-ref.schema.json","title":"TargetRef","description":"The single canonical way to address a target anywhere in the canvas protocol: beam targets, _pendingMutation.target, suggestedActions.target, surface_local_action.target, surface_mutation_resolved correlation. Targets address data by STABLE id/hash, never by view position. Ten variants discriminated by `kind`.","$defs":{"textRangeAnchor":{"type":"object","additionalProperties":false,"required":["primitiveId","contentHash","start","end"],"properties":{"primitiveId":{"type":"string","description":"the text primitive's containerId or elementId"},"contentHash":{"type":"string","description":"sha256[:16] of the text content at anchoring time"},"start":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"end":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"fallbackSegment":{"type":"object","additionalProperties":false,"description":"optional re-anchoring snippets on a content-hash miss","required":["before","selection","after"],"properties":{"before":{"type":"string","description":"~32 chars of context before the selection"},"selection":{"type":"string","description":"the selected text itself"},"after":{"type":"string","description":"~32 chars of context after the selection"}}}}},"bufferRegion":{"type":"object","additionalProperties":false,"required":["primitiveId","bufferContentHash","bbox"],"properties":{"primitiveId":{"type":"string","description":"the canvas-region or media primitive's elementId"},"bufferContentHash":{"type":"string","description":"sha256[:16] of the buffer at anchoring time (resolution fails on mismatch)"},"bbox":{"type":"object","additionalProperties":false,"description":"axis-aligned bounding box in buffer-native pixels (zoom/pan independent)","required":["x","y","w","h"],"properties":{"x":{"type":"number"},"y":{"type":"number"},"w":{"type":"number"},"h":{"type":"number"}}},"shape":{"type":"object","additionalProperties":false,"description":"optional non-rect selection (lasso, magic-wand)","required":["kind"],"properties":{"kind":{"enum":["rect","polygon","mask"]},"points":{"type":"array","description":"for 'polygon'","items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2}},"maskHash":{"type":"string","description":"for 'mask' — content-hash of a binary mask sized to bbox"}}}}}},"oneOf":[{"type":"object","additionalProperties":false,"required":["kind","canvasSessionId"],"properties":{"kind":{"const":"canvas"},"canvasSessionId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId"],"properties":{"kind":{"const":"container"},"containerId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","elementId"],"description":"any non-data primitive (heading, divider, status, …)","properties":{"kind":{"const":"element"},"elementId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId","rowKey","fieldKey"],"properties":{"kind":{"const":"rowField"},"containerId":{"type":"string"},"rowKey":{"type":"string"},"fieldKey":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId","itemKey"],"description":"list / tree node","properties":{"kind":{"const":"item"},"containerId":{"type":"string"},"itemKey":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId","pointKey"],"description":"chart data point","properties":{"kind":{"const":"point"},"containerId":{"type":"string"},"pointKey":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","anchor"],"properties":{"kind":{"const":"textRange"},"anchor":{"$ref":"#/$defs/textRangeAnchor"}}},{"type":"object","additionalProperties":false,"required":["kind","region"],"description":"pixel / canvas-region region","properties":{"kind":{"const":"region"},"region":{"$ref":"#/$defs/bufferRegion"}}},{"type":"object","additionalProperties":false,"required":["kind","primitiveId","bufferContentHash"],"description":"whole-buffer reference (canvas-region / media)","properties":{"kind":{"const":"buffer"},"primitiveId":{"type":"string"},"bufferContentHash":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","primitiveId","bufferContentHash","start","end","unit"],"description":"media / timeline trim / splice / scrub. For single-buffer media omit trackId+clipId; for a multi-track timeline trackId is required, clipId optional.","properties":{"kind":{"const":"timeRange"},"primitiveId":{"type":"string"},"bufferContentHash":{"type":"string"},"start":{"type":"number"},"end":{"type":"number"},"unit":{"enum":["seconds","samples","frames"]},"trackId":{"type":"string"},"clipId":{"type":"string"}}}]};const schema41 = {"type":"object","additionalProperties":false,"required":["primitiveId","contentHash","start","end"],"properties":{"primitiveId":{"type":"string","description":"the text primitive's containerId or elementId"},"contentHash":{"type":"string","description":"sha256[:16] of the text content at anchoring time"},"start":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"end":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"fallbackSegment":{"type":"object","additionalProperties":false,"description":"optional re-anchoring snippets on a content-hash miss","required":["before","selection","after"],"properties":{"before":{"type":"string","description":"~32 chars of context before the selection"},"selection":{"type":"string","description":"the selected text itself"},"after":{"type":"string","description":"~32 chars of context after the selection"}}}}};const schema42 = {"type":"object","additionalProperties":false,"required":["primitiveId","bufferContentHash","bbox"],"properties":{"primitiveId":{"type":"string","description":"the canvas-region or media primitive's elementId"},"bufferContentHash":{"type":"string","description":"sha256[:16] of the buffer at anchoring time (resolution fails on mismatch)"},"bbox":{"type":"object","additionalProperties":false,"description":"axis-aligned bounding box in buffer-native pixels (zoom/pan independent)","required":["x","y","w","h"],"properties":{"x":{"type":"number"},"y":{"type":"number"},"w":{"type":"number"},"h":{"type":"number"}}},"shape":{"type":"object","additionalProperties":false,"description":"optional non-rect selection (lasso, magic-wand)","required":["kind"],"properties":{"kind":{"enum":["rect","polygon","mask"]},"points":{"type":"array","description":"for 'polygon'","items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2}},"maskHash":{"type":"string","description":"for 'mask' — content-hash of a binary mask sized to bbox"}}}}};function validate26(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL="https://omadia.ai/protocol/1.0/target-ref.schema.json" */;let vErrors = null;let errors = 0;const evaluated0 = validate26.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}const _errs0 = errors;let valid0 = false;let passing0 = null;const _errs1 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.canvasSessionId === undefined){const err1 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "canvasSessionId"},message:"must have required property '"+"canvasSessionId"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}for(const key0 in data){if(!((key0 === "kind") || (key0 === "canvasSessionId"))){const err2 = {instancePath,schemaPath:"#/oneOf/0/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.kind !== undefined){if("canvas" !== data.kind){const err3 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/0/properties/kind/const",keyword:"const",params:{allowedValue: "canvas"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.canvasSessionId !== undefined){if(typeof data.canvasSessionId !== "string"){const err4 = {instancePath:instancePath+"/canvasSessionId",schemaPath:"#/oneOf/0/properties/canvasSessionId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}}else {const err5 = {instancePath,schemaPath:"#/oneOf/0/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}var _valid0 = _errs1 === errors;if(_valid0){valid0 = true;passing0 = 0;var props0 = true;}const _errs7 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err6 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}if(data.containerId === undefined){const err7 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}for(const key1 in data){if(!((key1 === "kind") || (key1 === "containerId"))){const err8 = {instancePath,schemaPath:"#/oneOf/1/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.kind !== undefined){if("container" !== data.kind){const err9 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/1/properties/kind/const",keyword:"const",params:{allowedValue: "container"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err10 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/1/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}}else {const err11 = {instancePath,schemaPath:"#/oneOf/1/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}var _valid0 = _errs7 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 1];}else {if(_valid0){valid0 = true;passing0 = 1;if(props0 !== true){props0 = true;}}const _errs13 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err12 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}if(data.elementId === undefined){const err13 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "elementId"},message:"must have required property '"+"elementId"+"'"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}for(const key2 in data){if(!((key2 === "kind") || (key2 === "elementId"))){const err14 = {instancePath,schemaPath:"#/oneOf/2/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key2},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.kind !== undefined){if("element" !== data.kind){const err15 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/2/properties/kind/const",keyword:"const",params:{allowedValue: "element"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.elementId !== undefined){if(typeof data.elementId !== "string"){const err16 = {instancePath:instancePath+"/elementId",schemaPath:"#/oneOf/2/properties/elementId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath,schemaPath:"#/oneOf/2/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}var _valid0 = _errs13 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 2];}else {if(_valid0){valid0 = true;passing0 = 2;if(props0 !== true){props0 = true;}}const _errs19 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err18 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}if(data.containerId === undefined){const err19 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}if(data.rowKey === undefined){const err20 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "rowKey"},message:"must have required property '"+"rowKey"+"'"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}if(data.fieldKey === undefined){const err21 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "fieldKey"},message:"must have required property '"+"fieldKey"+"'"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}for(const key3 in data){if(!((((key3 === "kind") || (key3 === "containerId")) || (key3 === "rowKey")) || (key3 === "fieldKey"))){const err22 = {instancePath,schemaPath:"#/oneOf/3/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key3},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}if(data.kind !== undefined){if("rowField" !== data.kind){const err23 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/3/properties/kind/const",keyword:"const",params:{allowedValue: "rowField"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err24 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/3/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data.rowKey !== undefined){if(typeof data.rowKey !== "string"){const err25 = {instancePath:instancePath+"/rowKey",schemaPath:"#/oneOf/3/properties/rowKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}if(data.fieldKey !== undefined){if(typeof data.fieldKey !== "string"){const err26 = {instancePath:instancePath+"/fieldKey",schemaPath:"#/oneOf/3/properties/fieldKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:"#/oneOf/3/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}var _valid0 = _errs19 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 3];}else {if(_valid0){valid0 = true;passing0 = 3;if(props0 !== true){props0 = true;}}const _errs29 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err28 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}if(data.containerId === undefined){const err29 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}if(data.itemKey === undefined){const err30 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "itemKey"},message:"must have required property '"+"itemKey"+"'"};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}for(const key4 in data){if(!(((key4 === "kind") || (key4 === "containerId")) || (key4 === "itemKey"))){const err31 = {instancePath,schemaPath:"#/oneOf/4/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key4},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}}if(data.kind !== undefined){if("item" !== data.kind){const err32 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/4/properties/kind/const",keyword:"const",params:{allowedValue: "item"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err33 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/4/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}}if(data.itemKey !== undefined){if(typeof data.itemKey !== "string"){const err34 = {instancePath:instancePath+"/itemKey",schemaPath:"#/oneOf/4/properties/itemKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}}}else {const err35 = {instancePath,schemaPath:"#/oneOf/4/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}var _valid0 = _errs29 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 4];}else {if(_valid0){valid0 = true;passing0 = 4;if(props0 !== true){props0 = true;}}const _errs37 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err36 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}if(data.containerId === undefined){const err37 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}if(data.pointKey === undefined){const err38 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "pointKey"},message:"must have required property '"+"pointKey"+"'"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}for(const key5 in data){if(!(((key5 === "kind") || (key5 === "containerId")) || (key5 === "pointKey"))){const err39 = {instancePath,schemaPath:"#/oneOf/5/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key5},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}}if(data.kind !== undefined){if("point" !== data.kind){const err40 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/5/properties/kind/const",keyword:"const",params:{allowedValue: "point"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err41 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/5/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}}if(data.pointKey !== undefined){if(typeof data.pointKey !== "string"){const err42 = {instancePath:instancePath+"/pointKey",schemaPath:"#/oneOf/5/properties/pointKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;}}}else {const err43 = {instancePath,schemaPath:"#/oneOf/5/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}var _valid0 = _errs37 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 5];}else {if(_valid0){valid0 = true;passing0 = 5;if(props0 !== true){props0 = true;}}const _errs45 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err44 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}if(data.anchor === undefined){const err45 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "anchor"},message:"must have required property '"+"anchor"+"'"};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}for(const key6 in data){if(!((key6 === "kind") || (key6 === "anchor"))){const err46 = {instancePath,schemaPath:"#/oneOf/6/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key6},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}}if(data.kind !== undefined){if("textRange" !== data.kind){const err47 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/6/properties/kind/const",keyword:"const",params:{allowedValue: "textRange"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}}if(data.anchor !== undefined){let data17 = data.anchor;if(data17 && typeof data17 == "object" && !Array.isArray(data17)){if(data17.primitiveId === undefined){const err48 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err48];}else {vErrors.push(err48);}errors++;}if(data17.contentHash === undefined){const err49 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "contentHash"},message:"must have required property '"+"contentHash"+"'"};if(vErrors === null){vErrors = [err49];}else {vErrors.push(err49);}errors++;}if(data17.start === undefined){const err50 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "start"},message:"must have required property '"+"start"+"'"};if(vErrors === null){vErrors = [err50];}else {vErrors.push(err50);}errors++;}if(data17.end === undefined){const err51 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "end"},message:"must have required property '"+"end"+"'"};if(vErrors === null){vErrors = [err51];}else {vErrors.push(err51);}errors++;}for(const key7 in data17){if(!(((((key7 === "primitiveId") || (key7 === "contentHash")) || (key7 === "start")) || (key7 === "end")) || (key7 === "fallbackSegment"))){const err52 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key7},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err52];}else {vErrors.push(err52);}errors++;}}if(data17.primitiveId !== undefined){if(typeof data17.primitiveId !== "string"){const err53 = {instancePath:instancePath+"/anchor/primitiveId",schemaPath:"#/$defs/textRangeAnchor/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err53];}else {vErrors.push(err53);}errors++;}}if(data17.contentHash !== undefined){if(typeof data17.contentHash !== "string"){const err54 = {instancePath:instancePath+"/anchor/contentHash",schemaPath:"#/$defs/textRangeAnchor/properties/contentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err54];}else {vErrors.push(err54);}errors++;}}if(data17.start !== undefined){let data20 = data17.start;if(!((typeof data20 == "number") && (!(data20 % 1) && !isNaN(data20)))){const err55 = {instancePath:instancePath+"/anchor/start",schemaPath:"#/$defs/textRangeAnchor/properties/start/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err55];}else {vErrors.push(err55);}errors++;}if(typeof data20 == "number"){if(data20 < 0 || isNaN(data20)){const err56 = {instancePath:instancePath+"/anchor/start",schemaPath:"#/$defs/textRangeAnchor/properties/start/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err56];}else {vErrors.push(err56);}errors++;}}}if(data17.end !== undefined){let data21 = data17.end;if(!((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21)))){const err57 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err57];}else {vErrors.push(err57);}errors++;}if(typeof data21 == "number"){if(data21 < 0 || isNaN(data21)){const err58 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err58];}else {vErrors.push(err58);}errors++;}}}if(data17.fallbackSegment !== undefined){let data22 = data17.fallbackSegment;if(data22 && typeof data22 == "object" && !Array.isArray(data22)){if(data22.before === undefined){const err59 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "before"},message:"must have required property '"+"before"+"'"};if(vErrors === null){vErrors = [err59];}else {vErrors.push(err59);}errors++;}if(data22.selection === undefined){const err60 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "selection"},message:"must have required property '"+"selection"+"'"};if(vErrors === null){vErrors = [err60];}else {vErrors.push(err60);}errors++;}if(data22.after === undefined){const err61 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "after"},message:"must have required property '"+"after"+"'"};if(vErrors === null){vErrors = [err61];}else {vErrors.push(err61);}errors++;}for(const key8 in data22){if(!(((key8 === "before") || (key8 === "selection")) || (key8 === "after"))){const err62 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key8},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err62];}else {vErrors.push(err62);}errors++;}}if(data22.before !== undefined){if(typeof data22.before !== "string"){const err63 = {instancePath:instancePath+"/anchor/fallbackSegment/before",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/before/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err63];}else {vErrors.push(err63);}errors++;}}if(data22.selection !== undefined){if(typeof data22.selection !== "string"){const err64 = {instancePath:instancePath+"/anchor/fallbackSegment/selection",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/selection/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err64];}else {vErrors.push(err64);}errors++;}}if(data22.after !== undefined){if(typeof data22.after !== "string"){const err65 = {instancePath:instancePath+"/anchor/fallbackSegment/after",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/after/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err65];}else {vErrors.push(err65);}errors++;}}}else {const err66 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err66];}else {vErrors.push(err66);}errors++;}}}else {const err67 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err67];}else {vErrors.push(err67);}errors++;}}}else {const err68 = {instancePath,schemaPath:"#/oneOf/6/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err68];}else {vErrors.push(err68);}errors++;}var _valid0 = _errs45 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}const _errs70 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err69 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err69];}else {vErrors.push(err69);}errors++;}if(data.region === undefined){const err70 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "region"},message:"must have required property '"+"region"+"'"};if(vErrors === null){vErrors = [err70];}else {vErrors.push(err70);}errors++;}for(const key9 in data){if(!((key9 === "kind") || (key9 === "region"))){const err71 = {instancePath,schemaPath:"#/oneOf/7/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key9},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err71];}else {vErrors.push(err71);}errors++;}}if(data.kind !== undefined){if("region" !== data.kind){const err72 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/7/properties/kind/const",keyword:"const",params:{allowedValue: "region"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err72];}else {vErrors.push(err72);}errors++;}}if(data.region !== undefined){let data27 = data.region;if(data27 && typeof data27 == "object" && !Array.isArray(data27)){if(data27.primitiveId === undefined){const err73 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err73];}else {vErrors.push(err73);}errors++;}if(data27.bufferContentHash === undefined){const err74 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bufferContentHash"},message:"must have required property '"+"bufferContentHash"+"'"};if(vErrors === null){vErrors = [err74];}else {vErrors.push(err74);}errors++;}if(data27.bbox === undefined){const err75 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bbox"},message:"must have required property '"+"bbox"+"'"};if(vErrors === null){vErrors = [err75];}else {vErrors.push(err75);}errors++;}for(const key10 in data27){if(!((((key10 === "primitiveId") || (key10 === "bufferContentHash")) || (key10 === "bbox")) || (key10 === "shape"))){const err76 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key10},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err76];}else {vErrors.push(err76);}errors++;}}if(data27.primitiveId !== undefined){if(typeof data27.primitiveId !== "string"){const err77 = {instancePath:instancePath+"/region/primitiveId",schemaPath:"#/$defs/bufferRegion/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err77];}else {vErrors.push(err77);}errors++;}}if(data27.bufferContentHash !== undefined){if(typeof data27.bufferContentHash !== "string"){const err78 = {instancePath:instancePath+"/region/bufferContentHash",schemaPath:"#/$defs/bufferRegion/properties/bufferContentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err78];}else {vErrors.push(err78);}errors++;}}if(data27.bbox !== undefined){let data30 = data27.bbox;if(data30 && typeof data30 == "object" && !Array.isArray(data30)){if(data30.x === undefined){const err79 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "x"},message:"must have required property '"+"x"+"'"};if(vErrors === null){vErrors = [err79];}else {vErrors.push(err79);}errors++;}if(data30.y === undefined){const err80 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "y"},message:"must have required property '"+"y"+"'"};if(vErrors === null){vErrors = [err80];}else {vErrors.push(err80);}errors++;}if(data30.w === undefined){const err81 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "w"},message:"must have required property '"+"w"+"'"};if(vErrors === null){vErrors = [err81];}else {vErrors.push(err81);}errors++;}if(data30.h === undefined){const err82 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "h"},message:"must have required property '"+"h"+"'"};if(vErrors === null){vErrors = [err82];}else {vErrors.push(err82);}errors++;}for(const key11 in data30){if(!((((key11 === "x") || (key11 === "y")) || (key11 === "w")) || (key11 === "h"))){const err83 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key11},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err83];}else {vErrors.push(err83);}errors++;}}if(data30.x !== undefined){if(!(typeof data30.x == "number")){const err84 = {instancePath:instancePath+"/region/bbox/x",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err84];}else {vErrors.push(err84);}errors++;}}if(data30.y !== undefined){if(!(typeof data30.y == "number")){const err85 = {instancePath:instancePath+"/region/bbox/y",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err85];}else {vErrors.push(err85);}errors++;}}if(data30.w !== undefined){if(!(typeof data30.w == "number")){const err86 = {instancePath:instancePath+"/region/bbox/w",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/w/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err86];}else {vErrors.push(err86);}errors++;}}if(data30.h !== undefined){if(!(typeof data30.h == "number")){const err87 = {instancePath:instancePath+"/region/bbox/h",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/h/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err87];}else {vErrors.push(err87);}errors++;}}}else {const err88 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err88];}else {vErrors.push(err88);}errors++;}}if(data27.shape !== undefined){let data35 = data27.shape;if(data35 && typeof data35 == "object" && !Array.isArray(data35)){if(data35.kind === undefined){const err89 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err89];}else {vErrors.push(err89);}errors++;}for(const key12 in data35){if(!(((key12 === "kind") || (key12 === "points")) || (key12 === "maskHash"))){const err90 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key12},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err90];}else {vErrors.push(err90);}errors++;}}if(data35.kind !== undefined){let data36 = data35.kind;if(!(((data36 === "rect") || (data36 === "polygon")) || (data36 === "mask"))){const err91 = {instancePath:instancePath+"/region/shape/kind",schemaPath:"#/$defs/bufferRegion/properties/shape/properties/kind/enum",keyword:"enum",params:{allowedValues: schema42.properties.shape.properties.kind.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err91];}else {vErrors.push(err91);}errors++;}}if(data35.points !== undefined){let data37 = data35.points;if(Array.isArray(data37)){const len0 = data37.length;for(let i0=0; i0 2){const err92 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err92];}else {vErrors.push(err92);}errors++;}if(data38.length < 2){const err93 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err93];}else {vErrors.push(err93);}errors++;}const len1 = data38.length;for(let i1=0; i1 6 || isNaN(data2)){const err5 = {instancePath:instancePath+"/level",schemaPath:"#/allOf/1/properties/level/maximum",keyword:"maximum",params:{comparison: "<=", limit: 6},message:"must be <= 6"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}if(data2 < 1 || isNaN(data2)){const err6 = {instancePath:instancePath+"/level",schemaPath:"#/allOf/1/properties/level/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}}}if(data && typeof data == "object" && !Array.isArray(data)){for(const key0 in data){if((((((((((((((((((key0 !== "type") && (key0 !== "content")) && (key0 !== "level")) && (key0 !== "id")) && (key0 !== "dataRef")) && (key0 !== "selectable")) && (key0 !== "loading")) && (key0 !== "error")) && (key0 !== "virtualized")) && (key0 !== "action")) && (key0 !== "style")) && (key0 !== "tone")) && (key0 !== "continuous-input")) && (key0 !== "selection-region")) && (key0 !== "realtime-output")) && (key0 !== "frame-precise-time")) && (key0 !== "suggestedActions")) && (key0 !== "dataClass")){const err7 = {instancePath,schemaPath:"#/unevaluatedProperties",keyword:"unevaluatedProperties",params:{unevaluatedProperty: key0},message:"must NOT have unevaluated properties"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}}validate31.errors = vErrors;return errors === 0;}validate31.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema45 = {"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"container"},"title":{"type":"string"},"layout":{"enum":["stack","split","grid","flow"]},"kind":{"enum":["modal","plain"]},"canAddItems":{"type":"boolean"},"canRemoveItems":{"type":"boolean"},"canReorder":{"type":"boolean"},"children":{"type":"array","items":{"$ref":"#/$defs/primitive"}}}}],"unevaluatedProperties":false};const wrapper0 = {validate: validate21};function validate34(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate34.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(validate23(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate23.errors : vErrors.concat(validate23.errors);errors = vErrors.length;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err0 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.type !== undefined){if("container" !== data.type){const err1 = {instancePath:instancePath+"/type",schemaPath:"#/allOf/1/properties/type/const",keyword:"const",params:{allowedValue: "container"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.title !== undefined){if(typeof data.title !== "string"){const err2 = {instancePath:instancePath+"/title",schemaPath:"#/allOf/1/properties/title/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.layout !== undefined){let data2 = data.layout;if(!((((data2 === "stack") || (data2 === "split")) || (data2 === "grid")) || (data2 === "flow"))){const err3 = {instancePath:instancePath+"/layout",schemaPath:"#/allOf/1/properties/layout/enum",keyword:"enum",params:{allowedValues: schema45.allOf[1].properties.layout.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.kind !== undefined){let data3 = data.kind;if(!((data3 === "modal") || (data3 === "plain"))){const err4 = {instancePath:instancePath+"/kind",schemaPath:"#/allOf/1/properties/kind/enum",keyword:"enum",params:{allowedValues: schema45.allOf[1].properties.kind.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.canAddItems !== undefined){if(typeof data.canAddItems !== "boolean"){const err5 = {instancePath:instancePath+"/canAddItems",schemaPath:"#/allOf/1/properties/canAddItems/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.canRemoveItems !== undefined){if(typeof data.canRemoveItems !== "boolean"){const err6 = {instancePath:instancePath+"/canRemoveItems",schemaPath:"#/allOf/1/properties/canRemoveItems/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.canReorder !== undefined){if(typeof data.canReorder !== "boolean"){const err7 = {instancePath:instancePath+"/canReorder",schemaPath:"#/allOf/1/properties/canReorder/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.children !== undefined){let data7 = data.children;if(Array.isArray(data7)){const len0 = data7.length;for(let i0=0; i0=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}}if(data.height !== undefined){let data2 = data.height;if(!((typeof data2 == "number") && (!(data2 % 1) && !isNaN(data2)))){const err7 = {instancePath:instancePath+"/height",schemaPath:"#/allOf/1/properties/height/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}if(typeof data2 == "number"){if(data2 < 1 || isNaN(data2)){const err8 = {instancePath:instancePath+"/height",schemaPath:"#/allOf/1/properties/height/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}}if(data.pixelFormat !== undefined){let data3 = data.pixelFormat;if(!((data3 === "rgba8") || (data3 === "rgba16"))){const err9 = {instancePath:instancePath+"/pixelFormat",schemaPath:"#/allOf/1/properties/pixelFormat/enum",keyword:"enum",params:{allowedValues: schema71.allOf[1].properties.pixelFormat.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.colorSpace !== undefined){if(typeof data.colorSpace !== "string"){const err10 = {instancePath:instancePath+"/colorSpace",schemaPath:"#/allOf/1/properties/colorSpace/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.dpi !== undefined){if(!(typeof data.dpi == "number")){const err11 = {instancePath:instancePath+"/dpi",schemaPath:"#/allOf/1/properties/dpi/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}}if(data && typeof data == "object" && !Array.isArray(data)){for(const key0 in data){if(((((((((((((((((((((key0 !== "type") && (key0 !== "width")) && (key0 !== "height")) && (key0 !== "pixelFormat")) && (key0 !== "colorSpace")) && (key0 !== "dpi")) && (key0 !== "id")) && (key0 !== "dataRef")) && (key0 !== "selectable")) && (key0 !== "loading")) && (key0 !== "error")) && (key0 !== "virtualized")) && (key0 !== "action")) && (key0 !== "style")) && (key0 !== "tone")) && (key0 !== "continuous-input")) && (key0 !== "selection-region")) && (key0 !== "realtime-output")) && (key0 !== "frame-precise-time")) && (key0 !== "suggestedActions")) && (key0 !== "dataClass")){const err12 = {instancePath,schemaPath:"#/unevaluatedProperties",keyword:"unevaluatedProperties",params:{unevaluatedProperty: key0},message:"must NOT have unevaluated properties"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}}validate94.errors = vErrors;return errors === 0;}validate94.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema72 = {"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","tracks","timebase"],"properties":{"type":{"const":"timeline"},"tracks":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","kind"],"properties":{"id":{"type":"string"},"kind":{"enum":["audio","video","marker"]}}}},"timebase":{"type":"object","additionalProperties":false,"properties":{"frameRate":{"type":"number"},"sampleRate":{"type":"number"}}},"duration":{"type":"number"},"playhead":{"type":"number"},"loopRegion":{}}}],"unevaluatedProperties":false};function validate97(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate97.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(validate23(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate23.errors : vErrors.concat(validate23.errors);errors = vErrors.length;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err0 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.tracks === undefined){const err1 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "tracks"},message:"must have required property '"+"tracks"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.timebase === undefined){const err2 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "timebase"},message:"must have required property '"+"timebase"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.type !== undefined){if("timeline" !== data.type){const err3 = {instancePath:instancePath+"/type",schemaPath:"#/allOf/1/properties/type/const",keyword:"const",params:{allowedValue: "timeline"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.tracks !== undefined){let data1 = data.tracks;if(Array.isArray(data1)){const len0 = data1.length;for(let i0=0; i0=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err56];}else {vErrors.push(err56);}errors++;}}}if(data17.end !== undefined){let data21 = data17.end;if(!((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21)))){const err57 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err57];}else {vErrors.push(err57);}errors++;}if(typeof data21 == "number"){if(data21 < 0 || isNaN(data21)){const err58 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err58];}else {vErrors.push(err58);}errors++;}}}if(data17.fallbackSegment !== undefined){let data22 = data17.fallbackSegment;if(data22 && typeof data22 == "object" && !Array.isArray(data22)){if(data22.before === undefined){const err59 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "before"},message:"must have required property '"+"before"+"'"};if(vErrors === null){vErrors = [err59];}else {vErrors.push(err59);}errors++;}if(data22.selection === undefined){const err60 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "selection"},message:"must have required property '"+"selection"+"'"};if(vErrors === null){vErrors = [err60];}else {vErrors.push(err60);}errors++;}if(data22.after === undefined){const err61 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "after"},message:"must have required property '"+"after"+"'"};if(vErrors === null){vErrors = [err61];}else {vErrors.push(err61);}errors++;}for(const key8 in data22){if(!(((key8 === "before") || (key8 === "selection")) || (key8 === "after"))){const err62 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key8},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err62];}else {vErrors.push(err62);}errors++;}}if(data22.before !== undefined){if(typeof data22.before !== "string"){const err63 = {instancePath:instancePath+"/anchor/fallbackSegment/before",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/before/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err63];}else {vErrors.push(err63);}errors++;}}if(data22.selection !== undefined){if(typeof data22.selection !== "string"){const err64 = {instancePath:instancePath+"/anchor/fallbackSegment/selection",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/selection/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err64];}else {vErrors.push(err64);}errors++;}}if(data22.after !== undefined){if(typeof data22.after !== "string"){const err65 = {instancePath:instancePath+"/anchor/fallbackSegment/after",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/after/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err65];}else {vErrors.push(err65);}errors++;}}}else {const err66 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err66];}else {vErrors.push(err66);}errors++;}}}else {const err67 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err67];}else {vErrors.push(err67);}errors++;}}}else {const err68 = {instancePath,schemaPath:"#/oneOf/6/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err68];}else {vErrors.push(err68);}errors++;}var _valid0 = _errs45 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}const _errs70 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err69 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err69];}else {vErrors.push(err69);}errors++;}if(data.region === undefined){const err70 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "region"},message:"must have required property '"+"region"+"'"};if(vErrors === null){vErrors = [err70];}else {vErrors.push(err70);}errors++;}for(const key9 in data){if(!((key9 === "kind") || (key9 === "region"))){const err71 = {instancePath,schemaPath:"#/oneOf/7/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key9},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err71];}else {vErrors.push(err71);}errors++;}}if(data.kind !== undefined){if("region" !== data.kind){const err72 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/7/properties/kind/const",keyword:"const",params:{allowedValue: "region"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err72];}else {vErrors.push(err72);}errors++;}}if(data.region !== undefined){let data27 = data.region;if(data27 && typeof data27 == "object" && !Array.isArray(data27)){if(data27.primitiveId === undefined){const err73 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err73];}else {vErrors.push(err73);}errors++;}if(data27.bufferContentHash === undefined){const err74 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bufferContentHash"},message:"must have required property '"+"bufferContentHash"+"'"};if(vErrors === null){vErrors = [err74];}else {vErrors.push(err74);}errors++;}if(data27.bbox === undefined){const err75 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bbox"},message:"must have required property '"+"bbox"+"'"};if(vErrors === null){vErrors = [err75];}else {vErrors.push(err75);}errors++;}for(const key10 in data27){if(!((((key10 === "primitiveId") || (key10 === "bufferContentHash")) || (key10 === "bbox")) || (key10 === "shape"))){const err76 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key10},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err76];}else {vErrors.push(err76);}errors++;}}if(data27.primitiveId !== undefined){if(typeof data27.primitiveId !== "string"){const err77 = {instancePath:instancePath+"/region/primitiveId",schemaPath:"#/$defs/bufferRegion/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err77];}else {vErrors.push(err77);}errors++;}}if(data27.bufferContentHash !== undefined){if(typeof data27.bufferContentHash !== "string"){const err78 = {instancePath:instancePath+"/region/bufferContentHash",schemaPath:"#/$defs/bufferRegion/properties/bufferContentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err78];}else {vErrors.push(err78);}errors++;}}if(data27.bbox !== undefined){let data30 = data27.bbox;if(data30 && typeof data30 == "object" && !Array.isArray(data30)){if(data30.x === undefined){const err79 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "x"},message:"must have required property '"+"x"+"'"};if(vErrors === null){vErrors = [err79];}else {vErrors.push(err79);}errors++;}if(data30.y === undefined){const err80 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "y"},message:"must have required property '"+"y"+"'"};if(vErrors === null){vErrors = [err80];}else {vErrors.push(err80);}errors++;}if(data30.w === undefined){const err81 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "w"},message:"must have required property '"+"w"+"'"};if(vErrors === null){vErrors = [err81];}else {vErrors.push(err81);}errors++;}if(data30.h === undefined){const err82 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "h"},message:"must have required property '"+"h"+"'"};if(vErrors === null){vErrors = [err82];}else {vErrors.push(err82);}errors++;}for(const key11 in data30){if(!((((key11 === "x") || (key11 === "y")) || (key11 === "w")) || (key11 === "h"))){const err83 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key11},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err83];}else {vErrors.push(err83);}errors++;}}if(data30.x !== undefined){if(!(typeof data30.x == "number")){const err84 = {instancePath:instancePath+"/region/bbox/x",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err84];}else {vErrors.push(err84);}errors++;}}if(data30.y !== undefined){if(!(typeof data30.y == "number")){const err85 = {instancePath:instancePath+"/region/bbox/y",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err85];}else {vErrors.push(err85);}errors++;}}if(data30.w !== undefined){if(!(typeof data30.w == "number")){const err86 = {instancePath:instancePath+"/region/bbox/w",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/w/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err86];}else {vErrors.push(err86);}errors++;}}if(data30.h !== undefined){if(!(typeof data30.h == "number")){const err87 = {instancePath:instancePath+"/region/bbox/h",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/h/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err87];}else {vErrors.push(err87);}errors++;}}}else {const err88 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err88];}else {vErrors.push(err88);}errors++;}}if(data27.shape !== undefined){let data35 = data27.shape;if(data35 && typeof data35 == "object" && !Array.isArray(data35)){if(data35.kind === undefined){const err89 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err89];}else {vErrors.push(err89);}errors++;}for(const key12 in data35){if(!(((key12 === "kind") || (key12 === "points")) || (key12 === "maskHash"))){const err90 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key12},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err90];}else {vErrors.push(err90);}errors++;}}if(data35.kind !== undefined){let data36 = data35.kind;if(!(((data36 === "rect") || (data36 === "polygon")) || (data36 === "mask"))){const err91 = {instancePath:instancePath+"/region/shape/kind",schemaPath:"#/$defs/bufferRegion/properties/shape/properties/kind/enum",keyword:"enum",params:{allowedValues: schema42.properties.shape.properties.kind.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err91];}else {vErrors.push(err91);}errors++;}}if(data35.points !== undefined){let data37 = data35.points;if(Array.isArray(data37)){const len0 = data37.length;for(let i0=0; i0 2){const err92 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err92];}else {vErrors.push(err92);}errors++;}if(data38.length < 2){const err93 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err93];}else {vErrors.push(err93);}errors++;}const len1 = data38.length;for(let i1=0; i1-\", kind ∈ {pixel,vector,audio,video,struct,...}. Same content → same id (automatic dedup).","pattern":"^[a-z]+-[0-9a-f]{16}$"},"signedToken":{"type":"string","minLength":1,"description":"HMAC signature over tenantId ‖ userId ‖ canvasSessionId ‖ dataRefBody ‖ expiryEpoch (see §Security). Server re-validates signature, scope, expiry on fetch."},"expiresAt":{"type":"string","format":"date-time","description":"ISO 8601 expiry. ≤ the server-secret lifetime."},"refreshable":{"type":"boolean","description":"Protocol 1.1 (issue #5): true → the server holds a refresh recipe and re-resolves this data deterministically; the client may surface an instant-refresh affordance. Absent = unknown (agent-fallback refresh)."},"containerId":{"type":"string","description":"Protocol 1.1: the canvas container (table/chart id) this ref's data feeds."}}};const schema37 = {"enum":["local","internal","external-effect"]};const schema43 = {"description":"Annotation on a data-carrying container so Tier 2 can derive mutability per dataClass. Either one string for the whole container, or per-field overrides for a mixed-source container.","oneOf":[{"type":"string"},{"type":"object","required":["default"],"additionalProperties":false,"properties":{"default":{"type":"string"},"fields":{"type":"object","additionalProperties":{"type":"string"}}}}]};const pattern4 = new RegExp("^[a-z]+-[0-9a-f]{16}$", "u");const func1 = __ajv_ucs2length;const schema38 = {"type":"object","additionalProperties":false,"required":["id","label","effect","target"],"properties":{"id":{"type":"string","description":"stable per (treeRevision, container) for idempotency"},"label":{"type":"string","description":"agent-authored, in the user's language"},"effect":{"$ref":"#/$defs/actionEffect"},"target":{"$ref":"https://omadia.ai/protocol/1.0/target-ref.schema.json"},"validUntilRevision":{"type":"string","description":"opaque RevisionId; dropped client-side when treeRevision moves past it (equality semantics)"},"validWhileDataRefs":{"type":"array","items":{"type":"string"}},"prompt":{"type":"string","description":"pre-filled beam text on click"}}};const schema40 = {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://omadia.ai/protocol/1.0/target-ref.schema.json","title":"TargetRef","description":"The single canonical way to address a target anywhere in the canvas protocol: beam targets, _pendingMutation.target, suggestedActions.target, surface_local_action.target, surface_mutation_resolved correlation. Targets address data by STABLE id/hash, never by view position. Ten variants discriminated by `kind`.","$defs":{"textRangeAnchor":{"type":"object","additionalProperties":false,"required":["primitiveId","contentHash","start","end"],"properties":{"primitiveId":{"type":"string","description":"the text primitive's containerId or elementId"},"contentHash":{"type":"string","description":"sha256[:16] of the text content at anchoring time"},"start":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"end":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"fallbackSegment":{"type":"object","additionalProperties":false,"description":"optional re-anchoring snippets on a content-hash miss","required":["before","selection","after"],"properties":{"before":{"type":"string","description":"~32 chars of context before the selection"},"selection":{"type":"string","description":"the selected text itself"},"after":{"type":"string","description":"~32 chars of context after the selection"}}}}},"bufferRegion":{"type":"object","additionalProperties":false,"required":["primitiveId","bufferContentHash","bbox"],"properties":{"primitiveId":{"type":"string","description":"the canvas-region or media primitive's elementId"},"bufferContentHash":{"type":"string","description":"sha256[:16] of the buffer at anchoring time (resolution fails on mismatch)"},"bbox":{"type":"object","additionalProperties":false,"description":"axis-aligned bounding box in buffer-native pixels (zoom/pan independent)","required":["x","y","w","h"],"properties":{"x":{"type":"number"},"y":{"type":"number"},"w":{"type":"number"},"h":{"type":"number"}}},"shape":{"type":"object","additionalProperties":false,"description":"optional non-rect selection (lasso, magic-wand)","required":["kind"],"properties":{"kind":{"enum":["rect","polygon","mask"]},"points":{"type":"array","description":"for 'polygon'","items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2}},"maskHash":{"type":"string","description":"for 'mask' — content-hash of a binary mask sized to bbox"}}}}}},"oneOf":[{"type":"object","additionalProperties":false,"required":["kind","canvasSessionId"],"properties":{"kind":{"const":"canvas"},"canvasSessionId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId"],"properties":{"kind":{"const":"container"},"containerId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","elementId"],"description":"any non-data primitive (heading, divider, status, …)","properties":{"kind":{"const":"element"},"elementId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId","rowKey","fieldKey"],"properties":{"kind":{"const":"rowField"},"containerId":{"type":"string"},"rowKey":{"type":"string"},"fieldKey":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId","itemKey"],"description":"list / tree node","properties":{"kind":{"const":"item"},"containerId":{"type":"string"},"itemKey":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","containerId","pointKey"],"description":"chart data point","properties":{"kind":{"const":"point"},"containerId":{"type":"string"},"pointKey":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","anchor"],"properties":{"kind":{"const":"textRange"},"anchor":{"$ref":"#/$defs/textRangeAnchor"}}},{"type":"object","additionalProperties":false,"required":["kind","region"],"description":"pixel / canvas-region region","properties":{"kind":{"const":"region"},"region":{"$ref":"#/$defs/bufferRegion"}}},{"type":"object","additionalProperties":false,"required":["kind","primitiveId","bufferContentHash"],"description":"whole-buffer reference (canvas-region / media)","properties":{"kind":{"const":"buffer"},"primitiveId":{"type":"string"},"bufferContentHash":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["kind","primitiveId","bufferContentHash","start","end","unit"],"description":"media / timeline trim / splice / scrub. For single-buffer media omit trackId+clipId; for a multi-track timeline trackId is required, clipId optional.","properties":{"kind":{"const":"timeRange"},"primitiveId":{"type":"string"},"bufferContentHash":{"type":"string"},"start":{"type":"number"},"end":{"type":"number"},"unit":{"enum":["seconds","samples","frames"]},"trackId":{"type":"string"},"clipId":{"type":"string"}}}]};const schema41 = {"type":"object","additionalProperties":false,"required":["primitiveId","contentHash","start","end"],"properties":{"primitiveId":{"type":"string","description":"the text primitive's containerId or elementId"},"contentHash":{"type":"string","description":"sha256[:16] of the text content at anchoring time"},"start":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"end":{"type":"integer","minimum":0,"description":"byte offset within that exact content"},"fallbackSegment":{"type":"object","additionalProperties":false,"description":"optional re-anchoring snippets on a content-hash miss","required":["before","selection","after"],"properties":{"before":{"type":"string","description":"~32 chars of context before the selection"},"selection":{"type":"string","description":"the selected text itself"},"after":{"type":"string","description":"~32 chars of context after the selection"}}}}};const schema42 = {"type":"object","additionalProperties":false,"required":["primitiveId","bufferContentHash","bbox"],"properties":{"primitiveId":{"type":"string","description":"the canvas-region or media primitive's elementId"},"bufferContentHash":{"type":"string","description":"sha256[:16] of the buffer at anchoring time (resolution fails on mismatch)"},"bbox":{"type":"object","additionalProperties":false,"description":"axis-aligned bounding box in buffer-native pixels (zoom/pan independent)","required":["x","y","w","h"],"properties":{"x":{"type":"number"},"y":{"type":"number"},"w":{"type":"number"},"h":{"type":"number"}}},"shape":{"type":"object","additionalProperties":false,"description":"optional non-rect selection (lasso, magic-wand)","required":["kind"],"properties":{"kind":{"enum":["rect","polygon","mask"]},"points":{"type":"array","description":"for 'polygon'","items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2}},"maskHash":{"type":"string","description":"for 'mask' — content-hash of a binary mask sized to bbox"}}}}};function validate26(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL="https://omadia.ai/protocol/1.0/target-ref.schema.json" */;let vErrors = null;let errors = 0;const evaluated0 = validate26.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}const _errs0 = errors;let valid0 = false;let passing0 = null;const _errs1 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.canvasSessionId === undefined){const err1 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "canvasSessionId"},message:"must have required property '"+"canvasSessionId"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}for(const key0 in data){if(!((key0 === "kind") || (key0 === "canvasSessionId"))){const err2 = {instancePath,schemaPath:"#/oneOf/0/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.kind !== undefined){if("canvas" !== data.kind){const err3 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/0/properties/kind/const",keyword:"const",params:{allowedValue: "canvas"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.canvasSessionId !== undefined){if(typeof data.canvasSessionId !== "string"){const err4 = {instancePath:instancePath+"/canvasSessionId",schemaPath:"#/oneOf/0/properties/canvasSessionId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}}else {const err5 = {instancePath,schemaPath:"#/oneOf/0/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}var _valid0 = _errs1 === errors;if(_valid0){valid0 = true;passing0 = 0;var props0 = true;}const _errs7 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err6 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}if(data.containerId === undefined){const err7 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}for(const key1 in data){if(!((key1 === "kind") || (key1 === "containerId"))){const err8 = {instancePath,schemaPath:"#/oneOf/1/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.kind !== undefined){if("container" !== data.kind){const err9 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/1/properties/kind/const",keyword:"const",params:{allowedValue: "container"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err10 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/1/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}}else {const err11 = {instancePath,schemaPath:"#/oneOf/1/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}var _valid0 = _errs7 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 1];}else {if(_valid0){valid0 = true;passing0 = 1;if(props0 !== true){props0 = true;}}const _errs13 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err12 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}if(data.elementId === undefined){const err13 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "elementId"},message:"must have required property '"+"elementId"+"'"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}for(const key2 in data){if(!((key2 === "kind") || (key2 === "elementId"))){const err14 = {instancePath,schemaPath:"#/oneOf/2/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key2},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.kind !== undefined){if("element" !== data.kind){const err15 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/2/properties/kind/const",keyword:"const",params:{allowedValue: "element"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.elementId !== undefined){if(typeof data.elementId !== "string"){const err16 = {instancePath:instancePath+"/elementId",schemaPath:"#/oneOf/2/properties/elementId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath,schemaPath:"#/oneOf/2/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}var _valid0 = _errs13 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 2];}else {if(_valid0){valid0 = true;passing0 = 2;if(props0 !== true){props0 = true;}}const _errs19 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err18 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}if(data.containerId === undefined){const err19 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}if(data.rowKey === undefined){const err20 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "rowKey"},message:"must have required property '"+"rowKey"+"'"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}if(data.fieldKey === undefined){const err21 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "fieldKey"},message:"must have required property '"+"fieldKey"+"'"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}for(const key3 in data){if(!((((key3 === "kind") || (key3 === "containerId")) || (key3 === "rowKey")) || (key3 === "fieldKey"))){const err22 = {instancePath,schemaPath:"#/oneOf/3/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key3},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}if(data.kind !== undefined){if("rowField" !== data.kind){const err23 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/3/properties/kind/const",keyword:"const",params:{allowedValue: "rowField"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err24 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/3/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data.rowKey !== undefined){if(typeof data.rowKey !== "string"){const err25 = {instancePath:instancePath+"/rowKey",schemaPath:"#/oneOf/3/properties/rowKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}if(data.fieldKey !== undefined){if(typeof data.fieldKey !== "string"){const err26 = {instancePath:instancePath+"/fieldKey",schemaPath:"#/oneOf/3/properties/fieldKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:"#/oneOf/3/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}var _valid0 = _errs19 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 3];}else {if(_valid0){valid0 = true;passing0 = 3;if(props0 !== true){props0 = true;}}const _errs29 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err28 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}if(data.containerId === undefined){const err29 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}if(data.itemKey === undefined){const err30 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "itemKey"},message:"must have required property '"+"itemKey"+"'"};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}for(const key4 in data){if(!(((key4 === "kind") || (key4 === "containerId")) || (key4 === "itemKey"))){const err31 = {instancePath,schemaPath:"#/oneOf/4/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key4},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}}if(data.kind !== undefined){if("item" !== data.kind){const err32 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/4/properties/kind/const",keyword:"const",params:{allowedValue: "item"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err33 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/4/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}}if(data.itemKey !== undefined){if(typeof data.itemKey !== "string"){const err34 = {instancePath:instancePath+"/itemKey",schemaPath:"#/oneOf/4/properties/itemKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}}}else {const err35 = {instancePath,schemaPath:"#/oneOf/4/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}var _valid0 = _errs29 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 4];}else {if(_valid0){valid0 = true;passing0 = 4;if(props0 !== true){props0 = true;}}const _errs37 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err36 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}if(data.containerId === undefined){const err37 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}if(data.pointKey === undefined){const err38 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "pointKey"},message:"must have required property '"+"pointKey"+"'"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}for(const key5 in data){if(!(((key5 === "kind") || (key5 === "containerId")) || (key5 === "pointKey"))){const err39 = {instancePath,schemaPath:"#/oneOf/5/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key5},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}}if(data.kind !== undefined){if("point" !== data.kind){const err40 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/5/properties/kind/const",keyword:"const",params:{allowedValue: "point"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err41 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/5/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}}if(data.pointKey !== undefined){if(typeof data.pointKey !== "string"){const err42 = {instancePath:instancePath+"/pointKey",schemaPath:"#/oneOf/5/properties/pointKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;}}}else {const err43 = {instancePath,schemaPath:"#/oneOf/5/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}var _valid0 = _errs37 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 5];}else {if(_valid0){valid0 = true;passing0 = 5;if(props0 !== true){props0 = true;}}const _errs45 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err44 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}if(data.anchor === undefined){const err45 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "anchor"},message:"must have required property '"+"anchor"+"'"};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}for(const key6 in data){if(!((key6 === "kind") || (key6 === "anchor"))){const err46 = {instancePath,schemaPath:"#/oneOf/6/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key6},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}}if(data.kind !== undefined){if("textRange" !== data.kind){const err47 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/6/properties/kind/const",keyword:"const",params:{allowedValue: "textRange"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}}if(data.anchor !== undefined){let data17 = data.anchor;if(data17 && typeof data17 == "object" && !Array.isArray(data17)){if(data17.primitiveId === undefined){const err48 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err48];}else {vErrors.push(err48);}errors++;}if(data17.contentHash === undefined){const err49 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "contentHash"},message:"must have required property '"+"contentHash"+"'"};if(vErrors === null){vErrors = [err49];}else {vErrors.push(err49);}errors++;}if(data17.start === undefined){const err50 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "start"},message:"must have required property '"+"start"+"'"};if(vErrors === null){vErrors = [err50];}else {vErrors.push(err50);}errors++;}if(data17.end === undefined){const err51 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "end"},message:"must have required property '"+"end"+"'"};if(vErrors === null){vErrors = [err51];}else {vErrors.push(err51);}errors++;}for(const key7 in data17){if(!(((((key7 === "primitiveId") || (key7 === "contentHash")) || (key7 === "start")) || (key7 === "end")) || (key7 === "fallbackSegment"))){const err52 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key7},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err52];}else {vErrors.push(err52);}errors++;}}if(data17.primitiveId !== undefined){if(typeof data17.primitiveId !== "string"){const err53 = {instancePath:instancePath+"/anchor/primitiveId",schemaPath:"#/$defs/textRangeAnchor/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err53];}else {vErrors.push(err53);}errors++;}}if(data17.contentHash !== undefined){if(typeof data17.contentHash !== "string"){const err54 = {instancePath:instancePath+"/anchor/contentHash",schemaPath:"#/$defs/textRangeAnchor/properties/contentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err54];}else {vErrors.push(err54);}errors++;}}if(data17.start !== undefined){let data20 = data17.start;if(!((typeof data20 == "number") && (!(data20 % 1) && !isNaN(data20)))){const err55 = {instancePath:instancePath+"/anchor/start",schemaPath:"#/$defs/textRangeAnchor/properties/start/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err55];}else {vErrors.push(err55);}errors++;}if(typeof data20 == "number"){if(data20 < 0 || isNaN(data20)){const err56 = {instancePath:instancePath+"/anchor/start",schemaPath:"#/$defs/textRangeAnchor/properties/start/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err56];}else {vErrors.push(err56);}errors++;}}}if(data17.end !== undefined){let data21 = data17.end;if(!((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21)))){const err57 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err57];}else {vErrors.push(err57);}errors++;}if(typeof data21 == "number"){if(data21 < 0 || isNaN(data21)){const err58 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err58];}else {vErrors.push(err58);}errors++;}}}if(data17.fallbackSegment !== undefined){let data22 = data17.fallbackSegment;if(data22 && typeof data22 == "object" && !Array.isArray(data22)){if(data22.before === undefined){const err59 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "before"},message:"must have required property '"+"before"+"'"};if(vErrors === null){vErrors = [err59];}else {vErrors.push(err59);}errors++;}if(data22.selection === undefined){const err60 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "selection"},message:"must have required property '"+"selection"+"'"};if(vErrors === null){vErrors = [err60];}else {vErrors.push(err60);}errors++;}if(data22.after === undefined){const err61 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "after"},message:"must have required property '"+"after"+"'"};if(vErrors === null){vErrors = [err61];}else {vErrors.push(err61);}errors++;}for(const key8 in data22){if(!(((key8 === "before") || (key8 === "selection")) || (key8 === "after"))){const err62 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key8},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err62];}else {vErrors.push(err62);}errors++;}}if(data22.before !== undefined){if(typeof data22.before !== "string"){const err63 = {instancePath:instancePath+"/anchor/fallbackSegment/before",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/before/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err63];}else {vErrors.push(err63);}errors++;}}if(data22.selection !== undefined){if(typeof data22.selection !== "string"){const err64 = {instancePath:instancePath+"/anchor/fallbackSegment/selection",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/selection/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err64];}else {vErrors.push(err64);}errors++;}}if(data22.after !== undefined){if(typeof data22.after !== "string"){const err65 = {instancePath:instancePath+"/anchor/fallbackSegment/after",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/after/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err65];}else {vErrors.push(err65);}errors++;}}}else {const err66 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err66];}else {vErrors.push(err66);}errors++;}}}else {const err67 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err67];}else {vErrors.push(err67);}errors++;}}}else {const err68 = {instancePath,schemaPath:"#/oneOf/6/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err68];}else {vErrors.push(err68);}errors++;}var _valid0 = _errs45 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}const _errs70 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err69 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err69];}else {vErrors.push(err69);}errors++;}if(data.region === undefined){const err70 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "region"},message:"must have required property '"+"region"+"'"};if(vErrors === null){vErrors = [err70];}else {vErrors.push(err70);}errors++;}for(const key9 in data){if(!((key9 === "kind") || (key9 === "region"))){const err71 = {instancePath,schemaPath:"#/oneOf/7/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key9},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err71];}else {vErrors.push(err71);}errors++;}}if(data.kind !== undefined){if("region" !== data.kind){const err72 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/7/properties/kind/const",keyword:"const",params:{allowedValue: "region"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err72];}else {vErrors.push(err72);}errors++;}}if(data.region !== undefined){let data27 = data.region;if(data27 && typeof data27 == "object" && !Array.isArray(data27)){if(data27.primitiveId === undefined){const err73 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err73];}else {vErrors.push(err73);}errors++;}if(data27.bufferContentHash === undefined){const err74 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bufferContentHash"},message:"must have required property '"+"bufferContentHash"+"'"};if(vErrors === null){vErrors = [err74];}else {vErrors.push(err74);}errors++;}if(data27.bbox === undefined){const err75 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bbox"},message:"must have required property '"+"bbox"+"'"};if(vErrors === null){vErrors = [err75];}else {vErrors.push(err75);}errors++;}for(const key10 in data27){if(!((((key10 === "primitiveId") || (key10 === "bufferContentHash")) || (key10 === "bbox")) || (key10 === "shape"))){const err76 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key10},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err76];}else {vErrors.push(err76);}errors++;}}if(data27.primitiveId !== undefined){if(typeof data27.primitiveId !== "string"){const err77 = {instancePath:instancePath+"/region/primitiveId",schemaPath:"#/$defs/bufferRegion/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err77];}else {vErrors.push(err77);}errors++;}}if(data27.bufferContentHash !== undefined){if(typeof data27.bufferContentHash !== "string"){const err78 = {instancePath:instancePath+"/region/bufferContentHash",schemaPath:"#/$defs/bufferRegion/properties/bufferContentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err78];}else {vErrors.push(err78);}errors++;}}if(data27.bbox !== undefined){let data30 = data27.bbox;if(data30 && typeof data30 == "object" && !Array.isArray(data30)){if(data30.x === undefined){const err79 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "x"},message:"must have required property '"+"x"+"'"};if(vErrors === null){vErrors = [err79];}else {vErrors.push(err79);}errors++;}if(data30.y === undefined){const err80 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "y"},message:"must have required property '"+"y"+"'"};if(vErrors === null){vErrors = [err80];}else {vErrors.push(err80);}errors++;}if(data30.w === undefined){const err81 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "w"},message:"must have required property '"+"w"+"'"};if(vErrors === null){vErrors = [err81];}else {vErrors.push(err81);}errors++;}if(data30.h === undefined){const err82 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "h"},message:"must have required property '"+"h"+"'"};if(vErrors === null){vErrors = [err82];}else {vErrors.push(err82);}errors++;}for(const key11 in data30){if(!((((key11 === "x") || (key11 === "y")) || (key11 === "w")) || (key11 === "h"))){const err83 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key11},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err83];}else {vErrors.push(err83);}errors++;}}if(data30.x !== undefined){if(!(typeof data30.x == "number")){const err84 = {instancePath:instancePath+"/region/bbox/x",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err84];}else {vErrors.push(err84);}errors++;}}if(data30.y !== undefined){if(!(typeof data30.y == "number")){const err85 = {instancePath:instancePath+"/region/bbox/y",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err85];}else {vErrors.push(err85);}errors++;}}if(data30.w !== undefined){if(!(typeof data30.w == "number")){const err86 = {instancePath:instancePath+"/region/bbox/w",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/w/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err86];}else {vErrors.push(err86);}errors++;}}if(data30.h !== undefined){if(!(typeof data30.h == "number")){const err87 = {instancePath:instancePath+"/region/bbox/h",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/h/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err87];}else {vErrors.push(err87);}errors++;}}}else {const err88 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err88];}else {vErrors.push(err88);}errors++;}}if(data27.shape !== undefined){let data35 = data27.shape;if(data35 && typeof data35 == "object" && !Array.isArray(data35)){if(data35.kind === undefined){const err89 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err89];}else {vErrors.push(err89);}errors++;}for(const key12 in data35){if(!(((key12 === "kind") || (key12 === "points")) || (key12 === "maskHash"))){const err90 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key12},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err90];}else {vErrors.push(err90);}errors++;}}if(data35.kind !== undefined){let data36 = data35.kind;if(!(((data36 === "rect") || (data36 === "polygon")) || (data36 === "mask"))){const err91 = {instancePath:instancePath+"/region/shape/kind",schemaPath:"#/$defs/bufferRegion/properties/shape/properties/kind/enum",keyword:"enum",params:{allowedValues: schema42.properties.shape.properties.kind.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err91];}else {vErrors.push(err91);}errors++;}}if(data35.points !== undefined){let data37 = data35.points;if(Array.isArray(data37)){const len0 = data37.length;for(let i0=0; i0 2){const err92 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err92];}else {vErrors.push(err92);}errors++;}if(data38.length < 2){const err93 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err93];}else {vErrors.push(err93);}errors++;}const len1 = data38.length;for(let i1=0; i1 6 || isNaN(data2)){const err5 = {instancePath:instancePath+"/level",schemaPath:"#/allOf/1/properties/level/maximum",keyword:"maximum",params:{comparison: "<=", limit: 6},message:"must be <= 6"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}if(data2 < 1 || isNaN(data2)){const err6 = {instancePath:instancePath+"/level",schemaPath:"#/allOf/1/properties/level/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}}}if(data && typeof data == "object" && !Array.isArray(data)){for(const key0 in data){if((((((((((((((((((key0 !== "type") && (key0 !== "content")) && (key0 !== "level")) && (key0 !== "id")) && (key0 !== "dataRef")) && (key0 !== "selectable")) && (key0 !== "loading")) && (key0 !== "error")) && (key0 !== "virtualized")) && (key0 !== "action")) && (key0 !== "style")) && (key0 !== "tone")) && (key0 !== "continuous-input")) && (key0 !== "selection-region")) && (key0 !== "realtime-output")) && (key0 !== "frame-precise-time")) && (key0 !== "suggestedActions")) && (key0 !== "dataClass")){const err7 = {instancePath,schemaPath:"#/unevaluatedProperties",keyword:"unevaluatedProperties",params:{unevaluatedProperty: key0},message:"must NOT have unevaluated properties"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}}validate31.errors = vErrors;return errors === 0;}validate31.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema45 = {"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type"],"properties":{"type":{"const":"container"},"title":{"type":"string"},"layout":{"enum":["stack","split","grid","flow"]},"kind":{"enum":["modal","plain"]},"canAddItems":{"type":"boolean"},"canRemoveItems":{"type":"boolean"},"canReorder":{"type":"boolean"},"children":{"type":"array","items":{"$ref":"#/$defs/primitive"}}}}],"unevaluatedProperties":false};const wrapper0 = {validate: validate21};function validate34(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate34.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(validate23(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate23.errors : vErrors.concat(validate23.errors);errors = vErrors.length;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err0 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.type !== undefined){if("container" !== data.type){const err1 = {instancePath:instancePath+"/type",schemaPath:"#/allOf/1/properties/type/const",keyword:"const",params:{allowedValue: "container"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.title !== undefined){if(typeof data.title !== "string"){const err2 = {instancePath:instancePath+"/title",schemaPath:"#/allOf/1/properties/title/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.layout !== undefined){let data2 = data.layout;if(!((((data2 === "stack") || (data2 === "split")) || (data2 === "grid")) || (data2 === "flow"))){const err3 = {instancePath:instancePath+"/layout",schemaPath:"#/allOf/1/properties/layout/enum",keyword:"enum",params:{allowedValues: schema45.allOf[1].properties.layout.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.kind !== undefined){let data3 = data.kind;if(!((data3 === "modal") || (data3 === "plain"))){const err4 = {instancePath:instancePath+"/kind",schemaPath:"#/allOf/1/properties/kind/enum",keyword:"enum",params:{allowedValues: schema45.allOf[1].properties.kind.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.canAddItems !== undefined){if(typeof data.canAddItems !== "boolean"){const err5 = {instancePath:instancePath+"/canAddItems",schemaPath:"#/allOf/1/properties/canAddItems/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.canRemoveItems !== undefined){if(typeof data.canRemoveItems !== "boolean"){const err6 = {instancePath:instancePath+"/canRemoveItems",schemaPath:"#/allOf/1/properties/canRemoveItems/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.canReorder !== undefined){if(typeof data.canReorder !== "boolean"){const err7 = {instancePath:instancePath+"/canReorder",schemaPath:"#/allOf/1/properties/canReorder/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.children !== undefined){let data7 = data.children;if(Array.isArray(data7)){const len0 = data7.length;for(let i0=0; i0=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}}if(data.height !== undefined){let data2 = data.height;if(!((typeof data2 == "number") && (!(data2 % 1) && !isNaN(data2)))){const err7 = {instancePath:instancePath+"/height",schemaPath:"#/allOf/1/properties/height/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}if(typeof data2 == "number"){if(data2 < 1 || isNaN(data2)){const err8 = {instancePath:instancePath+"/height",schemaPath:"#/allOf/1/properties/height/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}}if(data.pixelFormat !== undefined){let data3 = data.pixelFormat;if(!((data3 === "rgba8") || (data3 === "rgba16"))){const err9 = {instancePath:instancePath+"/pixelFormat",schemaPath:"#/allOf/1/properties/pixelFormat/enum",keyword:"enum",params:{allowedValues: schema71.allOf[1].properties.pixelFormat.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.colorSpace !== undefined){if(typeof data.colorSpace !== "string"){const err10 = {instancePath:instancePath+"/colorSpace",schemaPath:"#/allOf/1/properties/colorSpace/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.dpi !== undefined){if(!(typeof data.dpi == "number")){const err11 = {instancePath:instancePath+"/dpi",schemaPath:"#/allOf/1/properties/dpi/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}}if(data && typeof data == "object" && !Array.isArray(data)){for(const key0 in data){if(((((((((((((((((((((key0 !== "type") && (key0 !== "width")) && (key0 !== "height")) && (key0 !== "pixelFormat")) && (key0 !== "colorSpace")) && (key0 !== "dpi")) && (key0 !== "id")) && (key0 !== "dataRef")) && (key0 !== "selectable")) && (key0 !== "loading")) && (key0 !== "error")) && (key0 !== "virtualized")) && (key0 !== "action")) && (key0 !== "style")) && (key0 !== "tone")) && (key0 !== "continuous-input")) && (key0 !== "selection-region")) && (key0 !== "realtime-output")) && (key0 !== "frame-precise-time")) && (key0 !== "suggestedActions")) && (key0 !== "dataClass")){const err12 = {instancePath,schemaPath:"#/unevaluatedProperties",keyword:"unevaluatedProperties",params:{unevaluatedProperty: key0},message:"must NOT have unevaluated properties"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}}validate94.errors = vErrors;return errors === 0;}validate94.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema72 = {"allOf":[{"$ref":"#/$defs/commonTraits"},{"required":["type","tracks","timebase"],"properties":{"type":{"const":"timeline"},"tracks":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["id","kind"],"properties":{"id":{"type":"string"},"kind":{"enum":["audio","video","marker"]}}}},"timebase":{"type":"object","additionalProperties":false,"properties":{"frameRate":{"type":"number"},"sampleRate":{"type":"number"}}},"duration":{"type":"number"},"playhead":{"type":"number"},"loopRegion":{}}}],"unevaluatedProperties":false};function validate97(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate97.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(validate23(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate23.errors : vErrors.concat(validate23.errors);errors = vErrors.length;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err0 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.tracks === undefined){const err1 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "tracks"},message:"must have required property '"+"tracks"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.timebase === undefined){const err2 = {instancePath,schemaPath:"#/allOf/1/required",keyword:"required",params:{missingProperty: "timebase"},message:"must have required property '"+"timebase"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.type !== undefined){if("timeline" !== data.type){const err3 = {instancePath:instancePath+"/type",schemaPath:"#/allOf/1/properties/type/const",keyword:"const",params:{allowedValue: "timeline"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.tracks !== undefined){let data1 = data.tracks;if(Array.isArray(data1)){const len0 = data1.length;for(let i0=0; i0=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}else {const err12 = {instancePath:instancePath+"/r",schemaPath:"#/properties/r/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.fill !== undefined){let data6 = data.fill;if(!((((((((((((((((data6 === "accent") || (data6 === "accent.glow")) || (data6 === "accent.glow-soft")) || (data6 === "accent.glow-core")) || (data6 === "surface")) || (data6 === "surface-raised")) || (data6 === "surface-sunken")) || (data6 === "text")) || (data6 === "text-muted")) || (data6 === "text-faint")) || (data6 === "neutral")) || (data6 === "info")) || (data6 === "success")) || (data6 === "warning")) || (data6 === "danger")) || (data6 === "transparent"))){const err13 = {instancePath:instancePath+"/fill",schemaPath:"#/$defs/colorToken/enum",keyword:"enum",params:{allowedValues: schema78.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data.stroke !== undefined){let data7 = data.stroke;if(!((((((((((((((((data7 === "accent") || (data7 === "accent.glow")) || (data7 === "accent.glow-soft")) || (data7 === "accent.glow-core")) || (data7 === "surface")) || (data7 === "surface-raised")) || (data7 === "surface-sunken")) || (data7 === "text")) || (data7 === "text-muted")) || (data7 === "text-faint")) || (data7 === "neutral")) || (data7 === "info")) || (data7 === "success")) || (data7 === "warning")) || (data7 === "danger")) || (data7 === "transparent"))){const err14 = {instancePath:instancePath+"/stroke",schemaPath:"#/$defs/colorToken/enum",keyword:"enum",params:{allowedValues: schema78.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.strokeW !== undefined){let data8 = data.strokeW;if(typeof data8 == "number"){if(data8 < 0 || isNaN(data8)){const err15 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}else {const err16 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err17 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}if(data.hitPadding !== undefined){let data10 = data.hitPadding;if(typeof data10 == "number"){if(data10 < 0 || isNaN(data10)){const err18 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}else {const err19 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}}else {const err20 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}validate106.errors = vErrors;return errors === 0;}validate106.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema81 = {"type":"object","additionalProperties":false,"required":["kind","cx","cy","r"],"properties":{"kind":{"const":"circle"},"cx":{"type":"number"},"cy":{"type":"number"},"r":{"type":"number","minimum":0},"fill":{"$ref":"#/$defs/colorToken"},"stroke":{"$ref":"#/$defs/colorToken"},"strokeW":{"type":"number","minimum":0},"id":{"type":"string"},"hitPadding":{"$ref":"#/$defs/hitPadding"}}};function validate108(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate108.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.cx === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "cx"},message:"must have required property '"+"cx"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.cy === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "cy"},message:"must have required property '"+"cy"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.r === undefined){const err3 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "r"},message:"must have required property '"+"r"+"'"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}for(const key0 in data){if(!(func5.call(schema81.properties, key0))){const err4 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.kind !== undefined){if("circle" !== data.kind){const err5 = {instancePath:instancePath+"/kind",schemaPath:"#/properties/kind/const",keyword:"const",params:{allowedValue: "circle"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.cx !== undefined){if(!(typeof data.cx == "number")){const err6 = {instancePath:instancePath+"/cx",schemaPath:"#/properties/cx/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.cy !== undefined){if(!(typeof data.cy == "number")){const err7 = {instancePath:instancePath+"/cy",schemaPath:"#/properties/cy/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.r !== undefined){let data3 = data.r;if(typeof data3 == "number"){if(data3 < 0 || isNaN(data3)){const err8 = {instancePath:instancePath+"/r",schemaPath:"#/properties/r/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}else {const err9 = {instancePath:instancePath+"/r",schemaPath:"#/properties/r/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.fill !== undefined){let data4 = data.fill;if(!((((((((((((((((data4 === "accent") || (data4 === "accent.glow")) || (data4 === "accent.glow-soft")) || (data4 === "accent.glow-core")) || (data4 === "surface")) || (data4 === "surface-raised")) || (data4 === "surface-sunken")) || (data4 === "text")) || (data4 === "text-muted")) || (data4 === "text-faint")) || (data4 === "neutral")) || (data4 === "info")) || (data4 === "success")) || (data4 === "warning")) || (data4 === "danger")) || (data4 === "transparent"))){const err10 = {instancePath:instancePath+"/fill",schemaPath:"#/$defs/colorToken/enum",keyword:"enum",params:{allowedValues: schema78.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.stroke !== undefined){let data5 = data.stroke;if(!((((((((((((((((data5 === "accent") || (data5 === "accent.glow")) || (data5 === "accent.glow-soft")) || (data5 === "accent.glow-core")) || (data5 === "surface")) || (data5 === "surface-raised")) || (data5 === "surface-sunken")) || (data5 === "text")) || (data5 === "text-muted")) || (data5 === "text-faint")) || (data5 === "neutral")) || (data5 === "info")) || (data5 === "success")) || (data5 === "warning")) || (data5 === "danger")) || (data5 === "transparent"))){const err11 = {instancePath:instancePath+"/stroke",schemaPath:"#/$defs/colorToken/enum",keyword:"enum",params:{allowedValues: schema78.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.strokeW !== undefined){let data6 = data.strokeW;if(typeof data6 == "number"){if(data6 < 0 || isNaN(data6)){const err12 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}else {const err13 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err14 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.hitPadding !== undefined){let data8 = data.hitPadding;if(typeof data8 == "number"){if(data8 < 0 || isNaN(data8)){const err15 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}else {const err16 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}validate108.errors = vErrors;return errors === 0;}validate108.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema85 = {"type":"object","additionalProperties":false,"required":["kind","x1","y1","x2","y2","stroke"],"properties":{"kind":{"const":"line"},"x1":{"type":"number"},"y1":{"type":"number"},"x2":{"type":"number"},"y2":{"type":"number"},"stroke":{"$ref":"#/$defs/colorToken"},"strokeW":{"type":"number","minimum":0},"id":{"type":"string"},"hitPadding":{"$ref":"#/$defs/hitPadding"}}};function validate110(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate110.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.x1 === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "x1"},message:"must have required property '"+"x1"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.y1 === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "y1"},message:"must have required property '"+"y1"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.x2 === undefined){const err3 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "x2"},message:"must have required property '"+"x2"+"'"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}if(data.y2 === undefined){const err4 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "y2"},message:"must have required property '"+"y2"+"'"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data.stroke === undefined){const err5 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "stroke"},message:"must have required property '"+"stroke"+"'"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}for(const key0 in data){if(!(func5.call(schema85.properties, key0))){const err6 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.kind !== undefined){if("line" !== data.kind){const err7 = {instancePath:instancePath+"/kind",schemaPath:"#/properties/kind/const",keyword:"const",params:{allowedValue: "line"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.x1 !== undefined){if(!(typeof data.x1 == "number")){const err8 = {instancePath:instancePath+"/x1",schemaPath:"#/properties/x1/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.y1 !== undefined){if(!(typeof data.y1 == "number")){const err9 = {instancePath:instancePath+"/y1",schemaPath:"#/properties/y1/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.x2 !== undefined){if(!(typeof data.x2 == "number")){const err10 = {instancePath:instancePath+"/x2",schemaPath:"#/properties/x2/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.y2 !== undefined){if(!(typeof data.y2 == "number")){const err11 = {instancePath:instancePath+"/y2",schemaPath:"#/properties/y2/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.stroke !== undefined){let data5 = data.stroke;if(!((((((((((((((((data5 === "accent") || (data5 === "accent.glow")) || (data5 === "accent.glow-soft")) || (data5 === "accent.glow-core")) || (data5 === "surface")) || (data5 === "surface-raised")) || (data5 === "surface-sunken")) || (data5 === "text")) || (data5 === "text-muted")) || (data5 === "text-faint")) || (data5 === "neutral")) || (data5 === "info")) || (data5 === "success")) || (data5 === "warning")) || (data5 === "danger")) || (data5 === "transparent"))){const err12 = {instancePath:instancePath+"/stroke",schemaPath:"#/$defs/colorToken/enum",keyword:"enum",params:{allowedValues: schema78.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.strokeW !== undefined){let data6 = data.strokeW;if(typeof data6 == "number"){if(data6 < 0 || isNaN(data6)){const err13 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}else {const err14 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err15 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.hitPadding !== undefined){let data8 = data.hitPadding;if(typeof data8 == "number"){if(data8 < 0 || isNaN(data8)){const err16 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}else {const err17 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}}else {const err18 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}validate110.errors = vErrors;return errors === 0;}validate110.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema88 = {"type":"object","additionalProperties":false,"required":["kind","points"],"properties":{"kind":{"const":"path"},"points":{"type":"array","items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2}},"closed":{"type":"boolean"},"fill":{"$ref":"#/$defs/colorToken"},"stroke":{"$ref":"#/$defs/colorToken"},"strokeW":{"type":"number","minimum":0},"id":{"type":"string"},"hitPadding":{"$ref":"#/$defs/hitPadding"}}};function validate112(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate112.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.points === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "points"},message:"must have required property '"+"points"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}for(const key0 in data){if(!((((((((key0 === "kind") || (key0 === "points")) || (key0 === "closed")) || (key0 === "fill")) || (key0 === "stroke")) || (key0 === "strokeW")) || (key0 === "id")) || (key0 === "hitPadding"))){const err2 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.kind !== undefined){if("path" !== data.kind){const err3 = {instancePath:instancePath+"/kind",schemaPath:"#/properties/kind/const",keyword:"const",params:{allowedValue: "path"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.points !== undefined){let data1 = data.points;if(Array.isArray(data1)){const len0 = data1.length;for(let i0=0; i0 2){const err4 = {instancePath:instancePath+"/points/" + i0,schemaPath:"#/properties/points/items/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data2.length < 2){const err5 = {instancePath:instancePath+"/points/" + i0,schemaPath:"#/properties/points/items/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}const len1 = data2.length;for(let i1=0; i1=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}else {const err13 = {instancePath:instancePath+"/strokeW",schemaPath:"#/properties/strokeW/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err14 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.hitPadding !== undefined){let data9 = data.hitPadding;if(typeof data9 == "number"){if(data9 < 0 || isNaN(data9)){const err15 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}else {const err16 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}validate112.errors = vErrors;return errors === 0;}validate112.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema92 = {"type":"object","additionalProperties":false,"required":["kind","x","y","w","h","dataRef"],"properties":{"kind":{"const":"sprite"},"x":{"type":"number"},"y":{"type":"number"},"w":{"type":"number"},"h":{"type":"number"},"dataRef":{"$ref":"https://omadia.ai/protocol/1.0/data-ref.schema.json"},"id":{"type":"string"},"hitPadding":{"$ref":"#/$defs/hitPadding"}}};function validate114(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate114.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.x === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "x"},message:"must have required property '"+"x"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.y === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "y"},message:"must have required property '"+"y"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.w === undefined){const err3 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "w"},message:"must have required property '"+"w"+"'"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}if(data.h === undefined){const err4 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "h"},message:"must have required property '"+"h"+"'"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data.dataRef === undefined){const err5 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "dataRef"},message:"must have required property '"+"dataRef"+"'"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}for(const key0 in data){if(!((((((((key0 === "kind") || (key0 === "x")) || (key0 === "y")) || (key0 === "w")) || (key0 === "h")) || (key0 === "dataRef")) || (key0 === "id")) || (key0 === "hitPadding"))){const err6 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.kind !== undefined){if("sprite" !== data.kind){const err7 = {instancePath:instancePath+"/kind",schemaPath:"#/properties/kind/const",keyword:"const",params:{allowedValue: "sprite"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.x !== undefined){if(!(typeof data.x == "number")){const err8 = {instancePath:instancePath+"/x",schemaPath:"#/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.y !== undefined){if(!(typeof data.y == "number")){const err9 = {instancePath:instancePath+"/y",schemaPath:"#/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.w !== undefined){if(!(typeof data.w == "number")){const err10 = {instancePath:instancePath+"/w",schemaPath:"#/properties/w/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.h !== undefined){if(!(typeof data.h == "number")){const err11 = {instancePath:instancePath+"/h",schemaPath:"#/properties/h/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.dataRef !== undefined){let data5 = data.dataRef;if(data5 && typeof data5 == "object" && !Array.isArray(data5)){if(data5.id === undefined){const err12 = {instancePath:instancePath+"/dataRef",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/required",keyword:"required",params:{missingProperty: "id"},message:"must have required property '"+"id"+"'"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}if(data5.signedToken === undefined){const err13 = {instancePath:instancePath+"/dataRef",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/required",keyword:"required",params:{missingProperty: "signedToken"},message:"must have required property '"+"signedToken"+"'"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}if(data5.expiresAt === undefined){const err14 = {instancePath:instancePath+"/dataRef",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/required",keyword:"required",params:{missingProperty: "expiresAt"},message:"must have required property '"+"expiresAt"+"'"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}for(const key1 in data5){if(!(((((key1 === "id") || (key1 === "signedToken")) || (key1 === "expiresAt")) || (key1 === "refreshable")) || (key1 === "containerId"))){const err15 = {instancePath:instancePath+"/dataRef",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data5.id !== undefined){let data6 = data5.id;if(typeof data6 === "string"){if(!pattern4.test(data6)){const err16 = {instancePath:instancePath+"/dataRef/id",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/id/pattern",keyword:"pattern",params:{pattern: "^[a-z]+-[0-9a-f]{16}$"},message:"must match pattern \""+"^[a-z]+-[0-9a-f]{16}$"+"\""};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}else {const err17 = {instancePath:instancePath+"/dataRef/id",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}if(data5.signedToken !== undefined){let data7 = data5.signedToken;if(typeof data7 === "string"){if(func1(data7) < 1){const err18 = {instancePath:instancePath+"/dataRef/signedToken",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/signedToken/minLength",keyword:"minLength",params:{limit: 1},message:"must NOT have fewer than 1 characters"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}else {const err19 = {instancePath:instancePath+"/dataRef/signedToken",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/signedToken/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}if(data5.expiresAt !== undefined){if(!(typeof data5.expiresAt === "string")){const err20 = {instancePath:instancePath+"/dataRef/expiresAt",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/expiresAt/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}}if(data5.refreshable !== undefined){if(typeof data5.refreshable !== "boolean"){const err21 = {instancePath:instancePath+"/dataRef/refreshable",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/refreshable/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}}if(data5.containerId !== undefined){if(typeof data5.containerId !== "string"){const err22 = {instancePath:instancePath+"/dataRef/containerId",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}}else {const err23 = {instancePath:instancePath+"/dataRef",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err24 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data.hitPadding !== undefined){let data12 = data.hitPadding;if(typeof data12 == "number"){if(data12 < 0 || isNaN(data12)){const err25 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}else {const err26 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}validate114.errors = vErrors;return errors === 0;}validate114.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema95 = {"type":"object","additionalProperties":false,"required":["kind","x","y","text"],"properties":{"kind":{"const":"text"},"x":{"type":"number"},"y":{"type":"number"},"text":{"type":"string"},"size":{"type":"number","exclusiveMinimum":0},"weight":{"type":"integer","minimum":100,"maximum":900},"register":{"$ref":"#/$defs/typeRegister"},"fill":{"$ref":"#/$defs/colorToken"},"id":{"type":"string"},"hitPadding":{"$ref":"#/$defs/hitPadding"}}};const schema96 = {"description":"the three Lume type registers (visual-spec.md §2.7)","enum":["display","prose","mono"]};function validate116(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate116.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.x === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "x"},message:"must have required property '"+"x"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.y === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "y"},message:"must have required property '"+"y"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.text === undefined){const err3 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "text"},message:"must have required property '"+"text"+"'"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}for(const key0 in data){if(!(func5.call(schema95.properties, key0))){const err4 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.kind !== undefined){if("text" !== data.kind){const err5 = {instancePath:instancePath+"/kind",schemaPath:"#/properties/kind/const",keyword:"const",params:{allowedValue: "text"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.x !== undefined){if(!(typeof data.x == "number")){const err6 = {instancePath:instancePath+"/x",schemaPath:"#/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.y !== undefined){if(!(typeof data.y == "number")){const err7 = {instancePath:instancePath+"/y",schemaPath:"#/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.text !== undefined){if(typeof data.text !== "string"){const err8 = {instancePath:instancePath+"/text",schemaPath:"#/properties/text/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.size !== undefined){let data4 = data.size;if(typeof data4 == "number"){if(data4 <= 0 || isNaN(data4)){const err9 = {instancePath:instancePath+"/size",schemaPath:"#/properties/size/exclusiveMinimum",keyword:"exclusiveMinimum",params:{comparison: ">", limit: 0},message:"must be > 0"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}else {const err10 = {instancePath:instancePath+"/size",schemaPath:"#/properties/size/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.weight !== undefined){let data5 = data.weight;if(!((typeof data5 == "number") && (!(data5 % 1) && !isNaN(data5)))){const err11 = {instancePath:instancePath+"/weight",schemaPath:"#/properties/weight/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}if(typeof data5 == "number"){if(data5 > 900 || isNaN(data5)){const err12 = {instancePath:instancePath+"/weight",schemaPath:"#/properties/weight/maximum",keyword:"maximum",params:{comparison: "<=", limit: 900},message:"must be <= 900"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}if(data5 < 100 || isNaN(data5)){const err13 = {instancePath:instancePath+"/weight",schemaPath:"#/properties/weight/minimum",keyword:"minimum",params:{comparison: ">=", limit: 100},message:"must be >= 100"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}}if(data.register !== undefined){let data6 = data.register;if(!(((data6 === "display") || (data6 === "prose")) || (data6 === "mono"))){const err14 = {instancePath:instancePath+"/register",schemaPath:"#/$defs/typeRegister/enum",keyword:"enum",params:{allowedValues: schema96.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.fill !== undefined){let data7 = data.fill;if(!((((((((((((((((data7 === "accent") || (data7 === "accent.glow")) || (data7 === "accent.glow-soft")) || (data7 === "accent.glow-core")) || (data7 === "surface")) || (data7 === "surface-raised")) || (data7 === "surface-sunken")) || (data7 === "text")) || (data7 === "text-muted")) || (data7 === "text-faint")) || (data7 === "neutral")) || (data7 === "info")) || (data7 === "success")) || (data7 === "warning")) || (data7 === "danger")) || (data7 === "transparent"))){const err15 = {instancePath:instancePath+"/fill",schemaPath:"#/$defs/colorToken/enum",keyword:"enum",params:{allowedValues: schema78.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err16 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}if(data.hitPadding !== undefined){let data9 = data.hitPadding;if(typeof data9 == "number"){if(data9 < 0 || isNaN(data9)){const err17 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}else {const err18 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}}}else {const err19 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}validate116.errors = vErrors;return errors === 0;}validate116.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema99 = {"type":"object","additionalProperties":false,"required":["kind","children"],"properties":{"kind":{"const":"group"},"transform":{"$ref":"#/$defs/transform"},"children":{"type":"array","items":{"$ref":"#/$defs/sceneNode"}},"id":{"type":"string"},"hitPadding":{"$ref":"#/$defs/hitPadding"}}};const schema100 = {"type":"object","additionalProperties":false,"properties":{"x":{"type":"number"},"y":{"type":"number"},"scale":{"type":"number"},"rotate":{"type":"number","description":"degrees"}}};const wrapper7 = {validate: validate105};function validate118(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate118.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.children === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "children"},message:"must have required property '"+"children"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}for(const key0 in data){if(!(((((key0 === "kind") || (key0 === "transform")) || (key0 === "children")) || (key0 === "id")) || (key0 === "hitPadding"))){const err2 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.kind !== undefined){if("group" !== data.kind){const err3 = {instancePath:instancePath+"/kind",schemaPath:"#/properties/kind/const",keyword:"const",params:{allowedValue: "group"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.transform !== undefined){let data1 = data.transform;if(data1 && typeof data1 == "object" && !Array.isArray(data1)){for(const key1 in data1){if(!((((key1 === "x") || (key1 === "y")) || (key1 === "scale")) || (key1 === "rotate"))){const err4 = {instancePath:instancePath+"/transform",schemaPath:"#/$defs/transform/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data1.x !== undefined){if(!(typeof data1.x == "number")){const err5 = {instancePath:instancePath+"/transform/x",schemaPath:"#/$defs/transform/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data1.y !== undefined){if(!(typeof data1.y == "number")){const err6 = {instancePath:instancePath+"/transform/y",schemaPath:"#/$defs/transform/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data1.scale !== undefined){if(!(typeof data1.scale == "number")){const err7 = {instancePath:instancePath+"/transform/scale",schemaPath:"#/$defs/transform/properties/scale/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data1.rotate !== undefined){if(!(typeof data1.rotate == "number")){const err8 = {instancePath:instancePath+"/transform/rotate",schemaPath:"#/$defs/transform/properties/rotate/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}}else {const err9 = {instancePath:instancePath+"/transform",schemaPath:"#/$defs/transform/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.children !== undefined){let data6 = data.children;if(Array.isArray(data6)){const len0 = data6.length;for(let i0=0; i0=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}else {const err13 = {instancePath:instancePath+"/hitPadding",schemaPath:"#/$defs/hitPadding/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}}else {const err14 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}validate118.errors = vErrors;return errors === 0;}validate118.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};function validate105(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate105.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(data && typeof data == "object" && !Array.isArray(data))){const err0 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}const _errs1 = errors;let valid0 = false;let passing0 = null;const _errs2 = errors;if(!(validate106(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate106.errors : vErrors.concat(validate106.errors);errors = vErrors.length;}var _valid0 = _errs2 === errors;if(_valid0){valid0 = true;passing0 = 0;var props0 = true;}const _errs3 = errors;if(!(validate108(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate108.errors : vErrors.concat(validate108.errors);errors = vErrors.length;}var _valid0 = _errs3 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 1];}else {if(_valid0){valid0 = true;passing0 = 1;if(props0 !== true){props0 = true;}}const _errs4 = errors;if(!(validate110(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate110.errors : vErrors.concat(validate110.errors);errors = vErrors.length;}var _valid0 = _errs4 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 2];}else {if(_valid0){valid0 = true;passing0 = 2;if(props0 !== true){props0 = true;}}const _errs5 = errors;if(!(validate112(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate112.errors : vErrors.concat(validate112.errors);errors = vErrors.length;}var _valid0 = _errs5 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 3];}else {if(_valid0){valid0 = true;passing0 = 3;if(props0 !== true){props0 = true;}}const _errs6 = errors;if(!(validate114(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate114.errors : vErrors.concat(validate114.errors);errors = vErrors.length;}var _valid0 = _errs6 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 4];}else {if(_valid0){valid0 = true;passing0 = 4;if(props0 !== true){props0 = true;}}const _errs7 = errors;if(!(validate116(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate116.errors : vErrors.concat(validate116.errors);errors = vErrors.length;}var _valid0 = _errs7 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 5];}else {if(_valid0){valid0 = true;passing0 = 5;if(props0 !== true){props0 = true;}}const _errs8 = errors;if(!(validate118(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate118.errors : vErrors.concat(validate118.errors);errors = vErrors.length;}var _valid0 = _errs8 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}}}}}}}if(!valid0){const err1 = {instancePath,schemaPath:"#/oneOf",keyword:"oneOf",params:{passingSchemas: passing0},message:"must match exactly one schema in oneOf"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}else {errors = _errs1;if(vErrors !== null){if(_errs1){vErrors.length = _errs1;}else {vErrors = null;}}}validate105.errors = vErrors;evaluated0.props = props0;return errors === 0;}validate105.evaluated = {"dynamicProps":true,"dynamicItems":false};function validate104(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate104.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.width === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "width"},message:"must have required property '"+"width"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.height === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "height"},message:"must have required property '"+"height"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}if(data.draw === undefined){const err3 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "draw"},message:"must have required property '"+"draw"+"'"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}for(const key0 in data){if(!((((((key0 === "type") || (key0 === "id")) || (key0 === "width")) || (key0 === "height")) || (key0 === "camera")) || (key0 === "draw"))){const err4 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.type !== undefined){if("scene" !== data.type){const err5 = {instancePath:instancePath+"/type",schemaPath:"#/properties/type/const",keyword:"const",params:{allowedValue: "scene"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.id !== undefined){if(typeof data.id !== "string"){const err6 = {instancePath:instancePath+"/id",schemaPath:"#/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.width !== undefined){let data2 = data.width;if(!((typeof data2 == "number") && (!(data2 % 1) && !isNaN(data2)))){const err7 = {instancePath:instancePath+"/width",schemaPath:"#/properties/width/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}if(typeof data2 == "number"){if(data2 < 1 || isNaN(data2)){const err8 = {instancePath:instancePath+"/width",schemaPath:"#/properties/width/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}}if(data.height !== undefined){let data3 = data.height;if(!((typeof data3 == "number") && (!(data3 % 1) && !isNaN(data3)))){const err9 = {instancePath:instancePath+"/height",schemaPath:"#/properties/height/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}if(typeof data3 == "number"){if(data3 < 1 || isNaN(data3)){const err10 = {instancePath:instancePath+"/height",schemaPath:"#/properties/height/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}}if(data.camera !== undefined){let data4 = data.camera;if(data4 && typeof data4 == "object" && !Array.isArray(data4)){for(const key1 in data4){if(!(((key1 === "x") || (key1 === "y")) || (key1 === "zoom"))){const err11 = {instancePath:instancePath+"/camera",schemaPath:"#/properties/camera/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data4.x !== undefined){if(!(typeof data4.x == "number")){const err12 = {instancePath:instancePath+"/camera/x",schemaPath:"#/properties/camera/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data4.y !== undefined){if(!(typeof data4.y == "number")){const err13 = {instancePath:instancePath+"/camera/y",schemaPath:"#/properties/camera/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data4.zoom !== undefined){let data7 = data4.zoom;if(typeof data7 == "number"){if(data7 <= 0 || isNaN(data7)){const err14 = {instancePath:instancePath+"/camera/zoom",schemaPath:"#/properties/camera/properties/zoom/exclusiveMinimum",keyword:"exclusiveMinimum",params:{comparison: ">", limit: 0},message:"must be > 0"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}else {const err15 = {instancePath:instancePath+"/camera/zoom",schemaPath:"#/properties/camera/properties/zoom/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}}else {const err16 = {instancePath:instancePath+"/camera",schemaPath:"#/properties/camera/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}if(data.draw !== undefined){let data8 = data.draw;if(Array.isArray(data8)){const len0 = data8.length;for(let i0=0; i0state LX expression","additionalProperties":{"$ref":"https://omadia.ai/protocol/1.1/lx-ast.schema.json"}},"view":{"$ref":"https://omadia.ai/protocol/1.1/lx-ast.schema.json","description":"pure state -> primitive/scene tree (an LX expression; a static view is {lit: })"},"events":{"type":"array","items":{"$ref":"#/$defs/eventBinding"}},"cadence":{"$ref":"#/$defs/cadenceSpec"},"capabilities":{"$ref":"https://omadia.ai/protocol/1.1/capability-manifest.schema.json#/$defs/capabilityList"},"ports":{"$ref":"https://omadia.ai/protocol/1.1/ports-wires.schema.json#/$defs/portsList"},"expose":{"$ref":"https://omadia.ai/protocol/1.1/ports-wires.schema.json#/$defs/exposeList"},"preset":{"$ref":"#/$defs/presetRef"}}},"stateSchema":{"type":"object","description":"a typed, CLOSED record (§1.1). Total serialised size is capped (default 256 KB, spike-tunable) — enforced by L1.","additionalProperties":{"$ref":"#/$defs/stateLeaf"}},"stateLeaf":{"type":"object","oneOf":[{"additionalProperties":false,"required":["type","init"],"properties":{"type":{"enum":["int","number"]},"min":{"type":"number"},"max":{"type":"number"},"init":{"type":"number"}}},{"additionalProperties":false,"required":["type","init"],"properties":{"type":{"const":"bool"},"init":{"type":"boolean"}}},{"additionalProperties":false,"required":["type","maxLength","init"],"properties":{"type":{"const":"string"},"maxLength":{"type":"integer","minimum":0},"init":{"type":"string"}}},{"additionalProperties":false,"required":["type","values","init"],"properties":{"type":{"const":"enum"},"values":{"type":"array","items":{"type":"string"},"minItems":1},"init":{"type":"string"}}},{"additionalProperties":false,"required":["type","of","maxLen","init"],"properties":{"type":{"const":"list"},"of":{"$ref":"#/$defs/stateLeaf"},"maxLen":{"type":"integer","minimum":0},"init":{"type":"array"}}},{"additionalProperties":false,"required":["type","fields","init"],"properties":{"type":{"const":"record"},"fields":{"$ref":"#/$defs/stateSchema"},"init":{"type":"object"}}},{"additionalProperties":false,"required":["type","w","h","of"],"properties":{"type":{"const":"grid"},"w":{"type":"integer","minimum":1},"h":{"type":"integer","minimum":1},"of":{"$ref":"#/$defs/stateLeaf"},"init":{}}},{"additionalProperties":false,"required":["type"],"properties":{"type":{"const":"dataRef"},"init":{"$ref":"https://omadia.ai/protocol/1.0/data-ref.schema.json"}}}]},"eventBinding":{"type":"object","additionalProperties":false,"required":["on","run"],"properties":{"on":{"enum":["tap","longPress","drag","pinch","swipe","pointerMove","key","tick","timer","wire"]},"target":{"$ref":"https://omadia.ai/protocol/1.0/target-ref.schema.json"},"key":{"type":"string","description":"for 'key' — declared keys only (e.g. 'ArrowLeft','Space')"},"rate":{"type":"number","exclusiveMinimum":0,"maximum":60,"description":"for 'tick' — declared, capped ≤60 Hz (§5)"},"everyMs":{"type":"number","exclusiveMinimum":0,"description":"for 'timer' — enforced minimum period; combined tick+timer wakeup budget is capped (§4)"},"captureLongPress":{"type":"boolean","description":"claim longPress over host context-invoke (§4)"},"run":{"type":"string","description":"the transition to evaluate"}}},"cadenceSpec":{"description":"declared per node/region, not globally (§5). default 'reactive'.","oneOf":[{"enum":["static","reactive"]},{"type":"object","additionalProperties":false,"required":["tick"],"properties":{"tick":{"type":"number","exclusiveMinimum":0,"maximum":60,"description":"Hz, ≤60"}}}]},"presetRef":{"type":"object","additionalProperties":false,"required":["id"],"description":"provenance if instantiated/forked (§8)","properties":{"id":{"type":"string","pattern":"^preset-[0-9a-f]{16}$","description":"content-addressed preset-"},"parent":{"type":"string","pattern":"^preset-[0-9a-f]{16}$","description":"fork lineage"},"params":{"type":"object","additionalProperties":true}}}}};const schema103 = {"type":"object","additionalProperties":false,"required":["type","id","state","transitions","view","events"],"properties":{"type":{"const":"lumen"},"id":{"type":"string","description":"stable; patches/wires/beam target it"},"state":{"$ref":"#/$defs/stateSchema"},"transitions":{"type":"object","description":"TransitionName → pure (state,event)->state LX expression","additionalProperties":{"$ref":"https://omadia.ai/protocol/1.1/lx-ast.schema.json"}},"view":{"$ref":"https://omadia.ai/protocol/1.1/lx-ast.schema.json","description":"pure state -> primitive/scene tree (an LX expression; a static view is {lit: })"},"events":{"type":"array","items":{"$ref":"#/$defs/eventBinding"}},"cadence":{"$ref":"#/$defs/cadenceSpec"},"capabilities":{"$ref":"https://omadia.ai/protocol/1.1/capability-manifest.schema.json#/$defs/capabilityList"},"ports":{"$ref":"https://omadia.ai/protocol/1.1/ports-wires.schema.json#/$defs/portsList"},"expose":{"$ref":"https://omadia.ai/protocol/1.1/ports-wires.schema.json#/$defs/exposeList"},"preset":{"$ref":"#/$defs/presetRef"}}};const schema139 = {"description":"declared per node/region, not globally (§5). default 'reactive'.","oneOf":[{"enum":["static","reactive"]},{"type":"object","additionalProperties":false,"required":["tick"],"properties":{"tick":{"type":"number","exclusiveMinimum":0,"maximum":60,"description":"Hz, ≤60"}}}]};const schema153 = {"type":"object","additionalProperties":false,"required":["id"],"description":"provenance if instantiated/forked (§8)","properties":{"id":{"type":"string","pattern":"^preset-[0-9a-f]{16}$","description":"content-addressed preset-"},"parent":{"type":"string","pattern":"^preset-[0-9a-f]{16}$","description":"fork lineage"},"params":{"type":"object","additionalProperties":true}}};const schema104 = {"type":"object","description":"a typed, CLOSED record (§1.1). Total serialised size is capped (default 256 KB, spike-tunable) — enforced by L1.","additionalProperties":{"$ref":"#/$defs/stateLeaf"}};const schema105 = {"type":"object","oneOf":[{"additionalProperties":false,"required":["type","init"],"properties":{"type":{"enum":["int","number"]},"min":{"type":"number"},"max":{"type":"number"},"init":{"type":"number"}}},{"additionalProperties":false,"required":["type","init"],"properties":{"type":{"const":"bool"},"init":{"type":"boolean"}}},{"additionalProperties":false,"required":["type","maxLength","init"],"properties":{"type":{"const":"string"},"maxLength":{"type":"integer","minimum":0},"init":{"type":"string"}}},{"additionalProperties":false,"required":["type","values","init"],"properties":{"type":{"const":"enum"},"values":{"type":"array","items":{"type":"string"},"minItems":1},"init":{"type":"string"}}},{"additionalProperties":false,"required":["type","of","maxLen","init"],"properties":{"type":{"const":"list"},"of":{"$ref":"#/$defs/stateLeaf"},"maxLen":{"type":"integer","minimum":0},"init":{"type":"array"}}},{"additionalProperties":false,"required":["type","fields","init"],"properties":{"type":{"const":"record"},"fields":{"$ref":"#/$defs/stateSchema"},"init":{"type":"object"}}},{"additionalProperties":false,"required":["type","w","h","of"],"properties":{"type":{"const":"grid"},"w":{"type":"integer","minimum":1},"h":{"type":"integer","minimum":1},"of":{"$ref":"#/$defs/stateLeaf"},"init":{}}},{"additionalProperties":false,"required":["type"],"properties":{"type":{"const":"dataRef"},"init":{"$ref":"https://omadia.ai/protocol/1.0/data-ref.schema.json"}}}]};const wrapper8 = {validate: validate126};const wrapper9 = {validate: validate125};function validate126(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate126.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(data && typeof data == "object" && !Array.isArray(data))){const err0 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}const _errs1 = errors;let valid0 = false;let passing0 = null;const _errs2 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err1 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.init === undefined){const err2 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "init"},message:"must have required property '"+"init"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}for(const key0 in data){if(!((((key0 === "type") || (key0 === "min")) || (key0 === "max")) || (key0 === "init"))){const err3 = {instancePath,schemaPath:"#/oneOf/0/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.type !== undefined){let data0 = data.type;if(!((data0 === "int") || (data0 === "number"))){const err4 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/0/properties/type/enum",keyword:"enum",params:{allowedValues: schema105.oneOf[0].properties.type.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.min !== undefined){if(!(typeof data.min == "number")){const err5 = {instancePath:instancePath+"/min",schemaPath:"#/oneOf/0/properties/min/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.max !== undefined){if(!(typeof data.max == "number")){const err6 = {instancePath:instancePath+"/max",schemaPath:"#/oneOf/0/properties/max/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.init !== undefined){if(!(typeof data.init == "number")){const err7 = {instancePath:instancePath+"/init",schemaPath:"#/oneOf/0/properties/init/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}}var _valid0 = _errs2 === errors;if(_valid0){valid0 = true;passing0 = 0;var props0 = true;}const _errs11 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err8 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}if(data.init === undefined){const err9 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "init"},message:"must have required property '"+"init"+"'"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}for(const key1 in data){if(!((key1 === "type") || (key1 === "init"))){const err10 = {instancePath,schemaPath:"#/oneOf/1/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.type !== undefined){if("bool" !== data.type){const err11 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/1/properties/type/const",keyword:"const",params:{allowedValue: "bool"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.init !== undefined){if(typeof data.init !== "boolean"){const err12 = {instancePath:instancePath+"/init",schemaPath:"#/oneOf/1/properties/init/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}}var _valid0 = _errs11 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 1];}else {if(_valid0){valid0 = true;passing0 = 1;if(props0 !== true){props0 = true;}}const _errs16 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err13 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}if(data.maxLength === undefined){const err14 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "maxLength"},message:"must have required property '"+"maxLength"+"'"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}if(data.init === undefined){const err15 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "init"},message:"must have required property '"+"init"+"'"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}for(const key2 in data){if(!(((key2 === "type") || (key2 === "maxLength")) || (key2 === "init"))){const err16 = {instancePath,schemaPath:"#/oneOf/2/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key2},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}if(data.type !== undefined){if("string" !== data.type){const err17 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/2/properties/type/const",keyword:"const",params:{allowedValue: "string"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}if(data.maxLength !== undefined){let data7 = data.maxLength;if(!((typeof data7 == "number") && (!(data7 % 1) && !isNaN(data7)))){const err18 = {instancePath:instancePath+"/maxLength",schemaPath:"#/oneOf/2/properties/maxLength/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}if(typeof data7 == "number"){if(data7 < 0 || isNaN(data7)){const err19 = {instancePath:instancePath+"/maxLength",schemaPath:"#/oneOf/2/properties/maxLength/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}}if(data.init !== undefined){if(typeof data.init !== "string"){const err20 = {instancePath:instancePath+"/init",schemaPath:"#/oneOf/2/properties/init/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}}}var _valid0 = _errs16 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 2];}else {if(_valid0){valid0 = true;passing0 = 2;if(props0 !== true){props0 = true;}}const _errs23 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err21 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}if(data.values === undefined){const err22 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "values"},message:"must have required property '"+"values"+"'"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}if(data.init === undefined){const err23 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "init"},message:"must have required property '"+"init"+"'"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}for(const key3 in data){if(!(((key3 === "type") || (key3 === "values")) || (key3 === "init"))){const err24 = {instancePath,schemaPath:"#/oneOf/3/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key3},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data.type !== undefined){if("enum" !== data.type){const err25 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/3/properties/type/const",keyword:"const",params:{allowedValue: "enum"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}if(data.values !== undefined){let data10 = data.values;if(Array.isArray(data10)){if(data10.length < 1){const err26 = {instancePath:instancePath+"/values",schemaPath:"#/oneOf/3/properties/values/minItems",keyword:"minItems",params:{limit: 1},message:"must NOT have fewer than 1 items"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}const len0 = data10.length;for(let i0=0; i0=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}}}if(data.init !== undefined){if(!(Array.isArray(data.init))){const err38 = {instancePath:instancePath+"/init",schemaPath:"#/oneOf/4/properties/init/type",keyword:"type",params:{type: "array"},message:"must be array"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}}}var _valid0 = _errs32 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 4];}else {if(_valid0){valid0 = true;passing0 = 4;if(props0 !== true){props0 = true;}}const _errs40 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err39 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}if(data.fields === undefined){const err40 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "fields"},message:"must have required property '"+"fields"+"'"};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}if(data.init === undefined){const err41 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "init"},message:"must have required property '"+"init"+"'"};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}for(const key5 in data){if(!(((key5 === "type") || (key5 === "fields")) || (key5 === "init"))){const err42 = {instancePath,schemaPath:"#/oneOf/5/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key5},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;}}if(data.type !== undefined){if("record" !== data.type){const err43 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/5/properties/type/const",keyword:"const",params:{allowedValue: "record"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}}if(data.fields !== undefined){if(!(wrapper9.validate(data.fields, {instancePath:instancePath+"/fields",parentData:data,parentDataProperty:"fields",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper9.validate.errors : vErrors.concat(wrapper9.validate.errors);errors = vErrors.length;}}if(data.init !== undefined){let data19 = data.init;if(!(data19 && typeof data19 == "object" && !Array.isArray(data19))){const err44 = {instancePath:instancePath+"/init",schemaPath:"#/oneOf/5/properties/init/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}}}var _valid0 = _errs40 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 5];}else {if(_valid0){valid0 = true;passing0 = 5;if(props0 !== true){props0 = true;}}const _errs46 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err45 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}if(data.w === undefined){const err46 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "w"},message:"must have required property '"+"w"+"'"};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}if(data.h === undefined){const err47 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "h"},message:"must have required property '"+"h"+"'"};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}if(data.of === undefined){const err48 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "of"},message:"must have required property '"+"of"+"'"};if(vErrors === null){vErrors = [err48];}else {vErrors.push(err48);}errors++;}for(const key6 in data){if(!(((((key6 === "type") || (key6 === "w")) || (key6 === "h")) || (key6 === "of")) || (key6 === "init"))){const err49 = {instancePath,schemaPath:"#/oneOf/6/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key6},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err49];}else {vErrors.push(err49);}errors++;}}if(data.type !== undefined){if("grid" !== data.type){const err50 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/6/properties/type/const",keyword:"const",params:{allowedValue: "grid"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err50];}else {vErrors.push(err50);}errors++;}}if(data.w !== undefined){let data21 = data.w;if(!((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21)))){const err51 = {instancePath:instancePath+"/w",schemaPath:"#/oneOf/6/properties/w/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err51];}else {vErrors.push(err51);}errors++;}if(typeof data21 == "number"){if(data21 < 1 || isNaN(data21)){const err52 = {instancePath:instancePath+"/w",schemaPath:"#/oneOf/6/properties/w/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err52];}else {vErrors.push(err52);}errors++;}}}if(data.h !== undefined){let data22 = data.h;if(!((typeof data22 == "number") && (!(data22 % 1) && !isNaN(data22)))){const err53 = {instancePath:instancePath+"/h",schemaPath:"#/oneOf/6/properties/h/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err53];}else {vErrors.push(err53);}errors++;}if(typeof data22 == "number"){if(data22 < 1 || isNaN(data22)){const err54 = {instancePath:instancePath+"/h",schemaPath:"#/oneOf/6/properties/h/minimum",keyword:"minimum",params:{comparison: ">=", limit: 1},message:"must be >= 1"};if(vErrors === null){vErrors = [err54];}else {vErrors.push(err54);}errors++;}}}if(data.of !== undefined){if(!(wrapper8.validate(data.of, {instancePath:instancePath+"/of",parentData:data,parentDataProperty:"of",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper8.validate.errors : vErrors.concat(wrapper8.validate.errors);errors = vErrors.length;}}}var _valid0 = _errs46 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}const _errs54 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err55 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err55];}else {vErrors.push(err55);}errors++;}for(const key7 in data){if(!((key7 === "type") || (key7 === "init"))){const err56 = {instancePath,schemaPath:"#/oneOf/7/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key7},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err56];}else {vErrors.push(err56);}errors++;}}if(data.type !== undefined){if("dataRef" !== data.type){const err57 = {instancePath:instancePath+"/type",schemaPath:"#/oneOf/7/properties/type/const",keyword:"const",params:{allowedValue: "dataRef"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err57];}else {vErrors.push(err57);}errors++;}}if(data.init !== undefined){let data25 = data.init;if(data25 && typeof data25 == "object" && !Array.isArray(data25)){if(data25.id === undefined){const err58 = {instancePath:instancePath+"/init",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/required",keyword:"required",params:{missingProperty: "id"},message:"must have required property '"+"id"+"'"};if(vErrors === null){vErrors = [err58];}else {vErrors.push(err58);}errors++;}if(data25.signedToken === undefined){const err59 = {instancePath:instancePath+"/init",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/required",keyword:"required",params:{missingProperty: "signedToken"},message:"must have required property '"+"signedToken"+"'"};if(vErrors === null){vErrors = [err59];}else {vErrors.push(err59);}errors++;}if(data25.expiresAt === undefined){const err60 = {instancePath:instancePath+"/init",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/required",keyword:"required",params:{missingProperty: "expiresAt"},message:"must have required property '"+"expiresAt"+"'"};if(vErrors === null){vErrors = [err60];}else {vErrors.push(err60);}errors++;}for(const key8 in data25){if(!(((((key8 === "id") || (key8 === "signedToken")) || (key8 === "expiresAt")) || (key8 === "refreshable")) || (key8 === "containerId"))){const err61 = {instancePath:instancePath+"/init",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key8},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err61];}else {vErrors.push(err61);}errors++;}}if(data25.id !== undefined){let data26 = data25.id;if(typeof data26 === "string"){if(!pattern4.test(data26)){const err62 = {instancePath:instancePath+"/init/id",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/id/pattern",keyword:"pattern",params:{pattern: "^[a-z]+-[0-9a-f]{16}$"},message:"must match pattern \""+"^[a-z]+-[0-9a-f]{16}$"+"\""};if(vErrors === null){vErrors = [err62];}else {vErrors.push(err62);}errors++;}}else {const err63 = {instancePath:instancePath+"/init/id",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err63];}else {vErrors.push(err63);}errors++;}}if(data25.signedToken !== undefined){let data27 = data25.signedToken;if(typeof data27 === "string"){if(func1(data27) < 1){const err64 = {instancePath:instancePath+"/init/signedToken",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/signedToken/minLength",keyword:"minLength",params:{limit: 1},message:"must NOT have fewer than 1 characters"};if(vErrors === null){vErrors = [err64];}else {vErrors.push(err64);}errors++;}}else {const err65 = {instancePath:instancePath+"/init/signedToken",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/signedToken/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err65];}else {vErrors.push(err65);}errors++;}}if(data25.expiresAt !== undefined){if(!(typeof data25.expiresAt === "string")){const err66 = {instancePath:instancePath+"/init/expiresAt",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/expiresAt/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err66];}else {vErrors.push(err66);}errors++;}}if(data25.refreshable !== undefined){if(typeof data25.refreshable !== "boolean"){const err67 = {instancePath:instancePath+"/init/refreshable",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/refreshable/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err67];}else {vErrors.push(err67);}errors++;}}if(data25.containerId !== undefined){if(typeof data25.containerId !== "string"){const err68 = {instancePath:instancePath+"/init/containerId",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err68];}else {vErrors.push(err68);}errors++;}}}else {const err69 = {instancePath:instancePath+"/init",schemaPath:"https://omadia.ai/protocol/1.0/data-ref.schema.json/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err69];}else {vErrors.push(err69);}errors++;}}}var _valid0 = _errs54 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 7];}else {if(_valid0){valid0 = true;passing0 = 7;if(props0 !== true){props0 = true;}}}}}}}}}if(!valid0){const err70 = {instancePath,schemaPath:"#/oneOf",keyword:"oneOf",params:{passingSchemas: passing0},message:"must match exactly one schema in oneOf"};if(vErrors === null){vErrors = [err70];}else {vErrors.push(err70);}errors++;}else {errors = _errs1;if(vErrors !== null){if(_errs1){vErrors.length = _errs1;}else {vErrors = null;}}}validate126.errors = vErrors;evaluated0.props = props0;return errors === 0;}validate126.evaluated = {"dynamicProps":true,"dynamicItems":false};function validate125(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate125.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){for(const key0 in data){if(!(validate126(data[key0], {instancePath:instancePath+"/" + key0.replace(/~/g, "~0").replace(/\//g, "~1"),parentData:data,parentDataProperty:key0,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate126.errors : vErrors.concat(validate126.errors);errors = vErrors.length;}}}else {const err0 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}validate125.errors = vErrors;return errors === 0;}validate125.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema107 = {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://omadia.ai/protocol/1.1/lx-ast.schema.json","title":"Lume Expressions (LX) — JSON AST","description":"omadia-canvas-protocol/1.1 (lumens-spec.md §2): the pure, total expression language of a Lumen's `transitions` and `view`, delivered as a JSON AST (never source text). This schema is the STRUCTURAL whitelist — every node must be one of the §2.2 forms and every `call` target one of the §2.3 std-lib names. Semantic guarantees that JSON Schema cannot express (gas ceiling, bounded iteration, state/event path resolution, totality of `if`/`match`) are enforced by the L1 static validator + interpreter. Unknown node shapes are hard-rejected (whitelist parser discipline, §0.1).","$ref":"#/$defs/lxNode","$defs":{"lxNode":{"type":"object","oneOf":[{"$ref":"#/$defs/lx_lit"},{"$ref":"#/$defs/lx_state"},{"$ref":"#/$defs/lx_event"},{"$ref":"#/$defs/lx_var"},{"$ref":"#/$defs/lx_let"},{"$ref":"#/$defs/lx_add"},{"$ref":"#/$defs/lx_sub"},{"$ref":"#/$defs/lx_mul"},{"$ref":"#/$defs/lx_div"},{"$ref":"#/$defs/lx_mod"},{"$ref":"#/$defs/lx_gt"},{"$ref":"#/$defs/lx_gte"},{"$ref":"#/$defs/lx_lt"},{"$ref":"#/$defs/lx_lte"},{"$ref":"#/$defs/lx_eq"},{"$ref":"#/$defs/lx_neq"},{"$ref":"#/$defs/lx_and"},{"$ref":"#/$defs/lx_or"},{"$ref":"#/$defs/lx_not"},{"$ref":"#/$defs/lx_if"},{"$ref":"#/$defs/lx_match"},{"$ref":"#/$defs/lx_record"},{"$ref":"#/$defs/lx_list"},{"$ref":"#/$defs/lx_get"},{"$ref":"#/$defs/lx_set"},{"$ref":"#/$defs/lx_call"}]},"lx_lit":{"type":"object","required":["lit"],"additionalProperties":false,"properties":{"lit":{"description":"any JSON literal: int/number/bool/string/list/record"}}},"lx_state":{"type":"object","required":["state"],"additionalProperties":false,"properties":{"state":{"type":"string","description":"dotted path into the declared state schema"},"at":{"type":"array","description":"grid access [x,y]; each an LX expr","items":{"$ref":"#/$defs/lxNode"},"minItems":2,"maxItems":2}}},"lx_event":{"type":"object","required":["event"],"additionalProperties":false,"properties":{"event":{"type":"string","description":"field of the triggering event"}}},"lx_var":{"type":"object","required":["var"],"additionalProperties":false,"properties":{"var":{"type":"string","description":"read a lexical binding: a `let` name, or an iteration binding (`it`/`idx`/`acc`) introduced by map/filter/fold (§2.3). Unbound ⇒ reject."}}},"lx_let":{"type":"object","required":["let","in"],"additionalProperties":false,"properties":{"let":{"type":"object","minProperties":1,"maxProperties":1,"additionalProperties":{"$ref":"#/$defs/lxNode"},"description":"single immutable, lexically-scoped binding {name: expr}; read with {var:name}"},"in":{"$ref":"#/$defs/lxNode"}}},"lx_add":{"type":"object","required":["+"],"additionalProperties":false,"properties":{"+":{"$ref":"#/$defs/argsNary"}}},"lx_sub":{"type":"object","required":["-"],"additionalProperties":false,"properties":{"-":{"$ref":"#/$defs/argsNary"}}},"lx_mul":{"type":"object","required":["*"],"additionalProperties":false,"properties":{"*":{"$ref":"#/$defs/argsNary"}}},"lx_div":{"type":"object","required":["/"],"additionalProperties":false,"properties":{"/":{"$ref":"#/$defs/argsBinary"}}},"lx_mod":{"type":"object","required":["mod"],"additionalProperties":false,"properties":{"mod":{"$ref":"#/$defs/argsBinary"}}},"lx_gt":{"type":"object","required":[">"],"additionalProperties":false,"properties":{">":{"$ref":"#/$defs/argsBinary"}}},"lx_gte":{"type":"object","required":[">="],"additionalProperties":false,"properties":{">=":{"$ref":"#/$defs/argsBinary"}}},"lx_lt":{"type":"object","required":["<"],"additionalProperties":false,"properties":{"<":{"$ref":"#/$defs/argsBinary"}}},"lx_lte":{"type":"object","required":["<="],"additionalProperties":false,"properties":{"<=":{"$ref":"#/$defs/argsBinary"}}},"lx_eq":{"type":"object","required":["=="],"additionalProperties":false,"properties":{"==":{"$ref":"#/$defs/argsBinary"}}},"lx_neq":{"type":"object","required":["!="],"additionalProperties":false,"properties":{"!=":{"$ref":"#/$defs/argsBinary"}}},"lx_and":{"type":"object","required":["and"],"additionalProperties":false,"properties":{"and":{"$ref":"#/$defs/argsNary"}}},"lx_or":{"type":"object","required":["or"],"additionalProperties":false,"properties":{"or":{"$ref":"#/$defs/argsNary"}}},"lx_not":{"type":"object","required":["not"],"additionalProperties":false,"properties":{"not":{"$ref":"#/$defs/lxNode"}}},"lx_if":{"type":"object","required":["if","then","else"],"additionalProperties":false,"properties":{"if":{"$ref":"#/$defs/lxNode"},"then":{"$ref":"#/$defs/lxNode"},"else":{"$ref":"#/$defs/lxNode"}}},"lx_match":{"type":"object","required":["match","cases","else"],"additionalProperties":false,"properties":{"match":{"$ref":"#/$defs/lxNode"},"cases":{"type":"array","items":{"type":"object","required":["when","then"],"additionalProperties":false,"properties":{"when":{"$ref":"#/$defs/lxNode"},"then":{"$ref":"#/$defs/lxNode"}}}},"else":{"$ref":"#/$defs/lxNode"}}},"lx_record":{"type":"object","required":["record"],"additionalProperties":false,"properties":{"record":{"type":"object","additionalProperties":{"$ref":"#/$defs/lxNode"}}}},"lx_list":{"type":"object","required":["list"],"additionalProperties":false,"properties":{"list":{"type":"array","items":{"$ref":"#/$defs/lxNode"}}}},"lx_get":{"type":"object","required":["get","key"],"additionalProperties":false,"properties":{"get":{"$ref":"#/$defs/lxNode","description":"a record or list expression"},"key":{"$ref":"#/$defs/lxNode","description":"a string (record field) or int (list/grid-row index) expression"}}},"lx_set":{"type":"object","required":["set"],"additionalProperties":false,"properties":{"set":{"type":"object","minProperties":1,"additionalProperties":{"$ref":"#/$defs/lxNode"},"description":"functional update {path: expr} → a NEW state (no mutation)"}}},"lx_call":{"type":"object","required":["call","args"],"additionalProperties":false,"properties":{"call":{"$ref":"#/$defs/stdlibName"},"args":{"type":"array","items":{"$ref":"#/$defs/lxNode"}}}},"argsBinary":{"type":"array","items":{"$ref":"#/$defs/lxNode"},"minItems":2,"maxItems":2},"argsNary":{"type":"array","items":{"$ref":"#/$defs/lxNode"},"minItems":2},"stdlibName":{"description":"lumens-spec.md §2.3 std-lib whitelist (bounded). map/filter/fold/range iterate only over state-bounded collections, making the gas bound static. No `while`, no general recursion. `random`/`now` read host-seeded context.","enum":["map","filter","fold","range","len","min","max","clamp","abs","floor","ceil","round","sqrt","sign","pow","concat","slice","contains","indexOf","keys","values","upper","lower","pad","fmt","random","now"]}}};const schema108 = {"type":"object","oneOf":[{"$ref":"#/$defs/lx_lit"},{"$ref":"#/$defs/lx_state"},{"$ref":"#/$defs/lx_event"},{"$ref":"#/$defs/lx_var"},{"$ref":"#/$defs/lx_let"},{"$ref":"#/$defs/lx_add"},{"$ref":"#/$defs/lx_sub"},{"$ref":"#/$defs/lx_mul"},{"$ref":"#/$defs/lx_div"},{"$ref":"#/$defs/lx_mod"},{"$ref":"#/$defs/lx_gt"},{"$ref":"#/$defs/lx_gte"},{"$ref":"#/$defs/lx_lt"},{"$ref":"#/$defs/lx_lte"},{"$ref":"#/$defs/lx_eq"},{"$ref":"#/$defs/lx_neq"},{"$ref":"#/$defs/lx_and"},{"$ref":"#/$defs/lx_or"},{"$ref":"#/$defs/lx_not"},{"$ref":"#/$defs/lx_if"},{"$ref":"#/$defs/lx_match"},{"$ref":"#/$defs/lx_record"},{"$ref":"#/$defs/lx_list"},{"$ref":"#/$defs/lx_get"},{"$ref":"#/$defs/lx_set"},{"$ref":"#/$defs/lx_call"}]};const schema109 = {"type":"object","required":["lit"],"additionalProperties":false,"properties":{"lit":{"description":"any JSON literal: int/number/bool/string/list/record"}}};const schema111 = {"type":"object","required":["event"],"additionalProperties":false,"properties":{"event":{"type":"string","description":"field of the triggering event"}}};const schema112 = {"type":"object","required":["var"],"additionalProperties":false,"properties":{"var":{"type":"string","description":"read a lexical binding: a `let` name, or an iteration binding (`it`/`idx`/`acc`) introduced by map/filter/fold (§2.3). Unbound ⇒ reject."}}};const schema110 = {"type":"object","required":["state"],"additionalProperties":false,"properties":{"state":{"type":"string","description":"dotted path into the declared state schema"},"at":{"type":"array","description":"grid access [x,y]; each an LX expr","items":{"$ref":"#/$defs/lxNode"},"minItems":2,"maxItems":2}}};const wrapper11 = {validate: validate130};function validate131(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate131.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.state === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "state"},message:"must have required property '"+"state"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!((key0 === "state") || (key0 === "at"))){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.state !== undefined){if(typeof data.state !== "string"){const err2 = {instancePath:instancePath+"/state",schemaPath:"#/properties/state/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.at !== undefined){let data1 = data.at;if(Array.isArray(data1)){if(data1.length > 2){const err3 = {instancePath:instancePath+"/at",schemaPath:"#/properties/at/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}if(data1.length < 2){const err4 = {instancePath:instancePath+"/at",schemaPath:"#/properties/at/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}const len0 = data1.length;for(let i0=0; i0 1){const err3 = {instancePath:instancePath+"/let",schemaPath:"#/properties/let/maxProperties",keyword:"maxProperties",params:{limit: 1},message:"must NOT have more than 1 properties"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}if(Object.keys(data0).length < 1){const err4 = {instancePath:instancePath+"/let",schemaPath:"#/properties/let/minProperties",keyword:"minProperties",params:{limit: 1},message:"must NOT have fewer than 1 properties"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}for(const key1 in data0){if(!(wrapper11.validate(data0[key1], {instancePath:instancePath+"/let/" + key1.replace(/~/g, "~0").replace(/\//g, "~1"),parentData:data0,parentDataProperty:key1,rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}}else {const err5 = {instancePath:instancePath+"/let",schemaPath:"#/properties/let/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.in !== undefined){if(!(wrapper11.validate(data.in, {instancePath:instancePath+"/in",parentData:data,parentDataProperty:"in",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}}else {const err6 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}validate133.errors = vErrors;return errors === 0;}validate133.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema114 = {"type":"object","required":["+"],"additionalProperties":false,"properties":{"+":{"$ref":"#/$defs/argsNary"}}};const schema115 = {"type":"array","items":{"$ref":"#/$defs/lxNode"},"minItems":2};function validate136(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate136.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(Array.isArray(data)){if(data.length < 2){const err0 = {instancePath,schemaPath:"#/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}const len0 = data.length;for(let i0=0; i0 2){const err0 = {instancePath,schemaPath:"#/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.length < 2){const err1 = {instancePath,schemaPath:"#/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}const len0 = data.length;for(let i0=0; i0"],"additionalProperties":false,"properties":{">":{"$ref":"#/$defs/argsBinary"}}};function validate152(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate152.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data[">"] === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: ">"},message:"must have required property '"+">"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === ">")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data[">"] !== undefined){if(!(validate146(data[">"], {instancePath:instancePath+"/>",parentData:data,parentDataProperty:">",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate146.errors : vErrors.concat(validate146.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate152.errors = vErrors;return errors === 0;}validate152.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema122 = {"type":"object","required":[">="],"additionalProperties":false,"properties":{">=":{"$ref":"#/$defs/argsBinary"}}};function validate155(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate155.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data[">="] === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: ">="},message:"must have required property '"+">="+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === ">=")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data[">="] !== undefined){if(!(validate146(data[">="], {instancePath:instancePath+"/>=",parentData:data,parentDataProperty:">=",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate146.errors : vErrors.concat(validate146.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate155.errors = vErrors;return errors === 0;}validate155.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema123 = {"type":"object","required":["<"],"additionalProperties":false,"properties":{"<":{"$ref":"#/$defs/argsBinary"}}};function validate158(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate158.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data["<"] === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "<"},message:"must have required property '"+"<"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "<")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data["<"] !== undefined){if(!(validate146(data["<"], {instancePath:instancePath+"/<",parentData:data,parentDataProperty:"<",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate146.errors : vErrors.concat(validate146.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate158.errors = vErrors;return errors === 0;}validate158.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema124 = {"type":"object","required":["<="],"additionalProperties":false,"properties":{"<=":{"$ref":"#/$defs/argsBinary"}}};function validate161(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate161.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data["<="] === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "<="},message:"must have required property '"+"<="+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "<=")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data["<="] !== undefined){if(!(validate146(data["<="], {instancePath:instancePath+"/<=",parentData:data,parentDataProperty:"<=",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate146.errors : vErrors.concat(validate146.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate161.errors = vErrors;return errors === 0;}validate161.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema125 = {"type":"object","required":["=="],"additionalProperties":false,"properties":{"==":{"$ref":"#/$defs/argsBinary"}}};function validate164(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate164.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data["=="] === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "=="},message:"must have required property '"+"=="+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "==")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data["=="] !== undefined){if(!(validate146(data["=="], {instancePath:instancePath+"/==",parentData:data,parentDataProperty:"==",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate146.errors : vErrors.concat(validate146.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate164.errors = vErrors;return errors === 0;}validate164.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema126 = {"type":"object","required":["!="],"additionalProperties":false,"properties":{"!=":{"$ref":"#/$defs/argsBinary"}}};function validate167(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate167.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data["!="] === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "!="},message:"must have required property '"+"!="+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "!=")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data["!="] !== undefined){if(!(validate146(data["!="], {instancePath:instancePath+"/!=",parentData:data,parentDataProperty:"!=",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate146.errors : vErrors.concat(validate146.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate167.errors = vErrors;return errors === 0;}validate167.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema127 = {"type":"object","required":["and"],"additionalProperties":false,"properties":{"and":{"$ref":"#/$defs/argsNary"}}};function validate170(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate170.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.and === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "and"},message:"must have required property '"+"and"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "and")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.and !== undefined){if(!(validate136(data.and, {instancePath:instancePath+"/and",parentData:data,parentDataProperty:"and",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate136.errors : vErrors.concat(validate136.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate170.errors = vErrors;return errors === 0;}validate170.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema128 = {"type":"object","required":["or"],"additionalProperties":false,"properties":{"or":{"$ref":"#/$defs/argsNary"}}};function validate173(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate173.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.or === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "or"},message:"must have required property '"+"or"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "or")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.or !== undefined){if(!(validate136(data.or, {instancePath:instancePath+"/or",parentData:data,parentDataProperty:"or",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate136.errors : vErrors.concat(validate136.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate173.errors = vErrors;return errors === 0;}validate173.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema129 = {"type":"object","required":["not"],"additionalProperties":false,"properties":{"not":{"$ref":"#/$defs/lxNode"}}};function validate176(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate176.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.not === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "not"},message:"must have required property '"+"not"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(key0 === "not")){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.not !== undefined){if(!(wrapper11.validate(data.not, {instancePath:instancePath+"/not",parentData:data,parentDataProperty:"not",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate176.errors = vErrors;return errors === 0;}validate176.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema130 = {"type":"object","required":["if","then","else"],"additionalProperties":false,"properties":{"if":{"$ref":"#/$defs/lxNode"},"then":{"$ref":"#/$defs/lxNode"},"else":{"$ref":"#/$defs/lxNode"}}};function validate178(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate178.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.if === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "if"},message:"must have required property '"+"if"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.then === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "then"},message:"must have required property '"+"then"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.else === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "else"},message:"must have required property '"+"else"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}for(const key0 in data){if(!(((key0 === "if") || (key0 === "then")) || (key0 === "else"))){const err3 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.if !== undefined){if(!(wrapper11.validate(data.if, {instancePath:instancePath+"/if",parentData:data,parentDataProperty:"if",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}if(data.then !== undefined){if(!(wrapper11.validate(data.then, {instancePath:instancePath+"/then",parentData:data,parentDataProperty:"then",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}if(data.else !== undefined){if(!(wrapper11.validate(data.else, {instancePath:instancePath+"/else",parentData:data,parentDataProperty:"else",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}}else {const err4 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}validate178.errors = vErrors;return errors === 0;}validate178.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema131 = {"type":"object","required":["match","cases","else"],"additionalProperties":false,"properties":{"match":{"$ref":"#/$defs/lxNode"},"cases":{"type":"array","items":{"type":"object","required":["when","then"],"additionalProperties":false,"properties":{"when":{"$ref":"#/$defs/lxNode"},"then":{"$ref":"#/$defs/lxNode"}}}},"else":{"$ref":"#/$defs/lxNode"}}};function validate180(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate180.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.match === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "match"},message:"must have required property '"+"match"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.cases === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "cases"},message:"must have required property '"+"cases"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}if(data.else === undefined){const err2 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "else"},message:"must have required property '"+"else"+"'"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}for(const key0 in data){if(!(((key0 === "match") || (key0 === "cases")) || (key0 === "else"))){const err3 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.match !== undefined){if(!(wrapper11.validate(data.match, {instancePath:instancePath+"/match",parentData:data,parentDataProperty:"match",rootData,dynamicAnchors}))){vErrors = vErrors === null ? wrapper11.validate.errors : vErrors.concat(wrapper11.validate.errors);errors = vErrors.length;}}if(data.cases !== undefined){let data1 = data.cases;if(Array.isArray(data1)){const len0 = data1.length;for(let i0=0; i0 60 || isNaN(data3)){const err5 = {instancePath:instancePath+"/rate",schemaPath:"#/properties/rate/maximum",keyword:"maximum",params:{comparison: "<=", limit: 60},message:"must be <= 60"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}if(data3 <= 0 || isNaN(data3)){const err6 = {instancePath:instancePath+"/rate",schemaPath:"#/properties/rate/exclusiveMinimum",keyword:"exclusiveMinimum",params:{comparison: ">", limit: 0},message:"must be > 0"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}else {const err7 = {instancePath:instancePath+"/rate",schemaPath:"#/properties/rate/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.everyMs !== undefined){let data4 = data.everyMs;if(typeof data4 == "number"){if(data4 <= 0 || isNaN(data4)){const err8 = {instancePath:instancePath+"/everyMs",schemaPath:"#/properties/everyMs/exclusiveMinimum",keyword:"exclusiveMinimum",params:{comparison: ">", limit: 0},message:"must be > 0"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}else {const err9 = {instancePath:instancePath+"/everyMs",schemaPath:"#/properties/everyMs/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.captureLongPress !== undefined){if(typeof data.captureLongPress !== "boolean"){const err10 = {instancePath:instancePath+"/captureLongPress",schemaPath:"#/properties/captureLongPress/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.run !== undefined){if(typeof data.run !== "string"){const err11 = {instancePath:instancePath+"/run",schemaPath:"#/properties/run/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}}else {const err12 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}validate195.errors = vErrors;return errors === 0;}validate195.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};const schema141 = {"type":"array","items":{"$ref":"#/$defs/capabilityRequest"}};const schema142 = {"type":"object","additionalProperties":false,"required":["cap"],"properties":{"cap":{"$ref":"#/$defs/capabilityName"},"effect":{"$ref":"#/$defs/effectClass","description":"agent's declared/expected class; Tier 2 re-derives and may upgrade (never downgrade)"},"scope":{"type":"object","description":"per-capability scope (spike-tunable). e.g. {namespace} for persist; {dataRef} for loadData; {endpoints:[...], shape} for fetch; {provider} for tiles; {kind} for generateAsset; {writeCapabilities} for writeData.","additionalProperties":true}}};const schema143 = {"description":"lumens-spec.md §6 catalog","enum":["persist","loadData","writeData","tiles","fetch","generateAsset","clipboard","share","savePreset"]};const schema144 = {"description":"CONCEPT.md §Security Surface effect classes. Egress carrying state/DataRef-derived data is external-effect (per-call confirmation) unless pre-approved at grant (§6).","enum":["local","internal","external-effect"]};function validate200(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate200.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.cap === undefined){const err0 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "cap"},message:"must have required property '"+"cap"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}for(const key0 in data){if(!(((key0 === "cap") || (key0 === "effect")) || (key0 === "scope"))){const err1 = {instancePath,schemaPath:"#/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.cap !== undefined){let data0 = data.cap;if(!(((((((((data0 === "persist") || (data0 === "loadData")) || (data0 === "writeData")) || (data0 === "tiles")) || (data0 === "fetch")) || (data0 === "generateAsset")) || (data0 === "clipboard")) || (data0 === "share")) || (data0 === "savePreset"))){const err2 = {instancePath:instancePath+"/cap",schemaPath:"#/$defs/capabilityName/enum",keyword:"enum",params:{allowedValues: schema143.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.effect !== undefined){let data1 = data.effect;if(!(((data1 === "local") || (data1 === "internal")) || (data1 === "external-effect"))){const err3 = {instancePath:instancePath+"/effect",schemaPath:"#/$defs/effectClass/enum",keyword:"enum",params:{allowedValues: schema144.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.scope !== undefined){let data2 = data.scope;if(data2 && typeof data2 == "object" && !Array.isArray(data2)){}else {const err4 = {instancePath:instancePath+"/scope",schemaPath:"#/properties/scope/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}}else {const err5 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}validate200.errors = vErrors;return errors === 0;}validate200.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};function validate203(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate203.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(Array.isArray(data)){const len0 = data.length;for(let i0=0; i0 60 || isNaN(data9)){const err14 = {instancePath:instancePath+"/cadence/tick",schemaPath:"#/$defs/cadenceSpec/oneOf/1/properties/tick/maximum",keyword:"maximum",params:{comparison: "<=", limit: 60},message:"must be <= 60"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}if(data9 <= 0 || isNaN(data9)){const err15 = {instancePath:instancePath+"/cadence/tick",schemaPath:"#/$defs/cadenceSpec/oneOf/1/properties/tick/exclusiveMinimum",keyword:"exclusiveMinimum",params:{comparison: ">", limit: 0},message:"must be > 0"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}else {const err16 = {instancePath:instancePath+"/cadence/tick",schemaPath:"#/$defs/cadenceSpec/oneOf/1/properties/tick/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath:instancePath+"/cadence",schemaPath:"#/$defs/cadenceSpec/oneOf/1/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}var _valid0 = _errs18 === errors;if(_valid0 && valid5){valid5 = false;passing0 = [passing0, 1];}else {if(_valid0){valid5 = true;passing0 = 1;}}if(!valid5){const err18 = {instancePath:instancePath+"/cadence",schemaPath:"#/$defs/cadenceSpec/oneOf",keyword:"oneOf",params:{passingSchemas: passing0},message:"must match exactly one schema in oneOf"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}else {errors = _errs16;if(vErrors !== null){if(_errs16){vErrors.length = _errs16;}else {vErrors = null;}}}}if(data.capabilities !== undefined){if(!(validate203(data.capabilities, {instancePath:instancePath+"/capabilities",parentData:data,parentDataProperty:"capabilities",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate203.errors : vErrors.concat(validate203.errors);errors = vErrors.length;}}if(data.ports !== undefined){if(!(validate207(data.ports, {instancePath:instancePath+"/ports",parentData:data,parentDataProperty:"ports",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate207.errors : vErrors.concat(validate207.errors);errors = vErrors.length;}}if(data.expose !== undefined){if(!(validate211(data.expose, {instancePath:instancePath+"/expose",parentData:data,parentDataProperty:"expose",rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate211.errors : vErrors.concat(validate211.errors);errors = vErrors.length;}}if(data.preset !== undefined){let data13 = data.preset;if(data13 && typeof data13 == "object" && !Array.isArray(data13)){if(data13.id === undefined){const err19 = {instancePath:instancePath+"/preset",schemaPath:"#/$defs/presetRef/required",keyword:"required",params:{missingProperty: "id"},message:"must have required property '"+"id"+"'"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}for(const key3 in data13){if(!(((key3 === "id") || (key3 === "parent")) || (key3 === "params"))){const err20 = {instancePath:instancePath+"/preset",schemaPath:"#/$defs/presetRef/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key3},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}}if(data13.id !== undefined){let data14 = data13.id;if(typeof data14 === "string"){if(!pattern10.test(data14)){const err21 = {instancePath:instancePath+"/preset/id",schemaPath:"#/$defs/presetRef/properties/id/pattern",keyword:"pattern",params:{pattern: "^preset-[0-9a-f]{16}$"},message:"must match pattern \""+"^preset-[0-9a-f]{16}$"+"\""};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}}else {const err22 = {instancePath:instancePath+"/preset/id",schemaPath:"#/$defs/presetRef/properties/id/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}if(data13.parent !== undefined){let data15 = data13.parent;if(typeof data15 === "string"){if(!pattern10.test(data15)){const err23 = {instancePath:instancePath+"/preset/parent",schemaPath:"#/$defs/presetRef/properties/parent/pattern",keyword:"pattern",params:{pattern: "^preset-[0-9a-f]{16}$"},message:"must match pattern \""+"^preset-[0-9a-f]{16}$"+"\""};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}else {const err24 = {instancePath:instancePath+"/preset/parent",schemaPath:"#/$defs/presetRef/properties/parent/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data13.params !== undefined){let data16 = data13.params;if(data16 && typeof data16 == "object" && !Array.isArray(data16)){}else {const err25 = {instancePath:instancePath+"/preset/params",schemaPath:"#/$defs/presetRef/properties/params/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}}else {const err26 = {instancePath:instancePath+"/preset",schemaPath:"#/$defs/presetRef/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}validate124.errors = vErrors;return errors === 0;}validate124.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};function validate123(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL="https://omadia.ai/protocol/1.1/lumen.schema.json" */;let vErrors = null;let errors = 0;const evaluated0 = validate123.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(validate124(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate124.errors : vErrors.concat(validate124.errors);errors = vErrors.length;}validate123.errors = vErrors;return errors === 0;}validate123.evaluated = {"props":true,"dynamicProps":false,"dynamicItems":false};function validate21(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate21.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}const _errs1 = errors;let valid0 = false;let passing0 = null;const _errs2 = errors;if(!(validate22(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate22.errors : vErrors.concat(validate22.errors);errors = vErrors.length;}var _valid0 = _errs2 === errors;if(_valid0){valid0 = true;passing0 = 0;var props0 = true;}const _errs3 = errors;if(!(validate31(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate31.errors : vErrors.concat(validate31.errors);errors = vErrors.length;}var _valid0 = _errs3 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 1];}else {if(_valid0){valid0 = true;passing0 = 1;if(props0 !== true){props0 = true;}}const _errs4 = errors;if(!(validate34(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate34.errors : vErrors.concat(validate34.errors);errors = vErrors.length;}var _valid0 = _errs4 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 2];}else {if(_valid0){valid0 = true;passing0 = 2;if(props0 !== true){props0 = true;}}const _errs5 = errors;if(!(validate37(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate37.errors : vErrors.concat(validate37.errors);errors = vErrors.length;}var _valid0 = _errs5 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 3];}else {if(_valid0){valid0 = true;passing0 = 3;if(props0 !== true){props0 = true;}}const _errs6 = errors;if(!(validate40(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate40.errors : vErrors.concat(validate40.errors);errors = vErrors.length;}var _valid0 = _errs6 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 4];}else {if(_valid0){valid0 = true;passing0 = 4;if(props0 !== true){props0 = true;}}const _errs7 = errors;if(!(validate43(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate43.errors : vErrors.concat(validate43.errors);errors = vErrors.length;}var _valid0 = _errs7 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 5];}else {if(_valid0){valid0 = true;passing0 = 5;if(props0 !== true){props0 = true;}}const _errs8 = errors;if(!(validate48(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate48.errors : vErrors.concat(validate48.errors);errors = vErrors.length;}var _valid0 = _errs8 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}const _errs9 = errors;if(!(validate51(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate51.errors : vErrors.concat(validate51.errors);errors = vErrors.length;}var _valid0 = _errs9 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 7];}else {if(_valid0){valid0 = true;passing0 = 7;if(props0 !== true){props0 = true;}}const _errs10 = errors;if(!(validate54(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate54.errors : vErrors.concat(validate54.errors);errors = vErrors.length;}var _valid0 = _errs10 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 8];}else {if(_valid0){valid0 = true;passing0 = 8;if(props0 !== true){props0 = true;}}const _errs11 = errors;if(!(validate57(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate57.errors : vErrors.concat(validate57.errors);errors = vErrors.length;}var _valid0 = _errs11 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 9];}else {if(_valid0){valid0 = true;passing0 = 9;if(props0 !== true){props0 = true;}}const _errs12 = errors;if(!(validate60(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate60.errors : vErrors.concat(validate60.errors);errors = vErrors.length;}var _valid0 = _errs12 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 10];}else {if(_valid0){valid0 = true;passing0 = 10;if(props0 !== true){props0 = true;}}const _errs13 = errors;if(!(validate63(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate63.errors : vErrors.concat(validate63.errors);errors = vErrors.length;}var _valid0 = _errs13 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 11];}else {if(_valid0){valid0 = true;passing0 = 11;if(props0 !== true){props0 = true;}}const _errs14 = errors;if(!(validate66(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate66.errors : vErrors.concat(validate66.errors);errors = vErrors.length;}var _valid0 = _errs14 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 12];}else {if(_valid0){valid0 = true;passing0 = 12;if(props0 !== true){props0 = true;}}const _errs15 = errors;if(!(validate70(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate70.errors : vErrors.concat(validate70.errors);errors = vErrors.length;}var _valid0 = _errs15 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 13];}else {if(_valid0){valid0 = true;passing0 = 13;if(props0 !== true){props0 = true;}}const _errs16 = errors;if(!(validate73(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate73.errors : vErrors.concat(validate73.errors);errors = vErrors.length;}var _valid0 = _errs16 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 14];}else {if(_valid0){valid0 = true;passing0 = 14;if(props0 !== true){props0 = true;}}const _errs17 = errors;if(!(validate76(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate76.errors : vErrors.concat(validate76.errors);errors = vErrors.length;}var _valid0 = _errs17 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 15];}else {if(_valid0){valid0 = true;passing0 = 15;if(props0 !== true){props0 = true;}}const _errs18 = errors;if(!(validate79(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate79.errors : vErrors.concat(validate79.errors);errors = vErrors.length;}var _valid0 = _errs18 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 16];}else {if(_valid0){valid0 = true;passing0 = 16;if(props0 !== true){props0 = true;}}const _errs19 = errors;if(!(validate82(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate82.errors : vErrors.concat(validate82.errors);errors = vErrors.length;}var _valid0 = _errs19 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 17];}else {if(_valid0){valid0 = true;passing0 = 17;if(props0 !== true){props0 = true;}}const _errs20 = errors;if(!(validate85(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate85.errors : vErrors.concat(validate85.errors);errors = vErrors.length;}var _valid0 = _errs20 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 18];}else {if(_valid0){valid0 = true;passing0 = 18;if(props0 !== true){props0 = true;}}const _errs21 = errors;if(!(validate88(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate88.errors : vErrors.concat(validate88.errors);errors = vErrors.length;}var _valid0 = _errs21 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 19];}else {if(_valid0){valid0 = true;passing0 = 19;if(props0 !== true){props0 = true;}}const _errs22 = errors;if(!(validate91(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate91.errors : vErrors.concat(validate91.errors);errors = vErrors.length;}var _valid0 = _errs22 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 20];}else {if(_valid0){valid0 = true;passing0 = 20;if(props0 !== true){props0 = true;}}const _errs23 = errors;if(!(validate94(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate94.errors : vErrors.concat(validate94.errors);errors = vErrors.length;}var _valid0 = _errs23 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 21];}else {if(_valid0){valid0 = true;passing0 = 21;if(props0 !== true){props0 = true;}}const _errs24 = errors;if(!(validate97(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate97.errors : vErrors.concat(validate97.errors);errors = vErrors.length;}var _valid0 = _errs24 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 22];}else {if(_valid0){valid0 = true;passing0 = 22;if(props0 !== true){props0 = true;}}const _errs25 = errors;if(!(validate100(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate100.errors : vErrors.concat(validate100.errors);errors = vErrors.length;}var _valid0 = _errs25 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 23];}else {if(_valid0){valid0 = true;passing0 = 23;if(props0 !== true){props0 = true;}}const _errs26 = errors;if(!(validate103(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate103.errors : vErrors.concat(validate103.errors);errors = vErrors.length;}var _valid0 = _errs26 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 24];}else {if(_valid0){valid0 = true;passing0 = 24;if(props0 !== true){props0 = true;}}const _errs27 = errors;if(!(validate123(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate123.errors : vErrors.concat(validate123.errors);errors = vErrors.length;}var _valid0 = _errs27 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 25];}else {if(_valid0){valid0 = true;passing0 = 25;if(props0 !== true){props0 = true;}}}}}}}}}}}}}}}}}}}}}}}}}}}if(!valid0){const err0 = {instancePath,schemaPath:"#/oneOf",keyword:"oneOf",params:{passingSchemas: passing0},message:"must match exactly one schema in oneOf"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}else {errors = _errs1;if(vErrors !== null){if(_errs1){vErrors.length = _errs1;}else {vErrors = null;}}}if(data && typeof data == "object" && !Array.isArray(data)){if(data.type === undefined){const err1 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "type"},message:"must have required property '"+"type"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}else {const err2 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}validate21.errors = vErrors;evaluated0.props = props0;return errors === 0;}validate21.evaluated = {"dynamicProps":true,"dynamicItems":false};function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL="https://omadia.ai/protocol/1.0/canvas-tree.schema.json" */;let vErrors = null;let errors = 0;const evaluated0 = validate20.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}if(!(validate21(data, {instancePath,parentData,parentDataProperty,rootData,dynamicAnchors}))){vErrors = vErrors === null ? validate21.errors : vErrors.concat(validate21.errors);errors = vErrors.length;}else {var props0 = validate21.evaluated.props;}validate20.errors = vErrors;evaluated0.props = props0;return errors === 0;}validate20.evaluated = {"dynamicProps":true,"dynamicItems":false};export const validateSurfaceEvent = validate218;const schema154 = {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://omadia.ai/protocol/1.0/surface-events.schema.json","title":"Surface stream events","description":"The surface_* event family Tier 2 streams to Tier 1 (folded into the SDK ChatStreamEvent union). Every event carries the envelope {canvasSessionId, surfaceSeq}. `treeRevision`/producesRevision/basedOnRevision/revision are OPAQUE RevisionId values — compared by EQUALITY only, never arithmetic (v1 implements them as a monotonic integer rendered as a string).","$defs":{"revisionId":{"type":"string","description":"opaque, equality-only; v1 = stringified monotonic integer"},"dataRef":{"$ref":"https://omadia.ai/protocol/1.0/data-ref.schema.json"},"targetRef":{"$ref":"https://omadia.ai/protocol/1.0/target-ref.schema.json"},"envelope":{"type":"object","properties":{"canvasSessionId":{"type":"string"},"surfaceSeq":{"type":"integer","description":"server-assigned, monotonic per canvasSessionId; gaps trigger a snapshot request"}},"required":["canvasSessionId","surfaceSeq"]}},"oneOf":[{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","producesRevision","tree","protocolVersion","opsCatalogVersion"],"properties":{"type":{"const":"surface_snapshot"},"producesRevision":{"$ref":"#/$defs/revisionId"},"tree":{"$ref":"https://omadia.ai/protocol/1.0/canvas-tree.schema.json"},"protocolVersion":{"type":"string"},"opsCatalogVersion":{"type":"string"}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","basedOnRevision","producesRevision","patches"],"properties":{"type":{"const":"surface_patch"},"basedOnRevision":{"$ref":"#/$defs/revisionId"},"producesRevision":{"$ref":"#/$defs/revisionId"},"patches":{"type":"array","items":{"type":"object","description":"tree-path-targeted mutation (op/path/value); reject if basedOnRevision mismatches the client revision"}}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","revision","dataRef"],"properties":{"type":{"const":"surface_data_ref_created"},"revision":{"$ref":"#/$defs/revisionId"},"dataRef":{"$ref":"#/$defs/dataRef"},"schema":{},"sizeHint":{"type":"integer"}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","revision","id","reason"],"properties":{"type":{"const":"surface_data_ref_invalidated"},"revision":{"$ref":"#/$defs/revisionId"},"id":{"type":"string"},"reason":{"type":"string"}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","forActionId","basedOnRevision","status"],"properties":{"type":{"const":"surface_action_result"},"forActionId":{"type":"string"},"basedOnRevision":{"$ref":"#/$defs/revisionId"},"status":{"type":"string"},"message":{"type":"string"},"followUpPatch":{}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","revision","effect","operation","target"],"properties":{"type":{"const":"surface_local_action"},"revision":{"$ref":"#/$defs/revisionId"},"effect":{"enum":["preview","durable"],"description":"preview does NOT mutate the revision; durable is always followed by a surface_patch"},"operation":{"type":"string","description":"must be in the client's handshake-declared localOperations"},"params":{},"target":{"$ref":"#/$defs/targetRef"}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","revision","severity","message"],"properties":{"type":{"const":"surface_error"},"revision":{"$ref":"#/$defs/revisionId"},"severity":{"enum":["info","warning","error"]},"message":{"type":"string"},"scope":{}}}],"unevaluatedProperties":false},{"allOf":[{"$ref":"#/$defs/envelope"},{"required":["type","revision","forMutationId","status"],"properties":{"type":{"const":"surface_mutation_resolved"},"revision":{"$ref":"#/$defs/revisionId"},"forMutationId":{"type":"string","description":"correlates a _pendingMutation by mutationId"},"status":{"enum":["success","modified","rejected","invalid","conflict"]},"actualValue":{},"error":{"type":"object","additionalProperties":false,"properties":{"message":{"type":"string"},"code":{"type":"string"}}},"originAuthor":{"type":"string","description":"v2+ multi-user provenance; empty in v1"},"originSession":{"type":"string"}}}],"unevaluatedProperties":false}]};const schema155 = {"type":"object","properties":{"canvasSessionId":{"type":"string"},"surfaceSeq":{"type":"integer","description":"server-assigned, monotonic per canvasSessionId; gaps trigger a snapshot request"}},"required":["canvasSessionId","surfaceSeq"]};const schema156 = {"type":"string","description":"opaque, equality-only; v1 = stringified monotonic integer"};function validate220(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){/*# sourceURL="https://omadia.ai/protocol/1.0/target-ref.schema.json" */;let vErrors = null;let errors = 0;const evaluated0 = validate220.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}const _errs0 = errors;let valid0 = false;let passing0 = null;const _errs1 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err0 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data.canvasSessionId === undefined){const err1 = {instancePath,schemaPath:"#/oneOf/0/required",keyword:"required",params:{missingProperty: "canvasSessionId"},message:"must have required property '"+"canvasSessionId"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}for(const key0 in data){if(!((key0 === "kind") || (key0 === "canvasSessionId"))){const err2 = {instancePath,schemaPath:"#/oneOf/0/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key0},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.kind !== undefined){if("canvas" !== data.kind){const err3 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/0/properties/kind/const",keyword:"const",params:{allowedValue: "canvas"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.canvasSessionId !== undefined){if(typeof data.canvasSessionId !== "string"){const err4 = {instancePath:instancePath+"/canvasSessionId",schemaPath:"#/oneOf/0/properties/canvasSessionId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}}else {const err5 = {instancePath,schemaPath:"#/oneOf/0/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}var _valid0 = _errs1 === errors;if(_valid0){valid0 = true;passing0 = 0;var props0 = true;}const _errs7 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err6 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}if(data.containerId === undefined){const err7 = {instancePath,schemaPath:"#/oneOf/1/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}for(const key1 in data){if(!((key1 === "kind") || (key1 === "containerId"))){const err8 = {instancePath,schemaPath:"#/oneOf/1/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key1},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.kind !== undefined){if("container" !== data.kind){const err9 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/1/properties/kind/const",keyword:"const",params:{allowedValue: "container"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err10 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/1/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}}else {const err11 = {instancePath,schemaPath:"#/oneOf/1/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}var _valid0 = _errs7 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 1];}else {if(_valid0){valid0 = true;passing0 = 1;if(props0 !== true){props0 = true;}}const _errs13 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err12 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}if(data.elementId === undefined){const err13 = {instancePath,schemaPath:"#/oneOf/2/required",keyword:"required",params:{missingProperty: "elementId"},message:"must have required property '"+"elementId"+"'"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}for(const key2 in data){if(!((key2 === "kind") || (key2 === "elementId"))){const err14 = {instancePath,schemaPath:"#/oneOf/2/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key2},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.kind !== undefined){if("element" !== data.kind){const err15 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/2/properties/kind/const",keyword:"const",params:{allowedValue: "element"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.elementId !== undefined){if(typeof data.elementId !== "string"){const err16 = {instancePath:instancePath+"/elementId",schemaPath:"#/oneOf/2/properties/elementId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}else {const err17 = {instancePath,schemaPath:"#/oneOf/2/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}var _valid0 = _errs13 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 2];}else {if(_valid0){valid0 = true;passing0 = 2;if(props0 !== true){props0 = true;}}const _errs19 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err18 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}if(data.containerId === undefined){const err19 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}if(data.rowKey === undefined){const err20 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "rowKey"},message:"must have required property '"+"rowKey"+"'"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}if(data.fieldKey === undefined){const err21 = {instancePath,schemaPath:"#/oneOf/3/required",keyword:"required",params:{missingProperty: "fieldKey"},message:"must have required property '"+"fieldKey"+"'"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}for(const key3 in data){if(!((((key3 === "kind") || (key3 === "containerId")) || (key3 === "rowKey")) || (key3 === "fieldKey"))){const err22 = {instancePath,schemaPath:"#/oneOf/3/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key3},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}}if(data.kind !== undefined){if("rowField" !== data.kind){const err23 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/3/properties/kind/const",keyword:"const",params:{allowedValue: "rowField"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err24 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/3/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}if(data.rowKey !== undefined){if(typeof data.rowKey !== "string"){const err25 = {instancePath:instancePath+"/rowKey",schemaPath:"#/oneOf/3/properties/rowKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}if(data.fieldKey !== undefined){if(typeof data.fieldKey !== "string"){const err26 = {instancePath:instancePath+"/fieldKey",schemaPath:"#/oneOf/3/properties/fieldKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}}else {const err27 = {instancePath,schemaPath:"#/oneOf/3/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}var _valid0 = _errs19 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 3];}else {if(_valid0){valid0 = true;passing0 = 3;if(props0 !== true){props0 = true;}}const _errs29 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err28 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}if(data.containerId === undefined){const err29 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}if(data.itemKey === undefined){const err30 = {instancePath,schemaPath:"#/oneOf/4/required",keyword:"required",params:{missingProperty: "itemKey"},message:"must have required property '"+"itemKey"+"'"};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}for(const key4 in data){if(!(((key4 === "kind") || (key4 === "containerId")) || (key4 === "itemKey"))){const err31 = {instancePath,schemaPath:"#/oneOf/4/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key4},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}}if(data.kind !== undefined){if("item" !== data.kind){const err32 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/4/properties/kind/const",keyword:"const",params:{allowedValue: "item"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err33 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/4/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}}if(data.itemKey !== undefined){if(typeof data.itemKey !== "string"){const err34 = {instancePath:instancePath+"/itemKey",schemaPath:"#/oneOf/4/properties/itemKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}}}else {const err35 = {instancePath,schemaPath:"#/oneOf/4/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}var _valid0 = _errs29 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 4];}else {if(_valid0){valid0 = true;passing0 = 4;if(props0 !== true){props0 = true;}}const _errs37 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err36 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}if(data.containerId === undefined){const err37 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "containerId"},message:"must have required property '"+"containerId"+"'"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}if(data.pointKey === undefined){const err38 = {instancePath,schemaPath:"#/oneOf/5/required",keyword:"required",params:{missingProperty: "pointKey"},message:"must have required property '"+"pointKey"+"'"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}for(const key5 in data){if(!(((key5 === "kind") || (key5 === "containerId")) || (key5 === "pointKey"))){const err39 = {instancePath,schemaPath:"#/oneOf/5/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key5},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}}if(data.kind !== undefined){if("point" !== data.kind){const err40 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/5/properties/kind/const",keyword:"const",params:{allowedValue: "point"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}}if(data.containerId !== undefined){if(typeof data.containerId !== "string"){const err41 = {instancePath:instancePath+"/containerId",schemaPath:"#/oneOf/5/properties/containerId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}}if(data.pointKey !== undefined){if(typeof data.pointKey !== "string"){const err42 = {instancePath:instancePath+"/pointKey",schemaPath:"#/oneOf/5/properties/pointKey/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;}}}else {const err43 = {instancePath,schemaPath:"#/oneOf/5/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}var _valid0 = _errs37 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 5];}else {if(_valid0){valid0 = true;passing0 = 5;if(props0 !== true){props0 = true;}}const _errs45 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err44 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}if(data.anchor === undefined){const err45 = {instancePath,schemaPath:"#/oneOf/6/required",keyword:"required",params:{missingProperty: "anchor"},message:"must have required property '"+"anchor"+"'"};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}for(const key6 in data){if(!((key6 === "kind") || (key6 === "anchor"))){const err46 = {instancePath,schemaPath:"#/oneOf/6/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key6},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}}if(data.kind !== undefined){if("textRange" !== data.kind){const err47 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/6/properties/kind/const",keyword:"const",params:{allowedValue: "textRange"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}}if(data.anchor !== undefined){let data17 = data.anchor;if(data17 && typeof data17 == "object" && !Array.isArray(data17)){if(data17.primitiveId === undefined){const err48 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err48];}else {vErrors.push(err48);}errors++;}if(data17.contentHash === undefined){const err49 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "contentHash"},message:"must have required property '"+"contentHash"+"'"};if(vErrors === null){vErrors = [err49];}else {vErrors.push(err49);}errors++;}if(data17.start === undefined){const err50 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "start"},message:"must have required property '"+"start"+"'"};if(vErrors === null){vErrors = [err50];}else {vErrors.push(err50);}errors++;}if(data17.end === undefined){const err51 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/required",keyword:"required",params:{missingProperty: "end"},message:"must have required property '"+"end"+"'"};if(vErrors === null){vErrors = [err51];}else {vErrors.push(err51);}errors++;}for(const key7 in data17){if(!(((((key7 === "primitiveId") || (key7 === "contentHash")) || (key7 === "start")) || (key7 === "end")) || (key7 === "fallbackSegment"))){const err52 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key7},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err52];}else {vErrors.push(err52);}errors++;}}if(data17.primitiveId !== undefined){if(typeof data17.primitiveId !== "string"){const err53 = {instancePath:instancePath+"/anchor/primitiveId",schemaPath:"#/$defs/textRangeAnchor/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err53];}else {vErrors.push(err53);}errors++;}}if(data17.contentHash !== undefined){if(typeof data17.contentHash !== "string"){const err54 = {instancePath:instancePath+"/anchor/contentHash",schemaPath:"#/$defs/textRangeAnchor/properties/contentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err54];}else {vErrors.push(err54);}errors++;}}if(data17.start !== undefined){let data20 = data17.start;if(!((typeof data20 == "number") && (!(data20 % 1) && !isNaN(data20)))){const err55 = {instancePath:instancePath+"/anchor/start",schemaPath:"#/$defs/textRangeAnchor/properties/start/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err55];}else {vErrors.push(err55);}errors++;}if(typeof data20 == "number"){if(data20 < 0 || isNaN(data20)){const err56 = {instancePath:instancePath+"/anchor/start",schemaPath:"#/$defs/textRangeAnchor/properties/start/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err56];}else {vErrors.push(err56);}errors++;}}}if(data17.end !== undefined){let data21 = data17.end;if(!((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21)))){const err57 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err57];}else {vErrors.push(err57);}errors++;}if(typeof data21 == "number"){if(data21 < 0 || isNaN(data21)){const err58 = {instancePath:instancePath+"/anchor/end",schemaPath:"#/$defs/textRangeAnchor/properties/end/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0"};if(vErrors === null){vErrors = [err58];}else {vErrors.push(err58);}errors++;}}}if(data17.fallbackSegment !== undefined){let data22 = data17.fallbackSegment;if(data22 && typeof data22 == "object" && !Array.isArray(data22)){if(data22.before === undefined){const err59 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "before"},message:"must have required property '"+"before"+"'"};if(vErrors === null){vErrors = [err59];}else {vErrors.push(err59);}errors++;}if(data22.selection === undefined){const err60 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "selection"},message:"must have required property '"+"selection"+"'"};if(vErrors === null){vErrors = [err60];}else {vErrors.push(err60);}errors++;}if(data22.after === undefined){const err61 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/required",keyword:"required",params:{missingProperty: "after"},message:"must have required property '"+"after"+"'"};if(vErrors === null){vErrors = [err61];}else {vErrors.push(err61);}errors++;}for(const key8 in data22){if(!(((key8 === "before") || (key8 === "selection")) || (key8 === "after"))){const err62 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key8},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err62];}else {vErrors.push(err62);}errors++;}}if(data22.before !== undefined){if(typeof data22.before !== "string"){const err63 = {instancePath:instancePath+"/anchor/fallbackSegment/before",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/before/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err63];}else {vErrors.push(err63);}errors++;}}if(data22.selection !== undefined){if(typeof data22.selection !== "string"){const err64 = {instancePath:instancePath+"/anchor/fallbackSegment/selection",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/selection/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err64];}else {vErrors.push(err64);}errors++;}}if(data22.after !== undefined){if(typeof data22.after !== "string"){const err65 = {instancePath:instancePath+"/anchor/fallbackSegment/after",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/properties/after/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err65];}else {vErrors.push(err65);}errors++;}}}else {const err66 = {instancePath:instancePath+"/anchor/fallbackSegment",schemaPath:"#/$defs/textRangeAnchor/properties/fallbackSegment/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err66];}else {vErrors.push(err66);}errors++;}}}else {const err67 = {instancePath:instancePath+"/anchor",schemaPath:"#/$defs/textRangeAnchor/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err67];}else {vErrors.push(err67);}errors++;}}}else {const err68 = {instancePath,schemaPath:"#/oneOf/6/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err68];}else {vErrors.push(err68);}errors++;}var _valid0 = _errs45 === errors;if(_valid0 && valid0){valid0 = false;passing0 = [passing0, 6];}else {if(_valid0){valid0 = true;passing0 = 6;if(props0 !== true){props0 = true;}}const _errs70 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.kind === undefined){const err69 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err69];}else {vErrors.push(err69);}errors++;}if(data.region === undefined){const err70 = {instancePath,schemaPath:"#/oneOf/7/required",keyword:"required",params:{missingProperty: "region"},message:"must have required property '"+"region"+"'"};if(vErrors === null){vErrors = [err70];}else {vErrors.push(err70);}errors++;}for(const key9 in data){if(!((key9 === "kind") || (key9 === "region"))){const err71 = {instancePath,schemaPath:"#/oneOf/7/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key9},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err71];}else {vErrors.push(err71);}errors++;}}if(data.kind !== undefined){if("region" !== data.kind){const err72 = {instancePath:instancePath+"/kind",schemaPath:"#/oneOf/7/properties/kind/const",keyword:"const",params:{allowedValue: "region"},message:"must be equal to constant"};if(vErrors === null){vErrors = [err72];}else {vErrors.push(err72);}errors++;}}if(data.region !== undefined){let data27 = data.region;if(data27 && typeof data27 == "object" && !Array.isArray(data27)){if(data27.primitiveId === undefined){const err73 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "primitiveId"},message:"must have required property '"+"primitiveId"+"'"};if(vErrors === null){vErrors = [err73];}else {vErrors.push(err73);}errors++;}if(data27.bufferContentHash === undefined){const err74 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bufferContentHash"},message:"must have required property '"+"bufferContentHash"+"'"};if(vErrors === null){vErrors = [err74];}else {vErrors.push(err74);}errors++;}if(data27.bbox === undefined){const err75 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/required",keyword:"required",params:{missingProperty: "bbox"},message:"must have required property '"+"bbox"+"'"};if(vErrors === null){vErrors = [err75];}else {vErrors.push(err75);}errors++;}for(const key10 in data27){if(!((((key10 === "primitiveId") || (key10 === "bufferContentHash")) || (key10 === "bbox")) || (key10 === "shape"))){const err76 = {instancePath:instancePath+"/region",schemaPath:"#/$defs/bufferRegion/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key10},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err76];}else {vErrors.push(err76);}errors++;}}if(data27.primitiveId !== undefined){if(typeof data27.primitiveId !== "string"){const err77 = {instancePath:instancePath+"/region/primitiveId",schemaPath:"#/$defs/bufferRegion/properties/primitiveId/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err77];}else {vErrors.push(err77);}errors++;}}if(data27.bufferContentHash !== undefined){if(typeof data27.bufferContentHash !== "string"){const err78 = {instancePath:instancePath+"/region/bufferContentHash",schemaPath:"#/$defs/bufferRegion/properties/bufferContentHash/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err78];}else {vErrors.push(err78);}errors++;}}if(data27.bbox !== undefined){let data30 = data27.bbox;if(data30 && typeof data30 == "object" && !Array.isArray(data30)){if(data30.x === undefined){const err79 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "x"},message:"must have required property '"+"x"+"'"};if(vErrors === null){vErrors = [err79];}else {vErrors.push(err79);}errors++;}if(data30.y === undefined){const err80 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "y"},message:"must have required property '"+"y"+"'"};if(vErrors === null){vErrors = [err80];}else {vErrors.push(err80);}errors++;}if(data30.w === undefined){const err81 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "w"},message:"must have required property '"+"w"+"'"};if(vErrors === null){vErrors = [err81];}else {vErrors.push(err81);}errors++;}if(data30.h === undefined){const err82 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/required",keyword:"required",params:{missingProperty: "h"},message:"must have required property '"+"h"+"'"};if(vErrors === null){vErrors = [err82];}else {vErrors.push(err82);}errors++;}for(const key11 in data30){if(!((((key11 === "x") || (key11 === "y")) || (key11 === "w")) || (key11 === "h"))){const err83 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key11},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err83];}else {vErrors.push(err83);}errors++;}}if(data30.x !== undefined){if(!(typeof data30.x == "number")){const err84 = {instancePath:instancePath+"/region/bbox/x",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/x/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err84];}else {vErrors.push(err84);}errors++;}}if(data30.y !== undefined){if(!(typeof data30.y == "number")){const err85 = {instancePath:instancePath+"/region/bbox/y",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/y/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err85];}else {vErrors.push(err85);}errors++;}}if(data30.w !== undefined){if(!(typeof data30.w == "number")){const err86 = {instancePath:instancePath+"/region/bbox/w",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/w/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err86];}else {vErrors.push(err86);}errors++;}}if(data30.h !== undefined){if(!(typeof data30.h == "number")){const err87 = {instancePath:instancePath+"/region/bbox/h",schemaPath:"#/$defs/bufferRegion/properties/bbox/properties/h/type",keyword:"type",params:{type: "number"},message:"must be number"};if(vErrors === null){vErrors = [err87];}else {vErrors.push(err87);}errors++;}}}else {const err88 = {instancePath:instancePath+"/region/bbox",schemaPath:"#/$defs/bufferRegion/properties/bbox/type",keyword:"type",params:{type: "object"},message:"must be object"};if(vErrors === null){vErrors = [err88];}else {vErrors.push(err88);}errors++;}}if(data27.shape !== undefined){let data35 = data27.shape;if(data35 && typeof data35 == "object" && !Array.isArray(data35)){if(data35.kind === undefined){const err89 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/required",keyword:"required",params:{missingProperty: "kind"},message:"must have required property '"+"kind"+"'"};if(vErrors === null){vErrors = [err89];}else {vErrors.push(err89);}errors++;}for(const key12 in data35){if(!(((key12 === "kind") || (key12 === "points")) || (key12 === "maskHash"))){const err90 = {instancePath:instancePath+"/region/shape",schemaPath:"#/$defs/bufferRegion/properties/shape/additionalProperties",keyword:"additionalProperties",params:{additionalProperty: key12},message:"must NOT have additional properties"};if(vErrors === null){vErrors = [err90];}else {vErrors.push(err90);}errors++;}}if(data35.kind !== undefined){let data36 = data35.kind;if(!(((data36 === "rect") || (data36 === "polygon")) || (data36 === "mask"))){const err91 = {instancePath:instancePath+"/region/shape/kind",schemaPath:"#/$defs/bufferRegion/properties/shape/properties/kind/enum",keyword:"enum",params:{allowedValues: schema42.properties.shape.properties.kind.enum},message:"must be equal to one of the allowed values"};if(vErrors === null){vErrors = [err91];}else {vErrors.push(err91);}errors++;}}if(data35.points !== undefined){let data37 = data35.points;if(Array.isArray(data37)){const len0 = data37.length;for(let i0=0; i0 2){const err92 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/maxItems",keyword:"maxItems",params:{limit: 2},message:"must NOT have more than 2 items"};if(vErrors === null){vErrors = [err92];}else {vErrors.push(err92);}errors++;}if(data38.length < 2){const err93 = {instancePath:instancePath+"/region/shape/points/" + i0,schemaPath:"#/$defs/bufferRegion/properties/shape/properties/points/items/minItems",keyword:"minItems",params:{limit: 2},message:"must NOT have fewer than 2 items"};if(vErrors === null){vErrors = [err93];}else {vErrors.push(err93);}errors++;}const len1 = data38.length;for(let i1=0; i1=": [{ "var": "nx" }, { "lit": 300 }] }] } }, + "in": { + "set": { + "x": { "call": "clamp", "args": [{ "var": "nx" }, { "lit": 0 }, { "lit": 300 }] }, + "vx": { "if": { "var": "hitWall" }, "then": { "-": [{ "lit": 0 }, { "state": "vx" }] }, "else": { "state": "vx" } }, + "bounces": { "if": { "var": "hitWall" }, "then": { "+": [{ "state": "bounces" }, { "lit": 1 }] }, "else": { "state": "bounces" } } + } + } + } + }, + "reverse": { "set": { "vx": { "-": [{ "lit": 0 }, { "state": "vx" }] } } } + }, + "view": { + "record": { + "type": { "lit": "scene" }, + "width": { "lit": 320 }, + "height": { "lit": 120 }, + "draw": { + "list": [ + { "record": { "kind": { "lit": "rect" }, "x": { "lit": 0 }, "y": { "lit": 0 }, "w": { "lit": 320 }, "h": { "lit": 120 }, "fill": { "lit": "surface-sunken" } } }, + { "record": { "kind": { "lit": "circle" }, "cx": { "state": "x" }, "cy": { "lit": 60 }, "r": { "lit": 10 }, "fill": { "lit": "accent" }, "id": { "lit": "ball" } } }, + { "record": { "kind": { "lit": "text" }, "x": { "lit": 8 }, "y": { "lit": 16 }, "text": { "call": "concat", "args": [{ "lit": "bounces " }, { "call": "fmt", "args": [{ "state": "bounces" }] }] }, "register": { "lit": "mono" }, "fill": { "lit": "text" } } } + ] + } + } + }, + "events": [ + { "on": "tick", "rate": 60, "run": "step" }, + { "on": "tap", "run": "reverse" }, + { "on": "key", "key": "Space", "run": "reverse" } + ], + "cadence": { "tick": 60 } +} diff --git a/app/test/fixtures/lumens/defrag-viz.json b/app/test/fixtures/lumens/defrag-viz.json new file mode 100644 index 0000000..50f5d54 --- /dev/null +++ b/app/test/fixtures/lumens/defrag-viz.json @@ -0,0 +1,40 @@ +{ + "type": "lumen", + "id": "defrag-viz", + "state": { + "frame": { "type": "int", "min": 0, "init": 0 } + }, + "transitions": { + "step": { "set": { "frame": { "+": [{ "state": "frame" }, { "lit": 1 }] } } } + }, + "view": { + "record": { + "type": { "lit": "scene" }, + "width": { "lit": 256 }, + "height": { "lit": 64 }, + "draw": { + "call": "map", + "args": [ + { "call": "range", "args": [{ "lit": 8 }] }, + { + "record": { + "kind": { "lit": "rect" }, + "x": { "call": "max", "args": [{ "*": [{ "var": "idx" }, { "lit": 30 }] }, { "-": [{ "lit": 220 }, { "*": [{ "state": "frame" }, { "lit": 5 }] }] }] }, + "y": { "lit": 20 }, + "w": { "lit": 24 }, + "h": { "lit": 24 }, + "r": { "lit": 4 }, + "fill": { "if": { "==": [{ "mod": [{ "var": "idx" }, { "lit": 2 }] }, { "lit": 0 }] }, "then": { "lit": "accent" }, "else": { "lit": "accent.glow" } }, + "id": { "call": "concat", "args": [{ "lit": "b" }, { "call": "fmt", "args": [{ "var": "idx" }] }] } + } + } + ] + } + } + }, + "events": [ + { "on": "tick", "rate": 30, "run": "step" }, + { "on": "tap", "run": "step" } + ], + "cadence": { "tick": 30 } +} diff --git a/app/test/fixtures/lumens/map-explore.json b/app/test/fixtures/lumens/map-explore.json new file mode 100644 index 0000000..94e4578 --- /dev/null +++ b/app/test/fixtures/lumens/map-explore.json @@ -0,0 +1,61 @@ +{ + "type": "lumen", + "id": "map-explore", + "state": { + "zoom": { "type": "int", "min": 1, "max": 5, "init": 2 }, + "sel": { "type": "string", "maxLength": 32, "init": "" }, + "markers": { + "type": "list", + "of": { "type": "record", "fields": { "id": { "type": "string", "maxLength": 8, "init": "" }, "x": { "type": "number", "init": 0 }, "y": { "type": "number", "init": 0 } }, "init": {} }, + "maxLen": 32, + "init": [ + { "id": "a", "x": 40, "y": 40 }, + { "id": "b", "x": 120, "y": 80 }, + { "id": "c", "x": 200, "y": 50 } + ] + } + }, + "transitions": { + "select": { "set": { "sel": { "event": "id" } } }, + "zoomIn": { "set": { "zoom": { "call": "clamp", "args": [{ "+": [{ "state": "zoom" }, { "lit": 1 }] }, { "lit": 1 }, { "lit": 5 }] } } }, + "zoomOut": { "set": { "zoom": { "call": "clamp", "args": [{ "-": [{ "state": "zoom" }, { "lit": 1 }] }, { "lit": 1 }, { "lit": 5 }] } } } + }, + "view": { + "record": { + "type": { "lit": "scene" }, + "width": { "lit": 256 }, + "height": { "lit": 128 }, + "draw": { + "call": "concat", + "args": [ + { "list": [{ "record": { "kind": { "lit": "rect" }, "x": { "lit": 0 }, "y": { "lit": 0 }, "w": { "lit": 256 }, "h": { "lit": 128 }, "fill": { "lit": "surface-sunken" } } }] }, + { + "call": "map", + "args": [ + { "state": "markers" }, + { + "record": { + "kind": { "lit": "circle" }, + "cx": { "get": { "var": "it" }, "key": { "lit": "x" } }, + "cy": { "get": { "var": "it" }, "key": { "lit": "y" } }, + "r": { "+": [{ "lit": 6 }, { "state": "zoom" }] }, + "fill": { "if": { "==": [{ "get": { "var": "it" }, "key": { "lit": "id" } }, { "state": "sel" }] }, "then": { "lit": "success" }, "else": { "lit": "accent" } }, + "id": { "get": { "var": "it" }, "key": { "lit": "id" } } + } + } + ] + } + ] + } + } + }, + "events": [ + { "on": "tap", "run": "select" }, + { "on": "key", "key": "+", "run": "zoomIn" }, + { "on": "key", "key": "-", "run": "zoomOut" } + ], + "cadence": "reactive", + "capabilities": [ + { "cap": "tiles", "effect": "internal", "scope": { "provider": "osm" } } + ] +} diff --git a/app/test/fixtures/lumens/workflow-wizard.json b/app/test/fixtures/lumens/workflow-wizard.json new file mode 100644 index 0000000..4fb5e41 --- /dev/null +++ b/app/test/fixtures/lumens/workflow-wizard.json @@ -0,0 +1,34 @@ +{ + "type": "lumen", + "id": "workflow-wizard", + "state": { + "step": { "type": "int", "min": 0, "max": 2, "init": 0 }, + "done": { "type": "bool", "init": false } + }, + "transitions": { + "next": { "set": { "step": { "call": "clamp", "args": [{ "+": [{ "state": "step" }, { "lit": 1 }] }, { "lit": 0 }, { "lit": 2 }] } } }, + "prev": { "set": { "step": { "call": "clamp", "args": [{ "-": [{ "state": "step" }, { "lit": 1 }] }, { "lit": 0 }, { "lit": 2 }] } } }, + "finish": { "set": { "done": { "lit": true } } } + }, + "view": { + "record": { + "type": { "lit": "container" }, + "layout": { "lit": "stack" }, + "children": { + "list": [ + { "record": { "type": { "lit": "heading" }, "level": { "lit": 2 }, "content": { "call": "concat", "args": [{ "lit": "Step " }, { "call": "fmt", "args": [{ "+": [{ "state": "step" }, { "lit": 1 }] }] }, { "lit": " of 3" }] } } }, + { "record": { "type": { "lit": "status" }, "text": { "if": { "state": "done" }, "then": { "lit": "Complete" }, "else": { "lit": "In progress" } } } }, + { "record": { "type": { "lit": "button" }, "id": { "lit": "prev" }, "label": { "lit": "Back" } } }, + { "record": { "type": { "lit": "button" }, "id": { "lit": "next" }, "label": { "lit": "Next" } } }, + { "record": { "type": { "lit": "button" }, "id": { "lit": "finish" }, "label": { "lit": "Finish" } } } + ] + } + } + }, + "events": [ + { "on": "tap", "target": { "kind": "element", "elementId": "next" }, "run": "next" }, + { "on": "tap", "target": { "kind": "element", "elementId": "prev" }, "run": "prev" }, + { "on": "tap", "target": { "kind": "element", "elementId": "finish" }, "run": "finish" } + ], + "cadence": "reactive" +} diff --git a/app/test/node/animate.test.ts b/app/test/node/animate.test.ts new file mode 100644 index 0000000..21b36b5 --- /dev/null +++ b/app/test/node/animate.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from 'vitest'; +import { sampleAnimation, reducedMotionValue, animateToCss, cssTimingFunction, type Animate } from '../../src/renderer/src/render/scene/animate.js'; + +const fade: Animate = { property: 'opacity', from: 0, to: 1, durationMs: 200, easing: 'linear' }; + +describe('sampleAnimation (§5 declarative motion)', () => { + it('interpolates from→to over the duration (linear)', () => { + expect(sampleAnimation(fade, 0).value).toBe(0); + expect(sampleAnimation(fade, 100).value).toBeCloseTo(0.5); + expect(sampleAnimation(fade, 200)).toEqual({ value: 1, done: true }); + }); + it('honours delayMs (holds at `from` until the delay passes)', () => { + const delayed: Animate = { ...fade, delayMs: 50 }; + expect(sampleAnimation(delayed, 25).value).toBe(0); + expect(sampleAnimation(delayed, 50).value).toBe(0); + expect(sampleAnimation(delayed, 150).value).toBeCloseTo(0.5); + }); + it('eases (ease-out is ahead of linear at the midpoint)', () => { + const eo: Animate = { ...fade, easing: 'ease-out' }; + expect(sampleAnimation(eo, 100).value).toBeGreaterThan(0.5); + }); + it('loops forever when repeat=true (never done)', () => { + const loop: Animate = { ...fade, repeat: true }; + expect(sampleAnimation(loop, 250).done).toBe(false); // past one cycle, still looping + expect(sampleAnimation(loop, 250).value).toBeCloseTo(0.25); // 50ms into 2nd cycle + }); + it('repeats a finite number of cycles then settles at `to`', () => { + const twice: Animate = { ...fade, repeat: 2 }; + expect(sampleAnimation(twice, 399).done).toBe(false); + expect(sampleAnimation(twice, 400)).toEqual({ value: 1, done: true }); + }); +}); + +describe('reduced motion (visual-spec §2.11 collapse)', () => { + it('collapses instantly to the final value', () => { + expect(sampleAnimation(fade, 0, { reducedMotion: true })).toEqual({ value: 1, done: true }); + expect(reducedMotionValue(fade)).toBe(1); + }); + it('animateToCss drops the transition under reduced motion', () => { + expect(animateToCss(fade, { reducedMotion: true })).toEqual({ value: 1, transition: null }); + }); +}); + +describe('GPU/CSS path (zero JS per frame)', () => { + it('emits a CSS transition with a Lume timing function', () => { + const css = animateToCss({ ...fade, easing: 'standard' }); + expect(css.transition).toContain('opacity 200ms'); + expect(css.transition).toContain('--lume-ease-standard'); + expect(css.value).toBe(1); + }); + it('maps easing tokens to Lume CSS vars', () => { + expect(cssTimingFunction('emphasis')).toContain('--lume-ease-emphasis'); + expect(cssTimingFunction('linear')).toBe('linear'); + }); +}); diff --git a/app/test/node/dirty.test.ts b/app/test/node/dirty.test.ts new file mode 100644 index 0000000..b8e4692 --- /dev/null +++ b/app/test/node/dirty.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, it } from 'vitest'; +import { collectStateReads, changedStatePaths, isDirty, RegionMemo } from '../../src/renderer/src/render/lumen/dirty.js'; +import type { LxNode } from '../../src/renderer/src/lx/index.js'; + +describe('collectStateReads', () => { + it('gathers every state path an expression reads', () => { + const node: LxNode = { if: { '>': [{ state: 'score' }, { lit: 0 }] }, then: { state: 'pos.x' }, else: { state: 'board', at: [{ state: 'cx' }, { lit: 0 }] } }; + expect([...collectStateReads(node)].sort()).toEqual(['board', 'cx', 'pos.x', 'score']); + }); + it('a static region (no state reads) collects nothing', () => { + expect(collectStateReads({ lit: { type: 'text', content: 'hi' } }).size).toBe(0); + }); +}); + +describe('changedStatePaths + isDirty', () => { + it('detects changed top-level keys', () => { + expect([...changedStatePaths({ a: 1, b: 2 }, { a: 1, b: 3 })]).toEqual(['b']); + }); + it('prefix-matches: a read of pos.x is dirty when pos changed', () => { + expect(isDirty(new Set(['pos.x']), new Set(['pos']))).toBe(true); + expect(isDirty(new Set(['pos.x']), new Set(['score']))).toBe(false); + }); + it('a read of a record is dirty when a sub-field changed', () => { + expect(isDirty(new Set(['pos']), new Set(['pos.x']))).toBe(true); + }); +}); + +describe('RegionMemo (§5 re-evaluate only dirty regions)', () => { + it('re-evaluates only when the region’s reads changed; static once', () => { + const memo = new RegionMemo(); + let scoreEvals = 0; + let staticEvals = 0; + const scoreNode: LxNode = { state: 'score' }; + const staticNode: LxNode = { lit: 'banner' }; + + const step = (changed: Set) => { + memo.evaluate('score', scoreNode, changed, () => { scoreEvals++; return 1; }); + memo.evaluate('banner', staticNode, changed, () => { staticEvals++; return 'banner'; }); + }; + + step(new Set()); // first paint — both evaluate once + expect([scoreEvals, staticEvals]).toEqual([1, 1]); + + step(new Set(['pos'])); // unrelated change — neither re-evaluates + expect([scoreEvals, staticEvals]).toEqual([1, 1]); + + step(new Set(['score'])); // score changed — only score re-evaluates + expect([scoreEvals, staticEvals]).toEqual([2, 1]); + + step(new Set(['anything'])); // static region never re-evaluates + expect(staticEvals).toBe(1); + }); +}); diff --git a/app/test/node/lumenRuntime.test.ts b/app/test/node/lumenRuntime.test.ts new file mode 100644 index 0000000..4930561 --- /dev/null +++ b/app/test/node/lumenRuntime.test.ts @@ -0,0 +1,137 @@ +import { describe, expect, it } from 'vitest'; +import { + applyEvent, + applyWireInput, + evalView, + initState, + matchTransition, + tickRate, + type LumenSpec, +} from '../../src/renderer/src/render/lumen/lumenRuntime.js'; + +const ctx = { now: 0, seed: 1 }; + +describe('initState', () => { + it('seeds leaves from the schema (defaults + declared init)', () => { + const state = initState({ + count: { type: 'int', init: 0 }, + name: { type: 'string', init: 'hi' }, + mode: { type: 'enum', values: ['run', 'over'] }, + flag: { type: 'bool' }, + xs: { type: 'list', of: { type: 'int' } }, + }); + expect(state).toEqual({ count: 0, name: 'hi', mode: 'run', flag: false, xs: [] }); + }); + it('builds a w×h grid', () => { + const state = initState({ board: { type: 'grid', w: 3, h: 2, of: { type: 'bool', init: false } } }); + expect(state['board']).toEqual([[false, false, false], [false, false, false]]); + }); + it('builds a nested record', () => { + const state = initState({ pos: { type: 'record', fields: { x: { type: 'int', init: 5 }, y: { type: 'int' } } } }); + expect(state['pos']).toEqual({ x: 5, y: 0 }); + }); +}); + +const counter: LumenSpec = { + type: 'lumen', + id: 'counter', + state: { count: { type: 'int', init: 0 } }, + transitions: { inc: { set: { count: { '+': [{ state: 'count' }, { lit: 1 }] } } } }, + view: { record: { type: { lit: 'text' }, content: { call: 'fmt', args: [{ state: 'count' }] } } }, + events: [{ on: 'tap', run: 'inc' }], +}; + +describe('matchTransition', () => { + const events: LumenSpec['events'] = [ + { on: 'tap', target: { kind: 'element', elementId: 'btn' }, run: 'pressBtn' }, + { on: 'tap', run: 'anyTap' }, + { on: 'key', key: 'ArrowLeft', run: 'left' }, + ]; + it('matches a targeted tap by element id', () => { + expect(matchTransition(events, { on: 'tap', targetId: 'btn' })).toBe('pressBtn'); + }); + it('falls through to an untargeted tap', () => { + expect(matchTransition(events, { on: 'tap', targetId: 'other' })).toBe('anyTap'); + }); + it('matches a declared key', () => { + expect(matchTransition(events, { on: 'key', key: 'ArrowLeft' })).toBe('left'); + expect(matchTransition(events, { on: 'key', key: 'ArrowRight' })).toBeNull(); + }); + it('returns null when nothing matches', () => { + expect(matchTransition(events, { on: 'swipe' })).toBeNull(); + }); +}); + +describe('applyEvent', () => { + it('runs the matched transition, producing new state', () => { + let state = initState(counter.state); + state = applyEvent(counter, state, { on: 'tap' }, ctx); + state = applyEvent(counter, state, { on: 'tap' }, ctx); + expect(state['count']).toBe(2); + }); + it('returns the SAME state reference when no binding matches', () => { + const state = initState(counter.state); + expect(applyEvent(counter, state, { on: 'swipe' }, ctx)).toBe(state); + }); + it('a tick steps a simulation deterministically', () => { + const sim: LumenSpec = { + type: 'lumen', id: 'sim', + state: { x: { type: 'number', init: 0 }, v: { type: 'number', init: 2 } }, + transitions: { step: { set: { x: { '+': [{ state: 'x' }, { state: 'v' }] } } } }, + view: { lit: 1 }, + events: [{ on: 'tick', rate: 60, run: 'step' }], + cadence: { tick: 60 }, + }; + let s = initState(sim.state); + for (let i = 0; i < 3; i++) s = applyEvent(sim, s, { on: 'tick' }, ctx); + expect(s['x']).toBe(6); + }); +}); + +describe('evalView', () => { + it('evaluates the view to a primitive tree reflecting state', () => { + let state = initState(counter.state); + state = applyEvent(counter, state, { on: 'tap' }, ctx); + expect(evalView(counter, state, ctx)).toEqual({ type: 'text', content: '1' }); + }); +}); + +describe('cadence', () => { + it('tickRate reports the Hz for a ticking Lumen, null otherwise', () => { + expect(tickRate({ ...counter, cadence: { tick: 30 } })).toBe(30); + expect(tickRate({ ...counter, cadence: 'reactive' })).toBeNull(); + expect(tickRate(counter)).toBeNull(); + }); +}); + +describe('applyWireInput (§7 cross-element interaction → state)', () => { + const wired: LumenSpec = { + type: 'lumen', id: 'highlight', + state: { incoming: { type: 'list', of: { type: 'string' }, maxLen: 8, init: [] } }, + transitions: { recv: { set: { incoming: { event: 'value' } } } }, + view: { lit: 1 }, + events: [{ on: 'wire', run: 'recv' }], + }; + it('a wired in-port value drives the matched transition', () => { + let s = initState(wired.state); + s = applyWireInput(wired, s, 'selection', ['row-3'], { now: 0, seed: 1 }); + expect(s['incoming']).toEqual(['row-3']); + }); +}); + +describe('determinism (replay / share)', () => { + it('random in a transition is identical for the same seed', () => { + const dice: LumenSpec = { + type: 'lumen', id: 'dice', + state: { r: { type: 'number', init: 0 } }, + transitions: { roll: { set: { r: { call: 'random', args: [] } } } }, + view: { lit: 1 }, + events: [{ on: 'tap', run: 'roll' }], + }; + const a = applyEvent(dice, initState(dice.state), { on: 'tap' }, { now: 0, seed: 7 }); + const b = applyEvent(dice, initState(dice.state), { on: 'tap' }, { now: 0, seed: 7 }); + const c = applyEvent(dice, initState(dice.state), { on: 'tap' }, { now: 0, seed: 8 }); + expect(a['r']).toBe(b['r']); + expect(a['r']).not.toBe(c['r']); + }); +}); diff --git a/app/test/node/referenceLumens.test.ts b/app/test/node/referenceLumens.test.ts new file mode 100644 index 0000000..028aa75 --- /dev/null +++ b/app/test/node/referenceLumens.test.ts @@ -0,0 +1,120 @@ +import { describe, expect, it } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { validateLumen } from '../../src/renderer/src/validate/validator.js'; +import { validateLumenSemantics } from '../../src/renderer/src/lx/validate.js'; +import { applyEvent, evalView, initState, type LumenSpec } from '../../src/renderer/src/render/lumen/lumenRuntime.js'; +import type { LxValue, StateValue } from '../../src/renderer/src/lx/index.js'; + +// L9 — the four reference Lumens, traced end-to-end through the validator (L0) +// and interpreter (L1) exactly as the renderer would run them. This is the +// conformance capstone: it proves the whole Tier-1 stack composes. +const dir = join(dirname(fileURLToPath(import.meta.url)), '../fixtures/lumens'); +const load = (name: string): LumenSpec => JSON.parse(readFileSync(join(dir, `${name}.json`), 'utf8')) as LumenSpec; +const ctx = { now: 0, seed: 5 }; + +const REFERENCE = ['arcade-bounce', 'workflow-wizard', 'defrag-viz', 'map-explore']; + +describe('reference Lumens — structural + semantic validity', () => { + for (const name of REFERENCE) { + it(`${name} validates against the schema and the semantic layer`, () => { + const lumen = load(name); + const structural = validateLumen(lumen); + expect(structural.errors).toBeNull(); + expect(structural.ok).toBe(true); + expect(validateLumenSemantics(lumen)).toMatchObject({ ok: true }); + }); + } +}); + +function sceneDraw(tree: LxValue): unknown[] { + const t = tree as { type?: string; draw?: unknown[] }; + expect(t.type).toBe('scene'); + return t.draw ?? []; +} + +describe('arcade-bounce — a real bouncing game', () => { + const lumen = load('arcade-bounce'); + it('advances the ball each tick and bounces off the walls', () => { + let s = initState(lumen.state); + expect(s['x']).toBe(20); + s = applyEvent(lumen, s, { on: 'tick' }, ctx); + expect(s['x']).toBe(26); // 20 + vx(6) + // run enough ticks to hit the right wall at least once + for (let i = 0; i < 200; i++) s = applyEvent(lumen, s, { on: 'tick' }, ctx); + expect(s['bounces'] as number).toBeGreaterThan(0); + expect(s['x'] as number).toBeGreaterThanOrEqual(0); + expect(s['x'] as number).toBeLessThanOrEqual(300); + }); + it('tap reverses direction', () => { + let s = initState(lumen.state); // vx = 6 + s = applyEvent(lumen, s, { on: 'tap' }, ctx); + expect(s['vx']).toBe(-6); + }); + it('the view is a scene whose ball tracks state.x', () => { + let s = initState(lumen.state); + s = applyEvent(lumen, s, { on: 'tick' }, ctx); + const draw = sceneDraw(evalView(lumen, s, ctx)); + const ball = draw.find((n) => (n as { id?: string }).id === 'ball') as { cx?: number }; + expect(ball?.cx).toBe(26); + }); +}); + +describe('workflow-wizard — primitive-composed wizard', () => { + const lumen = load('workflow-wizard'); + it('advances and clamps steps, then finishes', () => { + let s = initState(lumen.state); + const tapNext = (st: StateValue) => applyEvent(lumen, st, { on: 'tap', targetId: 'next' }, ctx); + s = tapNext(s); + s = tapNext(s); + expect(s['step']).toBe(2); + s = tapNext(s); // clamped + expect(s['step']).toBe(2); + s = applyEvent(lumen, s, { on: 'tap', targetId: 'finish' }, ctx); + expect(s['done']).toBe(true); + }); + it('renders a container whose heading reflects the step', () => { + let s = initState(lumen.state); + s = applyEvent(lumen, s, { on: 'tap', targetId: 'next' }, ctx); + const tree = evalView(lumen, s, ctx) as { type: string; children: { content?: string }[] }; + expect(tree.type).toBe('container'); + expect(tree.children[0]?.content).toBe('Step 2 of 3'); + }); +}); + +describe('defrag-viz — scene built by map(range) over a frame counter', () => { + const lumen = load('defrag-viz'); + it('renders 8 blocks that compact left as the frame advances', () => { + let s = initState(lumen.state); + const at0 = sceneDraw(evalView(lumen, s, ctx)) as { x: number; id: string }[]; + expect(at0.length).toBe(8); + expect(at0[0]?.id).toBe('b0'); + const block5At0 = at0[5]!.x; // max(150, 220) = 220 + expect(block5At0).toBe(220); + for (let i = 0; i < 40; i++) s = applyEvent(lumen, s, { on: 'tick' }, ctx); + const after = sceneDraw(evalView(lumen, s, ctx)) as { x: number }[]; + expect(after[5]!.x).toBe(150); // fully compacted to idx*30 + }); +}); + +describe('map-explore — markers via map + get, selection + zoom', () => { + const lumen = load('map-explore'); + it('selecting a marker (scene-hit id) highlights only it', () => { + let s = initState(lumen.state); + s = applyEvent(lumen, s, { on: 'tap', targetId: 'b', payload: { id: 'b' } }, ctx); + expect(s['sel']).toBe('b'); + const draw = sceneDraw(evalView(lumen, s, ctx)) as { id?: string; fill?: string }[]; + const markerB = draw.find((n) => n.id === 'b'); + const markerA = draw.find((n) => n.id === 'a'); + expect(markerB?.fill).toBe('success'); + expect(markerA?.fill).toBe('accent'); + }); + it('zoom keys grow the markers and clamp at 5', () => { + let s = initState(lumen.state); // zoom 2 + s = applyEvent(lumen, s, { on: 'key', key: '+' }, ctx); + expect(s['zoom']).toBe(3); + for (let i = 0; i < 10; i++) s = applyEvent(lumen, s, { on: 'key', key: '+' }, ctx); + expect(s['zoom']).toBe(5); // clamped + }); +}); diff --git a/app/test/node/sceneTokens.test.ts b/app/test/node/sceneTokens.test.ts new file mode 100644 index 0000000..09d8bb5 --- /dev/null +++ b/app/test/node/sceneTokens.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { TOKEN_TO_CSSVAR } from '../../src/renderer/src/render/scene/tokenMap.js'; + +// Parity guard: every scene colorToken the renderer might receive must map to a +// Lume CSS variable, else the rasteriser would silently draw it transparent. +describe('scene token map parity with the synced schema', () => { + it('covers every colorToken (except transparent)', () => { + const schemaPath = join(dirname(fileURLToPath(import.meta.url)), '../../../docs/protocol/schema/scene.schema.json'); + const schema = JSON.parse(readFileSync(schemaPath, 'utf8')) as { $defs: { colorToken: { enum: string[] } } }; + const tokens = schema.$defs.colorToken.enum.filter((t) => t !== 'transparent'); + expect(tokens.length).toBeGreaterThan(0); + for (const token of tokens) { + expect(TOKEN_TO_CSSVAR[token], `missing CSS-var mapping for scene token '${token}'`).toBeTruthy(); + } + }); +}); diff --git a/app/test/node/wires.test.ts b/app/test/node/wires.test.ts new file mode 100644 index 0000000..29a2ec2 --- /dev/null +++ b/app/test/node/wires.test.ts @@ -0,0 +1,79 @@ +import { describe, expect, it } from 'vitest'; +import { + validateWireGraph, + resolveWires, + readExposed, + type Wire, + type WireableElement, +} from '../../src/renderer/src/render/lumen/wires.js'; + +// The canonical §7 example: a table exposes/out-ports its selection, wired to a +// map Lumen's selection in-port → selecting a row highlights the map markers, +// Tier-1, no turn. +const elements: Record = { + table: { ports: [{ name: 'selection', dir: 'out', type: 'selection' }], expose: [{ name: 'selection', type: 'selection' }] }, + map: { ports: [{ name: 'selection', dir: 'in', type: 'selection' }] }, + slider: { ports: [{ name: 'value', dir: 'out', type: 'number' }] }, +}; + +const wire = (fromId: string, fromPort: string, toId: string, toPort: string): Wire => ({ + from: { ref: { kind: 'element', elementId: fromId }, port: fromPort }, + to: { ref: { kind: 'element', elementId: toId }, port: toPort }, +}); + +describe('validateWireGraph (§7 static check)', () => { + it('accepts a well-typed wire by stable id', () => { + expect(validateWireGraph(elements, [wire('table', 'selection', 'map', 'selection')])).toMatchObject({ ok: true }); + }); + it('rejects an unknown source/target element', () => { + expect(validateWireGraph(elements, [wire('ghost', 'selection', 'map', 'selection')]).ok).toBe(false); + expect(validateWireGraph(elements, [wire('table', 'selection', 'ghost', 'selection')]).ok).toBe(false); + }); + it('rejects a missing out-port / in-port', () => { + expect(validateWireGraph(elements, [wire('table', 'nope', 'map', 'selection')]).ok).toBe(false); + expect(validateWireGraph(elements, [wire('table', 'selection', 'map', 'nope')]).ok).toBe(false); + }); + it('rejects incompatible port types', () => { + const r = validateWireGraph(elements, [wire('slider', 'value', 'map', 'selection')]); + expect(r.ok).toBe(false); + expect(r.errors.join()).toMatch(/incompatible/); + }); + it('rejects an in-port driven by more than one wire', () => { + const r = validateWireGraph( + { ...elements, table2: { ports: [{ name: 'selection', dir: 'out', type: 'selection' }] } }, + [wire('table', 'selection', 'map', 'selection'), wire('table2', 'selection', 'map', 'selection')], + ); + expect(r.ok).toBe(false); + expect(r.errors.join()).toMatch(/more than one wire/); + }); + it("'any' is compatible with anything", () => { + const els: Record = { + a: { ports: [{ name: 'o', dir: 'out', type: 'any' }] }, + b: { ports: [{ name: 'i', dir: 'in', type: 'number' }] }, + }; + expect(validateWireGraph(els, [wire('a', 'o', 'b', 'i')]).ok).toBe(true); + }); +}); + +describe('resolveWires (Tier-1 propagation)', () => { + it('routes a source out value to the wired target in-port', () => { + const out = { 'table.selection': ['row-3'] }; + expect(resolveWires([wire('table', 'selection', 'map', 'selection')], out)).toEqual({ 'map.selection': ['row-3'] }); + }); + it('skips a wire whose source has no current value', () => { + expect(resolveWires([wire('table', 'selection', 'map', 'selection')], {})).toEqual({}); + }); +}); + +describe('readExposed (least-privilege published interface)', () => { + const published = { table: { selection: ['row-1'], secret: 'internal' } }; + it('returns a value the element actually exposed', () => { + expect(readExposed(elements, published, 'table', 'selection')).toEqual(['row-1']); + }); + it('returns undefined for an un-exposed field (private state stays private)', () => { + expect(readExposed(elements, published, 'table', 'secret')).toBeUndefined(); + }); + it('returns undefined for an unknown element', () => { + expect(readExposed(elements, published, 'ghost', 'selection')).toBeUndefined(); + }); +}); diff --git a/app/test/renderer/scene.test.ts b/app/test/renderer/scene.test.ts new file mode 100644 index 0000000..71bad49 --- /dev/null +++ b/app/test/renderer/scene.test.ts @@ -0,0 +1,113 @@ +import { describe, expect, it } from 'vitest'; +import { hitTestScene, clientToBuffer } from '../../src/renderer/src/render/scene/hitTest.js'; +import { rasterizeScene, type Ctx2D } from '../../src/renderer/src/render/scene/rasterize.js'; +import type { Scene } from '../../src/renderer/src/render/scene/types.js'; + +describe('scene hit-testing (buffer-native → TargetRef)', () => { + const scene: Scene = { + type: 'scene', + width: 200, + height: 200, + draw: [ + { kind: 'rect', x: 0, y: 0, w: 100, h: 100, fill: 'surface', id: 'bg' }, + { kind: 'circle', cx: 50, cy: 50, r: 10, fill: 'accent', id: 'dot' }, + { kind: 'rect', x: 0, y: 0, w: 100, h: 100, fill: 'transparent' }, // no id ⇒ not a target + ], + }; + + it('returns the topmost id-bearing node containing the point', () => { + expect(hitTestScene(scene, 50, 50)).toBe('dot'); // circle painted above bg + }); + it('falls through to a lower node when the top one misses', () => { + expect(hitTestScene(scene, 90, 90)).toBe('bg'); + }); + it('returns null when nothing is hit', () => { + expect(hitTestScene(scene, 150, 150)).toBeNull(); + }); + it('a tiny node still gets a ≥44pt hit area', () => { + const tiny: Scene = { type: 'scene', width: 100, height: 100, draw: [{ kind: 'circle', cx: 50, cy: 50, r: 1, fill: 'accent', id: 'pip' }] }; + expect(hitTestScene(tiny, 65, 50)).toBe('pip'); // 15px away — inside the 44pt box + expect(hitTestScene(tiny, 90, 90)).toBeNull(); + }); + it('descends into a translated group (local-space geometry)', () => { + const grouped: Scene = { + type: 'scene', width: 200, height: 200, + draw: [{ kind: 'group', transform: { x: 100, y: 100 }, children: [{ kind: 'rect', x: 0, y: 0, w: 20, h: 20, fill: 'accent', id: 'inner' }] }], + }; + expect(hitTestScene(grouped, 110, 110)).toBe('inner'); // world (110,110) → local (10,10) + expect(hitTestScene(grouped, 10, 10)).toBeNull(); + }); +}); + +describe('clientToBuffer (pointer → buffer coords)', () => { + it('undoes element-fit scaling', () => { + const scene: Scene = { type: 'scene', width: 100, height: 100, draw: [] }; + const buf = clientToBuffer(scene, { x: 100, y: 50 }, { left: 0, top: 0, width: 200, height: 100 }); + expect(buf).toEqual({ x: 50, y: 50 }); // canvas shown 2× wide + }); + it('undoes the scene camera (zoom + pan)', () => { + const scene: Scene = { type: 'scene', width: 100, height: 100, camera: { x: 10, y: 0, zoom: 2 }, draw: [] }; + const buf = clientToBuffer(scene, { x: 20, y: 0 }, { left: 0, top: 0, width: 100, height: 100 }); + expect(buf.x).toBeCloseTo(20); // 20 / 2 + 10 + }); +}); + +describe('scene rasteriser (mock ctx, no DOM)', () => { + function mockCtx() { + const calls: string[] = []; + const ctx: Ctx2D = { + save: () => calls.push('save'), + restore: () => calls.push('restore'), + translate: (x, y) => calls.push(`translate(${x},${y})`), + scale: (x, y) => calls.push(`scale(${x},${y})`), + rotate: (a) => calls.push(`rotate(${a.toFixed(3)})`), + beginPath: () => calls.push('beginPath'), + moveTo: (x, y) => calls.push(`moveTo(${x},${y})`), + lineTo: (x, y) => calls.push(`lineTo(${x},${y})`), + closePath: () => calls.push('closePath'), + arc: (x, y, r) => calls.push(`arc(${x},${y},${r})`), + rect: (x, y, w, h) => calls.push(`rect(${x},${y},${w},${h})`), + fill: () => calls.push(`fill:${ctx.fillStyle as string}`), + stroke: () => calls.push(`stroke:${ctx.strokeStyle as string}@${ctx.lineWidth}`), + fillText: (t, x, y) => calls.push(`text:${t}@${x},${y}:${ctx.fillStyle as string}`), + drawImage: () => calls.push('drawImage'), + fillStyle: '', + strokeStyle: '', + lineWidth: 1, + font: '', + }; + return { ctx, calls }; + } + const resolve = (t: string | undefined) => (t === undefined || t === 'transparent' ? 'transparent' : `c:${t}`); + + it('draws a filled+stroked rect with resolved theme tokens', () => { + const { ctx, calls } = mockCtx(); + const scene: Scene = { type: 'scene', width: 50, height: 50, draw: [{ kind: 'rect', x: 1, y: 2, w: 3, h: 4, fill: 'accent', stroke: 'text', strokeW: 2 }] }; + rasterizeScene(ctx, scene, resolve); + expect(calls).toContain('rect(1,2,3,4)'); + expect(calls).toContain('fill:c:accent'); + expect(calls).toContain('stroke:c:text@2'); + }); + it('applies the camera (scale + translate) around the draw-list', () => { + const { ctx, calls } = mockCtx(); + const scene: Scene = { type: 'scene', width: 50, height: 50, camera: { x: 5, y: 6, zoom: 2 }, draw: [{ kind: 'circle', cx: 0, cy: 0, r: 1, fill: 'accent' }] }; + rasterizeScene(ctx, scene, resolve); + expect(calls[0]).toBe('save'); + expect(calls).toContain('scale(2,2)'); + expect(calls).toContain('translate(-5,-6)'); + expect(calls[calls.length - 1]).toBe('restore'); + }); + it('a transparent fill issues no fill op', () => { + const { ctx, calls } = mockCtx(); + const scene: Scene = { type: 'scene', width: 9, height: 9, draw: [{ kind: 'rect', x: 0, y: 0, w: 1, h: 1, fill: 'transparent' }] }; + rasterizeScene(ctx, scene, resolve); + expect(calls.some((c) => c.startsWith('fill:'))).toBe(false); + }); + it('a sprite with no resolved image draws an on-theme placeholder', () => { + const { ctx, calls } = mockCtx(); + const scene: Scene = { type: 'scene', width: 9, height: 9, draw: [{ kind: 'sprite', x: 0, y: 0, w: 4, h: 4, dataRef: { id: 'pixel-deadbeefdeadbeef' } }] }; + rasterizeScene(ctx, scene, resolve); + expect(calls).toContain('rect(0,0,4,4)'); + expect(calls.some((c) => c === 'drawImage')).toBe(false); + }); +}); diff --git a/app/tools/gen-validator/genValidator.ts b/app/tools/gen-validator/genValidator.ts index 90f27b7..6b5b14f 100644 --- a/app/tools/gen-validator/genValidator.ts +++ b/app/tools/gen-validator/genValidator.ts @@ -32,13 +32,34 @@ const load = (name: string): object => JSON.parse(readFileSync(join(schemaDir, `${name}.schema.json`), 'utf8')) as object; const ajv = new Ajv2020({ allErrors: true, strict: false, code: { source: true, esm: true } }); -for (const name of ['data-ref', 'target-ref', 'canvas-tree', 'handshake', 'sentinels', 'surface-events']) { - ajv.addSchema(load(name)); +for (const name of [ + 'data-ref', 'target-ref', 'canvas-tree', 'handshake', 'sentinels', 'surface-events', + // omadia-canvas-protocol/1.1 — Lumens (Live Interactivity), additive. + 'lx-ast', 'scene', 'ports-wires', 'capability-manifest', 'lumen', +]) { + const schema = load(name) as { $defs?: { primitive?: { oneOf: { $ref: string }[] } } }; + // omadia-canvas-protocol/1.1: extend the canvas-tree `primitive` oneOf with + // `scene` and `lumen` IN PLACE (keeping the 1.0 $id). Additive — every 1.0 + // tree still validates. Crucially, doing it under the SAME id means BOTH + // `validateTree` AND `validateSurfaceEvent` (whose surface_snapshot refs + // `tree` → 1.0 canvas-tree) accept a Lumen-bearing tree; a separate 1.1 id + // would only fix validateTree and the envelope path would still reject it. + if (name === 'canvas-tree' && schema.$defs?.primitive) { + schema.$defs.primitive.oneOf.push( + { $ref: 'https://omadia.ai/protocol/1.1/scene.schema.json' }, + { $ref: 'https://omadia.ai/protocol/1.1/lumen.schema.json' }, + ); + } + ajv.addSchema(schema); } let code = standaloneCode(ajv, { validateTree: 'https://omadia.ai/protocol/1.0/canvas-tree.schema.json', validateSurfaceEvent: 'https://omadia.ai/protocol/1.0/surface-events.schema.json', + // 1.1 — the Lumen whitelist parsers (structural; the L1 interpreter adds semantics). + validateLumen: 'https://omadia.ai/protocol/1.1/lumen.schema.json', + validateScene: 'https://omadia.ai/protocol/1.1/scene.schema.json', + validateLxNode: 'https://omadia.ai/protocol/1.1/lx-ast.schema.json', }); // Ajv emits ESM exports but still pulls runtime helpers via require() — diff --git a/docs/lumens-spec.md b/docs/lumens-spec.md index 22aebaf..360fdef 100644 --- a/docs/lumens-spec.md +++ b/docs/lumens-spec.md @@ -150,24 +150,37 @@ no prototypes, no functions-as-values beyond the named std-lib. | `lit` | `{lit: value}` | literal | | `state` | `{state: path}` | read a `state` slice (dotted path; `grid` via `{state, at:[x,y]}`) | | `event` | `{event: field}` | read a field of the triggering event | -| `var` / `let` | `{let:{name:expr}, in:expr}` | bind a local; lexically scoped, immutable | +| `let` | `{let:{name:expr}, in:expr}` | bind a local; lexically scoped, immutable | +| `var` | `{var: name}` | read a `let` binding or an iteration binding (`it`/`idx`/`acc`, §2.3); unbound ⇒ reject | | arithmetic | `{"+":[a,b]}` `-` `*` `/` `mod` | numeric | | comparison | `{">":[a,b]}` `>=` `<` `<=` `==` `!=` | boolean | | logic | `{and:[…]}` `or` `not` | boolean | | `if` | `{if:c, then:a, else:b}` | total conditional (both branches required) | | `match` | `{match:expr, cases:[{when,then}], else}` | total switch | | record/list ctor | `{record:{…}}` `{list:[…]}` | construction | +| `get` | `{get:expr, key:expr}` | project a field of a record (string key) or element of a list (int index) — the read-side complement of `state` paths, so `map` bodies can read fields of `it` | | `set` | `{set:{path: expr}}` | **functional** update → returns a new state (no mutation) | | std-lib call | `{call:name, args:[…]}` | from the §2.3 whitelist only | ### 2.3 Standard library (whitelist, bounded) -`map` `filter` `fold` `range` `len` `min` `max` `clamp` `abs` `floor` `round` -`concat` `slice` `contains` `indexOf` `keys` `values` string ops (`upper` -`lower` `pad` `fmt`) and a small math set. **`map`/`filter`/`fold`/`range` -iterate only over collections bounded by `state`** (which is size-capped) — this -is what makes the gas bound a *static* property. **No `while`, no general -recursion.** `random()` and `now()` read host-seeded context values (§0.3). +`map` `filter` `fold` `range` `len` `min` `max` `clamp` `abs` `floor` `ceil` +`round` `sqrt` `sign` `pow` `concat` `slice` `contains` `indexOf` `keys` +`values` string ops (`upper` `lower` `pad` `fmt`) and a small math set. +**`map`/`filter`/`fold`/`range` iterate only over collections bounded by +`state`** (which is size-capped) — this is what makes the gas bound a *static* +property. **No `while`, no general recursion.** `random()` and `now()` read +host-seeded context values (§0.3). + +**Iteration bindings (no lambdas).** LX has no functions-as-values, so the +higher-order forms take an **expression body** read through reserved `var` +bindings, not a closure: `{call:"map", args:[coll, body]}` evaluates `body` per +element with `{var:"it"}` = the element and `{var:"idx"}` = its index; +`{call:"filter", args:[coll, pred]}` keeps elements where `pred` (read with the +same `it`/`idx`) is true; `{call:"fold", args:[coll, init, body]}` threads +`{var:"acc"}` (seeded from `init`) alongside `it`/`idx`. `{call:"range", +args:[n]}` yields `0..n-1` (bounded). These bindings are lexically scoped to the +body and immutable — the same discipline as `let`. ### 2.4 Gas & determinism contract diff --git a/scripts/sync-canvas-schema.mjs b/scripts/sync-canvas-schema.mjs index 137a425..71fcec6 100644 --- a/scripts/sync-canvas-schema.mjs +++ b/scripts/sync-canvas-schema.mjs @@ -60,6 +60,12 @@ const SCHEMAS = [ 'handshake', 'sentinels', 'surface-events', + // omadia-canvas-protocol/1.1 — Lumens (Live Interactivity), additive. + 'lx-ast', + 'scene', + 'ports-wires', + 'capability-manifest', + 'lumen', ]; if (!existsSync(schemaSrc)) {