- docs/examples/writeonce-framework: library project (no fn main) — wo.toml, README (what it is + the honest v1 limits + the proxy TLS/h2 story), and http/types.wo: pub Req/Resp records + the response builders (ok_text/ ok_json/created/not_found/bad_request/unauthorized/conflict/server_error/ redirect). Typechecks + emits entry-less via woc --emit (1767-byte image). - docs/examples/web-app: manifest with the real [deps] entry (future GitHub URL as documentation; the gate substitutes a file:// remote) + README (routes table, run instructions, nginx h2-in-front sketch). Code lands with Task 4. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2 KiB
2 KiB
writeonce-framework
A web framework written in writeonce, consumed as a [deps] dependency
(iteration 15). Spec: docs/superpowers/specs/2026-08-18-web-framework-design.md §B.
[deps]
writeonce-framework = { git = "https://github.com/shoneyj/writeonce-framework", rev = "v0.1.0" }
What it is
- HTTP/1.1 keep-alive server core (
http/): request parsing (Content-Lengthbodies), response serialization, a blocking serve loop that answers 400 to malformed requests, 500 to trapping handlers (and survives), closes every fd, and honors SIGTERM. - Router (
router/): method + path table with:paramcaptures intoreq.params; first match wins; no match is the framework's 404. - Handlers without closures: the language has no function values by
doctrine, so a route handler is a class satisfying the
Handlerinterface (fn handle(req: Req) -> Resp), dispatched structurally — a non-conforming handler is a compile error (WO-E205). Middleware is its own interface (fn before(req: Req) -> ?Resp; nil = continue, aRespshort-circuits). - Data layer for free: handlers use
@table+ the query surface directly — durable, compiler-checked persistence in the same binary. No ORM, no database server.
Honest limits (v1, all deliberate)
- Single-threaded, blocking — one request at a time. Concurrency arrives underneath this same surface with the shard/fiber iterations (8/11).
- TLS: none, anywhere. Deploy behind nginx/caddy; the proxy terminates TLS+ALPN and gives browsers HTTP/2 while this backend speaks HTTP/1.1 keep-alive. See the web-app sample's README for the nginx sketch.
Content-Lengthbodies only (no chunked encoding), no WebSockets/SSE, JSON-first (no templates).
The consuming sample
docs/examples/web-app — a small storefront importing this framework
through [deps]. Its acceptance (just web-app) exercises the whole chain:
fetch → lock → build → serve → durable restart.