fix(js): keep standard sse same-origin

Require non-empty data-slhx-sse values at build time and have the standard runtime reject cross-origin EventSource URLs with slhx:sse-error instead of opening an implicit external stream.

req: push/006

req: diagnostics/002
This commit is contained in:
slhx agent
2026-06-01 21:07:14 +02:00
parent 0315044f53
commit 56f4db88c4
4 changed files with 28 additions and 3 deletions
+6 -1
View File
@@ -637,7 +637,12 @@
function bindSse(root) {
const url = root.getAttribute("data-slhx-sse");
if (!url || sseSources.has(root) || typeof EventSource === "undefined") return;
const source = new EventSource(new URL(url, location.href).href);
const href = new URL(url, location.href);
if (href.origin !== location.origin) {
emit(root, "slhx:sse-error", url);
return;
}
const source = new EventSource(href.href);
source.addEventListener("slhx", (event) => applySseMessage(root, event));
source.addEventListener("message", (event) => applySseMessage(root, event));
source.addEventListener("error", () => emit(root, "slhx:sse-error", url));
+5 -2
View File
@@ -218,12 +218,15 @@ fn runtime_refuses_partial_updates_on_fingerprint_mismatch() {
#[test]
fn runtime_applies_sse_effect_batches_inside_roots() {
// req: push/001 req: push/003 req: runtime/001
// req: push/001 req: push/003 req: push/006 req: runtime/001
let source = slhx_js::RUNTIME_JS;
assert!(source.contains("const sseSources = new WeakMap()"));
assert!(source.contains("const url = root.getAttribute(\"data-slhx-sse\")"));
assert!(source.contains("new EventSource(new URL(url, location.href).href)"));
assert!(source.contains("const href = new URL(url, location.href)"));
assert!(source.contains("if (href.origin !== location.origin)"));
assert!(source.contains("emit(root, \"slhx:sse-error\", url)"));
assert!(source.contains("new EventSource(href.href)"));
assert!(source.contains("source.addEventListener(\"slhx\", (event) => applySseMessage(root, event))"));
assert!(source.contains("source.addEventListener(\"message\", (event) => applySseMessage(root, event))"));
assert!(source.contains("applyBatch(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength), root)"));