Build tooling: updated OCaml bootstrapper, compile-modules, bundle.sh, sx-build-all. WASM browser: rebuilt sx_browser.bc.js/wasm, sx-platform-2.js, .sxbc bytecode files. CSSX/Tailwind: reworked cssx.sx templates and tw-layout, added tw-type support. Content: refreshed essays, plans, geography, reactive islands, docs, demos, handlers. New tools: bisect_sxbc.sh, test-spa.js, render-trace.sx, morph playwright spec. Tests: added test-match.sx, test-examples.sx, updated test-tw.sx and web tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
299 lines
11 KiB
Plaintext
299 lines
11 KiB
Plaintext
;; Reference API endpoints — live demos for hypermedia attribute docs
|
|
;;
|
|
;; These replace the Python endpoints in bp/pages/routes.py.
|
|
;; Each defhandler with :path registers as a public route automatically.
|
|
|
|
;; --- sx-get demo: server time ---
|
|
|
|
(defhandler ref-time
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.time))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((now (helper "now" "%H:%M:%S")))
|
|
(<>
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Server time: " (strong now))
|
|
(~docs/oob-code :target-id "ref-wire-sx-get"
|
|
:text (str "(span :class \"text-stone-800 text-sm\" \"Server time: \" (strong \"" now "\"))")))))
|
|
|
|
;; --- sx-post demo: greet ---
|
|
|
|
(defhandler ref-greet
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.greet))))"
|
|
:method :post
|
|
:csrf false
|
|
:returns "element"
|
|
(&key)
|
|
(let ((name (helper "request-form" "name" "stranger")))
|
|
(<>
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Hello, " (strong name) "!")
|
|
(~docs/oob-code :target-id "ref-wire-sx-post"
|
|
:text (str "(span :class \"text-stone-800 text-sm\" \"Hello, \" (strong \"" name "\") \"!\")")))))
|
|
|
|
;; --- sx-put demo: status update ---
|
|
|
|
(defhandler ref-status
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.status))))"
|
|
:method :put
|
|
:csrf false
|
|
:returns "element"
|
|
(&key)
|
|
(let ((status (helper "request-form" "status" "unknown")))
|
|
(<>
|
|
(span (~tw :tokens "text-stone-700 text-sm") "Status: " (strong status) " — updated via PUT")
|
|
(~docs/oob-code :target-id "ref-wire-sx-put"
|
|
:text (str "(span :class \"text-stone-700 text-sm\" \"Status: \" (strong \"" status "\") \" — updated via PUT\")")))))
|
|
|
|
;; --- sx-patch demo: theme ---
|
|
|
|
(defhandler ref-theme
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.theme))))"
|
|
:method :patch
|
|
:csrf false
|
|
:returns "element"
|
|
(&key)
|
|
(let ((theme (helper "request-form" "theme" "unknown")))
|
|
(<>
|
|
theme
|
|
(~docs/oob-code :target-id "ref-wire-sx-patch"
|
|
:text (str "\"" theme "\"")))))
|
|
|
|
;; --- sx-delete demo ---
|
|
|
|
(defhandler ref-delete-item
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.(item.<sx:item_id>)))))"
|
|
:method :delete
|
|
:csrf false
|
|
:returns "element"
|
|
(&key)
|
|
(<>
|
|
(~docs/oob-code :target-id "ref-wire-sx-delete" :text "\"\"")))
|
|
|
|
;; --- sx-trigger demo: search ---
|
|
|
|
(defhandler ref-trigger-search
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.trigger-search))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((q (helper "request-arg" "q" "")))
|
|
(let ((sx-text (if (= q "")
|
|
"(span :class \"text-stone-400 text-sm\" \"Start typing to trigger a search.\")"
|
|
(str "(span :class \"text-stone-800 text-sm\" \"Results for: \" (strong \"" q "\"))"))))
|
|
(<>
|
|
(if (= q "")
|
|
(span (~tw :tokens "text-stone-400 text-sm") "Start typing to trigger a search.")
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Results for: " (strong q)))
|
|
(~docs/oob-code :target-id "ref-wire-sx-trigger" :text sx-text)))))
|
|
|
|
;; --- sx-swap demo ---
|
|
|
|
(defhandler ref-swap-item
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.swap-item))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((now (helper "now" "%H:%M:%S")))
|
|
(<>
|
|
(div (~tw :tokens "text-sm text-violet-700") (str "New item (" now ")"))
|
|
(~docs/oob-code :target-id "ref-wire-sx-swap"
|
|
:text (str "(div :class \"text-sm text-violet-700\" \"New item (" now ")\")")))))
|
|
|
|
;; --- sx-swap-oob demo ---
|
|
|
|
(defhandler ref-oob
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.oob))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((now (helper "now" "%H:%M:%S")))
|
|
(<>
|
|
(span (~tw :tokens "text-emerald-700 text-sm") "Main updated at " now)
|
|
(div :id "ref-oob-side" :sx-swap-oob "innerHTML"
|
|
(span (~tw :tokens "text-violet-700 text-sm") "OOB updated at " now))
|
|
(~docs/oob-code :target-id "ref-wire-sx-swap-oob"
|
|
:text (str "(<> (span ... \"" now "\") (div :id \"ref-oob-side\" :sx-swap-oob \"innerHTML\" ...))")))))
|
|
|
|
;; --- sx-select demo ---
|
|
|
|
(defhandler ref-select-page
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.select-page))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((now (helper "now" "%H:%M:%S")))
|
|
(<>
|
|
(div :id "the-header" (h3 "Page header — not selected"))
|
|
(div :id "the-content"
|
|
(span (~tw :tokens "text-emerald-700 text-sm")
|
|
"This fragment was selected from a larger response. Time: " now))
|
|
(div :id "the-footer" (p "Page footer — not selected"))
|
|
(~docs/oob-code :target-id "ref-wire-sx-select"
|
|
:text (str "(<> (div :id \"the-header\" ...) (div :id \"the-content\" ... \"" now "\") (div :id \"the-footer\" ...))")))))
|
|
|
|
;; --- sx-sync demo: slow echo ---
|
|
|
|
(defhandler ref-slow-echo
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.slow-echo))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((q (helper "request-arg" "q" "")))
|
|
(sleep 800)
|
|
(<>
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Echo: " (strong q))
|
|
(~docs/oob-code :target-id "ref-wire-sx-sync"
|
|
:text (str "(span :class \"text-stone-800 text-sm\" \"Echo: \" (strong \"" q "\"))")))))
|
|
|
|
;; --- sx-prompt demo ---
|
|
|
|
(defhandler ref-prompt-echo
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.prompt-echo))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((name (helper "request-header" "SX-Prompt" "anonymous")))
|
|
(<>
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Hello, " (strong name) "!")
|
|
(~docs/oob-code :target-id "ref-wire-sx-prompt"
|
|
:text (str "(span :class \"text-stone-800 text-sm\" \"Hello, \" (strong \"" name "\") \"!\")")))))
|
|
|
|
;; --- Error demo ---
|
|
|
|
(defhandler ref-error-500
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.error-500))))"
|
|
:method :get
|
|
:returns "nil"
|
|
(&key)
|
|
(abort 500 "Server error"))
|
|
|
|
|
|
;; ==========================================================================
|
|
;; Remaining reference endpoints — migrated from Python
|
|
;; ==========================================================================
|
|
|
|
;; --- sx-encoding demo: file upload name ---
|
|
|
|
(defhandler ref-upload-name
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.upload-name))))"
|
|
:method :post
|
|
:csrf false
|
|
:returns "element"
|
|
(&key)
|
|
(let ((name (helper "request-file-name" "file")))
|
|
(let ((display (if (nil? name) "(no file)" name)))
|
|
(let ((sx-text (str "(span :class \"text-stone-800 text-sm\" \"Received: \" (strong \"" display "\"))")))
|
|
(<>
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Received: " (strong display))
|
|
(~docs/oob-code :target-id "ref-wire-sx-encoding" :text sx-text))))))
|
|
|
|
;; --- sx-headers demo: echo custom headers ---
|
|
|
|
(defhandler ref-echo-headers
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.echo-headers))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((all-headers (into (list) (helper "request-headers-all"))))
|
|
(let ((custom (filter
|
|
(fn (pair) (starts-with? (first pair) "x-"))
|
|
all-headers)))
|
|
(let ((sx-text
|
|
(if (empty? custom)
|
|
"(span :class \"text-stone-400 text-sm\" \"No custom headers received.\")"
|
|
(str "(ul :class \"text-sm text-stone-700 space-y-1\" "
|
|
(join " " (map (fn (pair) (str "(li (strong \"" (first pair) "\") \": \" \"" (nth pair 1) "\")")) custom))
|
|
")"))))
|
|
(<>
|
|
(if (empty? custom)
|
|
(span (~tw :tokens "text-stone-400 text-sm") "No custom headers received.")
|
|
(ul (~tw :tokens "text-sm text-stone-700 space-y-1")
|
|
(map (fn (pair) (li (strong (first pair)) ": " (nth pair 1))) custom)))
|
|
(~docs/oob-code :target-id "ref-wire-sx-headers" :text sx-text))))))
|
|
|
|
;; --- sx-include demo: echo GET query params ---
|
|
|
|
(defhandler ref-echo-vals-get
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.echo-vals))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((vals (into (list) (helper "request-args-all"))))
|
|
(let ((sx-text
|
|
(if (empty? vals)
|
|
"(span :class \"text-stone-400 text-sm\" \"No values received.\")"
|
|
(str "(ul :class \"text-sm text-stone-700 space-y-1\" "
|
|
(join " " (map (fn (pair) (str "(li (strong \"" (first pair) "\") \": \" \"" (nth pair 1) "\")")) vals))
|
|
")"))))
|
|
(<>
|
|
(if (empty? vals)
|
|
(span (~tw :tokens "text-stone-400 text-sm") "No values received.")
|
|
(ul (~tw :tokens "text-sm text-stone-700 space-y-1")
|
|
(map (fn (pair) (li (strong (first pair)) ": " (nth pair 1))) vals)))
|
|
(~docs/oob-code :target-id "ref-wire-sx-include" :text sx-text)))))
|
|
|
|
;; --- sx-vals demo: echo POST form values ---
|
|
|
|
(defhandler ref-echo-vals-post
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.echo-vals))))"
|
|
:method :post
|
|
:csrf false
|
|
:returns "element"
|
|
(&key)
|
|
(let ((vals (into (list) (helper "request-form-all"))))
|
|
(let ((sx-text
|
|
(if (empty? vals)
|
|
"(span :class \"text-stone-400 text-sm\" \"No values received.\")"
|
|
(str "(ul :class \"text-sm text-stone-700 space-y-1\" "
|
|
(join " " (map (fn (pair) (str "(li (strong \"" (first pair) "\") \": \" \"" (nth pair 1) "\")")) vals))
|
|
")"))))
|
|
(<>
|
|
(if (empty? vals)
|
|
(span (~tw :tokens "text-stone-400 text-sm") "No values received.")
|
|
(ul (~tw :tokens "text-sm text-stone-700 space-y-1")
|
|
(map (fn (pair) (li (strong (first pair)) ": " (nth pair 1))) vals)))
|
|
(~docs/oob-code :target-id "ref-wire-sx-vals" :text sx-text)))))
|
|
|
|
;; --- sx-retry demo: flaky endpoint (fails 2/3 times) ---
|
|
|
|
(defhandler ref-flaky
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.flaky))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((prev (helper "state-get" "ref-flaky-n" 0)))
|
|
(let ((n (+ prev 1)))
|
|
(helper "state-set!" "ref-flaky-n" n)
|
|
(if (not (= (mod n 3) 0))
|
|
(do
|
|
(set-response-status 503)
|
|
"")
|
|
(let ((sx-text (str "(span :class \"text-emerald-700 text-sm\" \"Success on attempt \" \"" n "\" \"!\")")))
|
|
(<>
|
|
(span (~tw :tokens "text-emerald-700 text-sm") "Success on attempt " (str n) "!")
|
|
(~docs/oob-code :target-id "ref-wire-sx-retry" :text sx-text)))))))
|
|
|
|
;; --- sx-trigger-event demo: response header triggers ---
|
|
|
|
(defhandler ref-trigger-event
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.trigger-event))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((now (helper "now" "%H:%M:%S")))
|
|
(set-response-header "SX-Trigger" "showNotice")
|
|
(<>
|
|
(span (~tw :tokens "text-stone-800 text-sm") "Loaded at " (strong now) " — check the border!"))))
|
|
|
|
;; --- sx-retarget demo: response header retargets ---
|
|
|
|
(defhandler ref-retarget
|
|
:path "/sx/(geography.(hypermedia.(reference.(api.retarget))))"
|
|
:method :get
|
|
:returns "element"
|
|
(&key)
|
|
(let ((now (helper "now" "%H:%M:%S")))
|
|
(set-response-header "SX-Retarget" "#ref-hdr-retarget-alt")
|
|
(<>
|
|
(span (~tw :tokens "text-violet-700 text-sm") "Retargeted at " (strong now)))))
|