boundary.sx was mixing three concerns in one file:
- Core SX I/O primitives (the language contract)
- Deployment-specific layout I/O (app architecture)
- Per-service page helpers (fully app-specific)
Now split into three tiers:
1. shared/sx/ref/boundary.sx — core I/O only (frag, query, current-user, etc.)
2. shared/sx/ref/boundary-app.sx — deployment layout contexts (*-header-ctx, *-ctx)
3. {service}/sx/boundary.sx — per-service page helpers
The boundary parser loads all three tiers automatically. Validation error
messages now point to the correct file for each tier.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
198 lines
5.1 KiB
Plaintext
198 lines
5.1 KiB
Plaintext
;; ==========================================================================
|
|
;; boundary.sx — SX language boundary contract
|
|
;;
|
|
;; Declares the core I/O primitives that any SX host must provide.
|
|
;; This is the LANGUAGE contract — not deployment-specific.
|
|
;;
|
|
;; Pure primitives (Tier 1) are declared in primitives.sx.
|
|
;; Deployment-specific I/O (layout contexts) lives in boundary-app.sx.
|
|
;; Per-service page helpers live in {service}/sx/boundary.sx.
|
|
;;
|
|
;; Format:
|
|
;; (define-io-primitive "name"
|
|
;; :params (param1 param2 &key ...)
|
|
;; :returns "type"
|
|
;; :async true
|
|
;; :doc "description"
|
|
;; :context :request)
|
|
;;
|
|
;; ==========================================================================
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Tier 1: Pure primitives — declared in primitives.sx
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(declare-tier :pure :source "primitives.sx")
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Tier 2: Core I/O primitives — async, side-effectful, need host context
|
|
;; --------------------------------------------------------------------------
|
|
|
|
;; Cross-service communication
|
|
|
|
(define-io-primitive "frag"
|
|
:params (service frag-type &key)
|
|
:returns "string"
|
|
:async true
|
|
:doc "Fetch cross-service HTML fragment."
|
|
:context :request)
|
|
|
|
(define-io-primitive "query"
|
|
:params (service query-name &key)
|
|
:returns "any"
|
|
:async true
|
|
:doc "Fetch data from another service via internal HTTP."
|
|
:context :request)
|
|
|
|
(define-io-primitive "action"
|
|
:params (service action-name &key)
|
|
:returns "any"
|
|
:async true
|
|
:doc "Call an action on another service via internal HTTP."
|
|
:context :request)
|
|
|
|
(define-io-primitive "service"
|
|
:params (service-or-method &rest args &key)
|
|
:returns "any"
|
|
:async true
|
|
:doc "Call a domain service method. Two-arg: (service svc method). One-arg: (service method) uses bound handler service."
|
|
:context :request)
|
|
|
|
;; Request context
|
|
|
|
(define-io-primitive "current-user"
|
|
:params ()
|
|
:returns "dict?"
|
|
:async true
|
|
:doc "Current authenticated user dict, or nil."
|
|
:context :request)
|
|
|
|
(define-io-primitive "htmx-request?"
|
|
:params ()
|
|
:returns "boolean"
|
|
:async true
|
|
:doc "True if current request has HX-Request header."
|
|
:context :request)
|
|
|
|
(define-io-primitive "request-arg"
|
|
:params (name &rest default)
|
|
:returns "any"
|
|
:async true
|
|
:doc "Read a query string argument from the current request."
|
|
:context :request)
|
|
|
|
(define-io-primitive "request-path"
|
|
:params ()
|
|
:returns "string"
|
|
:async true
|
|
:doc "Current request path."
|
|
:context :request)
|
|
|
|
(define-io-primitive "request-view-args"
|
|
:params (key)
|
|
:returns "any"
|
|
:async true
|
|
:doc "Read a URL view argument from the current request."
|
|
:context :request)
|
|
|
|
(define-io-primitive "g"
|
|
:params (key)
|
|
:returns "any"
|
|
:async true
|
|
:doc "Read a value from the Quart request-local g object."
|
|
:context :request)
|
|
|
|
(define-io-primitive "csrf-token"
|
|
:params ()
|
|
:returns "string"
|
|
:async true
|
|
:doc "Current CSRF token string."
|
|
:context :request)
|
|
|
|
(define-io-primitive "abort"
|
|
:params (status &rest message)
|
|
:returns "nil"
|
|
:async true
|
|
:doc "Raise HTTP error from SX."
|
|
:context :request)
|
|
|
|
;; Routing
|
|
|
|
(define-io-primitive "url-for"
|
|
:params (endpoint &key)
|
|
:returns "string"
|
|
:async true
|
|
:doc "Generate URL for a named endpoint."
|
|
:context :request)
|
|
|
|
(define-io-primitive "route-prefix"
|
|
:params ()
|
|
:returns "string"
|
|
:async true
|
|
:doc "Service URL prefix for dev/prod routing."
|
|
:context :request)
|
|
|
|
;; Navigation and relations
|
|
|
|
(define-io-primitive "nav-tree"
|
|
:params ()
|
|
:returns "list"
|
|
:async true
|
|
:doc "Navigation tree as list of node dicts."
|
|
:context :request)
|
|
|
|
(define-io-primitive "get-children"
|
|
:params (&key parent-type parent-id)
|
|
:returns "list"
|
|
:async true
|
|
:doc "Fetch child entities for a parent."
|
|
:context :request)
|
|
|
|
;; Config and host context (sync — no await needed)
|
|
|
|
(define-io-primitive "app-url"
|
|
:params (service &rest path)
|
|
:returns "string"
|
|
:async false
|
|
:doc "Full URL for a service: (app-url \"blog\" \"/my-post/\")."
|
|
:context :config)
|
|
|
|
(define-io-primitive "asset-url"
|
|
:params (&rest path)
|
|
:returns "string"
|
|
:async false
|
|
:doc "Versioned static asset URL."
|
|
:context :config)
|
|
|
|
(define-io-primitive "config"
|
|
:params (key)
|
|
:returns "any"
|
|
:async false
|
|
:doc "Read a value from app-config.yaml."
|
|
:context :config)
|
|
|
|
(define-io-primitive "jinja-global"
|
|
:params (key &rest default)
|
|
:returns "any"
|
|
:async false
|
|
:doc "Read a Jinja environment global."
|
|
:context :request)
|
|
|
|
(define-io-primitive "relations-from"
|
|
:params (entity-type)
|
|
:returns "list"
|
|
:async false
|
|
:doc "List of RelationDef dicts for an entity type."
|
|
:context :config)
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Boundary types — what's allowed to cross the host-SX boundary
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(define-boundary-types
|
|
(list "number" "string" "boolean" "nil" "keyword"
|
|
"list" "dict" "sx-source" "style-value"))
|