diff --git a/sx/sx/plans.sx b/sx/sx/plans.sx index 0656062..2a1b892 100644 --- a/sx/sx/plans.sx +++ b/sx/sx/plans.sx @@ -1575,7 +1575,9 @@ (li (strong "Boundary enforcement: ") "boundary.sx + SX_BOUNDARY_STRICT=1 validates all primitives/IO/helpers at registration.") (li (strong "Dependency analysis: ") "deps.sx computes per-page component bundles — only definitions a page actually uses are sent.") (li (strong "IO detection: ") "deps.sx classifies every component as pure or IO-dependent. Server expands IO components, serializes pure ones for client.") - (li (strong "Client-side routing: ") "router.sx matches URL patterns. Pure pages render instantly without server roundtrips. Pages with :data fall through to server transparently."))) + (li (strong "Client-side routing: ") "router.sx matches URL patterns. Pure pages render instantly without server roundtrips. Pages with :data fall through to server transparently.") + (li (strong "Client IO proxy: ") "IO primitives registered on the client call back to the server via fetch. Components with IO deps can render client-side.") + (li (strong "Streaming/suspense: ") "defpage :stream true enables chunked HTML. ~suspense placeholders show loading skeletons; __sxResolve() fills in content as IO completes."))) ;; ----------------------------------------------------------------------- ;; Phase 1 @@ -1882,8 +1884,11 @@ (~doc-section :title "Phase 6: Streaming & Suspense" :id "phase-6" - (div :class "rounded border border-green-200 bg-green-50 p-4 mb-4" - (p :class "text-green-900 font-medium" "Status: Implemented") + (div :class "rounded border border-green-300 bg-green-50 p-4 mb-4" + (div :class "flex items-center gap-2 mb-2" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (a :href "/isomorphism/streaming" :class "text-green-700 underline text-sm font-medium" "Live streaming demo")) + (p :class "text-green-900 font-medium" "What it enables") (p :class "text-green-800" "Server streams partially-evaluated SX as IO resolves. Client renders available subtrees immediately with loading skeletons, fills in suspended parts as data arrives.")) (~doc-subsection :title "What was built" @@ -1934,16 +1939,31 @@ (li "shared/sx/evaluator.py — defpage :stream/:fallback parsing") (li "shared/sx/pages.py — execute_page_streaming(), streaming route mounting") (li "shared/sx/helpers.py — sx_page_streaming_parts(), sx_streaming_resolve_script()") - (li "shared/static/scripts/sx.js — Sx.resolveSuspense(), __sxPending queue, __sxResolve bootstrap") - (li "shared/sx/async_eval.py — reset/shift special forms (continuation foundation)"))) + (li "shared/sx/ref/boot.sx — resolve-suspense spec (canonical)") + (li "shared/sx/ref/bootstrap_js.py — resolveSuspense on Sx object, __sxPending/Resolve init") + (li "shared/static/scripts/sx-browser.js — bootstrapped output (DO NOT EDIT)") + (li "shared/sx/async_eval.py — reset/shift special forms (continuation foundation)") + (li "sx/sx/streaming-demo.sx — demo content component") + (li "sx/sxc/pages/docs.sx — streaming-demo defpage") + (li "sx/sxc/pages/helpers.py — streaming-demo-data page helper"))) - (~doc-subsection :title "Verification" + (~doc-subsection :title "Demonstration" + (p "The " (a :href "/isomorphism/streaming" :class "text-violet-700 underline" "streaming demo page") " exercises the full pipeline:") + (ol :class "list-decimal pl-5 text-stone-700 space-y-1" + (li "Navigate to " (a :href "/isomorphism/streaming" :class "text-violet-700 underline" "/isomorphism/streaming")) + (li "The page skeleton appears " (strong "instantly") " — animated loading skeletons fill the content area") + (li "After ~1.5 seconds, the real content replaces the skeletons (streamed from server)") + (li "Open the Network tab — observe " (code "Transfer-Encoding: chunked") " on the document response") + (li "The document response shows multiple chunks arriving over time: shell first, then resolution scripts"))) + + (~doc-subsection :title "What to verify" (ul :class "list-disc pl-5 text-stone-700 space-y-1" - (li "Navigate to " (a :href "/isomorphism/streaming" "/isomorphism/streaming") " — the streaming demo page") - (li "The page skeleton appears instantly (loading skeletons)") - (li "After ~1.5 seconds, the content fills in (streamed from server)") - (li "Open Network tab — observe chunked transfer encoding on the document response") - (li "The document response should show multiple chunks arriving over time")))) + (li (strong "Instant shell: ") "The page HTML arrives immediately — no waiting for the 1.5s data fetch") + (li (strong "Suspense placeholders: ") "The " (code "~suspense") " component renders a " (code "data-suspense") " wrapper with animated fallback content") + (li (strong "Resolution: ") "The " (code "__sxResolve()") " inline script replaces the placeholder with real rendered content") + (li (strong "Chunked encoding: ") "Network tab shows the document as a chunked response with multiple frames") + (li (strong "Concurrent IO: ") "Header and content resolve independently — whichever finishes first appears first") + (li (strong "HTMX fallback: ") "SX/HTMX requests bypass streaming and receive a standard response")))) ;; ----------------------------------------------------------------------- ;; Phase 7