import { markFlattenedInnerRoot } from "../runtime/flattenedRoot"; export { FLATTENED_INNER_ROOT_STRIP_ATTRS } from "../runtime/flattenedRoot"; import { parseHostVariableValues } from "../runtime/getVariables"; import { cssVariableName } from "../tokenSlug"; import { readFileSync, existsSync } from "fs"; import { resolve, relative, dirname, isAbsolute, sep } from "path"; import { CSS_URL_RE, isNonRelativeUrl } from "./assetPaths.js"; import { transformSync } from "esbuild"; import { compileHtml, type MediaDurationProber } from "./htmlCompiler"; import { RUNTIME_BOOTSTRAP_ATTR, parseHTMLContent, stripEmbeddedRuntimeScripts, } from "./htmlDocument"; // rewriteSubCompPaths functions are used by inlineSubCompositions (shared module) import { buildVariablesByCompScript, scopeCssToComposition, wrapInlineScriptWithErrorBoundary, wrapScopedCompositionScript, } from "./compositionScoping"; import { validateHyperframeHtmlContract } from "./staticGuard"; import { getHyperframeRuntimeScript } from "../generated/runtime-inline"; import { readDeclaredDefaults } from "../runtime/getVariables"; import { inlineSubCompositions } from "./inlineSubCompositions"; import { queryByAttr } from "../utils/cssSelector"; import { isSafePath, resolveWithinProject } from "../safePath.js"; import { HF_COLOR_GRADING_ATTR } from "../colorGrading"; const DEFAULT_RUNTIME_SCRIPT_URL = ""; function getRuntimeScriptUrl(): string { const configured = (process.env.HYPERFRAME_RUNTIME_URL || "").trim(); return configured || DEFAULT_RUNTIME_SCRIPT_URL; } function injectInterceptor(html: string, runtimeMode: "inline" | "placeholder" = "inline"): string { const sanitized = stripEmbeddedRuntimeScripts(html); if (sanitized.includes(RUNTIME_BOOTSTRAP_ATTR)) return sanitized; // Three modes for the runtime `; } else if (runtimeMode === "placeholder") { tag = ``; } else { const inlinedRuntime = getHyperframeRuntimeScript(); tag = ``; } if (sanitized.includes("")) { // Use a function replacer so `String.prototype.replace`'s substitution // patterns (`$&`, `$$`, `$'`, `` $` ``, `$1`–`$99`) inside the inlined // runtime IIFE are passed through verbatim. The minified runtime // contains the literal sequence `$&` as part of legitimate JS, and // the older `(pattern, string)` form would expand it to the matched // ``, silently corrupting the runtime and breaking every // timeline in the bundle with a parse-time SyntaxError. return sanitized.replace("", () => `${tag}\n`); } const htmlOpenMatch = sanitized.match(/]*>/i); if (htmlOpenMatch?.index != null) { const insertPos = htmlOpenMatch.index + htmlOpenMatch[0].length; return `${sanitized.slice(0, insertPos)}${tag}${sanitized.slice(insertPos)}`; } const doctypeIdx = sanitized.toLowerCase().indexOf("= 0) { const insertPos = sanitized.indexOf(">", doctypeIdx) + 1; return sanitized.slice(0, insertPos) + tag + sanitized.slice(insertPos); } return tag + sanitized; } function isRelativeUrl(url: string): boolean { return !isNonRelativeUrl(url) && !isAbsolute(url); } function safeReadFile(filePath: string): string | null { if (!existsSync(filePath)) return null; try { return readFileSync(filePath, "utf-8"); } catch { return null; } } const CSS_IMPORT_RE = /@import\s+(?:url\(\s*(["']?)([^)"']+)\1\s*\)|(["'])([^"']+)\3)\s*([^;]*);\s*/g; const CSS_COMMENT_RE = /\/\*[\s\S]*?\*\//g; function withCommentsStripped( css: string, fn: (stripped: string) => T, ): { result: T; restore: (s: string) => string } { const comments: string[] = []; const stripped = css.replace(CSS_COMMENT_RE, (m) => { const idx = comments.length; comments.push(m); return `/*__hf_c${idx}__*/`; }); const result = fn(stripped); const restore = (s: string) => { let out = s; for (let i = 0; i < comments.length; i++) { out = out.replace(`/*__hf_c${i}__*/`, comments[i]!); } return out; }; return { result, restore }; } function rebaseCssUrls(css: string, cssFileDir: string, projectDir: string): string { const resolvedRoot = resolve(projectDir); const resolvedDir = resolve(cssFileDir); if (resolvedDir === resolvedRoot) return css; return css.replace(CSS_URL_RE, (full, quote: string, urlValue: string) => { if (!urlValue || !isRelativeUrl(urlValue)) return full; const { basePath, suffix } = splitUrlSuffix(urlValue.trim()); if (!basePath) return full; const absolutePath = resolve(resolvedDir, basePath); const rebased = relative(resolvedRoot, absolutePath).split(sep).join("/"); if (rebased === basePath) return full; return `url(${quote || ""}${rebased}${suffix}${quote || ""})`; }); } function rebaseRelativePath(urlValue: string, fromDir: string, toDir: string): string { const { basePath, suffix } = splitUrlSuffix(urlValue.trim()); if (!basePath) return urlValue; const absolutePath = resolve(fromDir, basePath); const rebased = relative(resolve(toDir), absolutePath).split(sep).join("/"); return appendSuffixToUrl(rebased, suffix); } function rebaseSrcsetPaths(srcsetValue: string, fromDir: string, toDir: string): string { if (!srcsetValue) return srcsetValue; return srcsetValue .split(",") .map((rawCandidate) => { const candidate = rawCandidate.trim(); if (!candidate) return candidate; const parts = candidate.split(/\s+/); const first = parts[0] ?? ""; if (parts.length === 0 || !isRelativeUrl(first)) return candidate; parts[0] = rebaseRelativePath(first, fromDir, toDir); return parts.join(" "); }) .join(", "); } function rebaseColorGradingLutPath(value: string, fromDir: string, toDir: string): string { if (!value.trim().startsWith("{")) return value; let parsed: unknown; try { parsed = JSON.parse(value); } catch { return value; } if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return value; const lut = Reflect.get(parsed, "lut"); if (typeof lut === "string") { if (!isRelativeUrl(lut)) return value; Reflect.set(parsed, "lut", rebaseRelativePath(lut, fromDir, toDir)); return JSON.stringify(parsed); } if (typeof lut !== "object" || lut === null || Array.isArray(lut)) return value; const lutSrc = Reflect.get(lut, "src"); if (typeof lutSrc !== "string" || !isRelativeUrl(lutSrc)) return value; Reflect.set(lut, "src", rebaseRelativePath(lutSrc, fromDir, toDir)); return JSON.stringify(parsed); } function rebaseEntryAuthoredAssetPaths( document: Document, sourceDir: string, projectDir: string, ): void { for (const styleEl of [...document.querySelectorAll("style")]) { styleEl.textContent = rebaseCssUrls(styleEl.textContent || "", sourceDir, projectDir); } for (const el of [...document.querySelectorAll("[style]")]) { const styleAttr = el.getAttribute("style"); if (styleAttr) el.setAttribute("style", rebaseCssUrls(styleAttr, sourceDir, projectDir)); } for (const el of [...document.querySelectorAll("[src], [href], [poster], [xlink\\:href]")]) { if (el.tagName === "LINK" && (el.getAttribute("rel") || "").toLowerCase() === "stylesheet") continue; if (el.tagName === "SCRIPT" && el.hasAttribute("src")) continue; for (const attr of ["src", "href", "poster", "xlink:href"] as const) { const value = el.getAttribute(attr); if (!value || !isRelativeUrl(value)) continue; el.setAttribute(attr, rebaseRelativePath(value, sourceDir, projectDir)); } } for (const el of [...document.querySelectorAll("[srcset]")]) { const srcset = el.getAttribute("srcset"); if (srcset) el.setAttribute("srcset", rebaseSrcsetPaths(srcset, sourceDir, projectDir)); } for (const el of [...document.querySelectorAll(`[${HF_COLOR_GRADING_ATTR}]`)]) { const value = el.getAttribute(HF_COLOR_GRADING_ATTR); if (value) el.setAttribute( HF_COLOR_GRADING_ATTR, rebaseColorGradingLutPath(value, sourceDir, projectDir), ); } } function inlineCssFile( css: string, cssFileDir: string, projectDir: string, visited: Set = new Set(), ): string { const { result: strippedCss, restore: restoreComments } = withCommentsStripped(css, (s) => s); const importPlaceholders: string[] = []; const withPlaceholders = strippedCss.replace( CSS_IMPORT_RE, (full, _q1, urlPath, _q2, barePath, mediaQuery) => { const importPath = urlPath ?? barePath; if (!importPath || !isRelativeUrl(importPath)) return full; const resolved = resolve(cssFileDir, importPath); // @import is resolved relative to the CSS file, but must stay within the // project root; isSafePath also blocks symlink escapes (content is inlined). if (!isSafePath(projectDir, resolved)) return full; if (visited.has(resolved)) return ""; const content = safeReadFile(resolved); if (content == null) return full; visited.add(resolved); const inlined = inlineCssFile(content, dirname(resolved), projectDir, visited); const trimmedMedia = (mediaQuery || "").trim(); const block = trimmedMedia ? `@media ${trimmedMedia} {\n${inlined}\n}\n` : inlined + "\n"; const idx = importPlaceholders.length; importPlaceholders.push(block); return `/*__hf_import_${idx}__*/`; }, ); let rebased = rebaseCssUrls(withPlaceholders, cssFileDir, projectDir); rebased = restoreComments(rebased); for (let i = 0; i < importPlaceholders.length; i++) { rebased = rebased.replace(`/*__hf_import_${i}__*/`, importPlaceholders[i]!); } return rebased; } function safeReadFileBuffer(filePath: string): Buffer | null { if (!existsSync(filePath)) return null; try { return readFileSync(filePath); } catch { return null; } } function splitUrlSuffix(urlValue: string): { basePath: string; suffix: string } { const queryIdx = urlValue.indexOf("?"); const hashIdx = urlValue.indexOf("#"); if (queryIdx < 0 && hashIdx < 0) return { basePath: urlValue, suffix: "" }; const cutIdx = queryIdx < 0 ? hashIdx : hashIdx < 0 ? queryIdx : Math.min(queryIdx, hashIdx); return { basePath: urlValue.slice(0, cutIdx), suffix: urlValue.slice(cutIdx) }; } function appendSuffixToUrl(baseUrl: string, suffix: string): string { if (!suffix) return baseUrl; if (suffix.startsWith("#")) return `${baseUrl}${suffix}`; if (suffix.startsWith("?")) { const queryWithOptionalHash = suffix.slice(1); if (!queryWithOptionalHash) return baseUrl; const hashIdx = queryWithOptionalHash.indexOf("#"); const queryPart = hashIdx >= 0 ? queryWithOptionalHash.slice(0, hashIdx) : queryWithOptionalHash; const hashPart = hashIdx >= 0 ? queryWithOptionalHash.slice(hashIdx) : ""; if (!queryPart) return `${baseUrl}${hashPart}`; const joiner = baseUrl.includes("?") ? "&" : "?"; return `${baseUrl}${joiner}${queryPart}${hashPart}`; } return baseUrl; } const INLINE_MIME: Record = { ".svg": "image/svg+xml", ".json": "application/json", ".txt": "text/plain", ".cube": "text/plain", ".xml": "application/xml", }; function maybeInlineRelativeAssetUrl(urlValue: string, projectDir: string): string | null { if (!urlValue || !isRelativeUrl(urlValue)) return null; const { basePath, suffix } = splitUrlSuffix(urlValue.trim()); if (!basePath) return null; const filePath = resolveWithinProject(projectDir, basePath); if (!filePath) return null; const ext = filePath.toLowerCase().match(/\.[^.]+$/)?.[0] ?? ""; const mimeType = INLINE_MIME[ext]; if (!mimeType) return null; const content = safeReadFileBuffer(filePath); if (content == null) return null; const dataUrl = `data:${mimeType};base64,${content.toString("base64")}`; return appendSuffixToUrl(dataUrl, suffix); } function warnColorGradingLutNotInlined(lutSrc: string): void { const trimmed = lutSrc.trim(); if (!isRelativeUrl(trimmed)) return; console.warn( `[HyperFrames] Could not inline color grading LUT "${trimmed}". The rendered bundle may not be self-contained.`, ); } // fallow-ignore-next-line complexity function rewriteColorGradingLutWithInlinedAssets(value: string, projectDir: string): string { if (!value.trim().startsWith("{")) return value; let parsed: unknown; try { parsed = JSON.parse(value); } catch { return value; } if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return value; const lut = Reflect.get(parsed, "lut"); if (typeof lut === "string") { const inlined = maybeInlineRelativeAssetUrl(lut, projectDir); if (!inlined) { warnColorGradingLutNotInlined(lut); return value; } Reflect.set(parsed, "lut", inlined); return JSON.stringify(parsed); } if (typeof lut !== "object" || lut === null || Array.isArray(lut)) return value; const lutSrc = Reflect.get(lut, "src"); if (typeof lutSrc !== "string") return value; const inlined = maybeInlineRelativeAssetUrl(lutSrc, projectDir); if (!inlined) { warnColorGradingLutNotInlined(lutSrc); return value; } Reflect.set(lut, "src", inlined); return JSON.stringify(parsed); } function rewriteSrcsetWithInlinedAssets(srcsetValue: string, projectDir: string): string { if (!srcsetValue) return srcsetValue; return srcsetValue .split(",") .map((rawCandidate) => { const candidate = rawCandidate.trim(); if (!candidate) return candidate; const parts = candidate.split(/\s+/); if (parts.length === 0) return candidate; const maybeInlined = maybeInlineRelativeAssetUrl(parts[0] ?? "", projectDir); if (maybeInlined) parts[0] = maybeInlined; return parts.join(" "); }) .join(", "); } function rewriteCssUrlsWithInlinedAssets(cssText: string, projectDir: string): string { if (!cssText) return cssText; return cssText.replace( /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g, (_full, quote: string, rawUrl: string) => { const maybeInlined = maybeInlineRelativeAssetUrl((rawUrl || "").trim(), projectDir); if (!maybeInlined) return _full; return `url(${quote || ""}${maybeInlined}${quote || ""})`; }, ); } function cssAttributeSelector(attr: string, value: string): string { const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); return `[${attr}="${escaped}"]`; } function uniqueCompositionId(baseId: string, index: number): string { return `${baseId}__hf${index}`; } export type BundledHostCompositionIdentity = { authoredCompositionId: string | null; runtimeCompositionId: string | null; }; function getBundledHostCompositionIdentity(host: Element): BundledHostCompositionIdentity { const currentCompositionId = (host.getAttribute("data-composition-id") || "").trim() || null; const authoredCompositionId = (host.getAttribute("data-hf-original-composition-id") || currentCompositionId || "").trim() || null; return { authoredCompositionId, runtimeCompositionId: currentCompositionId, }; } function getBundledTrackedCompositionHosts(document: Document): Element[] { const hosts = Array.from( document.querySelectorAll("[data-composition-src], [data-composition-id]"), ); return hosts.filter((host) => { if (host.hasAttribute("data-composition-src")) return true; const authoredCompositionId = getBundledHostCompositionIdentity(host).authoredCompositionId; if (!authoredCompositionId) return false; return !!document.getElementById(`${authoredCompositionId}-template`); }); } function shouldAssignBundledRuntimeCompositionId(host: Element, document: Document): boolean { if (host.hasAttribute("data-composition-src")) return true; const authoredCompositionId = getBundledHostCompositionIdentity(host).authoredCompositionId; if (!authoredCompositionId) return false; if (!document.getElementById(`${authoredCompositionId}-template`)) return false; return host.children.length === 0; } function countBundledAuthoredCompositionIds(hosts: Element[]): Map { const counts = new Map(); for (const host of hosts) { const authoredCompositionId = getBundledHostCompositionIdentity(host).authoredCompositionId; if (!authoredCompositionId) continue; counts.set(authoredCompositionId, (counts.get(authoredCompositionId) || 0) + 1); } return counts; } // fallow-ignore-next-line complexity export function assignBundledRuntimeCompositionIds( hosts: Element[], counts: Map = countBundledAuthoredCompositionIds(hosts), ): Map { const instanceByCompositionId = new Map(); const identities = new Map(); for (const host of hosts) { const { authoredCompositionId, runtimeCompositionId: previousRuntimeCompositionId } = getBundledHostCompositionIdentity(host); const shouldAssign = shouldAssignBundledRuntimeCompositionId(host, host.ownerDocument); if (!authoredCompositionId) { identities.set(host, { authoredCompositionId: null, runtimeCompositionId: previousRuntimeCompositionId, }); continue; } const duplicateInstance = (counts.get(authoredCompositionId) || 0) > 1; let runtimeCompositionId = previousRuntimeCompositionId || authoredCompositionId; if (shouldAssign) { const instanceIndex = duplicateInstance ? (instanceByCompositionId.get(authoredCompositionId) || 0) + 1 : 0; if (duplicateInstance) { instanceByCompositionId.set(authoredCompositionId, instanceIndex); host.setAttribute("data-hf-original-composition-id", authoredCompositionId); } else { host.removeAttribute("data-hf-original-composition-id"); } runtimeCompositionId = duplicateInstance ? uniqueCompositionId(authoredCompositionId, instanceIndex) : authoredCompositionId; host.setAttribute("data-composition-id", runtimeCompositionId); } identities.set(host, { authoredCompositionId, runtimeCompositionId, }); } return identities; } export function prepareFlattenedInnerRoot(innerRoot: Element): Element { const prepared = innerRoot.cloneNode(true) as Element; markFlattenedInnerRoot(prepared); const w = prepared.getAttribute("data-width"); const h = prepared.getAttribute("data-height"); const widthVal = w ? `${w}px` : "100%"; const heightVal = h ? `${h}px` : "100%"; const existingStyle = (prepared.getAttribute("style") || "").trim(); const fill = `width:${widthVal};height:${heightVal}`; prepared.setAttribute("style", existingStyle ? `${existingStyle};${fill}` : fill); return prepared; } function enforceCompositionPixelSizing(document: Document): void { const compositionEls = [ ...document.querySelectorAll("[data-composition-id][data-width][data-height]"), ]; if (compositionEls.length === 0) return; const sizeMap = new Map(); for (const el of compositionEls) { const compId = el.getAttribute("data-composition-id"); const w = Number(el.getAttribute("data-width")); const h = Number(el.getAttribute("data-height")); if (compId && Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) { sizeMap.set(compId, { w, h }); } } if (sizeMap.size === 0) return; for (const styleEl of document.querySelectorAll("style")) { let css = styleEl.textContent || ""; let modified = false; for (const [compId, { w, h }] of sizeMap) { const escaped = compId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const blockRe = new RegExp( `(\\[data-composition-id=["']${escaped}["']\\]\\s*\\{)([^}]*)(})`, "g", ); css = css.replace(blockRe, (_, open, body, close) => { const newBody = body .replace(/(\bwidth\s*:\s*)100%/g, `$1${w}px`) .replace(/(\bheight\s*:\s*)100%/g, `$1${h}px`); if (newBody !== body) modified = true; return open + newBody + close; }); } if (modified) styleEl.textContent = css; } } function autoHealMissingCompositionIds(document: Document): void { const compositionIdRe = /data-composition-id=["']([^"']+)["']/gi; const referencedIds = new Set(); for (const el of document.querySelectorAll("style, script")) { const text = (el.textContent || "").trim(); if (!text) continue; let match: RegExpExecArray | null; while ((match = compositionIdRe.exec(text)) !== null) { const compId = (match[1] || "").trim(); if (compId) referencedIds.add(compId); } } if (referencedIds.size === 0) return; const existingIds = new Set(); for (const el of document.querySelectorAll("[data-composition-id]")) { const id = (el.getAttribute("data-composition-id") || "").trim(); if (id) existingIds.add(id); } for (const compId of referencedIds) { if (compId === "root" || existingIds.has(compId)) continue; const candidates = [`${compId}-layer`, `${compId}-comp`, compId]; for (const targetId of candidates) { const found = document.getElementById(targetId); if (found && !found.getAttribute("data-composition-id")) { found.setAttribute("data-composition-id", compId); break; } } } } function coalesceHeadStylesAndBodyScripts(document: Document): void { const headStyleEls = [...document.querySelectorAll("head style")]; if (headStyleEls.length > 1) { const imports: string[] = []; const cssParts: string[] = []; const seenImports = new Set(); for (const el of headStyleEls) { const raw = (el.textContent || "").trim(); if (!raw) continue; const nonImportCss = raw.replace(CSS_IMPORT_RE, (match) => { const cleaned = match.trim(); if (!seenImports.has(cleaned)) { seenImports.add(cleaned); imports.push(cleaned); } return ""; }); const trimmed = nonImportCss.trim(); if (trimmed) cssParts.push(trimmed); } const merged = [...imports, ...cssParts].join("\n\n").trim(); if (merged) { headStyleEls[0]!.textContent = merged; for (let i = 1; i < headStyleEls.length; i++) headStyleEls[i]!.remove(); } } const bodyInlineScripts = [...document.querySelectorAll("body script")].filter((el) => { if (el.hasAttribute(RUNTIME_BOOTSTRAP_ATTR) || el.hasAttribute("src")) return false; const type = (el.getAttribute("type") || "").trim().toLowerCase(); return !type || type === "text/javascript" || type === "application/javascript"; }); if (bodyInlineScripts.length > 0) { const mergedJs = joinJsChunks(bodyInlineScripts.map((el) => el.textContent || "")); for (const el of bodyInlineScripts) el.remove(); if (mergedJs) { const stripped = stripJsCommentsParserSafe(mergedJs); const inlineScript = document.createElement("script"); inlineScript.textContent = stripped; document.body.appendChild(inlineScript); } } } /** * Force subpixel glyph positioning so headless rendering paths * (chrome-headless-shell with BeginFrame) lay text out identically to full * Chrome. `text-rendering: auto` resolves to `optimizeSpeed` (integer glyph * advances) in headless-shell but `geometricPrecision` in full Chrome, which * shifts line-wrap points and any animation that reads measured text width. * Mirrors the producer's `injectTextRenderingRule` so bundled previews and * compiled renders stay byte-aligned. `*` has zero specificity, so authored * class/id rules still override. */ function injectTextRenderingRule(document: Document): void { const head = document.head; if (!head) return; if (document.querySelector("style[data-hyperframes-text-rendering]")) return; const styleEl = document.createElement("style"); styleEl.setAttribute("data-hyperframes-text-rendering", "true"); styleEl.textContent = "html,body,*{text-rendering:geometricPrecision}"; head.insertBefore(styleEl, head.firstChild); } /** * Concatenate JS chunks safely. Goals: * - Each chunk's last statement is terminated, so joining can't introduce ASI * surprises (e.g. `a()` followed by `(b)()` — the second chunk would parse * as a call on the first's return value). * - In the common case (chunk already ends with `;` — typical of esbuild * output and IIFE-wrapped composition scripts ending in `})();`), the join * produces clean output: chunks separated by `\n` with no stray bare * semicolon lines. * - Defensive against trailing line comments. If a chunk ends with `// ...` * and we appended `;` on the same line, the appended semicolon would be * swallowed by the comment, leaving the next chunk's first statement * attached to the previous chunk's last expression — exactly the ASI * hazard this helper exists to prevent. So when a chunk doesn't already * end in `;`, we append `\n;` instead — the newline closes any line * comment, and the standalone `;` becomes the statement separator. */ function joinJsChunks(chunks: string[]): string { return chunks .map((chunk) => chunk.trim()) .filter((chunk) => chunk.length > 0) .map((chunk) => (chunk.endsWith(";") ? chunk : chunk + "\n;")) .join("\n"); } function stripJsCommentsParserSafe(source: string): string { if (!source) return source; try { const result = transformSync(source, { loader: "js", minify: false, legalComments: "none" }); return result.code.trim(); } catch { return source; } } export interface BundleOptions { /** Project-relative HTML entry to bundle. Defaults to `index.html`. */ entryFile?: string; /** Optional media duration prober (e.g., ffprobe). If omitted, media durations are not resolved. */ probeMediaDuration?: MediaDurationProber; /** * How to handle the HyperFrames runtime ` so the caller can * substitute it with a real URL via string replace. Used by the dev studio * server and vite preview to point at a local runtime endpoint, which keeps * the runtime cacheable across hot-reloads instead of re-inlining ~150 KB * on every change. * * The `HYPERFRAME_RUNTIME_URL` env var, when set, takes precedence over both * modes and emits `