Fix navigation: deep URL routing, back button, render timeout

- request-handler.sx: replace all dots (not just `.(`) and auto-quote
  undefined symbols as strings so 3-level URLs like
  /sx/(geography.(reactive.(examples.counter))) resolve correctly
- sx-platform.js: register popstate handler (was missing from manual
  boot sequence) and fetch full HTML for back/forward navigation
- sx_ref.ml: add CEK step limit (10M steps) checked every 4096 steps
  so runaway renders return 500 instead of blocking the worker forever
- Rename test-runner.sx → runner-placeholder.sx to avoid `test-` skip
- Playwright config: pin testDir, single worker, ignore worktrees

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 17:54:33 +00:00
parent 20b3dfb8a0
commit 84a48f0de3
5 changed files with 120 additions and 85 deletions

View File

@@ -329,17 +329,17 @@
];
var loaded = 0, bcCount = 0, srcCount = 0;
if (K.beginModuleLoad) K.beginModuleLoad();
var inBatch = false;
for (var i = 0; i < files.length; i++) {
if (!inBatch && K.beginModuleLoad) { K.beginModuleLoad(); inBatch = true; }
var r = loadBytecodeFile(files[i]);
if (r) { bcCount++; continue; }
// Bytecode not available — end batch, load source, restart batch
if (K.endModuleLoad) K.endModuleLoad();
// Bytecode not available — end batch, load source
if (inBatch && K.endModuleLoad) { K.endModuleLoad(); inBatch = false; }
r = loadSxFile(files[i]);
if (typeof r === "number") { loaded += r; srcCount++; }
if (K.beginModuleLoad) K.beginModuleLoad();
}
if (K.endModuleLoad) K.endModuleLoad();
if (inBatch && K.endModuleLoad) K.endModuleLoad();
console.log("[sx-platform] Loaded " + files.length + " files (" + bcCount + " bytecode, " + srcCount + " source, " + loaded + " exprs)");
return loaded;
}
@@ -397,6 +397,43 @@
"hydrated:", !!islands[j]._sxBoundislandhydrated || !!islands[j]["_sxBound" + "island-hydrated"],
"children:", islands[j].children.length);
}
// Register popstate handler for back/forward navigation.
// Fetch HTML (not SX) and extract #main-panel content.
window.addEventListener("popstate", function() {
var url = location.pathname + location.search;
var target = document.querySelector("#main-panel");
if (!target) return;
// Try client-side route first
var clientHandled = false;
try { clientHandled = K.eval('(try-client-route "' + url.replace(/"/g, '\\"') + '" "#main-panel")'); } catch(e) {}
if (clientHandled) return;
// Server fetch — request full HTML (no SX-Request header)
fetch(url)
.then(function(r) { return r.text(); })
.then(function(html) {
if (!html) return;
// Parse the full HTML and extract #main-panel
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
var srcPanel = doc.querySelector("#main-panel");
var srcNav = doc.querySelector("#sx-nav");
if (srcPanel) {
target.outerHTML = srcPanel.outerHTML;
}
// Also update nav if present
var navTarget = document.querySelector("#sx-nav");
if (srcNav && navTarget) {
navTarget.outerHTML = srcNav.outerHTML;
}
// Re-hydrate
var newTarget = document.querySelector("#main-panel");
if (newTarget) {
try { K.eval("(post-swap (dom-query \"#main-panel\"))"); } catch(e) {}
try { K.eval("(sx-hydrate-islands (dom-query \"#main-panel\"))"); } catch(e) {}
}
})
.catch(function(e) { console.warn("[sx] popstate fetch error:", e); });
});
console.log("[sx] boot done");
}
}