;; lib/host/feed.sx — Feed domain endpoints on the host. The first domain migrated ;; onto the SX host: read the activity timeline (GET /feed) and create activities ;; (POST /feed). Both go straight through the feed subsystem's public API; the ;; write path runs behind the host middleware stack (auth + ACL). Depends on ;; lib/feed/* + lib/host/handler.sx + lib/host/middleware.sx (write routes only). ;; ── read ─────────────────────────────────────────────────────────── ;; GET /feed -> recent-first activities as a JSON envelope. ;; Query: ?actor= (filter) ?limit= (cap, applied after filtering). (define host/feed-timeline (fn (req) (let ((base (feed/recent (feed/all))) (actor (dream-query-param req "actor"))) (let ((filtered (if actor (feed/by-actor base actor) base)) (limit (dream-query-param req "limit"))) (let ((capped (if limit (feed/take filtered (string->number limit)) filtered))) (host/ok (feed/items capped))))))) ;; Public read route group. (define host/feed-routes (list (dream-get "/feed" host/feed-timeline))) ;; ── write ────────────────────────────────────────────────────────── ;; POST /feed -> create an activity from the JSON body. Returns 201 + the created ;; (normalised) activity. Body must be a JSON object; anything else -> 400. (define host/feed-create (fn (req) (let ((raw (dream-json-body req))) (if (= (type-of raw) "dict") (host/ok-status 201 (feed/post raw)) (host/error 400 "invalid activity"))))) ;; Guarded write route group: POST /feed behind auth + ACL ("post" on "feed"). ;; resolve : token -> principal | nil (injected auth policy, e.g. token lookup ;; against the identity subsystem). Errors thrown downstream become a JSON 500. (define host/feed-write-routes (fn (resolve) (list (dream-post "/feed" (host/pipeline (list host/wrap-errors (host/require-auth resolve) (host/require-permission "post" (fn (req) "feed"))) host/feed-create)))))