ident
All repositories: gitoria
3.8 KB
// api.hl — the answers of the function routes: JSON, redirects, the HTML error page, and// the STRICT JSON body. Statics only; the routes are in project.hl.//// STRICT: a body must be a JSON object; an unknown field, a missing field and a field of// the wrong type are each a 400 whose `error` names the field. hl:json's JSON.parse// aborts the request (500) on invalid input and the language has no catch (hybriel #12),// so the body's syntax is checked first by jsoncheck.hl (copied from tickets).import { Response } from 'hl:http1'import { jsonErrorAt } from './jsoncheck.hl'static jsonHeaders = { 'Content-Type' = 'application/json; charset=utf-8' 'Cache-Control' = 'no-store' }static htmlHeaders = { 'Content-Type' = 'text/html; charset=utf-8' 'Cache-Control' = 'no-store' }static reply = (status, value) => { return new Response(JSON.stringify(value), { status = status headers = jsonHeaders }) }static fail = (status, message) => { return reply(status, { error = message }) }static redirect = (url) => { return new Response('', { status = 302 headers = { 'Location' = url 'Cache-Control' = 'no-store' } }) }// THE STRICT BODY: `spec` maps each allowed field to { type ('String' | 'Number' |// 'Boolean' | 'List'), required }. Answers { error } or { body }.static strictBody = (req, spec) => {let raw = req.bodyif (raw == null || raw.trim() == '') { return { error = 'a JSON object body is required' } }let at = jsonErrorAt(raw)if (at >= 0) { return { error = 'the body is not valid JSON (at character ' + at + ')' } }let t = raw.trim()if (t[0] != '{') { return { error = 'the body must be a JSON object' } }let b = JSON.parse(raw)for (k of b.keys()) {if (spec[k] == null) { return { error = 'unknown field: ' + k } }}for (k of spec.keys()) {let f = spec[k]let v = b[k]if (v == null) {if (f.required) { return { error = 'missing field: ' + k } }} else if (f.type == 'List') {if (hlTypeName(v) != 'Hybrid' || v.length == null) { return { error = 'field ' + k + ' must be a list' } }} else if (hlTypeName(v) != f.type) {return { error = 'field ' + k + ' must be a ' + f.type.toLowerCase() }}}return { body = b }}// ---- the HTML error page of the login button (never a redirect) ------------------------static escapeHtml = (s) => { return ('' + s).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"') }static errorPage = (status, title, message) => {let html = '<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>ident | ' + escapeHtml(title) + '</title><style>:root{--dark:rgb(25, 30, 35);--darker:rgb(15, 20, 25);--light:rgb(195, 200, 205);--lighter:rgb(245, 250, 255);--red:#f44747;--color-background:var(--dark);--color-surface:rgb(35, 40, 45);--color-border:rgb(70, 75, 80);--color-text:var(--light);--color-danger:var(--red);--color-accent:#ce9178}html{color-scheme:dark}body{margin:0;font:16px/1.5 system-ui,sans-serif;color:var(--color-text);background:var(--color-background)}application-header{display:block;padding:.6rem 1rem;background:var(--darker);border-bottom:1px solid var(--color-border)}application-header a{font-weight:800;font-size:1.15rem;color:var(--color-accent);text-decoration:none}main{padding:2rem 1rem}ident-error{display:block;max-width:34rem;margin:0 auto;padding:1rem;background:var(--color-surface);border:1px solid var(--color-border);border-radius:.5rem}h1{margin:0 0 .5rem;font-size:1.2rem;color:var(--color-danger)}p{margin:0;overflow-wrap:anywhere}</style></head><body><application-header><a href="/">ident</a></application-header><main><ident-error id="identerror"><h1>' + escapeHtml(title) + '</h1><p id="errormessage">' + escapeHtml(message) + '</p></ident-error></main></body></html>'return new Response(html, { status = status headers = htmlHeaders })}
Branches
- mainmain branch
Latest commits
- 836f644fident#24: installable app (manifest, service worker, data-free offline /start), own iconmre
- 8bebbbf2deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
- cc063ea2deploy.sh: never send .git or .gitignore to Byrodinmre
- 81b15b7bState of 2026-09-27, before the move to gitoriamre