Files
sitegeist-local/sandbox.js
T
2026-03-17 11:10:09 -06:00

58 lines
1.8 KiB
JavaScript

// Minimal sandbox.js - just listens for sandbox-load and writes the content
window.addEventListener("message", (event) => {
if (event.data.type === "sandbox-load") {
// Validate HTML and JavaScript syntax before document.write()
try {
// Parse HTML to extract script tags
const parser = new DOMParser();
const doc = parser.parseFromString(event.data.code, "text/html");
// Check for HTML parser errors
const parserError = doc.querySelector("parsererror");
if (parserError) {
throw new Error(`HTML parse error: ${parserError.textContent}`);
}
// Validate JavaScript in all script tags (except type="module")
const scriptTags = Array.from(doc.querySelectorAll("script"));
for (let i = 0; i < scriptTags.length; i++) {
const scriptContent = scriptTags[i].textContent || "";
const scriptType = scriptTags[i].getAttribute("type");
// Skip validation for module scripts - new Function() can't validate module syntax
if (scriptType === "module") {
continue;
}
if (scriptContent.trim()) {
try {
// Use Function constructor to validate syntax without executing
new Function(scriptContent);
} catch (jsError) {
throw new Error(`JavaScript syntax error in <script> tag ${i + 1}: ${jsError.message}`);
}
}
}
} catch (validationError) {
// Send validation error back to parent
window.parent.postMessage(
{
type: "sandbox-error",
error: validationError.message || String(validationError),
stack: validationError.stack || "",
},
"*"
);
return;
}
// Write the complete HTML (which includes runtime + user code)
document.open();
document.write(event.data.code);
document.close();
}
});
// Signal ready to parent
window.parent.postMessage({ type: "sandbox-ready" }, "*");