import express, { type ErrorRequestHandler } from 'express'; import { mkdirSync } from 'node:fs'; import { dirname, resolve } from 'node:path'; import { page, start, type LivePageRequestContext } from 'redweb'; import { DashboardAuth, sessionToken } from './auth'; import { Cards, PrivateCards } from './cards'; import { DashboardStore } from './store'; import { runApp } from './run-app'; export interface DashboardOptions { port?: number; database?: string; origin?: string; sessionLifetimeMs?: number; } export function databasePath() { return resolve(process.env.DASHBOARD_DATABASE ?? 'data/dashboard.sqlite'); } export function createApp(options: DashboardOptions = {}) { const port = options.port ?? Number(process.env.PORT ?? 8181); const configuredOrigin = options.origin ?? process.env.DASHBOARD_ORIGIN; if (configuredOrigin && (!/^https?:$/.test(new URL(configuredOrigin).protocol) || new URL(configuredOrigin).origin !== configuredOrigin)) { throw new Error('DASHBOARD_ORIGIN must be an exact HTTP(S) origin without a path.'); } if (process.env.NODE_ENV === 'production' && !configuredOrigin?.startsWith('https://')) throw new Error('Production requires an explicit HTTPS DASHBOARD_ORIGIN.'); const filename = options.database ?? databasePath(); mkdirSync(dirname(filename), { recursive: true }); const store = new DashboardStore(filename); try { const cards = new PrivateCards(store); const auth = new DashboardAuth(store, options.sessionLifetimeMs); const app = express(); app.disable('x-powered-by'); app.use(express.urlencoded({ extended: false, limit: '4kb', parameterLimit: 4 })); const invalidBody: ErrorRequestHandler = (_error, _request, response, _next) => { if (!response.destroyed) response.status(400).send('Invalid form submission.'); }; app.use(invalidBody); const origin = () => configuredOrigin ?? `http://127.0.0.1:${(server.server.address() as { port: number }).port}`; @page('/login', { live: false, css: 'app.css', head: { title: 'Sign in ยท Your cards' } }) class Login { render() { return

Your private workspace

Sign in with the credentials created by your administrator.

; } } @page('/', { css: 'app.css', authorize: context => cards.allowed(context), head: { title: 'Your cards' } }) class Dashboard { private readonly workspace = new Cards(cards); render(context: LivePageRequestContext) { return

Your cards

Signed in as {context.principal}

{this.workspace}

Open another tab to see your changes instantly.

; } } auth.mount(app, origin, account => server.revoke(account)); const server = start([Login, Dashboard], { server: app, port, bind: configuredOrigin ? '0.0.0.0' : '127.0.0.1', logger: null, templateRoot: __dirname, origins: value => value === origin(), authenticate: request => request.method === 'GET' && request.url?.split('?')[0] === '/login' ? true : store.session(sessionToken(request.headers.cookie))?.account, }); let closing: Promise | undefined; const shutdown = () => { auth.close(); if (!closing) { closing = server.shutdown().finally(() => store.close()); } return closing; }; server.server.once('error', () => { void shutdown().catch(() => {}); }); return { server: server.server, shutdown, }; } catch (error) { store.close(); throw error; } } if (require.main === module) { const app = runApp(createApp); app?.server.once('listening', () => console.log(`Dashboard: ${process.env.DASHBOARD_ORIGIN ?? `http://127.0.0.1:${(app.server.address() as { port: number }).port}`}/login`)); }