Simplify render pipeline, sandbox context, and db helpers; fix route
precedence so the most recently saved route wins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app.all("*") dispatcher hand-rolled a SELECT * FROM routes while
every other read goes through the model layer. Use model.getRoute for
consistency; the handler only reads structure_id/id/verb/handler, all
of which it returns.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `e.stack ? \`${e}\n\n${e.stack}\` : \`${e}\`` + createLog(...true)
pattern appeared in four catch blocks. Extract formatError(e) and
logError(structureId, routeId, e) and call them instead. Behavior and
the 500 response body are unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateRoute/updateDb/updateStruct/updateTemplate/updateScaffoldPage
were the same UPDATE-by-id builder with a different table and field
list. Extract a single update(table, fields, obj) and express each as
a one-liner. (updateScaffoldPage's two stray debug console.logs went
away with the rewrite; it keeps its changes>0 return.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove the shared-mutable-state dance where each db library was run in
the handler context via `context.sql = x; run; module.exports = null`.
Split into three single-purpose functions:
- makeConsole(structureId, routeId) — the logs-table-backed console
- runLibrary(sql, source, console) — eval one library in its own context
- makeLibs(structureId, console) — the require() targets map
Libraries are still evaluated eagerly per request (no laziness), and
still see `sql` and `console`, so behavior is preserved. Verified the
prime db library's top-level console.log still fires on a live request.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The matcher loop kept the last match instead of the first. Since
routes[verb] is ordered by updated_at DESC, that meant the OLDEST
route won when two routes matched the same path. Break on first
match so the most recently saved route wins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the one branchy bootstrapTemplateWithHTMXetc (six positional
args, five jobs) with small pure functions: headChrome, blissAttrs,
decoratePage, decorateFragment, and a decorate() entry point. The
route/clone/copy provenance triple becomes a single `source` value
({structureId, routeId, copyUrl}) threaded through render — the same
data the inspector roadmap needs.
Collapse the four copy-pasted render sites (res.render, ws.render,
template preview, scaffold preview) onto renderTemplate + decorate,
and dedupe the per-structure route() closure into makeRoute().
Emitted HTML (head chrome + data-bliss-* attributes) is unchanged;
verified full-page and htmx-fragment output.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>