From 47a920f19a944edbc1935a1c1b342004eda42949 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Tue, 25 Aug 2026 04:41:00 +0200 Subject: [PATCH] feat(serve+view): file serving, downloads, supported systems; rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rename the two libraries: writeonce-framework -> writeonce-serve (`use serve`), wo-html -> writeonce-view (`use view`). Names say the ROLE now; every sample, script, gate and live doc follows - stories/specs/plans keep the old names: they are dated records, and both library READMEs carry a "renamed 2026-08-25" note - serve/http/files.wo: StaticFiles { dir, max_bytes } — traversal refused not normalised, extension content types, attachment disposition for archives. Lifted out of the shop, which had said in a comment that it belonged in the framework - shop drops its private copy and mounts the framework's - site: /dl/*path over $WO_DIST (default ./dist), 16 MiB ceiling - /install gains supported systems — Linux x86-64, glibc >= 2.38, not musl — read off `file` and the binaries' GLIBC_ symbol versions, not off a wish list; plus GitHub release as primary, /dl as mirror, and the sha256 verify step - site-accept: 17 -> 21 checks (supported systems, gzip download with a binary-safe probe, checksum, /dl traversal 404) Verified on 192.168.0.165: the real 960,820-byte tarball downloads as application/gzip and its sha256 matches the published digest. Gates: oop-accept MET, site 21/0, web-app 46/0, fibers 10/0, db-actor 8/0; shop rebuilt and its /assets served by the framework. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 4 +- compiler/src/CODE-LOGIC.md | 2 +- docs/00-code-review.md | 2 +- docs/examples/shop/README.md | 12 ++-- docs/examples/shop/layout/app.wo | 8 +-- docs/examples/shop/main.wo | 10 +-- docs/examples/shop/orders/controller.wo | 2 +- docs/examples/shop/orders/view.wo | 2 +- docs/examples/shop/product_list/controller.wo | 2 +- docs/examples/shop/product_list/view.wo | 2 +- docs/examples/shop/product_page/controller.wo | 2 +- docs/examples/shop/product_page/view.wo | 2 +- docs/examples/shop/static_files/controller.wo | 33 --------- docs/examples/shop/wo.toml | 4 +- docs/examples/site/CODE-LOGIC.md | 15 +++- docs/examples/site/README.md | 15 ++-- docs/examples/site/admin/controller.wo | 2 +- docs/examples/site/chapter/controller.wo | 2 +- docs/examples/site/chapter/view.wo | 2 +- docs/examples/site/content.wo | 16 ++--- docs/examples/site/favicon/controller.wo | 2 +- docs/examples/site/health/controller.wo | 2 +- docs/examples/site/home/controller.wo | 2 +- docs/examples/site/home/view.wo | 4 +- docs/examples/site/install/controller.wo | 2 +- docs/examples/site/install/view.wo | 57 ++++++++++++--- docs/examples/site/layout/app.wo | 8 +-- docs/examples/site/layout/footer.wo | 2 +- docs/examples/site/layout/header.wo | 2 +- docs/examples/site/main.wo | 21 ++++-- docs/examples/site/packages/controller.wo | 19 ++--- docs/examples/site/packages/view.wo | 2 +- docs/examples/site/wo.toml | 8 +-- docs/examples/web-app/README.md | 2 +- docs/examples/web-app/main.wo | 8 +-- docs/examples/web-app/wo.toml | 6 +- .../README.md | 26 ++++++- .../app.wo | 0 .../http/auth.wo | 0 docs/examples/writeonce-serve/http/files.wo | 72 +++++++++++++++++++ .../http/form.wo | 0 .../http/multipart.wo | 0 .../http/nego.wo | 0 .../http/secure.wo | 0 .../http/types.wo | 2 +- .../http/ws.wo | 0 .../http/wsframe.wo | 0 .../internal/parse.wo | 0 .../internal/serve.wo | 0 .../router/router.wo | 0 .../wo.toml | 4 +- .../{wo-html => writeonce-view}/README.md | 9 ++- .../{wo-html => writeonce-view}/html.wo | 2 +- .../{wo-html => writeonce-view}/wo.toml | 4 +- docs/plan/discarded.md | 2 +- docs/plan/oop-vm/08-builtin-surface.md | 2 +- docs/stories/00-status.md | 2 +- .../hold/18-memory-db-features.md | 2 +- justfile | 4 +- scripts/site-accept.sh | 39 ++++++++-- scripts/web-app-accept.sh | 10 +-- tests/corpus/run/raw-text-literal/fixture.wo | 2 +- 62 files changed, 310 insertions(+), 158 deletions(-) delete mode 100644 docs/examples/shop/static_files/controller.wo rename docs/examples/{writeonce-framework => writeonce-serve}/README.md (90%) rename docs/examples/{writeonce-framework => writeonce-serve}/app.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/auth.wo (100%) create mode 100644 docs/examples/writeonce-serve/http/files.wo rename docs/examples/{writeonce-framework => writeonce-serve}/http/form.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/multipart.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/nego.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/secure.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/types.wo (98%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/ws.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/http/wsframe.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/internal/parse.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/internal/serve.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/router/router.wo (100%) rename docs/examples/{writeonce-framework => writeonce-serve}/wo.toml (80%) rename docs/examples/{wo-html => writeonce-view}/README.md (91%) rename docs/examples/{wo-html => writeonce-view}/html.wo (99%) rename docs/examples/{wo-html => writeonce-view}/wo.toml (74%) diff --git a/README.md b/README.md index 0878464..65e5573 100644 --- a/README.md +++ b/README.md @@ -269,7 +269,7 @@ dependencies, declared in the manifest: ```toml [deps] -niceframework = { git = "https://github.com/shoneyj/niceframework", rev = "v0.1.0" } +niceserve = { git = "https://github.com/shoneyj/niceframework", rev = "v0.1.0" } ``` `woc` fetches each dep (via the `git` binary) into `.wo-deps//`, pins @@ -303,7 +303,7 @@ acceptance tests: just employee # compile + run every mode against a durable database ``` -- **`docs/examples/writeonce-framework/` + `docs/examples/web-app/`** — a web +- **`docs/examples/writeonce-serve/` + `docs/examples/web-app/`** — a web framework written in writeonce (HTTP/1.1 behind a TLS-terminating proxy, router with `:param` captures, interface-based handlers) and a storefront consuming it **as a `[deps]` dependency**, with `@table` persistence. Run: diff --git a/compiler/src/CODE-LOGIC.md b/compiler/src/CODE-LOGIC.md index 238780e..b76bb12 100644 --- a/compiler/src/CODE-LOGIC.md +++ b/compiler/src/CODE-LOGIC.md @@ -332,7 +332,7 @@ Things worth knowing before editing them: - **`{{ e }}` desugars to `esc(${e})`, resolved by ordinary name lookup.** `desugar_interp` in `parser.ml` builds a `Call` on an `Ident "esc"` — precisely what a developer wrote by hand before. The - compiler learns nothing about HTML, `esc` stays wo-html's ordinary + compiler learns nothing about HTML, `esc` stays writeonce-view's ordinary `pub fn`, a typo'd field inside the hole is a normal name/type error, and a locally defined `esc` shadows deliberately (a custom escaper is a feature). `${ }` inside the same literal stays raw — that is the diff --git a/docs/00-code-review.md b/docs/00-code-review.md index 8123503..5e672f2 100644 --- a/docs/00-code-review.md +++ b/docs/00-code-review.md @@ -79,7 +79,7 @@ the number or produce the benchmark. | 22's battery never run | 22 is ⬜ "needs a spec first"; no `bench/baseline.json`, no `just db-bench`; `runtime/bench/` is the retired C prototype's harness | | TSan covers one demo | only `scripts/fibers-accept.sh` builds and runs `wovm_tsan` | | no fuzzing, no CI | no `.github/`, no fuzz target | -| one framework, five samples, one consumer | exact: `writeonce-framework`; employee, employee-list, fibers, gc-cycle, log-watcher; `web-app` | +| one framework, five samples, one consumer | exact: `writeonce-serve`; employee, employee-list, fibers, gc-cycle, log-watcher; `web-app` | ### Consequence diff --git a/docs/examples/shop/README.md b/docs/examples/shop/README.md index 0592262..e3bd455 100644 --- a/docs/examples/shop/README.md +++ b/docs/examples/shop/README.md @@ -38,19 +38,19 @@ fn render() -> Text { } ``` -Every `render()` makes its class a **component** — wo-html's structural +Every `render()` makes its class a **component** — writeonce-view's structural `Component` interface, satisfied by having the method, never declared. Parent components hold children directly (`cards: multi Component`) and render them with `render_all`, so `ProductListPage` knows nothing about `ProductCard` beyond `render()`. The document itself is a component too: `AppShell { title, content }` in `layout/app.wo`, which links a real stylesheet rather than inlining one — that is why it is its own shell and -not wo-html's `Layout`. +not writeonce-view's `Layout`. Two holes, and the difference is the whole escaping story: - `{{ expr }}` **HTML-escapes** — it compiles to a call to the `esc` in - scope (wo-html's, unless the app declares its own). Display data goes + scope (writeonce-view's, unless the app declares its own). Display data goes here; a typo'd field is a compile error, not a broken page. - `${ expr }` is **raw** — for markup you built yourself, like the `${stock}` fragment above or `${content}` in the app shell. @@ -70,7 +70,7 @@ up, or sandbox. | `product_list/view.wo` | VIEW — classes with `fn render() -> Text`, fields = exactly what is displayed | `product-list/view.html` | | `product_list/controller.wo` | CONTROLLER — query the model, fill the view, answer a `Resp`; beside its view in the same module | component `.ts` + service | | `product_page/`, `orders/` | one module per feature: `view.wo` + `controller.wo` | feature folders | -| `static_files/controller.wo` | `/assets/*` from disk, traversal-safe, typed | `angular.json` assets | +| `/assets/*` | served by the framework's `StaticFiles` — the template no longer carries its own copy | `angular.json` assets | | `assets/style.css` | ONE real stylesheet, sectioned per feature | the `.scss` files | | the `render()` bodies | ONE raw text literal each: real newlines, real double-quoted attributes, source indentation removed at compile time, `${}` raw holes and `{{ }}` auto-escaping ones | Vue `