Audited
A document can come from a model. Nova reads it against its schema, and an audit reads it against itself, before anybody presses anything.
pnpm add @niscorp/nova @niscorp/prism @niscorp/strata zodOne action that is fine
This file draws nothing, so it needs no kit: only the schema and the audit. The action is a ticket with one button and the trigger that answers it.
import { ActionDefinitionSchema, auditAction } from '@niscorp/nova';
import type { ActionDefinition } from '@niscorp/nova';
const ticket: ActionDefinition = {
id: 'ticket',
data: { seats: 2 },
layout: {
component: 'Stack',
children: [
{ component: 'Text', children: '{{$.seats}} seats' },
{ component: 'Button', ref: 'more', children: 'One more' },
],
},
triggers: [{ event: 'ui:click', ref: 'more', do: [{ increment: 'seats' }] }],
};
console.log(auditAction(ticket));Code in a document
An action has the keys an action has, and no other. There is nowhere in it to put code, so the schema refuses this when it is read, and nothing is run.
const withCode = { ...ticket, script: "fetch('https://example.com/seats')" };
const parsed = ActionDefinitionSchema.safeParse(withCode);
console.log(parsed.success, parsed.error?.issues.map((issue) => issue.message));A button nothing answers
This one parses, and would be drawn. A screen can be polite and still be broken at the press. auditAction reads the document against itself: every ref in the layout against the triggers, every binding against the data.
const deadButton: ActionDefinition = { ...ticket, triggers: [] };
console.log(auditAction(deadButton));A call to an endpoint that is not there
This one parses too. The audit finds a step that calls an endpoint the action never declared, without running it.
const phantomCall: ActionDefinition = {
...ticket,
triggers: [{ event: 'ui:click', ref: 'more', do: [{ call: 'charge' }] }],
};
console.log(auditAction(phantomCall));Run it.
One clean audit, one refusal by the schema, and two documents the audit found out. Each message is Nova’s own, and precise enough to hand back to whoever wrote the document.
npx tsx audit.mts{ ok: true, issues: [] }
false [ 'Unrecognized key: "script"' ]
{
ok: false,
issues: [ 'layout ref "more" has no trigger — dead chrome' ]
}
{
ok: false,
issues: [ 'step calls endpoint "charge" but endpoints has no "charge"' ]
}