Fix island state loss on SX navigation + cache busting

Island markers rendered during SX navigation responses had no
data-sx-state attribute, so hydration found empty kwargs and path
was nil in the copyright display. Now adapter-dom.sx serializes
keyword args into data-sx-state on island markers, matching what
adapter-html.sx does for SSR.

Also fix post-swap to use parent element for outerHTML swaps in
SX responses (was using detached old target). Add SX source file
hashes to wasm_hash for proper browser cache busting — changing
any .sx file now busts the cache. Remove stale .sxbc bytecode
cache files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 17:36:27 +00:00
parent aa4c911178
commit 20b3dfb8a0
12 changed files with 2768 additions and 3100 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,464 +0,0 @@
(sxbc 1 "8dd29bf7bc354b48"
(code
:bytecode (1 1 0 128 0 0 5 51 3 0 128 2 0 5 51 5 0 128 4 0 5 51 7 0 128 6 0 5 51 9 0 128 8 0 5 51 11 0 128 10 0 5 51 13 0 128 12 0 5 51 15 0 128 14 0 5 51 17 0 128 16 0 5 52 19 0 0 128 18 0 5 51 21 0 128 20 0 5 51 23 0 128 22 0 5 51 25 0 128 24 0 5 51 27 0 128 26 0 5 51 29 0 128 28 0 5 51 31 0 128 30 0 5 52 19 0 0 128 32 0 5 52 19 0 0 128 33 0 5 51 35 0 128 34 0 5 51 37 0 128 36 0 5 51 39 0 128 38 0 5 51 41 0 128 40 0 5 51 43 0 128 42 0 50)
:constants (
"HEAD_HOIST_SELECTOR"
"meta, title, link[rel='canonical'], script[type='application/ld+json']"
"hoist-head-elements-full"
(code :arity 1
:bytecode (20 0 0 16 0 20 1 0 48 2 17 1 51 3 0 16 1 52 2 0 2 50)
:constants (
"dom-query-all"
"HEAD_HOIST_SELECTOR"
"for-each"
(code :arity 1
:bytecode (20 1 0 16 0 48 1 52 0 0 1 17 1 16 1 1 3 0 52 2 0 2 33 30 0 20 4 0 20 5 0 16 0 48 1 48 1 5 20 6 0 20 7 0 16 0 48 1 16 0 49 2 32 205 0 16 1 1 8 0 52 2 0 2 33 103 0 20 9 0 16 0 1 10 0 48 2 17 2 20 9 0 16 0 1 11 0 48 2 17 3 16 2 33 20 0 20 12 0 1 14 0 16 2 1 15 0 52 13 0 3 48 1 32 1 0 2 5 16 3 33 20 0 20 12 0 1 16 0 16 3 1 15 0 52 13 0 3 48 1 32 1 0 2 5 20 6 0 20 7 0 16 0 48 1 16 0 48 2 5 20 17 0 16 0 49 1 32 90 0 16 1 1 18 0 52 2 0 2 6 33 18 0 5 20 9 0 16 0 1 19 0 48 2 1 20 0 52 2 0 2 33 34 0 20 12 0 1 21 0 48 1 5 20 6 0 20 7 0 16 0 48 1 16 0 48 2 5 20 17 0 16 0 49 1 32 22 0 20 6 0 20 7 0 16 0 48 1 16 0 48 2 5 20 17 0 16 0 49 1 50)
:constants (
"lower"
"dom-tag-name"
"="
"title"
"set-document-title"
"dom-text-content"
"dom-remove-child"
"dom-parent"
"meta"
"dom-get-attr"
"name"
"property"
"remove-head-element"
"str"
"meta[name=\""
"\"]"
"meta[property=\""
"dom-append-to-head"
"link"
"rel"
"canonical"
"link[rel=\"canonical\"]"))))
"sx-mount"
(code :arity 3
:bytecode (20 0 0 16 0 48 1 17 3 16 3 33 90 0 20 2 0 16 3 48 1 52 1 0 1 33 42 0 20 3 0 16 1 16 2 48 2 17 4 20 4 0 16 3 1 5 0 48 2 5 20 6 0 16 3 16 4 48 2 5 20 7 0 16 3 48 1 32 1 0 2 5 20 8 0 16 3 48 1 5 20 9 0 16 3 48 1 5 20 10 0 16 3 48 1 5 20 11 0 49 0 32 1 0 2 50)
:constants (
"resolve-mount-target"
"empty?"
"dom-child-list"
"sx-render-with-env"
"dom-set-text-content"
""
"dom-append"
"hoist-head-elements-full"
"process-elements"
"sx-hydrate-elements"
"sx-hydrate-islands"
"run-post-render-hooks"))
"resolve-suspense"
(code :arity 2
:bytecode (20 0 0 2 48 1 5 20 1 0 1 3 0 16 0 1 4 0 52 2 0 3 48 1 17 2 16 2 33 93 0 20 5 0 16 1 48 1 17 3 20 6 0 2 48 1 17 4 20 7 0 16 2 1 8 0 48 2 5 51 10 0 1 2 1 4 16 3 52 9 0 2 5 20 11 0 16 2 48 1 5 20 12 0 16 2 48 1 5 20 13 0 16 2 48 1 5 20 14 0 48 0 5 20 15 0 16 2 1 16 0 1 17 0 16 0 65 1 0 49 3 32 14 0 20 18 0 1 19 0 16 0 52 2 0 2 49 1 50)
:constants (
"process-sx-scripts"
"dom-query"
"str"
"[data-suspense=\""
"\"]"
"parse"
"get-render-env"
"dom-set-text-content"
""
"for-each"
(code :arity 1 :upvalue-count 2
:bytecode (20 0 0 18 0 20 1 0 16 0 18 1 2 48 3 49 2 50)
:constants (
"dom-append"
"render-to-dom"))
"process-elements"
"sx-hydrate-elements"
"sx-hydrate-islands"
"run-post-render-hooks"
"dom-dispatch"
"sx:resolved"
"id"
"log-warn"
"resolveSuspense: no element for id="))
"sx-hydrate-elements"
(code :arity 1
:bytecode (20 0 0 16 0 6 34 6 0 5 20 1 0 48 0 1 2 0 48 2 17 1 51 4 0 16 1 52 3 0 2 50)
:constants (
"dom-query-all"
"dom-body"
"[data-sx]"
"for-each"
(code :arity 1
:bytecode (20 1 0 16 0 1 2 0 48 2 52 0 0 1 33 22 0 20 3 0 16 0 1 2 0 48 2 5 20 4 0 16 0 2 49 2 32 1 0 2 50)
:constants (
"not"
"is-processed?"
"hydrated"
"mark-processed!"
"sx-update-element"))))
"sx-update-element"
(code :arity 2
:bytecode (20 0 0 16 0 48 1 17 2 16 2 33 96 0 20 1 0 16 2 1 2 0 48 2 17 3 16 3 33 75 0 20 3 0 16 2 48 1 17 4 20 4 0 16 4 16 1 48 2 17 5 20 5 0 16 3 16 5 48 2 17 6 20 6 0 16 2 1 7 0 48 2 5 20 8 0 16 2 16 6 48 2 5 16 1 33 14 0 20 9 0 16 2 16 4 16 1 49 3 32 1 0 2 32 1 0 2 32 1 0 2 50)
:constants (
"resolve-mount-target"
"dom-get-attr"
"data-sx"
"parse-env-attr"
"merge-envs"
"sx-render-with-env"
"dom-set-text-content"
""
"dom-append"
"store-env-attr"))
"sx-render-component"
(code :arity 3
:bytecode (16 0 1 1 0 52 0 0 2 33 5 0 16 0 32 9 0 1 1 0 16 0 52 2 0 2 17 3 20 3 0 16 2 48 1 17 4 20 4 0 16 4 16 3 48 2 17 5 16 5 52 6 0 1 52 5 0 1 33 16 0 1 8 0 16 3 52 2 0 2 52 7 0 1 32 40 0 16 3 52 10 0 1 52 9 0 1 17 6 51 12 0 1 6 1 1 16 1 52 13 0 1 52 11 0 2 5 20 14 0 16 6 16 4 2 49 3 50)
:constants (
"starts-with?"
"~"
"str"
"get-render-env"
"env-get"
"not"
"component?"
"error"
"Unknown component: "
"list"
"make-symbol"
"for-each"
(code :arity 1 :upvalue-count 2
:bytecode (20 0 0 18 0 20 1 0 20 2 0 16 0 48 1 48 1 48 2 5 20 0 0 18 0 18 1 16 0 52 3 0 2 49 2 50)
:constants (
"append!"
"make-keyword"
"to-kebab"
"dict-get"))
"keys"
"render-to-dom"))
"process-sx-scripts"
(code :arity 1
:bytecode (20 0 0 16 0 48 1 17 1 51 2 0 16 1 52 1 0 2 50)
:constants (
"query-sx-scripts"
"for-each"
(code :arity 1
:bytecode (20 1 0 16 0 1 2 0 48 2 52 0 0 1 33 173 0 20 3 0 16 0 1 2 0 48 2 5 20 4 0 16 0 48 1 17 1 20 5 0 16 0 1 6 0 48 2 33 12 0 20 7 0 16 0 16 1 49 2 32 125 0 16 1 52 8 0 1 6 34 11 0 5 16 1 52 10 0 1 52 9 0 1 33 4 0 2 32 97 0 20 5 0 16 0 1 11 0 48 2 33 21 0 20 12 0 16 1 48 1 17 2 51 14 0 16 2 52 13 0 2 32 63 0 20 5 0 16 0 1 15 0 48 2 33 43 0 20 16 0 16 0 1 15 0 48 2 17 2 20 17 0 16 2 48 1 17 3 16 3 33 13 0 20 18 0 16 3 16 1 2 49 3 32 1 0 2 32 7 0 20 19 0 16 1 49 1 32 1 0 2 50)
:constants (
"not"
"is-processed?"
"script"
"mark-processed!"
"dom-text-content"
"dom-has-attr?"
"data-components"
"process-component-script"
"nil?"
"empty?"
"trim"
"data-init"
"sx-parse"
"for-each"
(code :arity 1
:bytecode (20 0 0 16 0 49 1 50)
:constants (
"cek-eval"))
"data-mount"
"dom-get-attr"
"dom-query"
"sx-mount"
"sx-load-components"))))
"process-component-script"
(code :arity 2
:bytecode (20 0 0 16 0 1 1 0 48 2 17 2 16 2 52 2 0 1 33 38 0 16 1 6 33 15 0 5 16 1 52 5 0 1 52 4 0 1 52 3 0 1 33 10 0 20 6 0 16 1 49 1 32 1 0 2 32 239 0 16 1 6 33 15 0 5 16 1 52 5 0 1 52 4 0 1 52 3 0 1 17 3 20 7 0 1 8 0 48 1 17 4 16 4 16 2 52 9 0 2 33 103 0 16 3 33 41 0 20 10 0 1 8 0 16 2 48 2 5 20 10 0 1 11 0 16 1 48 2 5 20 6 0 16 1 48 1 5 20 12 0 1 13 0 48 1 32 54 0 20 7 0 1 11 0 48 1 17 5 16 5 33 28 0 20 6 0 16 5 48 1 5 20 12 0 1 15 0 16 2 1 16 0 52 14 0 3 48 1 32 11 0 20 17 0 48 0 5 20 18 0 48 0 32 84 0 16 3 33 50 0 20 10 0 1 8 0 16 2 48 2 5 20 10 0 1 11 0 16 1 48 2 5 20 6 0 16 1 48 1 5 20 12 0 1 19 0 16 2 1 16 0 52 14 0 3 48 1 32 29 0 20 20 0 1 8 0 48 1 5 20 20 0 1 11 0 48 1 5 20 17 0 48 0 5 20 18 0 48 0 5 20 21 0 16 2 49 1 50)
:constants (
"dom-get-attr"
"data-hash"
"nil?"
"not"
"empty?"
"trim"
"sx-load-components"
"local-storage-get"
"sx-components-hash"
"="
"local-storage-set"
"sx-components-src"
"log-info"
"components: downloaded (cookie stale)"
"str"
"components: cached ("
")"
"clear-sx-comp-cookie"
"browser-reload"
"components: downloaded ("
"local-storage-remove"
"set-sx-comp-cookie"))
"_page-routes"
"list"
"process-page-scripts"
(code
:bytecode (20 0 0 48 0 17 0 20 1 0 1 3 0 16 0 52 4 0 1 1 5 0 52 2 0 3 48 1 5 51 7 0 16 0 52 6 0 2 5 20 1 0 1 8 0 20 9 0 52 4 0 1 1 10 0 52 2 0 3 49 1 50)
:constants (
"query-page-scripts"
"log-info"
"str"
"pages: found "
"len"
" script tags"
"for-each"
(code :arity 1
:bytecode (20 1 0 16 0 1 2 0 48 2 52 0 0 1 33 128 0 20 3 0 16 0 1 2 0 48 2 5 20 4 0 16 0 48 1 17 1 20 5 0 1 7 0 16 1 33 9 0 16 1 52 8 0 1 32 3 0 1 9 0 52 6 0 2 48 1 5 16 1 6 33 15 0 5 16 1 52 11 0 1 52 10 0 1 52 0 0 1 33 43 0 20 12 0 16 1 48 1 17 2 20 5 0 1 13 0 16 2 52 8 0 1 1 14 0 52 6 0 3 48 1 5 51 16 0 16 2 52 15 0 2 32 8 0 20 17 0 1 18 0 49 1 32 1 0 2 50)
:constants (
"not"
"is-processed?"
"pages"
"mark-processed!"
"dom-text-content"
"log-info"
"str"
"pages: script text length="
"len"
0
"empty?"
"trim"
"parse"
"pages: parsed "
" entries"
"for-each"
(code :arity 1
:bytecode (20 0 0 20 1 0 16 0 1 3 0 20 4 0 16 0 1 6 0 52 5 0 2 48 1 65 1 0 52 2 0 2 49 2 50)
:constants (
"append!"
"_page-routes"
"merge"
"parsed"
"parse-route-pattern"
"get"
"path"))
"log-warn"
"pages: script tag is empty"))
"pages: "
"_page-routes"
" routes loaded"))
"sx-hydrate-islands"
(code :arity 1
:bytecode (20 0 0 16 0 6 34 6 0 5 20 1 0 48 0 1 2 0 48 2 17 1 20 3 0 1 5 0 16 1 52 6 0 1 1 7 0 16 0 33 6 0 1 8 0 32 3 0 1 9 0 52 4 0 4 48 1 5 51 11 0 16 1 52 10 0 2 50)
:constants (
"dom-query-all"
"dom-body"
"[data-sx-island]"
"log-info"
"str"
"sx-hydrate-islands: "
"len"
" island(s) in "
"subtree"
"document"
"for-each"
(code :arity 1
:bytecode (20 0 0 16 0 1 1 0 48 2 33 25 0 20 2 0 1 4 0 20 5 0 16 0 1 6 0 48 2 52 3 0 2 49 1 32 41 0 20 2 0 1 7 0 20 5 0 16 0 1 6 0 48 2 52 3 0 2 48 1 5 20 8 0 16 0 1 1 0 48 2 5 20 9 0 16 0 49 1 50)
:constants (
"is-processed?"
"island-hydrated"
"log-info"
"str"
" skip (already hydrated): "
"dom-get-attr"
"data-sx-island"
" hydrating: "
"mark-processed!"
"hydrate-island"))))
"hydrate-island"
(code :arity 1
:bytecode (20 0 0 16 0 1 1 0 48 2 17 1 20 0 0 16 0 1 2 0 48 2 6 34 4 0 5 1 3 0 17 2 1 5 0 16 1 52 4 0 2 17 3 20 6 0 2 48 1 17 4 20 7 0 16 4 16 3 48 2 17 5 16 5 52 9 0 1 6 34 7 0 5 16 5 52 10 0 1 52 8 0 1 33 17 0 20 11 0 1 12 0 16 3 52 4 0 2 49 1 32 149 0 20 14 0 16 2 48 1 52 13 0 1 6 34 4 0 5 65 0 0 17 6 52 15 0 0 17 7 20 16 0 16 5 52 17 0 1 16 4 48 2 17 8 51 19 0 1 8 1 6 16 5 52 20 0 1 52 18 0 2 5 20 21 0 51 22 0 1 7 1 5 1 8 51 23 0 1 3 48 2 17 9 20 24 0 16 0 1 25 0 48 2 5 20 26 0 16 0 16 9 48 2 5 20 27 0 16 0 1 28 0 16 7 48 3 5 20 29 0 16 0 48 1 5 20 30 0 1 31 0 16 3 1 32 0 16 7 52 33 0 1 1 34 0 52 4 0 5 49 1 50)
:constants (
"dom-get-attr"
"data-sx-island"
"data-sx-state"
"{}"
"str"
"~"
"get-render-env"
"env-get"
"not"
"component?"
"island?"
"log-warn"
"hydrate-island: unknown island "
"first"
"sx-parse"
"list"
"env-merge"
"component-closure"
"for-each"
(code :arity 1 :upvalue-count 2
:bytecode (20 0 0 18 0 16 0 18 1 16 0 52 1 0 2 33 11 0 18 1 16 0 52 2 0 2 32 1 0 2 49 3 50)
:constants (
"env-bind!"
"dict-has?"
"dict-get"))
"component-params"
"cek-try"
(code :upvalue-count 3
:bytecode (20 0 0 51 1 0 0 0 51 2 0 0 1 0 2 49 2 50)
:constants (
"with-island-scope"
(code :arity 1 :upvalue-count 1
:bytecode (20 0 0 18 0 16 0 49 2 50)
:constants (
"append!"))
(code :upvalue-count 2
:bytecode (20 0 0 18 0 52 1 0 1 18 1 2 49 3 50)
:constants (
"render-to-dom"
"component-body"))))
(code :arity 1 :upvalue-count 1
:bytecode (20 0 0 1 2 0 18 0 1 3 0 16 0 52 1 0 4 48 1 5 20 4 0 1 5 0 2 48 2 17 1 20 6 0 16 1 1 7 0 1 8 0 48 3 5 20 6 0 16 1 1 9 0 1 10 0 48 3 5 20 11 0 16 1 1 12 0 18 0 1 13 0 16 0 52 1 0 4 48 2 5 16 1 50)
:constants (
"log-warn"
"str"
"hydrate-island FAILED: "
" — "
"dom-create-element"
"div"
"dom-set-attr"
"class"
"sx-island-error"
"style"
"padding:8px;margin:4px 0;border:1px solid #ef4444;border-radius:4px;background:#fef2f2;color:#b91c1c;font-family:monospace;font-size:12px;white-space:pre-wrap"
"dom-set-text-content"
"Island error: "
"
"))
"dom-set-text-content"
""
"dom-append"
"dom-set-data"
"sx-disposers"
"process-elements"
"log-info"
"hydrated island: "
" ("
"len"
" disposers)"))
"dispose-island"
(code :arity 1
:bytecode (20 0 0 16 0 1 1 0 48 2 17 1 16 1 33 24 0 51 3 0 16 1 52 2 0 2 5 20 4 0 16 0 1 1 0 2 48 3 32 1 0 2 5 20 5 0 16 0 1 6 0 49 2 50)
:constants (
"dom-get-data"
"sx-disposers"
"for-each"
(code :arity 1
:bytecode (20 0 0 16 0 48 1 33 7 0 16 0 49 0 32 1 0 2 50)
:constants (
"callable?"))
"dom-set-data"
"clear-processed!"
"island-hydrated"))
"dispose-islands-in"
(code :arity 1
:bytecode (16 0 33 98 0 20 0 0 16 0 1 1 0 48 2 17 1 16 1 6 33 11 0 5 16 1 52 3 0 1 52 2 0 1 33 62 0 51 5 0 16 1 52 4 0 2 17 2 16 2 52 3 0 1 52 2 0 1 33 34 0 20 6 0 1 8 0 16 2 52 9 0 1 1 10 0 52 7 0 3 48 1 5 20 12 0 16 2 52 11 0 2 32 1 0 2 32 1 0 2 32 1 0 2 50)
:constants (
"dom-query-all"
"[data-sx-island]"
"not"
"empty?"
"filter"
(code :arity 1
:bytecode (20 1 0 16 0 1 2 0 48 2 52 0 0 1 50)
:constants (
"not"
"is-processed?"
"island-hydrated"))
"log-info"
"str"
"disposing "
"len"
" island(s)"
"for-each"
"dispose-island"))
"force-dispose-islands-in"
(code :arity 1
:bytecode (16 0 33 70 0 20 0 0 16 0 1 1 0 48 2 17 1 16 1 6 33 11 0 5 16 1 52 3 0 1 52 2 0 1 33 34 0 20 4 0 1 6 0 16 1 52 7 0 1 1 8 0 52 5 0 3 48 1 5 20 10 0 16 1 52 9 0 2 32 1 0 2 32 1 0 2 50)
:constants (
"dom-query-all"
"[data-sx-island]"
"not"
"empty?"
"log-info"
"str"
"force-disposing "
"len"
" island(s)"
"for-each"
"dispose-island"))
"*pre-render-hooks*"
"*post-render-hooks*"
"register-pre-render-hook"
(code :arity 1
:bytecode (20 0 0 20 1 0 16 0 49 2 50)
:constants (
"append!"
"*pre-render-hooks*"))
"register-post-render-hook"
(code :arity 1
:bytecode (20 0 0 20 1 0 16 0 49 2 50)
:constants (
"append!"
"*post-render-hooks*"))
"run-pre-render-hooks"
(code
:bytecode (51 1 0 20 2 0 52 0 0 2 50)
:constants (
"for-each"
(code :arity 1
:bytecode (20 0 0 16 0 2 49 2 50)
:constants (
"cek-call"))
"*pre-render-hooks*"))
"run-post-render-hooks"
(code
:bytecode (20 0 0 1 2 0 20 4 0 52 3 0 1 1 5 0 52 1 0 3 48 1 5 51 7 0 20 4 0 52 6 0 2 50)
:constants (
"log-info"
"str"
"run-post-render-hooks: "
"len"
"*post-render-hooks*"
" hooks"
"for-each"
(code :arity 1
:bytecode (20 0 0 1 2 0 16 0 52 3 0 1 1 4 0 20 5 0 16 0 48 1 1 6 0 16 0 52 7 0 1 52 1 0 6 48 1 5 20 8 0 16 0 2 49 2 50)
:constants (
"log-info"
"str"
" hook type: "
"type-of"
" callable: "
"callable?"
" lambda: "
"lambda?"
"cek-call"))))
"boot-init"
(code
:bytecode (20 0 0 1 2 0 20 3 0 52 1 0 2 48 1 5 20 4 0 48 0 5 20 5 0 48 0 5 20 6 0 2 48 1 5 20 7 0 2 48 1 5 20 8 0 2 48 1 5 20 9 0 48 0 5 20 10 0 2 48 1 5 20 11 0 20 12 0 48 0 1 13 0 51 14 0 49 3 50)
:constants (
"log-info"
"str"
"sx-browser "
"SX_VERSION"
"init-css-tracking"
"process-page-scripts"
"process-sx-scripts"
"sx-hydrate-elements"
"sx-hydrate-islands"
"run-post-render-hooks"
"process-elements"
"dom-listen"
"dom-window"
"popstate"
(code :arity 1
:bytecode (20 0 0 1 1 0 49 1 50)
:constants (
"handle-popstate"
0)))))))

File diff suppressed because one or more lines are too long

View File

@@ -299,7 +299,11 @@
()
(let
((swap-result (swap-dom-nodes target content swap-style)))
(post-swap (or swap-result target)))))))))))))
(post-swap
(if
(= swap-style "outerHTML")
(dom-parent (or swap-result target))
(or swap-result target))))))))))))))
(define
handle-html-response
@@ -325,8 +329,15 @@
use-transition
(fn
()
(swap-html-string target html swap-style)
(post-swap target))))
(let
((swap-root (swap-html-string target html swap-style)))
(log-info
(str
"swap-root: "
(if swap-root (dom-tag-name swap-root) "nil")
" target: "
(dom-tag-name target)))
(post-swap (or swap-root target))))))
(let
((container (dom-create-element "div" nil)))
(dom-set-inner-html container (dom-body-inner-html doc))

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long