;; lib/host/static.sx — serve the client kernel + assets so the blog can boot the ;; SX-htmx hypermedia engine (web/engine.sx) and run as a SPA. The native ;; http-listen host reads files with the `file-read` primitive (no perform), so ;; GET /static/** maps to a file under the static root (default "shared/static", ;; resolved against the server cwd — mount ./shared/static there in the container). ;; Depends on lib/dream/types.sx (dream-response/-html-status/-param) + router. (define host/static-root "shared/static") (define host/static-use-root! (fn (r) (set! host/static-root r))) ;; content-type by file extension; default to octet-stream. (define host/static--ctype (fn (path) (cond ((ends-with? path ".js") "application/javascript; charset=utf-8") ((ends-with? path ".mjs") "application/javascript; charset=utf-8") ((ends-with? path ".css") "text/css; charset=utf-8") ((ends-with? path ".json") "application/json; charset=utf-8") ((ends-with? path ".map") "application/json; charset=utf-8") ((ends-with? path ".svg") "image/svg+xml") ((ends-with? path ".png") "image/png") ((ends-with? path ".woff2") "font/woff2") ((ends-with? path ".wasm") "application/wasm") (true "application/octet-stream")))) ;; reject empty, absolute, or traversal paths. (define host/static--safe? (fn (rel) (and (> (len rel) 0) (not (starts-with? rel "/")) (not (string-contains? rel ".."))))) ;; Serve one asset by its path relative to the static root. file-read THROWS on a ;; missing file, so gate on file-exists? first and return a 404 instead. (define host/static-serve (fn (rel) (if (not (host/static--safe? rel)) (dream-html-status 403 "Forbidden") (let ((path (str host/static-root "/" rel))) (if (not (file-exists? path)) (dream-html-status 404 "Not Found") (dream-response 200 {:content-type (host/static--ctype rel) :cache-control "public, max-age=3600"} (file-read path))))))) ;; Route group: GET /static/** -> file under the static root. A plain route LIST ;; (like host/feed-routes); host/serve combines + flattens the groups itself. (define host/static-routes (list (dream-get "/static/**" (fn (req) (host/static-serve (dream-param req "**"))))))