Moss · guide

A page that arrives drawn

A request for a page is answered with the caller’s screen already in the HTML, and with who may keep it.

Install it
pnpm add @niscorp/moss @niscorp/charter @niscorp/nova @niscorp/prism @niscorp/strata @niscorp/tide @niscorp/vex zod @electric-sql/pglite jsdom
Step 1 of 4

The app, booted

The theatre again. This time the question is what a browser gets when it asks for the page itself.

The app, booted
import { PGlite } from '@electric-sql/pglite';
import { JSDOM } from 'jsdom';
import { createServer, defineApp, mintDevToken, renderDocument } from '@niscorp/moss';
import { renderSnapshot } from '@niscorp/moss/terminal/dom/server';
import type { ActionDefinition } from '@niscorp/nova';
import { createPglitePool } from '@niscorp/vex/pglite';

const db = new PGlite();
const runtime = { db, pool: createPglitePool(db), session: 'dev-open' as const };
const charter = {
  public: ['programme'],
  member: ['programme', 'seats'],
  manager: { extends: ['member'], allow: ['takings'] },
};
const assignments = { grace: ['member'], ruth: ['manager'] };
const text = (says: string) => ({ component: 'Text', children: says });
const actions: Record<string, ActionDefinition> = {
  programme: { id: 'programme', layout: text('This week: The Tempest') },
  seats: {
    id: 'seats',
    data: { held: 0 },
    triggers: [{ event: 'ui:click', ref: 'hold', do: [{ increment: 'held' }] }],
    layout: {
      component: 'Stack',
      children: [
        text('Seats held: {{$.held}}'),
        { component: 'Button', ref: 'hold', props: { label: 'Hold a seat' } },
      ],
    },
  },
  takings: { id: 'takings', layout: text('Saturday took 4,180') },
};
const app = defineApp({
  charter,
  assignments,
  actions,
  shell: { canvases: [{ id: 'main', initial: ['takings', 'seats', 'programme'] }] },
});
const server = await createServer(app, runtime);
Step 2 of 4

How a page is drawn

renderDocument reads the caller’s shell as it stands, hands the snapshot to draw, and writes the result into your HTML template beside the snapshot it was drawn from.

draw is the same component kit the browser uses, run on the server. This one is Nova’s plain kit. It needs something to build elements in, and on a server that is jsdom.

How a page is drawn
const template = '<!doctype html><html><head></head><body><div id="root"></div></body></html>';
const pageFor = (who: string | null) =>
  renderDocument({
    server,
    template,
    request: { path: '/', cookie: who === null ? null : 'nisc.token=' + mintDevToken(who) },
    draw: (snapshot) => renderSnapshot({ snapshot, window: new JSDOM('').window }),
  });
Step 3 of 4

For nobody, and for Grace

Who is asking comes from the session cookie. With none, the page is drawn for nobody, and is the same for everybody.

The words of the screen are in the HTML before any script runs. The browser’s terminal then takes over the elements that are already there.

For nobody, and for Grace
const open = await pageFor(null);
const hers = await pageFor('grace');
console.log('nobody:', open.drawn, open.html.includes('This week: The Tempest'));
console.log('grace:', hers.drawn, hers.html.includes('Seats held: 0'));
Step 4 of 4

Who may keep it

A page drawn for nobody may be kept by a cache. A page drawn for somebody is private and must not be stored. Moss sets the header from who asked, so it cannot be got wrong per route.

Who may keep it
console.log('nobody:', open.headers['cache-control']);
console.log('grace:', hers.headers['cache-control']);
server.close();
Then

Run it.

That both pages were drawn with their own screen in them, and the cache header for each.

Run it
npx tsx page.mts
It prints
nobody: true true
grace: true true
nobody: no-cache
grace: private, no-store