-- site — writeonce.de: the language tutorial, served BY the language. -- Full stack in one binary: porch ([deps]) for HTTP/routing/ -- auth, writeonce-view ([deps]) for server-rendered pages with Tailwind-style -- utilities, @table + WAL for the chapters themselves. The site is its own -- final chapter: /ch/serving shows this file's shape. -- -- SITE_TOKEN=... WO_DATA=./data ./site 8080 -- SITE_HOST=0.0.0.0 ... ./site 8080 (reachable from the network) -- WO_DIST=/srv/dist ... (where /dl serves tarballs from) -- -- Behind nginx/caddy for writeonce.de: the proxy terminates TLS and -- forwards to 127.0.0.1:8080 (the framework speaks HTTP/1.1 keep-alive). -- -- This file is the BOOTSTRAP and nothing else: seed, routes, serve. The -- model is types.wo; every feature is a directory holding its view and -- its controller. use env use porch use porch/http use porch/router use home use chapter use install use packages use admin use health use favicon fn main(args: multi Text) -> Int { if len(args) < 1 { print_err("usage: site (SITE_TOKEN gates /admin; WO_DATA makes chapters durable)"); return 2; } let port = parse_int(args[0]); if port == nil { print_err("site: must be a number"); return 2; } let token = env.get("SITE_TOKEN"); if token == nil { print_err("site: SITE_TOKEN is required (the admin route's bearer token)"); return 2; } -- Bind to loopback unless SITE_HOST says otherwise. Behind a proxy -- loopback is right; SITE_HOST=0.0.0.0 (or a LAN address) is how you -- reach it from another machine while developing. let host = "127.0.0.1"; let h = env.get("SITE_HOST"); if h != nil { host = "${h}"; } -- Where the release tarballs live. `just dist` writes them to ./dist; -- a deployment points WO_DIST at wherever it keeps them. let dist = "dist"; let d = env.get("WO_DIST"); if d != nil { dist = "${d}"; } seed_if_empty(); let app = App { middleware: [], routes: [] }; app.use_mw(Mw { m: Logging {} }); app.get("/", Home {}); app.get("/install", ShowInstall {}); app.get("/packages", ShowPackages {}); app.get("/packages/:name", ShowPackage {}); app.get("/health", Health {}); app.get("/favicon.svg", Favicon {}); -- 16 MiB ceiling: the toolchain tarball is under 1 MiB today, and -- `max_bytes` is a hard truncation point, not a hint. app.get("/dl/*path", StaticFiles { dir: dist, max_bytes: 16777216 }); app.get("/ch/:slug", ShowChapter {}); app.post("/admin/ch/:slug", AdminEdit { token: "${token}" }); print_err("site: listening on ${host}:${port}"); return app.serve(host, port); }