Moss · guides
How to do things with Moss.
Each guide is a file you can run, set in the theatre’s world. What it prints is what the installed package printed.
First steps.
The smallest app: a charter, who wears which role, and three screens, booted on a Postgres that lives in the process. The file prints the application Moss serves Linus, and somebody who is not signed in.
pnpm add @niscorp/moss @niscorp/charter @niscorp/nova @niscorp/prism @niscorp/strata @niscorp/vex zod @electric-sql/pglitenpx tsx first.mtsimport { PGlite } from '@electric-sql/pglite';
import { createServer, defineApp } from '@niscorp/moss';
import { createPglitePool } from '@niscorp/vex/pglite';
const app = defineApp({
charter: {
public: ['programme'],
member: ['programme', 'me.*'],
usher: ['programme', 'door.*'],
},
assignments: { grace: ['member'], linus: ['member', 'usher'] },
actions: {
programme: { id: 'programme', layout: { component: 'Text', props: { value: 'The Tempest, 2026-10-23' } } },
'me.pass': { id: 'me.pass', layout: { component: 'Text', props: { value: 'Your season pass' } } },
'door.list': { id: 'door.list', layout: { component: 'Text', props: { value: 'Who is coming tonight' } } },
},
});
const db = new PGlite();
const server = await createServer(app, { db, pool: createPglitePool(db), session: 'dev-open' });
console.log(await server.catalogOf('linus'));
console.log(await server.catalogOf(null));
server.close();{ ids: [ 'door.list', 'me.pass', 'programme' ], hash: '98205f02' }
{ ids: [ 'programme' ], hash: 'aa850b95' }That is what GET /catalog answers each of them. session: 'dev-open' trusts any well-formed token, which suits a file like this one and never a deployment. To serve the same app, hand it to serve from @niscorp/moss/node, with a Postgres and a way to verify a session.
Then, one at a time.
Each is a file of its own and adds one thing. Read them in order, or go to the one you need.