sx-pub Phase 1: DB schema, IPFS wiring, actor + webfinger + collections + status endpoints
Foundation for the sx-pub federated publishing protocol: - 6 SQLAlchemy models: actor, collections, documents, activities, followers, following - Conditional DB enablement in sx_docs (DATABASE_URL present → enable DB) - Python IO helpers: get_or_create_actor (auto-generates RSA keypair), list_collections, check_status, seed_default_collections - 4 defhandler endpoints returning text/sx (no JSON): /pub/actor, /pub/webfinger, /pub/collections, /pub/status - Alembic migration infrastructure for sx service - Docker compose: DB + pgbouncer + IPFS + env vars Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
98
sx/sx/handlers/pub-api.sx
Normal file
98
sx/sx/handlers/pub-api.sx
Normal file
@@ -0,0 +1,98 @@
|
||||
;; ==========================================================================
|
||||
;; sx-pub Phase 1 API endpoints — actor, webfinger, collections, status
|
||||
;;
|
||||
;; All responses are text/sx. No JSON.
|
||||
;; ==========================================================================
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; Actor
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(defhandler pub-actor
|
||||
:path "/pub/actor"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((actor (helper "pub-actor-data")))
|
||||
(do
|
||||
(set-response-header "Content-Type" "text/sx; charset=utf-8")
|
||||
(str
|
||||
"(SxActor"
|
||||
"\n :id \"https://" (get actor "domain") "/pub/actor\""
|
||||
"\n :type \"SxPublisher\""
|
||||
"\n :name \"" (get actor "display-name") "\""
|
||||
"\n :summary \"" (get actor "summary") "\""
|
||||
"\n :inbox \"/pub/inbox\""
|
||||
"\n :outbox \"/pub/outbox\""
|
||||
"\n :followers \"/pub/followers\""
|
||||
"\n :following \"/pub/following\""
|
||||
"\n :public-key-pem \"" (get actor "public-key-pem") "\")"))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; Webfinger
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(defhandler pub-webfinger
|
||||
:path "/pub/webfinger"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((resource (helper "request-arg" "resource" ""))
|
||||
(actor (helper "pub-actor-data")))
|
||||
(let ((expected (str "acct:" (get actor "preferred-username") "@" (get actor "domain"))))
|
||||
(if (!= resource expected)
|
||||
(do
|
||||
(set-response-status 404)
|
||||
(str "(Error :message \"Resource not found\")"))
|
||||
(do
|
||||
(set-response-header "Content-Type" "text/sx; charset=utf-8")
|
||||
(str
|
||||
"(SxWebfinger"
|
||||
"\n :subject \"" expected "\""
|
||||
"\n :actor \"https://" (get actor "domain") "/pub/actor\""
|
||||
"\n :type \"SxPublisher\")"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; Collections
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(defhandler pub-collections
|
||||
:path "/pub/collections"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((collections (helper "pub-collections-data")))
|
||||
(do
|
||||
(set-response-header "Content-Type" "text/sx; charset=utf-8")
|
||||
(let ((items (map (fn (c)
|
||||
(str "\n (SxCollection"
|
||||
" :slug \"" (get c "slug") "\""
|
||||
" :name \"" (get c "name") "\""
|
||||
" :description \"" (get c "description") "\""
|
||||
" :href \"/pub/" (get c "slug") "\")"))
|
||||
collections)))
|
||||
(str "(SxCollections" (join "" items) ")")))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; Status
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(defhandler pub-status
|
||||
:path "/pub/status"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((status (helper "pub-status-data")))
|
||||
(do
|
||||
(set-response-header "Content-Type" "text/sx; charset=utf-8")
|
||||
(str
|
||||
"(SxPubStatus"
|
||||
"\n :healthy " (get status "healthy")
|
||||
"\n :db \"" (get status "db") "\""
|
||||
"\n :ipfs \"" (get status "ipfs") "\""
|
||||
"\n :actor \"" (get status "actor") "\""
|
||||
"\n :domain \"" (or (get status "domain") "unknown") "\")"))))
|
||||
Reference in New Issue
Block a user