Moss · guide
Refused at boot
Two apps with one thing wrong in each. Moss reads the whole app before it serves, and says what is wrong.
pnpm add @niscorp/moss @niscorp/charter @niscorp/nova @niscorp/prism @niscorp/strata @niscorp/tide @niscorp/vex zod @electric-sql/pgliteStep 1 of 3
An app that is fine
Two screens and a charter. tryBoot boots an app on a fresh database and answers with what happened.
import { PGlite } from '@electric-sql/pglite';
import { createServer, defineApp, type NiscApp } from '@niscorp/moss';
import { createPglitePool } from '@niscorp/vex/pglite';
const text = (says: string) => ({ component: 'Text', children: says });
const fine: NiscApp = defineApp({
charter: { public: ['programme'], manager: ['*'] },
actions: {
programme: { id: 'programme', layout: text('This week: The Tempest') },
takings: { id: 'takings', layout: text('Saturday took 4,180') },
},
});
const tryBoot = async (app: NiscApp): Promise<string> => {
const db = new PGlite();
try {
(await createServer(app, { db, pool: createPglitePool(db), session: 'dev-open' })).close();
return 'booted';
} catch (error) {
return error instanceof Error ? error.message : String(error);
}
};
console.log(await tryBoot(fine));Step 2 of 3
A typo in a deny
The staff role is every screen except the takings, and the deny is mistyped.
Booted like this, staff would have the takings and nothing would fail. Moss runs Charter’s verifier first, and a deny that matches nothing is an error.
const typo = { ...fine, charter: { ...fine.charter, staff: { allow: ['*'], deny: ['takngs'] } } };
console.log(await tryBoot(typo));Step 3 of 3
A layout for a screen that is not there
A variant names the screen it is a layout of. This one names bar, and the app has no such screen.
const orphan = { ...fine, layouts: { 'bar.late': { action: 'bar', layout: text('Open late') } } };
console.log(await tryBoot(orphan));Then
Run it.
The app that boots, and the two that do not, each with the reason Moss gives.
npx tsx refused.mtsbooted Charter is incoherent — refusing to serve: dead-deny: role "staff" denies "takngs" (actions) which matches nothing — silent means unprotected Layout variants are incoherent — refusing to serve: layout variant "bar.late" reshapes unknown action "bar"