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.
pnpm add @niscorp/moss @niscorp/charter @niscorp/nova @niscorp/prism @niscorp/strata @niscorp/tide @niscorp/vex zod @electric-sql/pglite jsdomThe app, booted
The theatre again. This time the question is what a browser gets when it asks for the page itself.
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);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.
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 }),
});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.
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'));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.
console.log('nobody:', open.headers['cache-control']);
console.log('grace:', hers.headers['cache-control']);
server.close();Run it.
That both pages were drawn with their own screen in them, and the cache header for each.
npx tsx page.mtsnobody: true true grace: true true nobody: no-cache grace: private, no-store