Nova · guide

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.

Install it
pnpm add @niscorp/nova @niscorp/prism @niscorp/strata zod
Step 1 of 4

One 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.

One action that is fine
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));
Step 2 of 4

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.

Code in a document
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));
Step 3 of 4

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.

A button nothing answers
const deadButton: ActionDefinition = { ...ticket, triggers: [] };
console.log(auditAction(deadButton));
Step 4 of 4

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.

A call to an endpoint that is not there
const phantomCall: ActionDefinition = {
  ...ticket,
  triggers: [{ event: 'ui:click', ref: 'more', do: [{ call: 'charge' }] }],
};
console.log(auditAction(phantomCall));
Then

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.

Run it
npx tsx audit.mts
It prints
{ 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"' ]
}