import { encryptString, generateCspDigest } from "../../../core/encryption.js"; import { markHTMLString } from "../escape.js"; import { renderChild } from "./any.js"; import { createThinHead } from "./astro/head-and-content.js"; import { createRenderInstruction } from "./instruction.js"; import { renderSlotToString } from "./slot.js"; const internalProps = /* @__PURE__ */ new Set([ "server:component-path", "server:component-export", "server:component-directive", "server:defer" ]); function containsServerDirective(props) { return "server:component-directive" in props; } const SCRIPT_RE = /<\/script/giu; const COMMENT_RE = /"); for (const name in this.slots) { if (name === "fallback") { await renderChild(destination, this.slots.fallback(this.result)); } } destination.write( `` ); } getComponentPath() { if (this.componentPath) { return this.componentPath; } const componentPath = this.props["server:component-path"]; if (!componentPath) { throw new Error(`Could not find server component path`); } this.componentPath = componentPath; return componentPath; } getComponentExport() { if (this.componentExport) { return this.componentExport; } const componentExport = this.props["server:component-export"]; if (!componentExport) { throw new Error(`Could not find server component export`); } this.componentExport = componentExport; return componentExport; } async getHostId() { if (!this.hostId) { this.hostId = await crypto.randomUUID(); } return this.hostId; } async getIslandContent() { if (this.islandContent) { return this.islandContent; } const componentPath = this.getComponentPath(); const componentExport = this.getComponentExport(); const componentId = this.result.serverIslandNameMap.get(componentPath); if (!componentId) { throw new Error(`Could not find server component name`); } for (const key2 of Object.keys(this.props)) { if (internalProps.has(key2)) { delete this.props[key2]; } } const renderedSlots = {}; for (const name in this.slots) { if (name !== "fallback") { const content = await renderSlotToString(this.result, this.slots[name]); renderedSlots[name] = content.toString(); } } const key = await this.result.key; const propsEncrypted = Object.keys(this.props).length === 0 ? "" : await encryptString(key, JSON.stringify(this.props)); const hostId = await this.getHostId(); const slash = this.result.base.endsWith("/") ? "" : "/"; let serverIslandUrl = `${this.result.base}${slash}_server-islands/${componentId}${this.result.trailingSlash === "always" ? "/" : ""}`; const potentialSearchParams = createSearchParams( componentExport, propsEncrypted, safeJsonStringify(renderedSlots) ); const useGETRequest = isWithinURLLimit(serverIslandUrl, potentialSearchParams); if (useGETRequest) { serverIslandUrl += "?" + potentialSearchParams.toString(); this.result._metadata.extraHead.push( markHTMLString( `` ) ); } const method = useGETRequest ? ( // GET request `let response = await fetch('${serverIslandUrl}');` ) : ( // POST request `let data = { componentExport: ${safeJsonStringify(componentExport)}, encryptedProps: ${safeJsonStringify(propsEncrypted)}, slots: ${safeJsonStringify(renderedSlots)}, }; let response = await fetch('${serverIslandUrl}', { method: 'POST', body: JSON.stringify(data), });` ); this.islandContent = `${method}replaceServerIsland('${hostId}', response);`; return this.islandContent; } } const renderServerIslandRuntime = () => { return ``; }; const SERVER_ISLAND_REPLACER = markHTMLString( `async function replaceServerIsland(id, r) { let s = document.querySelector(\`script[data-island-id="\${id}"]\`); // If there's no matching script, or the request fails then return if (!s || r.status !== 200 || r.headers.get('content-type')?.split(';')[0].trim() !== 'text/html') return; // Load the HTML before modifying the DOM in case of errors let html = await r.text(); // Remove any placeholder content before the island script while (s.previousSibling && s.previousSibling.nodeType !== 8 && s.previousSibling.data !== '[if astro]>server-island-start line.trim()).filter((line) => line && !line.startsWith("//")).join(" ") ); export { ServerIslandComponent, containsServerDirective, renderServerIslandRuntime };