import { Link } from "@tanstack/react-router"; import { useEffect, useRef, useState } from "react"; import { mintEditorSession } from "~/fns/editor"; /** * The workbench runs on its own origin, so it is a normal (not opaque) document there: VS Code needs * IndexedDB, workers and webviews. It still can't reach forge cookies or pages, because those live on * a different origin, and the CSP on that origin pins what it may load and contact. */ const FRAME_SANDBOX = "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-downloads"; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } /** * Hosts VS Code for the Web for one ref. This page mints a ref-scoped editor token with the session * cookie and hands it to the editor origin over postMessage (exact target origin, re-checked after the * await), and re-mints when the editor asks for a refresh. The editor never sees cookies. */ export function WorkspaceEditor({ owner, repo, gitRef, editorOrigin, }: { owner: string; repo: string; gitRef: string; editorOrigin: string | null; }) { const frame = useRef(null); const [error, setError] = useState( editorOrigin ? null : "The editor origin isn't configured (set EDITOR_ORIGIN).", ); useEffect(() => { if (!editorOrigin) return; const origin = editorOrigin; async function handOver(target: Window, source: MessageEventSource | null) { try { const session = await mintEditorSession({ data: { owner, repo, ref: gitRef } }); if (frame.current?.contentWindow !== source) return; target.postMessage({ type: "gitfor-editor:init", session }, origin); } catch (failure) { setError(failure instanceof Error ? failure.message : "Couldn't start the editor"); } } function onMessage(event: MessageEvent) { const target = frame.current?.contentWindow; const message: unknown = event.data; if (!target || event.source !== target || event.origin !== origin || !isRecord(message)) return; if (message.type === "gitfor-editor:ready" || message.type === "gitfor-editor:refresh") { void handOver(target, event.source); } if (message.type === "gitfor-editor:error") setError(String(message.message ?? "The editor failed to load")); } window.addEventListener("message", onMessage); return () => window.removeEventListener("message", onMessage); }, [owner, repo, gitRef, editorOrigin]); return (
← {owner}/{repo} {gitRef} {error && ( {error} )}
{editorOrigin && (