fix: serve design studio through the component app production route
This commit is contained in:
1 parent
3987ddbcfe
commit
9a6a2e0a8d
11 files changed
+174
-47
No files matched your search
+4
-18
@@ -1,18 +1,4 @@
|
||||
import { startStudio } from "./studio.ts";
|
||||
|
||||
const studio = await startStudio();
|
||||
const site = Bun.spawn([process.execPath, "dist/server.js"], {
|
||||
stdout: "inherit",
|
||||
stderr: "inherit",
|
||||
stdin: "inherit",
|
||||
env: process.env,
|
||||
});
|
||||
const stop = () => {
|
||||
studio.stop(true);
|
||||
site.kill("SIGTERM");
|
||||
};
|
||||
process.on("SIGINT", stop);
|
||||
process.on("SIGTERM", stop);
|
||||
const code = await site.exited;
|
||||
studio.stop(true);
|
||||
process.exit(code);
|
||||
// Compatibility entry point: Studio is mounted in the app middleware now.
|
||||
const entry = "../dist/server.js";
|
||||
await import(entry);
|
||||
export {};
|
||||
@@ -0,0 +1,78 @@
|
||||
import { CORE_DESIGN_SYSTEMS } from "@wrnexus/design-system";
|
||||
|
||||
// Exercise the compiled entry point, including package-relative Studio assets.
|
||||
const reservation = Bun.serve({
|
||||
port: 0,
|
||||
hostname: "127.0.0.1",
|
||||
fetch: () => new Response(),
|
||||
});
|
||||
const port = reservation.port!;
|
||||
reservation.stop(true);
|
||||
const server = Bun.spawn([process.execPath, "dist/server.js"], {
|
||||
env: { ...process.env, PORT: String(port) },
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
const origin = `http://127.0.0.1:${port}`;
|
||||
try {
|
||||
let ready = false;
|
||||
for (let attempt = 0; attempt < 60; attempt++) {
|
||||
try {
|
||||
ready = (await fetch(origin)).ok;
|
||||
} catch {
|
||||
/* Wait for the server to listen. */
|
||||
}
|
||||
if (ready) break;
|
||||
await Bun.sleep(100);
|
||||
}
|
||||
if (!ready) throw Error("Compiled server did not become ready.");
|
||||
for (const path of [
|
||||
"/",
|
||||
"/components/button",
|
||||
"/design-studio/",
|
||||
"/design-studio/studio.js",
|
||||
"/design-studio/studio.css",
|
||||
]) {
|
||||
const response = await fetch(origin + path);
|
||||
if (!response.ok) throw Error(`${path} returned ${response.status}`);
|
||||
const policy = response.headers.get("content-security-policy") ?? "";
|
||||
if (path === "/" && !policy.includes("require-trusted-types-for"))
|
||||
throw Error(
|
||||
"Normal component pages lost the production security policy.",
|
||||
);
|
||||
if (
|
||||
path === "/design-studio/" &&
|
||||
(!policy.includes("frame-ancestors 'none'") ||
|
||||
policy.includes("require-trusted-types-for"))
|
||||
)
|
||||
throw Error("The app replaced Studio's isolated editor security policy.");
|
||||
}
|
||||
const application = await (
|
||||
await fetch(origin + "/design-studio/api/application")
|
||||
).json();
|
||||
if (application.enabled !== false)
|
||||
throw Error("Hosted Studio must remain export-only.");
|
||||
const preview = await fetch(origin + "/design-studio/api/preview", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json", origin },
|
||||
body: JSON.stringify({ system: CORE_DESIGN_SYSTEMS.soft }),
|
||||
});
|
||||
if (!preview.ok)
|
||||
throw Error(
|
||||
`Studio preview returned ${preview.status}: ${await preview.text()}`,
|
||||
);
|
||||
const { url } = await preview.json();
|
||||
if (
|
||||
!url.startsWith("/design-studio/preview/") ||
|
||||
!(await fetch(origin + url)).ok
|
||||
)
|
||||
throw Error("Studio preview was not mounted under the app path.");
|
||||
console.log(
|
||||
"Compiled server serves component pages, Studio assets, export-only APIs and previews on one port.",
|
||||
);
|
||||
} finally {
|
||||
server.kill("SIGTERM");
|
||||
await server.exited;
|
||||
const errors = await new Response(server.stderr).text();
|
||||
if (errors.trim()) console.error(errors);
|
||||
}
|
||||
Reference in new issue
Block a user