Phase 7c+7d: cache invalidation + offline data layer
7c: Client data cache management via element attributes (sx-cache-invalidate) and response headers (SX-Cache-Invalidate, SX-Cache-Update). Programmatic API: invalidate-page-cache, invalidate-all-page-cache, update-page-cache. 7d: Service Worker (sx-sw.js) with IndexedDB for offline-capable data caching. Network-first for /sx/data/ and /sx/io/, stale-while- revalidate for /static/. Cache invalidation propagates from in-memory cache to SW via postMessage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1974,7 +1974,7 @@
|
||||
(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"))
|
||||
(p :class "text-green-900 font-medium" "What it enables")
|
||||
(p :class "text-green-800" "Same SX code runs on either side. Runtime chooses optimal split via affinity annotations and render plans. Cross-host isomorphism verified by 61 automated tests."))
|
||||
(p :class "text-green-800" "Same SX code runs on either side. Runtime chooses optimal split via affinity annotations and render plans. Client data cache managed via invalidation headers and server-driven updates. Cross-host isomorphism verified by 61 automated tests."))
|
||||
|
||||
(~doc-subsection :title "7a. Affinity Annotations & Render Target"
|
||||
|
||||
@@ -2039,11 +2039,70 @@
|
||||
(li "Render plans visible on " (a :href "/isomorphism/affinity" "affinity demo page"))
|
||||
(li "Client page registry includes :render-plan for each page"))))
|
||||
|
||||
(~doc-subsection :title "7c. Optimistic Data Updates"
|
||||
(p "Extend existing apply-optimistic/revert-optimistic in engine.sx from DOM-level to data-level. Client updates cached data optimistically, sends mutation to server, reverts on rejection."))
|
||||
(~doc-subsection :title "7c. Cache Invalidation & Data Updates"
|
||||
|
||||
(div :class "rounded border border-green-300 bg-green-50 p-3 mb-4"
|
||||
(div :class "flex items-center gap-2 mb-1"
|
||||
(span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete"))
|
||||
(p :class "text-green-800 text-sm" "Client data cache management: invalidation on mutation, server-driven cache updates, and programmatic cache control from SX code."))
|
||||
|
||||
(p "The client-side page data cache (30-second TTL) now supports cache invalidation and server-driven updates, extending the existing DOM-level " (code "apply-optimistic") "/" (code "revert-optimistic") " to data-level cache management.")
|
||||
|
||||
(~doc-subsection :title "Element Attributes"
|
||||
(p "Component authors can declare cache invalidation on elements that trigger mutations:")
|
||||
(~doc-code :code (highlight ";; Clear specific page's cache after successful action\n(form :sx-post \"/cart/remove\"\n :sx-cache-invalidate \"cart-page\"\n ...)\n\n;; Clear ALL page caches after action\n(button :sx-post \"/admin/reset\"\n :sx-cache-invalidate \"*\")" "lisp"))
|
||||
(p "When the request succeeds, the named page's data cache is cleared. The next client-side navigation to that page will re-fetch fresh data from the server."))
|
||||
|
||||
(~doc-subsection :title "Response Headers"
|
||||
(p "The server can also control client cache via response headers:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (code "SX-Cache-Invalidate: page-name") " — clear cache for a page")
|
||||
(li (code "SX-Cache-Invalidate: *") " — clear all page caches")
|
||||
(li (code "SX-Cache-Update: page-name") " — replace cache with the response body (SX-format data)"))
|
||||
(p (code "SX-Cache-Update") " is the strongest form: the server pushes authoritative data directly into the client cache, so the user sees fresh data immediately on next navigation — no re-fetch needed."))
|
||||
|
||||
(~doc-subsection :title "Programmatic API"
|
||||
(p "Three functions available from SX orchestration code:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1 font-mono text-sm"
|
||||
(li "(invalidate-page-cache page-name)")
|
||||
(li "(invalidate-all-page-cache)")
|
||||
(li "(update-page-cache page-name data)")))
|
||||
|
||||
(~doc-subsection :title "Files"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1 font-mono text-sm"
|
||||
(li "shared/sx/ref/engine.sx — SX-Cache-Invalidate, SX-Cache-Update response headers")
|
||||
(li "shared/sx/ref/orchestration.sx — cache management functions, process-cache-directives")
|
||||
(li "shared/sx/ref/bootstrap_js.py — parseSxData platform function"))))
|
||||
|
||||
(~doc-subsection :title "7d. Offline Data Layer"
|
||||
(p "Service Worker intercepts /internal/data/ requests, serves from IndexedDB when offline, syncs when back online."))
|
||||
|
||||
(div :class "rounded border border-green-300 bg-green-50 p-3 mb-4"
|
||||
(div :class "flex items-center gap-2 mb-1"
|
||||
(span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete"))
|
||||
(p :class "text-green-800 text-sm" "Service Worker with IndexedDB caching for offline-capable page data and IO responses. Static assets cached via Cache API."))
|
||||
|
||||
(p "A Service Worker registered at " (code "/sx-sw.js") " provides three-tier caching:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (strong "/sx/data/* ") "— network-first with IndexedDB fallback. Page data is cached on successful fetch and served from IndexedDB when offline.")
|
||||
(li (strong "/sx/io/* ") "— network-first with IndexedDB fallback. IO proxy responses cached the same way.")
|
||||
(li (strong "/static/* ") "— stale-while-revalidate via Cache API. Serves cached CSS/JS/images immediately, updates in background."))
|
||||
|
||||
(p "Cache invalidation flows through to the Service Worker: when " (code "invalidate-page-cache") " clears the in-memory cache, it also sends a " (code "postMessage") " to the SW which removes matching entries from IndexedDB.")
|
||||
|
||||
(~doc-subsection :title "How It Works"
|
||||
(ol :class "list-decimal list-inside text-stone-700 space-y-2"
|
||||
(li "On boot, " (code "sx-browser.js") " registers the SW at " (code "/sx-sw.js") " (root scope)")
|
||||
(li "SW intercepts fetch events and routes by URL pattern")
|
||||
(li "For data/IO: try network first, on failure serve from IndexedDB")
|
||||
(li "For static assets: serve from Cache API, revalidate in background")
|
||||
(li "Cache invalidation propagates: element attr / response header → in-memory cache → SW message → IndexedDB")))
|
||||
|
||||
(~doc-subsection :title "Files"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1 font-mono text-sm"
|
||||
(li "shared/static/scripts/sx-sw.js — Service Worker (network-first + stale-while-revalidate)")
|
||||
(li "shared/sx/pages.py — mount_service_worker() serves SW at /sx-sw.js")
|
||||
(li "shared/sx/ref/bootstrap_js.py — SW registration in boot init")
|
||||
(li "shared/sx/ref/orchestration.sx — sw-post-message for cache invalidation"))))
|
||||
|
||||
(~doc-subsection :title "7e. Isomorphic Testing"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user