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.

Install it
pnpm add @niscorp/moss @niscorp/charter @niscorp/nova @niscorp/prism @niscorp/strata @niscorp/tide @niscorp/vex zod @electric-sql/pglite
Step 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.

An app that is fine
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.

A typo in a deny
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.

A layout for a screen that is not there
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.

Run it
npx tsx refused.mts
It prints
booted
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"