host: SX-native wire — reads + write bodies are text/sx, JSON CRUD deleted
Greenfield SX-native pivot (NOT a strangler): the host speaks SX/SXTP end to end;
JSON only at the future ActivityPub federation edge.
- OUTPUT: host/json-status -> host/sx-status — every host/ok/host/error response is
text/sx via the serialize primitive (NOT application/json). Flips feed, relations,
blog reads. Tests assert the SX envelope ({:ok true :data ...}).
- DELETE the blog JSON CRUD /posts (POST/PUT/DELETE) + bearer-based host/blog--protect:
a pure old-contract REST mirror. Create/edit go through the HTML editor forms;
programmatic writes speak SXTP. FOLLOW-UP: no browser delete route yet (was JSON-only,
no UI) — add POST /:slug/delete + cascade edge cleanup when the metamodel UI needs it.
- INPUT: host/sx-body (sxtp.sx) parses a text/sx request body to a string-keyed dict
(parse-safe + sxtp/-normalize). feed POST + relations attach/detach read it.
- UNIFIED field reader host/fields / host/field: text/sx body OR urlencoded form by
content-type. The blog form handlers (new/edit/relate/unrelate) + login read through
it — additive, urlencoded still works (no-engine / bootstrap fallback).
Conformance 290/290 (11 suites). Retires the strangler framing in the plan; adds the
'SX all the way out' wire table. The engine half (browser posts text/sx) follows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -171,3 +171,30 @@
|
||||
(fn (text)
|
||||
(let ((lst (parse text)))
|
||||
(sxtp/-pairs->dict (rest lst) {:msg (symbol->string (first lst))}))))
|
||||
|
||||
;; ── host write-body: a request's text/sx body -> string-keyed dict ──
|
||||
;; The write-side counterpart to host/sx-status: the SX engine posts text/sx for
|
||||
;; writes (boosted forms serialise their fields), so write handlers read the body
|
||||
;; through this instead of dream-json-body. parse-safe yields keyword-token keys;
|
||||
;; sxtp/-normalize deep-converts them to strings so (get p :field) works — the same
|
||||
;; shape dream-json-body produced from JSON. Empty / blank / non-dict / unparseable
|
||||
;; body -> nil (handlers then return 400).
|
||||
(define host/sx-body
|
||||
(fn (req)
|
||||
(let ((raw (dream-body req)))
|
||||
(if (or (nil? raw) (= raw ""))
|
||||
nil
|
||||
(let ((v (parse-safe raw)))
|
||||
(if (= (type-of v) "dict") (sxtp/-normalize v) nil))))))
|
||||
|
||||
;; ── unified write-field reader: text/sx body OR urlencoded form ─────
|
||||
;; A boosted form posts text/sx (the SX engine serialises its fields); a no-engine
|
||||
;; / pre-hydration submit (and the login bootstrap) posts urlencoded. Content-type
|
||||
;; decides. host/fields returns ALL fields as one string-keyed dict; host/field
|
||||
;; reads one by name. Form handlers read through these so both encodings work.
|
||||
(define host/fields
|
||||
(fn (req)
|
||||
(if (contains? (or (dream-content-type-of req) "") "text/sx")
|
||||
(or (host/sx-body req) {})
|
||||
(or (dream-form-fields req) {}))))
|
||||
(define host/field (fn (req name) (get (host/fields req) name)))
|
||||
|
||||
Reference in New Issue
Block a user