// The public demo's refusal (docs/website/DEMO_MODE.md §3.1). // // With DEMO_MODE on, the server answers a locked write `403 { code: // 'DEMO_LOCKED', message }`. Every request goes through api/client.js's req(), // installed modules' included, so req() reports the refusal here and the one // toast (components/DemoToast.jsx) shows it — wherever the action was, without // each form learning the code. The form still gets its ApiError as usual. // // The lock is the server's (DM10). Nothing here decides what is allowed; it // only explains what was refused. export const DEMO_LOCKED = 'DEMO_LOCKED' const listeners = new Set() /** Subscribe to refusals. Returns the unsubscribe function. */ export function onDemoLocked(fn) { listeners.add(fn) return () => listeners.delete(fn) } /** Report a refusal, if this response body is one. Returns whether it was. */ export function reportIfDemoLocked(body) { if (!body || typeof body !== 'object' || body.code !== DEMO_LOCKED) return false const message = typeof body.message === 'string' && body.message ? body.message : 'This is turned off on the demo site.' for (const fn of listeners) { try { fn(message) } catch { // A broken listener must not turn a refusal into a different error. } } return true } /** * Was this ApiError the demo's refusal? For the few screens that turn a 403 * into a sentence of their own ("only an administrator can…"), which would * otherwise blame the role of somebody who is signed in as an admin. */ export function isDemoLocked(err) { return Boolean(err && err.body && err.body.code === DEMO_LOCKED) } /** * "14:00 UTC" for the banner. The wipe runs on the hour in UTC (DM7), so the * banner says UTC rather than converting — a converted time in a reviewer's * zone reads as a different schedule from the one published on /beta. */ export function formatResetTime(iso) { const ms = Date.parse(iso) if (Number.isNaN(ms)) return null const d = new Date(ms) const hh = String(d.getUTCHours()).padStart(2, '0') const mm = String(d.getUTCMinutes()).padStart(2, '0') return `${hh}:${mm} UTC` }