doc to prefer literal html injection

This commit is contained in:
Your Name 2026-08-08 17:57:14 -04:00
parent 465cc74796
commit 684a89460f
2 changed files with 30 additions and 1 deletions

View file

@ -17,7 +17,29 @@ Requires a `.env` file with `VAPID_PUBLIC_KEY` and `VAPID_PRIVATE_KEY` for web p
Bliss is a browser-based low-code platform where users build mini web apps ("Structures") entirely through a `/workshop` UI. Each Structure has routes, templates, and SQLite databases — all stored in the main app database and executed at runtime via Node's `vm` module.
## Architecture
## Design philosophy: this is a hypermedia homestead
Bliss templates are not a web-app-with-an-API. There is no client-side framework,
no JSON contract, no build step — the HTML *is* the application, and it composes
by embedding more HTML (see "page-nesting primitive" below). Every template you
write or edit should lean into that instead of fighting it:
- **Prefer `<%~ %>` (raw) over `<%= %>` (HTML-escaped) in Eta templates, always,
unless you are interpolating into an HTML attribute value.** Attribute values
(`id="..."`, `data-*="..."`, `href="..."`, `style="..."`, `value="..."`) are
the one place escaping is not optional — an unescaped `"` there breaks the tag
itself, not just a security nicety. Everywhere else (text content, `<script>`
string literals, anything that isn't sitting inside `attr="…"`) use `<%~ %>`.
Arbitrary HTML/JS in user content is a *feature* here, not a bug to guard
against — see the `aim` structure's `message` template for the canonical
comment explaining why. When in doubt: default to raw, escape only when the
HTML would literally break otherwise.
- **Prefer htmx attributes over hand-rolled JS for anything hypermedia-shaped**
— polling (`hx-trigger="every 10s"`), lazy loading (`hx-trigger="load"`),
swapping (`hx-swap-oob`), cross-fragment events (`hx-trigger="foo from:body"`)
— instead of `setTimeout`/`fetch`/manual DOM patching. If htmx (or Hyperscript
for small imperative glue) can express it declaratively, don't write the
imperative version.
### Two layers of routes

View file

@ -41,6 +41,13 @@ own SQLite file). Ids are integers. Build a structure by: create it → add a db
write its library → add routes whose handlers call the library → add templates
the handlers render.
**Templates are hypermedia, not escaped-string templates.** Default to `<%~ %>`
(raw) over `<%= %>` (escaped) in Eta content — only use `<%= %>` inside an HTML
attribute value, where an unescaped `"` would break the tag. Reach for htmx
attributes (`hx-trigger="every 10s"`, `hx-swap-oob`, etc.) instead of JS
`setTimeout`/`fetch` polling loops. See CLAUDE.md's "hypermedia homestead"
section for the full rationale.
## Reads (JSON)
```bash