@bettercms-ai/preview-runtime 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -576,7 +576,13 @@ async function runValidationBatch(batch, ctx, deps) {
576
576
  }
577
577
  await deps.api(`/api/v1/projects/${ctx.projectId}/component-preview/bundles`, {
578
578
  method: "POST",
579
- body: { commitSha: ctx.commitSha, uploadKey: upload.uploadKey, checksum: `sha256:${sha256(runtime.bundle)}`, sizeBytes: runtime.bundle.byteLength }
579
+ body: {
580
+ commitSha: ctx.commitSha,
581
+ uploadKey: upload.uploadKey,
582
+ checksum: `sha256:${sha256(runtime.bundle)}`,
583
+ sizeBytes: runtime.bundle.byteLength,
584
+ ...deps.runtimeVersion ? { runtimeVersion: deps.runtimeVersion } : {}
585
+ }
580
586
  });
581
587
  } catch (error) {
582
588
  await runtime?.close().catch(() => {
@@ -784,7 +790,8 @@ async function renderInBrowser(browser, url, viewports, tokenNames, options, sig
784
790
  async function validateComponent() {
785
791
  const apiUrl = required("BCMS_API_URL");
786
792
  const apiKey = required("BCMS_API_KEY");
787
- const batch = resolveBatch();
793
+ const refresh = resolveRefresh();
794
+ const batch = refresh ? [] : resolveBatch();
788
795
  const ctx = {
789
796
  projectId: required("BCMS_PROJECT_ID"),
790
797
  commitSha: required("BCMS_COMMIT_SHA"),
@@ -915,26 +922,33 @@ async function validateComponent() {
915
922
  }
916
923
  };
917
924
  };
925
+ const putBundle = async (uploadUrl, bytes) => {
926
+ try {
927
+ const put = await fetch(uploadUrl, {
928
+ method: "PUT",
929
+ body: new Uint8Array(bytes),
930
+ headers: { "content-type": "application/gzip" },
931
+ signal: AbortSignal.timeout(BUNDLE_UPLOAD_TIMEOUT_MS)
932
+ });
933
+ return { ok: put.ok, status: put.status };
934
+ } catch (error) {
935
+ const name = error.name;
936
+ if (name !== "TimeoutError" && name !== "AbortError") throw error;
937
+ throw new ValidationFailure("COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED", `Storage did not accept the preview bundle within ${BUNDLE_UPLOAD_TIMEOUT_MS / 6e4} minutes.`);
938
+ }
939
+ };
940
+ const runtimeVersion = runnerVersion();
918
941
  const budget = Number(process.env.BCMS_BATCH_BUDGET_MS);
919
942
  try {
943
+ if (refresh) {
944
+ await runRuntimeRefresh(refresh, ctx, { api, prepare, putBundle, runtimeVersion });
945
+ return;
946
+ }
920
947
  const result = await runValidationBatch(batch, ctx, {
921
948
  api,
922
949
  prepare,
923
- putBundle: async (uploadUrl, bytes) => {
924
- try {
925
- const put = await fetch(uploadUrl, {
926
- method: "PUT",
927
- body: new Uint8Array(bytes),
928
- headers: { "content-type": "application/gzip" },
929
- signal: AbortSignal.timeout(BUNDLE_UPLOAD_TIMEOUT_MS)
930
- });
931
- return { ok: put.ok, status: put.status };
932
- } catch (error) {
933
- const name = error.name;
934
- if (name !== "TimeoutError" && name !== "AbortError") throw error;
935
- throw new ValidationFailure("COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED", `Storage did not accept the preview bundle within ${BUNDLE_UPLOAD_TIMEOUT_MS / 6e4} minutes.`);
936
- }
937
- },
950
+ putBundle,
951
+ runtimeVersion,
938
952
  budgetMs: Number.isFinite(budget) && budget > 0 ? budget : DEFAULT_BATCH_BUDGET_MS
939
953
  });
940
954
  if (batch.length > 1) {
@@ -945,6 +959,131 @@ async function validateComponent() {
945
959
  rmSync2(work, { recursive: true, force: true });
946
960
  }
947
961
  }
962
+ function runnerVersion() {
963
+ try {
964
+ const version = createRequire2(import.meta.url)("../package.json").version;
965
+ return typeof version === "string" ? version : void 0;
966
+ } catch {
967
+ return void 0;
968
+ }
969
+ }
970
+ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
971
+ var isRefreshItem = (value) => {
972
+ if (!value || typeof value !== "object") return false;
973
+ const item = value;
974
+ return ["componentId", "familyKey"].every((key) => typeof item[key] === "string" && item[key].trim() !== "") && Array.isArray(item.nativeViewports) && item.nativeViewports.length > 0 && item.nativeViewports.every(isViewport);
975
+ };
976
+ function resolveRefresh(env = process.env) {
977
+ const raw = env.BCMS_REFRESH?.trim();
978
+ if (!raw || raw === "null") return null;
979
+ let parsed;
980
+ try {
981
+ parsed = JSON.parse(raw);
982
+ } catch {
983
+ throw new CliFailure("COMPONENT_PREVIEW_REFRESH_INVALID: BCMS_REFRESH is not valid JSON.");
984
+ }
985
+ const plan = parsed;
986
+ if (!plan || typeof plan.refreshId !== "string" || !UUID.test(plan.refreshId) || !Array.isArray(plan.items) || plan.items.length === 0 || !plan.items.every(isRefreshItem)) {
987
+ throw new CliFailure("COMPONENT_PREVIEW_REFRESH_INVALID: BCMS_REFRESH must be { refreshId, items: [{ componentId, familyKey, nativeViewports }] }.");
988
+ }
989
+ return { refreshId: plan.refreshId, items: plan.items };
990
+ }
991
+ async function runRuntimeRefresh(plan, ctx, deps) {
992
+ const log = deps.log ?? ((line) => console.log(line));
993
+ const logError = deps.error ?? ((line) => console.error(line));
994
+ const propsMs = deps.timeouts?.propsMs ?? LOCAL_FETCH_TIMEOUT_MS;
995
+ const renderPerViewportMs = deps.timeouts?.renderPerViewportMs ?? RENDER_TIMEOUT_PER_VIEWPORT_MS;
996
+ const base = `/api/v1/projects/${ctx.projectId}`;
997
+ const fail2 = async (error) => {
998
+ const code = error instanceof ValidationFailure ? error.code : "COMPONENT_PREVIEW_REFRESH_FAILED";
999
+ const message = error.message.slice(0, 2e3);
1000
+ logError(`bcms-preview: ${code}: ${message} (runtime refresh ${plan.refreshId})`);
1001
+ await deps.api(`${base}/component-preview/refreshes/${plan.refreshId}/fail`, {
1002
+ method: "POST",
1003
+ body: { errorCode: code, errorMessage: message }
1004
+ }).catch((reportError) => logError(`bcms-preview: could not report the refresh failure: ${reportError.message}`));
1005
+ throw new CliFailure(`${code}: ${message}`);
1006
+ };
1007
+ let manifest;
1008
+ try {
1009
+ manifest = await deps.api(`${base}/component-preview/manifest?kinds=page`);
1010
+ } catch (error) {
1011
+ return fail2(error);
1012
+ }
1013
+ const missing = plan.items.filter((item) => !manifest.components.some((c) => c.id === item.componentId)).map((item) => item.componentId);
1014
+ if (missing.length > 0) {
1015
+ return fail2(new ValidationFailure(
1016
+ "COMPONENT_SOURCE_NOT_RECORDED",
1017
+ `Nothing to render for ${missing.join(", ")}: no file is recorded and it is neither placed on a page nor used in the layout. Validate it again.`
1018
+ ));
1019
+ }
1020
+ const listed = new Set(plan.items.map((item) => item.componentId));
1021
+ const scoped = { ...manifest, components: manifest.components.filter((c) => listed.has(c.id)) };
1022
+ let runtime;
1023
+ try {
1024
+ runtime = await deps.prepare(scoped);
1025
+ } catch (error) {
1026
+ return fail2(error);
1027
+ }
1028
+ const ready = runtime;
1029
+ try {
1030
+ const problems = [];
1031
+ for (const item of plan.items) {
1032
+ const entry = scoped.components.find((c) => c.id === item.componentId);
1033
+ try {
1034
+ const renderId = await bounded(
1035
+ `The preview runtime's props endpoint for ${item.componentId}`,
1036
+ propsMs,
1037
+ (signal) => ready.storeProps(item.componentId, entry.defaultProps, signal)
1038
+ );
1039
+ const render = await bounded(
1040
+ `Rendering ${item.componentId}`,
1041
+ renderPerViewportMs * item.nativeViewports.length,
1042
+ (signal) => ready.render(renderId, item.nativeViewports, scoped.brandTokenNames, { section: ready.kinds[item.componentId] !== "file" }, signal)
1043
+ );
1044
+ const lines = [
1045
+ ...render.missingTokens.length ? [`brand tokens used but not defined: ${render.missingTokens.join(", ")}`] : [],
1046
+ ...render.runtimeErrors + render.consoleErrors > 0 ? render.problems.length ? render.problems : [`${render.runtimeErrors + render.consoleErrors} runtime or console error(s)`] : []
1047
+ ];
1048
+ if (lines.length > 0) problems.push(`${item.componentId}: ${lines.slice(0, 3).map((line) => line.slice(0, 200)).join("; ")}`);
1049
+ else log(`bcms-preview: runtime refresh renders ${item.componentId}`);
1050
+ } catch (error) {
1051
+ problems.push(`${item.componentId}: ${error.message.slice(0, 200)}`);
1052
+ }
1053
+ }
1054
+ if (problems.length > 0) {
1055
+ return fail2(new ValidationFailure(
1056
+ "COMPONENT_PREVIEW_REFRESH_RENDER_FAILED",
1057
+ `Kept the current runtime: ${problems.length} of ${plan.items.length} component(s) did not render cleanly with this runner. ${problems.join(" | ")}`
1058
+ ));
1059
+ }
1060
+ try {
1061
+ const upload = await deps.api(`${base}/artifacts/upload-url`, { method: "POST" });
1062
+ const put = await deps.putBundle(upload.uploadUrl, ready.bundle);
1063
+ if (!put.ok) {
1064
+ throw new ValidationFailure("COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED", `Storage refused the preview bundle (HTTP ${put.status}).`);
1065
+ }
1066
+ await deps.api(`${base}/component-preview/bundles`, {
1067
+ method: "POST",
1068
+ body: {
1069
+ commitSha: ctx.commitSha,
1070
+ uploadKey: upload.uploadKey,
1071
+ checksum: `sha256:${sha256(ready.bundle)}`,
1072
+ sizeBytes: ready.bundle.byteLength,
1073
+ refreshId: plan.refreshId,
1074
+ ...deps.runtimeVersion ? { runtimeVersion: deps.runtimeVersion } : {}
1075
+ }
1076
+ });
1077
+ } catch (error) {
1078
+ return fail2(error);
1079
+ }
1080
+ log(`bcms-preview: runtime refreshed for ${plan.items.length} component(s) at ${ctx.commitSha}`);
1081
+ return { refreshed: true };
1082
+ } finally {
1083
+ await ready.close().catch(() => {
1084
+ });
1085
+ }
1086
+ }
948
1087
 
949
1088
  // src/cli.ts
950
1089
  function arg(name) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/build.ts","../src/validate.ts","../src/cli.ts"],"sourcesContent":["/**\n * Builds a component preview runtime from an unmodified Next.js or Astro app. Used by `bcms-preview build`\n * and by the validator.\n *\n * The manifest names which file implements which component:\n * { \"components\": [{ \"id\": \"cmp_1\", \"source\": { \"path\": \"src/components/Hero.astro\" } }] }\n *\n * 🔴 NOTHING IN THE CUSTOMER'S REPOSITORY IS CHANGED. Routes and a registry are generated into the\n * checkout, the framework builds, the result is packaged as a runtime release, and every generated file\n * is removed again — including when the build fails. In CI the checkout is thrown away anyway; on a\n * developer machine this is the difference between a tool and a mess.\n */\nimport { spawnSync } from \"node:child_process\";\nimport { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, extname, join, relative, resolve, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * `file`: a component module whose props ARE the component's fields — rendered with the props spread.\n * `section`: a section `npx @bettercms-ai/convert --componentize` extracted from a page. Its props are always\n * `{ blockId, bind, overrides, page }`, so it is rendered with the live props as `overrides`.\n * `page`: no file at all — the component is a placement on a page, or a section of the layout. The runtime\n * renders that page and keeps only the component's section (see scope.ts). Derived by the platform, never recorded.\n */\ntype SourceKind = \"file\" | \"section\" | \"page\";\ntype FileSource = { path: string; export?: string; kind?: \"file\" | \"section\" };\ntype PageSource = {\n kind: \"page\";\n route: string;\n blockId?: string;\n groupKey?: string | null;\n source?: Record<string, string> | null;\n layoutSectionId?: string;\n landmark?: \"header\" | \"footer\" | \"nav\" | null;\n bindings?: Record<string, string>;\n};\ntype ManifestEntry = { id: string; source: FileSource | PageSource };\ntype Manifest = { components: ManifestEntry[] };\ntype Framework = \"astro\" | \"next\";\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst PREVIEW_BASE = \"/__bettercms/component-preview\";\nconst COMPONENT_EXTENSIONS = new Set([\".astro\", \".tsx\", \".jsx\", \".ts\", \".js\", \".mjs\"]);\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n/** Every section file the codemod writes carries this (`// @bettercms-ai/convert section v2`, earlier `v1`). */\nconst SECTION_MARKER_PREFIX = \"// @bettercms-ai/convert section v\";\n\n/**\n * 🔴 THROWN, NOT `process.exit`. Writes to a piped stderr are asynchronous in Node, so exiting on the\n * next line dropped the message: in CI the step failed with no reason in the log at all. The single\n * handler at the bottom prints and sets the exit code, and the process ends once the write has flushed.\n */\nexport class CliFailure extends Error {}\n\nexport function fail(message: string): never {\n throw new CliFailure(message);\n}\n\n/**\n * Files a framework build rewrites in place. `next build` edits tsconfig.json and next-env.d.ts; an\n * `npm install --no-save` still rewrites the lockfile. Restored afterwards, so a preview build leaves the\n * app exactly as it found it.\n */\nfunction snapshot(root: string, names: string[]): () => void {\n const saved = names.map((name) => {\n const file = join(root, name);\n return { file, content: existsSync(file) ? readFileSync(file) : null };\n });\n return () => {\n for (const { file, content } of saved) {\n if (content === null) rmSync(file, { force: true });\n else writeFileSync(file, content);\n }\n };\n}\n\nconst MUTATED_BY_BUILD = [\"tsconfig.json\", \"next-env.d.ts\", \"package-lock.json\", \"pnpm-lock.yaml\", \"yarn.lock\", \"bun.lock\"];\n\nfunction readJson<T>(file: string): T {\n try {\n return JSON.parse(readFileSync(file, \"utf8\")) as T;\n } catch (error) {\n fail(`could not read ${file}: ${(error as Error).message}`);\n }\n}\n\nconst LANDMARKS = new Set([\"header\", \"footer\", \"nav\"]);\nconst isStringRecord = (value: unknown) =>\n !!value && typeof value === \"object\" && !Array.isArray(value) && Object.values(value).every((v) => typeof v === \"string\");\n\n/** A page source travels into a generated module as data: a same-origin path and plain strings, nothing else. */\nfunction pageSource(id: string, source: PageSource): PageSource {\n const { route, blockId, groupKey, layoutSectionId, landmark } = source;\n if (typeof route !== \"string\" || !route.startsWith(\"/\") || route.startsWith(\"//\") || /[\\s?#\\\\]/.test(route) || route.split(\"/\").includes(\"..\")) {\n fail(`component ${id} has an unsafe page route: ${String(route)}`);\n }\n if (typeof blockId === \"string\" && blockId) {\n if (groupKey != null && typeof groupKey !== \"string\") fail(`component ${id}: groupKey must be a string`);\n if (source.source != null && !isStringRecord(source.source)) fail(`component ${id}: source must map prop keys to page paths`);\n return { kind: \"page\", route, blockId, groupKey: groupKey ?? null, source: source.source ?? null };\n }\n if (typeof layoutSectionId === \"string\" && layoutSectionId) {\n if (landmark != null && !LANDMARKS.has(landmark)) fail(`component ${id}: unknown landmark ${String(landmark)}`);\n if (source.bindings != null && !isStringRecord(source.bindings)) fail(`component ${id}: bindings must map input ids to layout field ids`);\n return { kind: \"page\", route, layoutSectionId, landmark: landmark ?? null, bindings: source.bindings ?? {} };\n }\n fail(`component ${id}: a page source names neither a placement (blockId) nor a layout section (layoutSectionId)`);\n}\n\n/** Manifest paths travel from an API into generated imports: relative, inside the app, and real. */\nexport function validateManifest(root: string, manifest: Manifest): ManifestEntry[] {\n if (!manifest || !Array.isArray(manifest.components) || manifest.components.length === 0) {\n fail(\"the manifest lists no components\");\n }\n const seen = new Set<string>();\n return manifest.components.map((entry) => {\n if (!entry || typeof entry.id !== \"string\" || !entry.id.trim()) fail(\"a manifest entry has no id\");\n if (seen.has(entry.id)) fail(`component ${entry.id} is listed twice`);\n seen.add(entry.id);\n if (entry.source?.kind === \"page\") return { id: entry.id, source: pageSource(entry.id, entry.source) };\n const path = entry.source?.path;\n if (typeof path !== \"string\" || path.startsWith(\"/\") || path.includes(\"\\\\\") || path.split(\"/\").includes(\"..\")) {\n fail(`component ${entry.id} has an unsafe source path: ${String(path)}`);\n }\n if (!COMPONENT_EXTENSIONS.has(extname(path))) fail(`component ${entry.id}: unsupported file type ${extname(path)}`);\n if (!existsSync(join(root, path))) fail(`component ${entry.id}: ${path} does not exist`);\n const named = entry.source.export;\n if (named !== undefined && named !== \"default\" && !IDENTIFIER.test(named)) {\n fail(`component ${entry.id}: export \"${named}\" is not a valid identifier`);\n }\n // A section is recognised by its own marker as well as by the manifest: a source recorded before kinds\n // existed defaults to `file`, and rendering a section as a file hands it none of its copy.\n const head = readFileSync(join(root, path), \"utf8\").slice(0, 512);\n const kind: SourceKind = entry.source.kind === \"section\" || head.includes(SECTION_MARKER_PREFIX) ? \"section\" : \"file\";\n return { id: entry.id, source: { path, export: named ?? \"default\", kind } };\n });\n}\n\nfunction detectFramework(root: string): Framework {\n const pkg = readJson<{ dependencies?: Record<string, string>; devDependencies?: Record<string, string> }>(join(root, \"package.json\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.astro) return \"astro\";\n if (deps.next) return \"next\";\n fail(\"this app depends on neither astro nor next\");\n}\n\nfunction run(root: string, command: string, args: string[]) {\n const result = spawnSync(command, args, { cwd: root, stdio: \"inherit\", env: process.env });\n if (result.status !== 0) throw new Error(`${command} ${args.join(\" \")} exited with ${result.status}`);\n}\n\nfunction bin(root: string, name: string): string {\n const local = join(root, \"node_modules\", \".bin\", name);\n if (!existsSync(local)) fail(`${name} is not installed in ${root}. Install the app's dependencies first.`);\n return local;\n}\n\n/** A registry module: one import per file component, one data entry per page component, keyed by component id. */\nexport function registrySource(fromDir: string, root: string, entries: ManifestEntry[]): string {\n const imports: string[] = [];\n const keys: string[] = [];\n const kinds: string[] = [];\n const pages: string[] = [];\n entries.forEach((entry, index) => {\n const source = entry.source;\n kinds.push(` ${JSON.stringify(entry.id)}: ${JSON.stringify(source.kind ?? \"file\")},`);\n if (source.kind === \"page\") {\n pages.push(` ${JSON.stringify(entry.id)}: ${JSON.stringify(source)},`);\n return;\n }\n let specifier = relative(fromDir, join(root, source.path)).split(sep).join(\"/\");\n if (!specifier.startsWith(\".\")) specifier = `./${specifier}`;\n // TypeScript sources are imported without their extension, the way the app itself imports them.\n if ([\".tsx\", \".ts\", \".jsx\", \".js\"].includes(extname(specifier))) specifier = specifier.slice(0, -extname(specifier).length);\n const local = `Component${index}`;\n imports.push(source.export === undefined || source.export === \"default\"\n ? `import ${local} from ${JSON.stringify(specifier)};`\n : `import { ${source.export} as ${local} } from ${JSON.stringify(specifier)};`);\n keys.push(` ${JSON.stringify(entry.id)}: ${local},`);\n });\n return `${imports.join(\"\\n\")}\\n\\nexport const registry: Record<string, any> = {\\n${keys.join(\"\\n\")}\\n};\\n\\nexport const kinds: Record<string, \"file\" | \"section\" | \"page\"> = {\\n${kinds.join(\"\\n\")}\\n};\\n\\nexport const pages: Record<string, any> = {\\n${pages.join(\"\\n\")}\\n};\\n\\nconst own = (map: object, componentId: string) => Object.prototype.hasOwnProperty.call(map, componentId);\\nexport const has = (componentId: string): boolean => own(registry, componentId) || own(pages, componentId);\\n`;\n}\n\nfunction writeRuntimeLibrary(dir: string) {\n writeFileSync(join(dir, \"server.mjs\"), readFileSync(join(here, \"server.js\"), \"utf8\"));\n const types = join(here, \"server.d.ts\");\n if (existsSync(types)) writeFileSync(join(dir, \"server.d.mts\"), readFileSync(types, \"utf8\"));\n writeFileSync(join(dir, \"shell.ts\"), `export default ${JSON.stringify(readFileSync(join(here, \"shell.global.js\"), \"utf8\"))};\\n`);\n writeFileSync(join(dir, \"scope.ts\"), `export default ${JSON.stringify(readFileSync(join(here, \"scope-client.global.js\"), \"utf8\"))};\\n`);\n}\n\n/** CSS the app's layouts import. The render page has no layout, so it imports them itself. */\nfunction astroGlobalStyles(root: string): string[] {\n const found = new Set<string>();\n const scan = (dir: string) => {\n if (!existsSync(dir)) return;\n for (const name of readdirSync(dir)) {\n const full = join(dir, name);\n if (statSync(full).isDirectory()) scan(full);\n else if (name.endsWith(\".astro\")) {\n for (const match of readFileSync(full, \"utf8\").matchAll(/^\\s*import\\s+[\"']([^\"']+\\.css)[\"'];?/gm)) {\n const target = resolve(dirname(full), match[1]!);\n if (target.startsWith(root) && existsSync(target)) found.add(target);\n }\n }\n }\n };\n scan(join(root, \"src\", \"layouts\"));\n return [...found];\n}\n\nconst ASTRO_NODE_ADAPTER: Record<string, string> = { \"5\": \"^9\", \"6\": \"^10\", \"7\": \"^11\" };\n\nfunction ensureAstroNodeAdapter(root: string) {\n const require = createRequire(join(root, \"package.json\"));\n try {\n require.resolve(\"@astrojs/node\");\n return;\n } catch {\n // Not installed: add it without touching package.json or the lockfile.\n }\n const astroVersion = readJson<{ version: string }>(require.resolve(\"astro/package.json\")).version;\n const [major, minor] = astroVersion.split(\".\").map(Number);\n // @astrojs/node 11.1.3+ calls `app.getLogger()`, which Astro only has from 7.3 (its peer range still says\n // ^7.2.1), so on 7.0–7.2 the server crashed at startup: \"app.getLogger is not a function\".\n const range = major === 7 && minor! < 3 ? \">=11.0.0 <11.1.3\" : ASTRO_NODE_ADAPTER[String(major)];\n if (!range) fail(`Astro ${astroVersion} is not supported for component previews yet`);\n run(root, \"npm\", [\"install\", \"--no-save\", \"--no-audit\", \"--no-fund\", `@astrojs/node@${range}`]);\n}\n\nfunction buildAstro(root: string, entries: ManifestEntry[], out: string) {\n const configName = [\"astro.config.mjs\", \"astro.config.js\", \"astro.config.ts\", \"astro.config.mts\"].find((f) => existsSync(join(root, f)));\n if (!configName) fail(\"no astro.config file found\");\n ensureAstroNodeAdapter(root);\n\n const gen = join(root, \".bcms-preview\");\n const wrapper = join(root, \"astro.config.bcms-preview.mjs\");\n rmSync(gen, { recursive: true, force: true });\n mkdirSync(gen, { recursive: true });\n try {\n writeRuntimeLibrary(gen);\n writeFileSync(join(gen, \"registry.ts\"), registrySource(gen, root, entries));\n const handler = (method: string, body: string) =>\n `export const prerender = false;\\nexport const ${method} = ${body};\\n`;\n writeFileSync(join(gen, \"runtime.ts\"), `import { handleRuntime } from \"./server.mjs\";\\nimport shell from \"./shell\";\\n${handler(\"GET\", \"() => handleRuntime(shell)\")}`);\n writeFileSync(join(gen, \"session.ts\"), `import { handleSession } from \"./server.mjs\";\\nimport { has } from \"./registry\";\\n${handler(\"POST\", \"({ request }: { request: Request }) => handleSession(request, has)\")}`);\n writeFileSync(join(gen, \"props.ts\"), `import { handleProps } from \"./server.mjs\";\\nimport { has } from \"./registry\";\\n${handler(\"POST\", \"({ request }: { request: Request }) => handleProps(request, has)\")}`);\n writeFileSync(join(gen, \"health.ts\"), `import { handleHealth } from \"./server.mjs\";\\n${handler(\"GET\", \"() => handleHealth()\")}`);\n const styles = astroGlobalStyles(root)\n .map((file) => `import ${JSON.stringify(relative(gen, file).split(sep).join(\"/\"))};`)\n .join(\"\\n\");\n writeFileSync(join(gen, \"render.astro\"), `---\n${styles}\nimport { renderEntry, renderHeaders, renderPageSection } from \"./server.mjs\";\nimport { registry, kinds, pages } from \"./registry\";\nimport scope from \"./scope\";\nexport const prerender = false;\nconst headers = renderHeaders();\nconst entry = renderEntry(Astro.url.searchParams.get(\"id\"));\nif (entry && pages[entry.componentId]) return await renderPageSection(Astro.request, entry, pages[entry.componentId], scope);\nconst Component = entry ? registry[entry.componentId] : undefined;\nconst section = entry ? kinds[entry.componentId] === \"section\" : false;\nfor (const [name, value] of Object.entries(headers)) Astro.response.headers.set(name, value);\nif (!entry || !Component) return new Response(\"Not found\", { status: 404, headers });\n---\n<html lang=\"en\" data-bcms-preview-render=\"1\">\n <head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /></head>\n <body>{section ? <Component blockId=\"bcms-preview\" overrides={entry.props} page={{}} /> : <Component {...entry.props} />}</body>\n</html>\n`);\n writeFileSync(wrapper, `import user from \"./${configName}\";\nimport node from \"@astrojs/node\";\n\nconst routes = [\"runtime.ts\", \"session.ts\", \"props.ts\", \"render.astro\", \"health.ts\"];\n\nexport default {\n ...user,\n output: \"server\",\n base: ${JSON.stringify(PREVIEW_BASE)},\n adapter: node({ mode: \"standalone\" }),\n integrations: [\n ...(user.integrations ?? []),\n {\n name: \"bettercms-component-preview\",\n hooks: {\n \"astro:config:setup\": ({ injectRoute }) => {\n for (const file of routes) {\n injectRoute({\n pattern: \"/__bcms/\" + file.replace(/\\\\.(ts|astro)$/, \"\"),\n entrypoint: new URL(\"./.bcms-preview/\" + file, import.meta.url),\n prerender: false,\n });\n }\n },\n },\n },\n ],\n};\n`);\n rmSync(join(root, \"dist\"), { recursive: true, force: true });\n run(root, bin(root, \"astro\"), [\"build\", \"--config\", \"astro.config.bcms-preview.mjs\"]);\n } finally {\n rmSync(gen, { recursive: true, force: true });\n rmSync(wrapper, { force: true });\n }\n\n const app = join(out, \"app\");\n mkdirSync(app, { recursive: true });\n cpSync(join(root, \"dist\"), app, { recursive: true });\n cpSync(join(root, \"package.json\"), join(app, \"package.json\"));\n // Astro does not bundle its dependencies, so the server entry needs them on disk.\n cpSync(join(root, \"node_modules\"), join(app, \"node_modules\"), { recursive: true, verbatimSymlinks: true });\n writeFileSync(join(out, \"bcms-runtime.json\"), `${JSON.stringify({ kind: \"node\", dir: \"app\", entry: \"server/entry.mjs\" })}\\n`);\n}\n\nfunction buildNext(root: string, entries: ManifestEntry[], out: string) {\n const appDir = [\"app\", join(\"src\", \"app\")].map((d) => join(root, d)).find((d) => existsSync(d));\n if (!appDir) fail(\"no App Router directory (app/ or src/app/) found\");\n const configName = [\"next.config.mjs\", \"next.config.js\", \"next.config.ts\", \"next.config.cjs\"].find((f) => existsSync(join(root, f)));\n\n // `%5F%5Fbcms` is how a URL segment starting with an underscore is spelled in the App Router: a plain\n // `__bcms` folder is a PRIVATE folder and silently produces no routes at all.\n const gen = join(appDir, \"%5F%5Fbcms\");\n const userConfig = configName ? join(root, configName.replace(\"next.config\", \"next.config.bcms-user\")) : null;\n const wrapperName = configName && configName.endsWith(\".ts\") ? \"next.config.ts\" : \"next.config.mjs\";\n rmSync(gen, { recursive: true, force: true });\n mkdirSync(gen, { recursive: true });\n if (configName && userConfig) renameSync(join(root, configName), userConfig);\n try {\n writeRuntimeLibrary(gen);\n writeFileSync(join(gen, \"registry.ts\"), registrySource(gen, root, entries));\n const route = (name: string, source: string) => {\n mkdirSync(join(gen, name), { recursive: true });\n writeFileSync(join(gen, name, \"route.ts\"), `export const dynamic = \"force-dynamic\";\\n${source}`);\n };\n route(\"runtime\", `import { handleRuntime } from \"../server.mjs\";\\nimport shell from \"../shell\";\\nexport function GET() {\\n return handleRuntime(shell);\\n}\\n`);\n route(\"session\", `import { handleSession } from \"../server.mjs\";\\nimport { has } from \"../registry\";\\nexport function POST(request: Request) {\\n return handleSession(request, has);\\n}\\n`);\n route(\"props\", `import { handleProps } from \"../server.mjs\";\\nimport { has } from \"../registry\";\\nexport function POST(request: Request) {\\n return handleProps(request, has);\\n}\\n`);\n route(\"health\", `import { handleHealth } from \"../server.mjs\";\\nexport function GET() {\\n return handleHealth();\\n}\\n`);\n route(\"render-page\", `import { renderEntry, renderPageSection } from \"../server.mjs\";\\nimport { pages } from \"../registry\";\\nimport scope from \"../scope\";\\nexport function GET(request: Request) {\\n const entry = renderEntry(new URL(request.url).searchParams.get(\"id\"));\\n const page = entry ? pages[entry.componentId] : undefined;\\n if (!entry || !page) return new Response(\"Not found\", { status: 404 });\\n return renderPageSection(request, entry, page, scope);\\n}\\n`);\n mkdirSync(join(gen, \"render\"), { recursive: true });\n writeFileSync(join(gen, \"render\", \"page.tsx\"), `import { notFound, redirect } from \"next/navigation\";\nimport { renderEntry } from \"../server.mjs\";\nimport { registry, kinds, pages } from \"../registry\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function BetterCMSComponentPreview({ searchParams }: { searchParams: Promise<{ id?: string }> }) {\n const { id } = await searchParams;\n const entry = renderEntry(id);\n // A page-kind component answers with a whole document, which a page inside the root layout cannot be.\n // Relative on purpose: Next prefixes basePath onto a \"/\"-rooted redirect, and the browser resolves this one.\n if (entry && pages[entry.componentId]) redirect(\\`render-page?id=\\${encodeURIComponent(id!)}\\`);\n const Component = entry ? registry[entry.componentId] : undefined;\n if (!entry || !Component) notFound();\n // The marker the runtime page checks before acknowledging: a 404 or an error page never carries it.\n return (\n <>\n {kinds[entry.componentId] === \"section\"\n ? <Component blockId=\"bcms-preview\" overrides={entry.props} page={{}} />\n : <Component {...entry.props} />}\n <template data-bcms-preview-render=\"1\" />\n </>\n );\n}\n`);\n const importUser = userConfig ? `import user from \"./${relative(root, userConfig)}\";` : \"const user = {};\";\n writeFileSync(join(root, wrapperName), `${importUser}\n\n// No frame-ancestors here: next.config headers are fixed at build time, and the dashboard origin the\n// render frame must allow is runtime configuration. The platform's proxy sets it for this whole prefix.\nconst RENDER_HEADERS = [\n { key: \"referrer-policy\", value: \"no-referrer\" },\n { key: \"cache-control\", value: \"no-store\" },\n];\n\nexport default async function betterCMSComponentPreviewConfig(phase, context) {\n const resolved = typeof user === \"function\" ? await user(phase, context) : user;\n const userHeaders = resolved.headers;\n return {\n ...resolved,\n output: \"standalone\",\n basePath: ${JSON.stringify(PREVIEW_BASE)},\n async headers() {\n const own = typeof userHeaders === \"function\" ? await userHeaders() : [];\n return [...own, { source: \"/__bcms/render\", headers: RENDER_HEADERS }];\n },\n };\n}\n`);\n rmSync(join(root, \".next\"), { recursive: true, force: true });\n run(root, bin(root, \"next\"), [\"build\"]);\n } finally {\n rmSync(gen, { recursive: true, force: true });\n rmSync(join(root, wrapperName), { force: true });\n if (configName && userConfig && existsSync(userConfig)) renameSync(userConfig, join(root, configName));\n }\n\n const standalone = join(root, \".next\", \"standalone\");\n if (!existsSync(join(standalone, \"server.js\"))) fail(\"next build produced no standalone server\");\n const app = join(out, \"app\");\n mkdirSync(app, { recursive: true });\n cpSync(standalone, app, { recursive: true, verbatimSymlinks: true });\n if (existsSync(join(root, \".next\", \"static\"))) cpSync(join(root, \".next\", \"static\"), join(app, \".next\", \"static\"), { recursive: true });\n if (existsSync(join(root, \"public\"))) cpSync(join(root, \"public\"), join(app, \"public\"), { recursive: true });\n writeFileSync(join(out, \"bcms-runtime.json\"), `${JSON.stringify({ kind: \"node\", dir: \"app\", entry: \"server.js\" })}\\n`);\n}\n\nexport function buildPreviewRuntime(input: { root: string; manifestPath: string; out: string }) {\n const root = resolve(input.root);\n const out = resolve(input.out);\n const entries = validateManifest(root, readJson<Manifest>(resolve(input.manifestPath)));\n const framework = detectFramework(root);\n\n rmSync(out, { recursive: true, force: true });\n mkdirSync(out, { recursive: true });\n const restore = snapshot(root, MUTATED_BY_BUILD);\n try {\n if (framework === \"astro\") buildAstro(root, entries, out);\n else buildNext(root, entries, out);\n } finally {\n restore();\n }\n return {\n framework,\n out,\n components: entries.map((e) => e.id),\n kinds: Object.fromEntries(entries.map((e) => [e.id, e.source.kind ?? \"file\"])) as Record<string, SourceKind>,\n };\n}\n","/**\n * `bcms-preview validate` — validates components in CI with nothing configured in the repository.\n *\n * Run by `.github/workflows/bcms-component-validation.yml`, which BetterCMS commits and dispatches. One run\n * validates one component or a batch of them, and builds once either way: fetch the manifest, build a preview\n * runtime from the app as it is, package and upload that runtime, start it and one browser — then, for each\n * component in turn, render it with its default props at every native viewport, check brand tokens and the\n * console, claim its request and complete it.\n *\n * 🔴 NOTHING FAILS SILENTLY. A component whose checks fail is still COMPLETED — failed evidence is a\n * result the dashboard shows, with the failing checks. Anything that prevents a result (no source file\n * recorded, a build that breaks, a runtime that never starts, no browser) FAILS the request with a named\n * code and the reason, so the panel says what happened instead of waiting for the request to expire. In a\n * batch one component's failure is reported for that component and the rest carry on; a failure that\n * prevents every result (the build, the runtime, the upload) is reported for every component.\n */\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { mkdtempSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { createServer } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { Browser } from \"playwright\";\nimport { buildPreviewRuntime, CliFailure } from \"./build\";\n\nconst PREVIEW_ROUTE_BASE = \"/__bettercms/component-preview/__bcms\";\nconst RUNTIME_PATH = `${PREVIEW_ROUTE_BASE}/runtime`;\n\n/** Deadlines, so a hung API, app or browser fails the component it hangs instead of the whole 25-minute job. */\nconst API_TIMEOUT_MS = 60_000;\nconst LOCAL_FETCH_TIMEOUT_MS = 30_000;\nconst HEALTH_PROBE_TIMEOUT_MS = 5_000;\nconst RENDER_TIMEOUT_PER_VIEWPORT_MS = 90_000;\nconst BUNDLE_UPLOAD_TIMEOUT_MS = 5 * 60_000;\n/**\n * Ends well before the workflow's 25-minute job timeout — the clock starts only after checkout, install and `npx`\n * — so components not reached are reported, not killed.\n */\nexport const DEFAULT_BATCH_BUDGET_MS = 15 * 60_000;\n\nexport type Viewport = { name: string; width: number; height: number };\n/** One component to validate: what the dispatch names for it. */\nexport type BatchItem = { requestId: string; componentId: string; familyKey: string; nativeViewports: Viewport[] };\ntype RequestTarget = {\n componentId: string;\n componentVersion: number;\n candidateId: string;\n familyKey: string;\n familyContractHash: string;\n schemaHash: string;\n brandContractHash: string;\n dependenciesHash: string;\n commitSha: string;\n adapterHash: string;\n familyManifestHash: string;\n nativeViewports: Viewport[];\n};\ntype Claim = { request: RequestTarget; claimCapability: string };\nexport type Manifest = {\n components: {\n id: string;\n /** `{ path, export, kind? }` for a file or section; `{ kind: \"page\", route, … }` for a placement or layout section. */\n source: Record<string, unknown>;\n defaultProps: Record<string, unknown>;\n /** On an explicitly recorded source: the page this component would render from without it. */\n fallback?: { route: string };\n }[];\n brandTokenNames: string[];\n};\nexport type RenderResult = {\n results: { name: string; width: number; height: number; status: \"baseline-missing\"; candidateDigest: string }[];\n consoleErrors: number;\n runtimeErrors: number;\n missingTokens: string[];\n problems: string[];\n};\nexport type Api = <T>(path: string, init?: { method?: string; body?: unknown; claim?: string }) => Promise<T>;\n/** The built, packaged and started runtime every component in the run renders through. */\nexport type PreparedRuntime = {\n kinds: Record<string, string>;\n bundle: Buffer;\n storeProps(componentId: string, props: Record<string, unknown>, signal: AbortSignal): Promise<string>;\n render(renderId: string, viewports: Viewport[], tokenNames: string[], options: { section: boolean }, signal: AbortSignal): Promise<RenderResult>;\n /** The app server's own error lines so far — a component's are the ones logged while it rendered. */\n serverErrorCount(): number;\n serverErrorsSince(mark: number): string[];\n close(): Promise<void>;\n};\nexport type BatchContext = {\n projectId: string;\n commitSha: string;\n previewOrigin: string;\n run: { providerRunId: string; providerRunAttempt: number; providerRunUrl: string; workflowRef: string };\n};\nexport type BatchDeps = {\n api: Api;\n prepare(manifest: Manifest): Promise<PreparedRuntime>;\n putBundle(uploadUrl: string, bytes: Buffer): Promise<{ ok: boolean; status: number }>;\n log?(line: string): void;\n error?(line: string): void;\n /** Clock, budget and step deadlines; defaults are the constants above. Overridden by tests. */\n now?(): number;\n budgetMs?: number;\n timeouts?: { propsMs?: number; renderPerViewportMs?: number; apiMs?: number };\n};\n\n/** Runs `run` with a deadline: past it the signal aborts and the step fails with a message naming it. */\nasync function bounded<T>(what: string, ms: number, run: (signal: AbortSignal) => Promise<T>): Promise<T> {\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n const limit = ms >= 1000 ? `${Math.round(ms / 1000)} seconds` : `${ms} ms`;\n reject(new ValidationFailure(\"COMPONENT_VALIDATION_STEP_TIMEOUT\", `${what} did not finish within ${limit}.`));\n }, ms);\n });\n try {\n return await Promise.race([run(controller.signal), expired]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport class ValidationFailure extends Error {\n constructor(readonly code: string, message: string) {\n super(message);\n this.name = \"ValidationFailure\";\n }\n}\n\nfunction required(name: string, env: Record<string, string | undefined> = process.env): string {\n const value = env[name]?.trim();\n if (!value) throw new CliFailure(`${name} is not set. This command runs inside the BetterCMS component validation workflow.`);\n return value;\n}\n\nconst isViewport = (value: unknown): value is Viewport =>\n !!value && typeof value === \"object\"\n && typeof (value as Viewport).name === \"string\"\n && Number.isFinite((value as Viewport).width)\n && Number.isFinite((value as Viewport).height);\n\nconst isBatchItem = (value: unknown): value is BatchItem => {\n if (!value || typeof value !== \"object\") return false;\n const item = value as Record<string, unknown>;\n return [\"requestId\", \"componentId\", \"familyKey\"].every((key) => typeof item[key] === \"string\" && (item[key] as string).trim() !== \"\")\n && Array.isArray(item.nativeViewports) && item.nativeViewports.length > 0 && item.nativeViewports.every(isViewport);\n};\n\nconst invalidBatch = (detail: string) => new CliFailure(`COMPONENT_VALIDATION_BATCH_INVALID: ${detail}`);\n\n/**\n * What this run validates. `BCMS_BATCH` (the dispatch's `batch`, JSON) names several components; a dispatch\n * without one — `toJSON` of an absent key is `null` — names one through the single-component variables, which is\n * every dispatch a BetterCMS backend made before batches existed.\n */\nexport function resolveBatch(env: Record<string, string | undefined> = process.env): BatchItem[] {\n const raw = env.BCMS_BATCH?.trim();\n if (raw && raw !== \"null\") {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw invalidBatch(\"BCMS_BATCH is not valid JSON.\");\n }\n if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(isBatchItem)) {\n throw invalidBatch(\"BCMS_BATCH must be a non-empty array of { requestId, componentId, familyKey, nativeViewports }.\");\n }\n if (new Set(parsed.map((item) => item.requestId)).size !== parsed.length) {\n throw invalidBatch(\"BCMS_BATCH names the same request twice.\");\n }\n return parsed;\n }\n const requestId = required(\"BCMS_REQUEST_ID\", env);\n const componentId = required(\"BCMS_COMPONENT_ID\", env);\n const familyKey = required(\"BCMS_FAMILY_KEY\", env);\n let nativeViewports: unknown;\n try {\n nativeViewports = JSON.parse(required(\"BCMS_NATIVE_VIEWPORTS\", env));\n } catch (error) {\n if (error instanceof CliFailure) throw error;\n throw invalidBatch(\"BCMS_NATIVE_VIEWPORTS is not valid JSON.\");\n }\n const item = { requestId, componentId, familyKey, nativeViewports };\n if (!isBatchItem(item)) throw invalidBatch(\"BCMS_NATIVE_VIEWPORTS must be a non-empty array of { name, width, height }.\");\n return [item];\n}\n\nconst sha256 = (data: string | Buffer) => createHash(\"sha256\").update(data).digest(\"hex\");\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.keys(value as Record<string, unknown>).sort()\n .map((key) => `${JSON.stringify(key)}:${canonical((value as Record<string, unknown>)[key])}`).join(\",\")}}`;\n }\n return JSON.stringify(value);\n}\n\nconst toCliFailure = (error: unknown) =>\n new CliFailure(`${error instanceof ValidationFailure ? error.code : \"COMPONENT_VALIDATION_FAILED\"}: ${(error as Error).message.slice(0, 2000)}`);\n\n/**\n * Validates every component in `batch` against one build. Returns which components were reported as completed\n * and which failed; `exitCode` is 1 when any component could not produce a result (a completion whose checks\n * failed is still a result). Throws only when nothing could be validated at all, after reporting every\n * component's failure.\n */\nexport async function runValidationBatch(batch: BatchItem[], ctx: BatchContext, deps: BatchDeps) {\n const now = deps.now ?? Date.now;\n // Counted from the start, so the build and the upload spend the same budget the job timeout does.\n const deadline = now() + (deps.budgetMs ?? DEFAULT_BATCH_BUDGET_MS);\n const propsMs = deps.timeouts?.propsMs ?? LOCAL_FETCH_TIMEOUT_MS;\n const renderPerViewportMs = deps.timeouts?.renderPerViewportMs ?? RENDER_TIMEOUT_PER_VIEWPORT_MS;\n const apiMs = deps.timeouts?.apiMs ?? API_TIMEOUT_MS;\n const seconds = (ms: number) => `${Math.ceil(Math.max(ms, 0) / 1000)}s`;\n const log = deps.log ?? ((line: string) => console.log(line));\n const logError = deps.error ?? ((line: string) => console.error(line));\n const requestPath = (item: BatchItem) =>\n `/api/v1/projects/${ctx.projectId}/component-implementation/implementation-requests/${item.requestId}`;\n const completed: string[] = [];\n const failed: string[] = [];\n\n /**\n * 🔴 CLAIMED LAST, NOT FIRST. A claim credential lives minutes, and `complete` refuses an expired one.\n * Claiming before a framework build, a browser install and a render meant every real run finished with\n * a credential that had already lapsed — and the request sat \"running\" until it expired. Everything slow\n * happens first; each component's claim is followed only by its completion.\n */\n const claim = (item: BatchItem) => deps.api<Claim>(`${requestPath(item)}/claim`, {\n method: \"POST\",\n body: {\n componentId: item.componentId,\n commitSha: ctx.commitSha,\n adapter: {\n protocol: \"bcms-component-runtime-v1\",\n kind: \"project-route\",\n path: RUNTIME_PATH,\n familyKey: item.familyKey,\n previewOrigin: ctx.previewOrigin,\n nativeViewports: item.nativeViewports,\n },\n providerRunId: ctx.run.providerRunId,\n providerRunAttempt: ctx.run.providerRunAttempt,\n providerRunUrl: ctx.run.providerRunUrl,\n workflowRef: ctx.run.workflowRef,\n // The server caps this at the request's own expiry and at ten minutes.\n credentialExpiresAt: new Date(Date.now() + 10 * 60_000 - 5_000).toISOString(),\n },\n });\n\n // A failure before the claim is still reported: claim, then fail at once, so the dashboard names the reason\n // instead of showing \"running\" until the request expires.\n const report = async (item: BatchItem, held: Claim | null, error: unknown) => {\n const code = error instanceof ValidationFailure ? error.code : \"COMPONENT_VALIDATION_FAILED\";\n const message = (error as Error).message.slice(0, 2000);\n failed.push(item.componentId);\n logError(`bcms-preview: ${code}: ${message} (component ${item.componentId})`);\n const reported = held ?? await claim(item).catch((claimError) => {\n logError(`bcms-preview: could not claim request ${item.requestId} to report the failure: ${(claimError as Error).message}`);\n return null;\n });\n if (!reported) return;\n await deps.api(`${requestPath(item)}/fail`, {\n method: \"POST\",\n claim: reported.claimCapability,\n body: { componentId: item.componentId, errorCode: code, errorMessage: message },\n }).catch((reportError) => logError(`bcms-preview: could not report the failure: ${(reportError as Error).message}`));\n };\n\n let manifest: Manifest;\n try {\n // `kinds=page`: this validator builds page-kind entries. A 0.2.0 validator never asks, and never gets one.\n manifest = await deps.api<Manifest>(`/api/v1/projects/${ctx.projectId}/component-preview/manifest?kinds=page`);\n } catch (error) {\n for (const item of batch) await report(item, null, error);\n throw toCliFailure(error);\n }\n\n // A recorded file that fails while the component also renders from its page: the fix is to drop the file.\n // Known before the build, so a file that does not even build carries it too.\n const hintFor = (componentId: string) => {\n const entry = manifest.components.find((c) => c.id === componentId);\n return entry?.fallback && (entry.source as { kind?: unknown }).kind !== \"page\"\n ? [`Clear the recorded source: this component renders from page ${entry.fallback.route} without one.`]\n : [];\n };\n\n const pending: BatchItem[] = [];\n for (const item of batch) {\n if (manifest.components.some((c) => c.id === item.componentId)) {\n pending.push(item);\n } else {\n await report(item, null, new ValidationFailure(\n \"COMPONENT_SOURCE_NOT_RECORDED\",\n \"No file is recorded and this component is neither placed on a page nor used in the layout, so there is nothing to render. Place it, add it to the layout, or record its file.\",\n ));\n }\n }\n if (pending.length === 0) return { completed, failed, exitCode: 1 as const };\n\n let runtime: PreparedRuntime | null = null;\n try {\n runtime = await deps.prepare(manifest);\n // Uploaded before any claim: the upload needs only the key, and validated evidence pointing at a runtime\n // nobody can start renders nothing.\n const upload = await deps.api<{ uploadUrl: string; uploadKey: string }>(`/api/v1/projects/${ctx.projectId}/artifacts/upload-url`, { method: \"POST\" });\n const put = await deps.putBundle(upload.uploadUrl, runtime.bundle);\n if (!put.ok) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED\", `Storage refused the preview bundle (HTTP ${put.status}).`);\n }\n await deps.api(`/api/v1/projects/${ctx.projectId}/component-preview/bundles`, {\n method: \"POST\",\n body: { commitSha: ctx.commitSha, uploadKey: upload.uploadKey, checksum: `sha256:${sha256(runtime.bundle)}`, sizeBytes: runtime.bundle.byteLength },\n });\n } catch (error) {\n await runtime?.close().catch(() => {});\n for (const item of pending) {\n const hint = error instanceof ValidationFailure && error.code === \"COMPONENT_PREVIEW_BUILD_FAILED\" ? hintFor(item.componentId) : [];\n await report(item, null, hint.length ? new ValidationFailure((error as ValidationFailure).code, [(error as Error).message, ...hint].join(\" \")) : error);\n }\n throw toCliFailure(error);\n }\n\n const ready = runtime;\n try {\n for (const item of pending) {\n // Started only when this component's own worst case fits: props, every viewport's render, a claim and a\n // completion. One that does not fit is reported now; a smaller one after it may still fit.\n const worstCase = propsMs + renderPerViewportMs * item.nativeViewports.length + 2 * apiMs;\n const left = deadline - now();\n if (left < worstCase) {\n await report(item, null, new ValidationFailure(\n \"COMPONENT_VALIDATION_BATCH_TIMEOUT\",\n `The validation batch did not have enough time left for this component (needs up to ${seconds(worstCase)}, ${seconds(left)} left). Request validation again.`,\n ));\n continue;\n }\n const entry = manifest.components.find((c) => c.id === item.componentId)!;\n const hint = hintFor(item.componentId);\n let held: Claim | null = null;\n try {\n const mark = ready.serverErrorCount();\n const renderId = await bounded(\n `The preview runtime's props endpoint for ${item.componentId}`,\n propsMs,\n (signal) => ready.storeProps(item.componentId, entry.defaultProps, signal),\n );\n // The viewports the dispatch declared are exactly the ones the claim records as the adapter's.\n const render = await bounded(\n `Rendering ${item.componentId}`,\n renderPerViewportMs * item.nativeViewports.length,\n (signal) => ready.render(\n renderId,\n item.nativeViewports,\n manifest.brandTokenNames,\n // A page-kind render lifts a section too, and stamps its root.\n { section: ready.kinds[item.componentId] !== \"file\" },\n signal,\n ),\n );\n /**\n * The app's own server errors (`TypeError: Cannot read properties of undefined`) are the real reason a\n * render fails — the browser only sees \"500\". The first few logged while this component rendered are\n * kept for its evidence so the panel can say what broke.\n */\n const serverErrors = ready.serverErrorsSince(mark).slice(0, 5);\n\n held = await claim(item);\n const target = held.request;\n const checks = {\n brandKit: {\n status: render.missingTokens.length === 0 ? \"passed\" : \"failed\",\n contractHash: target.brandContractHash,\n missingTokens: render.missingTokens,\n },\n runtime: {\n status: render.runtimeErrors === 0 && render.consoleErrors === 0 ? \"passed\" : \"failed\",\n runtimeErrors: render.runtimeErrors,\n consoleErrors: render.consoleErrors,\n // Only on a failure, and bounded: the server's own error lines first (the real cause), then what the\n // browser saw. The database stores them and the panel shows the first one.\n ...(render.runtimeErrors + render.consoleErrors > 0\n ? { problems: [...hint, ...serverErrors.map((line) => `server: ${line}`), ...render.problems].slice(0, 10).map((line) => line.slice(0, 200)) }\n : {}),\n },\n visual: { status: \"baseline-missing\", reviewRequired: true, viewports: render.results },\n };\n\n const evidenceDigest = `sha256:${sha256(canonical({ requestId: item.requestId, commitSha: target.commitSha, checks }))}`;\n await deps.api(`${requestPath(item)}/complete`, {\n method: \"POST\",\n claim: held.claimCapability,\n body: {\n componentId: target.componentId,\n candidateId: target.candidateId,\n componentVersion: target.componentVersion,\n familyKey: target.familyKey,\n familyContractHash: target.familyContractHash,\n schemaHash: target.schemaHash,\n brandContractHash: target.brandContractHash,\n dependenciesHash: target.dependenciesHash,\n commitSha: target.commitSha,\n adapterHash: target.adapterHash,\n familyManifestHash: target.familyManifestHash,\n nativeViewports: target.nativeViewports,\n checks,\n evidenceDigest,\n },\n });\n completed.push(item.componentId);\n\n const passed = checks.brandKit.status === \"passed\" && checks.runtime.status === \"passed\";\n log(`bcms-preview: validation ${passed ? \"PASSED\" : \"FAILED\"} for ${item.componentId}`);\n if (!passed) {\n if (render.missingTokens.length) log(` brand tokens used but not defined: ${render.missingTokens.join(\", \")}`);\n for (const problem of [...hint, ...render.problems]) log(` ${problem}`);\n }\n } catch (error) {\n await report(item, held, error);\n }\n }\n } finally {\n await ready.close().catch(() => {});\n }\n return { completed, failed, exitCode: failed.length > 0 ? (1 as const) : (0 as const) };\n}\n\nfunction freePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => {\n const address = server.address();\n const port = typeof address === \"object\" && address ? address.port : 0;\n server.close(() => resolve(port));\n });\n });\n}\n\nasync function waitForOk(url: string, timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n try {\n if ((await fetch(url, { signal: AbortSignal.timeout(HEALTH_PROBE_TIMEOUT_MS) })).ok) return true;\n } catch {\n // not up yet\n }\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n\n/** Install Chromium for the bundled Playwright. On a Linux CI runner, with its system dependencies. */\nfunction ensureBrowser() {\n const require = createRequire(import.meta.url);\n const cli = join(dirname(require.resolve(\"playwright/package.json\")), \"cli.js\");\n const args = [cli, \"install\", \"chromium\"];\n if (process.platform === \"linux\" && process.env.CI) args.push(\"--with-deps\");\n const result = spawnSync(process.execPath, args, { stdio: \"inherit\" });\n if (result.status !== 0) {\n throw new ValidationFailure(\"COMPONENT_VALIDATION_BROWSER_UNAVAILABLE\", \"A headless browser could not be installed on this runner.\");\n }\n}\n\nexport async function renderInBrowser(browser: Browser, url: string, viewports: Viewport[], tokenNames: string[], options: { section: boolean }, signal?: AbortSignal): Promise<RenderResult> {\n let consoleErrors = 0;\n let runtimeErrors = 0;\n const missingTokens = new Set<string>();\n const results: RenderResult[\"results\"] = [];\n const problems: string[] = [];\n for (const viewport of viewports) {\n // Past its deadline the step has already failed; do not keep opening pages for it.\n if (signal?.aborted) break;\n const page = await browser.newPage({ viewport: { width: viewport.width, height: viewport.height } });\n // 🔴 A page stuck in goto/evaluate/screenshot past its deadline keeps running in the shared browser, and the\n // app errors it causes would land in the NEXT component's evidence. Closing it ends the stuck call.\n const onAbort = () => {\n page.close().catch(() => {});\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (signal?.aborted) onAbort();\n try {\n page.on(\"console\", (message) => {\n if (message.type() === \"error\") {\n consoleErrors += 1;\n problems.push(`${viewport.name} console: ${message.text().slice(0, 200)}`);\n }\n });\n page.on(\"pageerror\", (error) => {\n runtimeErrors += 1;\n problems.push(`${viewport.name} error: ${error.message.slice(0, 200)}`);\n });\n const response = await page.goto(url, { waitUntil: \"load\", timeout: 45_000 });\n await page.waitForLoadState(\"networkidle\", { timeout: 15_000 }).catch(() => {});\n const rendered = await page.locator(\"[data-bcms-preview-render]\").count();\n if (!response?.ok() || rendered === 0) {\n runtimeErrors += 1;\n problems.push(`${viewport.name}: the component page did not render (HTTP ${response?.status() ?? \"none\"})`);\n } else if (options.section && (await page.locator(\"[data-bcms-block]\").count()) === 0) {\n // The codemod stamps data-bcms-block on every section root, and the editor resolves a section's\n // fields by walking up to it: a section without one renders but cannot be edited.\n runtimeErrors += 1;\n problems.push(`${viewport.name}: the section rendered without its [data-bcms-block] root`);\n }\n /**\n * A token is MISSING only when the rendered page uses it and it resolves to nothing. `--bcms-*` are\n * guaranteed on pages BetterCMS renders itself, not in a customer's framework build, so asking\n * \"is every token defined?\" would fail every starter while saying nothing about the component. The\n * question worth a failure is \"does this component reference a brand token the app never defines?\"\n * — a component that will render unstyled on the live site. Cross-origin stylesheets cannot be read\n * and are skipped.\n */\n const missing = await page.evaluate((names: string[]) => {\n const referenced = new Set<string>();\n const scan = (text: string) => {\n for (const match of text.matchAll(/var\\(\\s*(--[A-Za-z0-9_-]+)/g)) referenced.add(match[1]!);\n };\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n for (const rule of Array.from(sheet.cssRules)) scan(rule.cssText);\n } catch {\n // cross-origin sheet\n }\n }\n document.querySelectorAll(\"[style]\").forEach((element) => scan(element.getAttribute(\"style\") ?? \"\"));\n const style = getComputedStyle(document.documentElement);\n return names.filter((name) => referenced.has(name) && !style.getPropertyValue(name).trim());\n }, tokenNames);\n for (const token of missing) missingTokens.add(token);\n const png = await page.screenshot({ fullPage: true });\n results.push({\n name: viewport.name,\n width: viewport.width,\n height: viewport.height,\n // No baseline exists for a first validation. The database requires this exact shape for it:\n // no baseline or diff digest, and the check marked as needing review.\n status: \"baseline-missing\",\n candidateDigest: `sha256:${sha256(png)}`,\n });\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n await page.close().catch(() => {});\n }\n }\n return { results, consoleErrors, runtimeErrors, missingTokens: [...missingTokens].sort(), problems };\n}\n\nexport async function validateComponent() {\n const apiUrl = required(\"BCMS_API_URL\");\n const apiKey = required(\"BCMS_API_KEY\");\n const batch = resolveBatch();\n const ctx: BatchContext = {\n projectId: required(\"BCMS_PROJECT_ID\"),\n commitSha: required(\"BCMS_COMMIT_SHA\"),\n previewOrigin: required(\"BCMS_PREVIEW_ORIGIN\"),\n run: {\n providerRunId: required(\"BCMS_RUN_ID\"),\n providerRunAttempt: Number(process.env.BCMS_RUN_ATTEMPT) || 1,\n providerRunUrl: required(\"BCMS_RUN_URL\"),\n workflowRef: required(\"BCMS_WORKFLOW_REF\"),\n },\n };\n\n const api: Api = async <T>(path: string, init: { method?: string; body?: unknown; claim?: string } = {}): Promise<T> => {\n let response: Response;\n let text: string;\n try {\n response = await fetch(new URL(path, apiUrl), {\n method: init.method ?? \"GET\",\n headers: {\n authorization: `Bearer ${apiKey}`,\n \"content-type\": \"application/json\",\n ...(init.claim ? { \"x-bcms-component-claim\": init.claim } : {}),\n },\n ...(init.body === undefined ? {} : { body: JSON.stringify(init.body) }),\n signal: AbortSignal.timeout(API_TIMEOUT_MS),\n });\n text = await response.text();\n } catch (error) {\n const name = (error as Error).name;\n if (name === \"TimeoutError\" || name === \"AbortError\") {\n throw new ValidationFailure(\"COMPONENT_VALIDATION_API_TIMEOUT\", `${init.method ?? \"GET\"} ${path} did not answer within ${API_TIMEOUT_MS / 1000} seconds.`);\n }\n throw error;\n }\n let parsed: { data?: unknown; error?: unknown; message?: unknown } | null = null;\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = null;\n }\n if (!response.ok) {\n const code = typeof parsed?.error === \"string\" && /^[A-Z][A-Z0-9_]*$/.test(parsed.error) ? parsed.error : `API_HTTP_${response.status}`;\n const detail = typeof parsed?.message === \"string\" ? parsed.message : typeof parsed?.error === \"string\" ? parsed.error : text.slice(0, 300);\n throw new ValidationFailure(code, `${init.method ?? \"GET\"} ${path} answered ${response.status}: ${detail}`);\n }\n return ((parsed && \"data\" in parsed ? parsed.data : parsed) ?? {}) as T;\n };\n\n const work = mkdtempSync(join(tmpdir(), \"bcms-validate-\"));\n\n const prepare = async (manifest: Manifest): Promise<PreparedRuntime> => {\n const manifestPath = join(work, \"manifest.json\");\n writeFileSync(manifestPath, JSON.stringify({ components: manifest.components.map(({ id, source, fallback }) => ({ id, source, ...(fallback ? { fallback } : {}) })) }));\n const out = join(work, \"runtime\");\n let built: ReturnType<typeof buildPreviewRuntime>;\n try {\n built = buildPreviewRuntime({ root: process.cwd(), manifestPath, out });\n } catch (error) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUILD_FAILED\", `The preview build failed: ${(error as Error).message}`);\n }\n\n // Packed before the runtime starts, so the bundle is exactly the tree that was built.\n const tarball = join(work, \"bundle.tgz\");\n if (spawnSync(\"tar\", [\"-czf\", tarball, \"-C\", out, \".\"], { stdio: \"inherit\" }).status !== 0) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_PACK_FAILED\", \"The preview runtime could not be packaged.\");\n }\n const bundle = readFileSync(tarball);\n\n const runtimeManifest = JSON.parse(readFileSync(join(out, \"bcms-runtime.json\"), \"utf8\")) as { dir: string; entry: string };\n const port = await freePort();\n const validatorKey = randomBytes(32).toString(\"base64url\");\n const local = `http://127.0.0.1:${port}`;\n // 🔴 The customer's code runs in this process tree. It gets no BetterCMS API key.\n const { BCMS_API_KEY: _withheld, ...inherited } = process.env;\n const child = spawn(process.execPath, [join(out, runtimeManifest.dir, runtimeManifest.entry)], {\n cwd: join(out, runtimeManifest.dir),\n env: {\n ...inherited,\n NODE_ENV: \"production\",\n PORT: String(port),\n HOST: \"127.0.0.1\",\n HOSTNAME: \"127.0.0.1\",\n BCMS_API_URL: apiUrl,\n BCMS_DASHBOARD_ORIGIN: local,\n BCMS_PREVIEW_ORIGIN: local,\n BCMS_PREVIEW_VALIDATOR_KEY: validatorKey,\n },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n // Still echoed to the CI log; every line that looks like an error is kept (bounded) so each component's\n // evidence can carry the ones logged while it rendered.\n const serverErrors: string[] = [];\n const collect = (stream: NodeJS.WriteStream) => (chunk: Buffer) => {\n stream.write(chunk);\n for (const line of chunk.toString(\"utf8\").split(\"\\n\")) {\n const clean = line.replace(/\\x1b\\[[0-9;]*m/g, \"\").trim();\n if (serverErrors.length < 500 && /\\b(error|exception)\\b/i.test(clean)) serverErrors.push(clean.slice(0, 200));\n }\n };\n child.stdout?.on(\"data\", collect(process.stdout));\n child.stderr?.on(\"data\", collect(process.stderr));\n\n let browser: Browser | null = null;\n try {\n if (!(await waitForOk(`${local}${PREVIEW_ROUTE_BASE}/health`, 60_000))) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_RUNTIME_DID_NOT_START\", \"The preview runtime did not start within 60 seconds.\");\n }\n ensureBrowser();\n const { chromium } = await import(\"playwright\");\n browser = await chromium.launch();\n } catch (error) {\n child.kill();\n throw error;\n }\n const shared = browser;\n\n return {\n kinds: built.kinds,\n bundle,\n storeProps: async (componentId, props, signal) => {\n const stored = await fetch(`${local}${PREVIEW_ROUTE_BASE}/props`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-bcms-validator-key\": validatorKey },\n body: JSON.stringify({ componentId, props }),\n signal,\n });\n if (!stored.ok) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_RUNTIME_REFUSED\", `The preview runtime refused the component (HTTP ${stored.status}).`);\n }\n return ((await stored.json()) as { id: string }).id;\n },\n render: (renderId, viewports, tokenNames, options, signal) =>\n renderInBrowser(shared, `${local}${PREVIEW_ROUTE_BASE}/render?id=${encodeURIComponent(renderId)}`, viewports, tokenNames, options, signal),\n serverErrorCount: () => serverErrors.length,\n serverErrorsSince: (mark) => serverErrors.slice(mark),\n close: async () => {\n child.kill();\n await shared.close().catch(() => {});\n },\n };\n };\n\n const budget = Number(process.env.BCMS_BATCH_BUDGET_MS);\n try {\n const result = await runValidationBatch(batch, ctx, {\n api,\n prepare,\n putBundle: async (uploadUrl, bytes) => {\n try {\n const put = await fetch(uploadUrl, {\n method: \"PUT\",\n body: new Uint8Array(bytes),\n headers: { \"content-type\": \"application/gzip\" },\n signal: AbortSignal.timeout(BUNDLE_UPLOAD_TIMEOUT_MS),\n });\n return { ok: put.ok, status: put.status };\n } catch (error) {\n const name = (error as Error).name;\n if (name !== \"TimeoutError\" && name !== \"AbortError\") throw error;\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED\", `Storage did not accept the preview bundle within ${BUNDLE_UPLOAD_TIMEOUT_MS / 60_000} minutes.`);\n }\n },\n budgetMs: Number.isFinite(budget) && budget > 0 ? budget : DEFAULT_BATCH_BUDGET_MS,\n });\n if (batch.length > 1) {\n console.log(`bcms-preview: ${result.completed.length} of ${batch.length} components completed, ${result.failed.length} could not be validated`);\n }\n if (result.exitCode) process.exitCode = 1;\n } finally {\n rmSync(work, { recursive: true, force: true });\n }\n}\n","/**\n * bcms-preview\n *\n * bcms-preview build --manifest <file> --out <dir> [--cwd <dir>]\n * bcms-preview validate (in CI; configured entirely by BCMS_* environment variables)\n */\nimport { buildPreviewRuntime, CliFailure } from \"./build\";\nimport { validateComponent } from \"./validate\";\n\nfunction arg(name: string): string | undefined {\n const index = process.argv.indexOf(`--${name}`);\n return index === -1 ? undefined : process.argv[index + 1];\n}\n\nasync function main() {\n const command = process.argv[2];\n if (command === \"build\") {\n const manifestPath = arg(\"manifest\");\n const out = arg(\"out\");\n if (!manifestPath || !out) throw new CliFailure(\"usage: bcms-preview build --manifest <file> --out <dir> [--cwd <dir>]\");\n console.log(JSON.stringify(buildPreviewRuntime({ root: arg(\"cwd\") ?? process.cwd(), manifestPath, out })));\n return;\n }\n if (command === \"validate\") {\n await validateComponent();\n return;\n }\n throw new CliFailure(\"usage: bcms-preview <build|validate>\");\n}\n\n/**\n * One handler for every failure, and no `process.exit`: writes to a piped stderr are asynchronous, so\n * exiting right after the write dropped the message and CI showed a failed step with no reason.\n */\nmain().catch((error) => {\n console.error(`bcms-preview: ${error instanceof CliFailure ? error.message : (error as Error).stack ?? String(error)}`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["require","spawnSync","readFileSync","rmSync","writeFileSync","createRequire","dirname","join","run","item","resolve","require","createRequire","join","dirname","spawnSync","writeFileSync","readFileSync","rmSync"]}
1
+ {"version":3,"sources":["../src/build.ts","../src/validate.ts","../src/cli.ts"],"sourcesContent":["/**\n * Builds a component preview runtime from an unmodified Next.js or Astro app. Used by `bcms-preview build`\n * and by the validator.\n *\n * The manifest names which file implements which component:\n * { \"components\": [{ \"id\": \"cmp_1\", \"source\": { \"path\": \"src/components/Hero.astro\" } }] }\n *\n * 🔴 NOTHING IN THE CUSTOMER'S REPOSITORY IS CHANGED. Routes and a registry are generated into the\n * checkout, the framework builds, the result is packaged as a runtime release, and every generated file\n * is removed again — including when the build fails. In CI the checkout is thrown away anyway; on a\n * developer machine this is the difference between a tool and a mess.\n */\nimport { spawnSync } from \"node:child_process\";\nimport { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, extname, join, relative, resolve, sep } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * `file`: a component module whose props ARE the component's fields — rendered with the props spread.\n * `section`: a section `npx @bettercms-ai/convert --componentize` extracted from a page. Its props are always\n * `{ blockId, bind, overrides, page }`, so it is rendered with the live props as `overrides`.\n * `page`: no file at all — the component is a placement on a page, or a section of the layout. The runtime\n * renders that page and keeps only the component's section (see scope.ts). Derived by the platform, never recorded.\n */\ntype SourceKind = \"file\" | \"section\" | \"page\";\ntype FileSource = { path: string; export?: string; kind?: \"file\" | \"section\" };\ntype PageSource = {\n kind: \"page\";\n route: string;\n blockId?: string;\n groupKey?: string | null;\n source?: Record<string, string> | null;\n layoutSectionId?: string;\n landmark?: \"header\" | \"footer\" | \"nav\" | null;\n bindings?: Record<string, string>;\n};\ntype ManifestEntry = { id: string; source: FileSource | PageSource };\ntype Manifest = { components: ManifestEntry[] };\ntype Framework = \"astro\" | \"next\";\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst PREVIEW_BASE = \"/__bettercms/component-preview\";\nconst COMPONENT_EXTENSIONS = new Set([\".astro\", \".tsx\", \".jsx\", \".ts\", \".js\", \".mjs\"]);\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n/** Every section file the codemod writes carries this (`// @bettercms-ai/convert section v2`, earlier `v1`). */\nconst SECTION_MARKER_PREFIX = \"// @bettercms-ai/convert section v\";\n\n/**\n * 🔴 THROWN, NOT `process.exit`. Writes to a piped stderr are asynchronous in Node, so exiting on the\n * next line dropped the message: in CI the step failed with no reason in the log at all. The single\n * handler at the bottom prints and sets the exit code, and the process ends once the write has flushed.\n */\nexport class CliFailure extends Error {}\n\nexport function fail(message: string): never {\n throw new CliFailure(message);\n}\n\n/**\n * Files a framework build rewrites in place. `next build` edits tsconfig.json and next-env.d.ts; an\n * `npm install --no-save` still rewrites the lockfile. Restored afterwards, so a preview build leaves the\n * app exactly as it found it.\n */\nfunction snapshot(root: string, names: string[]): () => void {\n const saved = names.map((name) => {\n const file = join(root, name);\n return { file, content: existsSync(file) ? readFileSync(file) : null };\n });\n return () => {\n for (const { file, content } of saved) {\n if (content === null) rmSync(file, { force: true });\n else writeFileSync(file, content);\n }\n };\n}\n\nconst MUTATED_BY_BUILD = [\"tsconfig.json\", \"next-env.d.ts\", \"package-lock.json\", \"pnpm-lock.yaml\", \"yarn.lock\", \"bun.lock\"];\n\nfunction readJson<T>(file: string): T {\n try {\n return JSON.parse(readFileSync(file, \"utf8\")) as T;\n } catch (error) {\n fail(`could not read ${file}: ${(error as Error).message}`);\n }\n}\n\nconst LANDMARKS = new Set([\"header\", \"footer\", \"nav\"]);\nconst isStringRecord = (value: unknown) =>\n !!value && typeof value === \"object\" && !Array.isArray(value) && Object.values(value).every((v) => typeof v === \"string\");\n\n/** A page source travels into a generated module as data: a same-origin path and plain strings, nothing else. */\nfunction pageSource(id: string, source: PageSource): PageSource {\n const { route, blockId, groupKey, layoutSectionId, landmark } = source;\n if (typeof route !== \"string\" || !route.startsWith(\"/\") || route.startsWith(\"//\") || /[\\s?#\\\\]/.test(route) || route.split(\"/\").includes(\"..\")) {\n fail(`component ${id} has an unsafe page route: ${String(route)}`);\n }\n if (typeof blockId === \"string\" && blockId) {\n if (groupKey != null && typeof groupKey !== \"string\") fail(`component ${id}: groupKey must be a string`);\n if (source.source != null && !isStringRecord(source.source)) fail(`component ${id}: source must map prop keys to page paths`);\n return { kind: \"page\", route, blockId, groupKey: groupKey ?? null, source: source.source ?? null };\n }\n if (typeof layoutSectionId === \"string\" && layoutSectionId) {\n if (landmark != null && !LANDMARKS.has(landmark)) fail(`component ${id}: unknown landmark ${String(landmark)}`);\n if (source.bindings != null && !isStringRecord(source.bindings)) fail(`component ${id}: bindings must map input ids to layout field ids`);\n return { kind: \"page\", route, layoutSectionId, landmark: landmark ?? null, bindings: source.bindings ?? {} };\n }\n fail(`component ${id}: a page source names neither a placement (blockId) nor a layout section (layoutSectionId)`);\n}\n\n/** Manifest paths travel from an API into generated imports: relative, inside the app, and real. */\nexport function validateManifest(root: string, manifest: Manifest): ManifestEntry[] {\n if (!manifest || !Array.isArray(manifest.components) || manifest.components.length === 0) {\n fail(\"the manifest lists no components\");\n }\n const seen = new Set<string>();\n return manifest.components.map((entry) => {\n if (!entry || typeof entry.id !== \"string\" || !entry.id.trim()) fail(\"a manifest entry has no id\");\n if (seen.has(entry.id)) fail(`component ${entry.id} is listed twice`);\n seen.add(entry.id);\n if (entry.source?.kind === \"page\") return { id: entry.id, source: pageSource(entry.id, entry.source) };\n const path = entry.source?.path;\n if (typeof path !== \"string\" || path.startsWith(\"/\") || path.includes(\"\\\\\") || path.split(\"/\").includes(\"..\")) {\n fail(`component ${entry.id} has an unsafe source path: ${String(path)}`);\n }\n if (!COMPONENT_EXTENSIONS.has(extname(path))) fail(`component ${entry.id}: unsupported file type ${extname(path)}`);\n if (!existsSync(join(root, path))) fail(`component ${entry.id}: ${path} does not exist`);\n const named = entry.source.export;\n if (named !== undefined && named !== \"default\" && !IDENTIFIER.test(named)) {\n fail(`component ${entry.id}: export \"${named}\" is not a valid identifier`);\n }\n // A section is recognised by its own marker as well as by the manifest: a source recorded before kinds\n // existed defaults to `file`, and rendering a section as a file hands it none of its copy.\n const head = readFileSync(join(root, path), \"utf8\").slice(0, 512);\n const kind: SourceKind = entry.source.kind === \"section\" || head.includes(SECTION_MARKER_PREFIX) ? \"section\" : \"file\";\n return { id: entry.id, source: { path, export: named ?? \"default\", kind } };\n });\n}\n\nfunction detectFramework(root: string): Framework {\n const pkg = readJson<{ dependencies?: Record<string, string>; devDependencies?: Record<string, string> }>(join(root, \"package.json\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.astro) return \"astro\";\n if (deps.next) return \"next\";\n fail(\"this app depends on neither astro nor next\");\n}\n\nfunction run(root: string, command: string, args: string[]) {\n const result = spawnSync(command, args, { cwd: root, stdio: \"inherit\", env: process.env });\n if (result.status !== 0) throw new Error(`${command} ${args.join(\" \")} exited with ${result.status}`);\n}\n\nfunction bin(root: string, name: string): string {\n const local = join(root, \"node_modules\", \".bin\", name);\n if (!existsSync(local)) fail(`${name} is not installed in ${root}. Install the app's dependencies first.`);\n return local;\n}\n\n/** A registry module: one import per file component, one data entry per page component, keyed by component id. */\nexport function registrySource(fromDir: string, root: string, entries: ManifestEntry[]): string {\n const imports: string[] = [];\n const keys: string[] = [];\n const kinds: string[] = [];\n const pages: string[] = [];\n entries.forEach((entry, index) => {\n const source = entry.source;\n kinds.push(` ${JSON.stringify(entry.id)}: ${JSON.stringify(source.kind ?? \"file\")},`);\n if (source.kind === \"page\") {\n pages.push(` ${JSON.stringify(entry.id)}: ${JSON.stringify(source)},`);\n return;\n }\n let specifier = relative(fromDir, join(root, source.path)).split(sep).join(\"/\");\n if (!specifier.startsWith(\".\")) specifier = `./${specifier}`;\n // TypeScript sources are imported without their extension, the way the app itself imports them.\n if ([\".tsx\", \".ts\", \".jsx\", \".js\"].includes(extname(specifier))) specifier = specifier.slice(0, -extname(specifier).length);\n const local = `Component${index}`;\n imports.push(source.export === undefined || source.export === \"default\"\n ? `import ${local} from ${JSON.stringify(specifier)};`\n : `import { ${source.export} as ${local} } from ${JSON.stringify(specifier)};`);\n keys.push(` ${JSON.stringify(entry.id)}: ${local},`);\n });\n return `${imports.join(\"\\n\")}\\n\\nexport const registry: Record<string, any> = {\\n${keys.join(\"\\n\")}\\n};\\n\\nexport const kinds: Record<string, \"file\" | \"section\" | \"page\"> = {\\n${kinds.join(\"\\n\")}\\n};\\n\\nexport const pages: Record<string, any> = {\\n${pages.join(\"\\n\")}\\n};\\n\\nconst own = (map: object, componentId: string) => Object.prototype.hasOwnProperty.call(map, componentId);\\nexport const has = (componentId: string): boolean => own(registry, componentId) || own(pages, componentId);\\n`;\n}\n\nfunction writeRuntimeLibrary(dir: string) {\n writeFileSync(join(dir, \"server.mjs\"), readFileSync(join(here, \"server.js\"), \"utf8\"));\n const types = join(here, \"server.d.ts\");\n if (existsSync(types)) writeFileSync(join(dir, \"server.d.mts\"), readFileSync(types, \"utf8\"));\n writeFileSync(join(dir, \"shell.ts\"), `export default ${JSON.stringify(readFileSync(join(here, \"shell.global.js\"), \"utf8\"))};\\n`);\n writeFileSync(join(dir, \"scope.ts\"), `export default ${JSON.stringify(readFileSync(join(here, \"scope-client.global.js\"), \"utf8\"))};\\n`);\n}\n\n/** CSS the app's layouts import. The render page has no layout, so it imports them itself. */\nfunction astroGlobalStyles(root: string): string[] {\n const found = new Set<string>();\n const scan = (dir: string) => {\n if (!existsSync(dir)) return;\n for (const name of readdirSync(dir)) {\n const full = join(dir, name);\n if (statSync(full).isDirectory()) scan(full);\n else if (name.endsWith(\".astro\")) {\n for (const match of readFileSync(full, \"utf8\").matchAll(/^\\s*import\\s+[\"']([^\"']+\\.css)[\"'];?/gm)) {\n const target = resolve(dirname(full), match[1]!);\n if (target.startsWith(root) && existsSync(target)) found.add(target);\n }\n }\n }\n };\n scan(join(root, \"src\", \"layouts\"));\n return [...found];\n}\n\nconst ASTRO_NODE_ADAPTER: Record<string, string> = { \"5\": \"^9\", \"6\": \"^10\", \"7\": \"^11\" };\n\nfunction ensureAstroNodeAdapter(root: string) {\n const require = createRequire(join(root, \"package.json\"));\n try {\n require.resolve(\"@astrojs/node\");\n return;\n } catch {\n // Not installed: add it without touching package.json or the lockfile.\n }\n const astroVersion = readJson<{ version: string }>(require.resolve(\"astro/package.json\")).version;\n const [major, minor] = astroVersion.split(\".\").map(Number);\n // @astrojs/node 11.1.3+ calls `app.getLogger()`, which Astro only has from 7.3 (its peer range still says\n // ^7.2.1), so on 7.0–7.2 the server crashed at startup: \"app.getLogger is not a function\".\n const range = major === 7 && minor! < 3 ? \">=11.0.0 <11.1.3\" : ASTRO_NODE_ADAPTER[String(major)];\n if (!range) fail(`Astro ${astroVersion} is not supported for component previews yet`);\n run(root, \"npm\", [\"install\", \"--no-save\", \"--no-audit\", \"--no-fund\", `@astrojs/node@${range}`]);\n}\n\nfunction buildAstro(root: string, entries: ManifestEntry[], out: string) {\n const configName = [\"astro.config.mjs\", \"astro.config.js\", \"astro.config.ts\", \"astro.config.mts\"].find((f) => existsSync(join(root, f)));\n if (!configName) fail(\"no astro.config file found\");\n ensureAstroNodeAdapter(root);\n\n const gen = join(root, \".bcms-preview\");\n const wrapper = join(root, \"astro.config.bcms-preview.mjs\");\n rmSync(gen, { recursive: true, force: true });\n mkdirSync(gen, { recursive: true });\n try {\n writeRuntimeLibrary(gen);\n writeFileSync(join(gen, \"registry.ts\"), registrySource(gen, root, entries));\n const handler = (method: string, body: string) =>\n `export const prerender = false;\\nexport const ${method} = ${body};\\n`;\n writeFileSync(join(gen, \"runtime.ts\"), `import { handleRuntime } from \"./server.mjs\";\\nimport shell from \"./shell\";\\n${handler(\"GET\", \"() => handleRuntime(shell)\")}`);\n writeFileSync(join(gen, \"session.ts\"), `import { handleSession } from \"./server.mjs\";\\nimport { has } from \"./registry\";\\n${handler(\"POST\", \"({ request }: { request: Request }) => handleSession(request, has)\")}`);\n writeFileSync(join(gen, \"props.ts\"), `import { handleProps } from \"./server.mjs\";\\nimport { has } from \"./registry\";\\n${handler(\"POST\", \"({ request }: { request: Request }) => handleProps(request, has)\")}`);\n writeFileSync(join(gen, \"health.ts\"), `import { handleHealth } from \"./server.mjs\";\\n${handler(\"GET\", \"() => handleHealth()\")}`);\n const styles = astroGlobalStyles(root)\n .map((file) => `import ${JSON.stringify(relative(gen, file).split(sep).join(\"/\"))};`)\n .join(\"\\n\");\n writeFileSync(join(gen, \"render.astro\"), `---\n${styles}\nimport { renderEntry, renderHeaders, renderPageSection } from \"./server.mjs\";\nimport { registry, kinds, pages } from \"./registry\";\nimport scope from \"./scope\";\nexport const prerender = false;\nconst headers = renderHeaders();\nconst entry = renderEntry(Astro.url.searchParams.get(\"id\"));\nif (entry && pages[entry.componentId]) return await renderPageSection(Astro.request, entry, pages[entry.componentId], scope);\nconst Component = entry ? registry[entry.componentId] : undefined;\nconst section = entry ? kinds[entry.componentId] === \"section\" : false;\nfor (const [name, value] of Object.entries(headers)) Astro.response.headers.set(name, value);\nif (!entry || !Component) return new Response(\"Not found\", { status: 404, headers });\n---\n<html lang=\"en\" data-bcms-preview-render=\"1\">\n <head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /></head>\n <body>{section ? <Component blockId=\"bcms-preview\" overrides={entry.props} page={{}} /> : <Component {...entry.props} />}</body>\n</html>\n`);\n writeFileSync(wrapper, `import user from \"./${configName}\";\nimport node from \"@astrojs/node\";\n\nconst routes = [\"runtime.ts\", \"session.ts\", \"props.ts\", \"render.astro\", \"health.ts\"];\n\nexport default {\n ...user,\n output: \"server\",\n base: ${JSON.stringify(PREVIEW_BASE)},\n adapter: node({ mode: \"standalone\" }),\n integrations: [\n ...(user.integrations ?? []),\n {\n name: \"bettercms-component-preview\",\n hooks: {\n \"astro:config:setup\": ({ injectRoute }) => {\n for (const file of routes) {\n injectRoute({\n pattern: \"/__bcms/\" + file.replace(/\\\\.(ts|astro)$/, \"\"),\n entrypoint: new URL(\"./.bcms-preview/\" + file, import.meta.url),\n prerender: false,\n });\n }\n },\n },\n },\n ],\n};\n`);\n rmSync(join(root, \"dist\"), { recursive: true, force: true });\n run(root, bin(root, \"astro\"), [\"build\", \"--config\", \"astro.config.bcms-preview.mjs\"]);\n } finally {\n rmSync(gen, { recursive: true, force: true });\n rmSync(wrapper, { force: true });\n }\n\n const app = join(out, \"app\");\n mkdirSync(app, { recursive: true });\n cpSync(join(root, \"dist\"), app, { recursive: true });\n cpSync(join(root, \"package.json\"), join(app, \"package.json\"));\n // Astro does not bundle its dependencies, so the server entry needs them on disk.\n cpSync(join(root, \"node_modules\"), join(app, \"node_modules\"), { recursive: true, verbatimSymlinks: true });\n writeFileSync(join(out, \"bcms-runtime.json\"), `${JSON.stringify({ kind: \"node\", dir: \"app\", entry: \"server/entry.mjs\" })}\\n`);\n}\n\nfunction buildNext(root: string, entries: ManifestEntry[], out: string) {\n const appDir = [\"app\", join(\"src\", \"app\")].map((d) => join(root, d)).find((d) => existsSync(d));\n if (!appDir) fail(\"no App Router directory (app/ or src/app/) found\");\n const configName = [\"next.config.mjs\", \"next.config.js\", \"next.config.ts\", \"next.config.cjs\"].find((f) => existsSync(join(root, f)));\n\n // `%5F%5Fbcms` is how a URL segment starting with an underscore is spelled in the App Router: a plain\n // `__bcms` folder is a PRIVATE folder and silently produces no routes at all.\n const gen = join(appDir, \"%5F%5Fbcms\");\n const userConfig = configName ? join(root, configName.replace(\"next.config\", \"next.config.bcms-user\")) : null;\n const wrapperName = configName && configName.endsWith(\".ts\") ? \"next.config.ts\" : \"next.config.mjs\";\n rmSync(gen, { recursive: true, force: true });\n mkdirSync(gen, { recursive: true });\n if (configName && userConfig) renameSync(join(root, configName), userConfig);\n try {\n writeRuntimeLibrary(gen);\n writeFileSync(join(gen, \"registry.ts\"), registrySource(gen, root, entries));\n const route = (name: string, source: string) => {\n mkdirSync(join(gen, name), { recursive: true });\n writeFileSync(join(gen, name, \"route.ts\"), `export const dynamic = \"force-dynamic\";\\n${source}`);\n };\n route(\"runtime\", `import { handleRuntime } from \"../server.mjs\";\\nimport shell from \"../shell\";\\nexport function GET() {\\n return handleRuntime(shell);\\n}\\n`);\n route(\"session\", `import { handleSession } from \"../server.mjs\";\\nimport { has } from \"../registry\";\\nexport function POST(request: Request) {\\n return handleSession(request, has);\\n}\\n`);\n route(\"props\", `import { handleProps } from \"../server.mjs\";\\nimport { has } from \"../registry\";\\nexport function POST(request: Request) {\\n return handleProps(request, has);\\n}\\n`);\n route(\"health\", `import { handleHealth } from \"../server.mjs\";\\nexport function GET() {\\n return handleHealth();\\n}\\n`);\n route(\"render-page\", `import { renderEntry, renderPageSection } from \"../server.mjs\";\\nimport { pages } from \"../registry\";\\nimport scope from \"../scope\";\\nexport function GET(request: Request) {\\n const entry = renderEntry(new URL(request.url).searchParams.get(\"id\"));\\n const page = entry ? pages[entry.componentId] : undefined;\\n if (!entry || !page) return new Response(\"Not found\", { status: 404 });\\n return renderPageSection(request, entry, page, scope);\\n}\\n`);\n mkdirSync(join(gen, \"render\"), { recursive: true });\n writeFileSync(join(gen, \"render\", \"page.tsx\"), `import { notFound, redirect } from \"next/navigation\";\nimport { renderEntry } from \"../server.mjs\";\nimport { registry, kinds, pages } from \"../registry\";\n\nexport const dynamic = \"force-dynamic\";\n\nexport default async function BetterCMSComponentPreview({ searchParams }: { searchParams: Promise<{ id?: string }> }) {\n const { id } = await searchParams;\n const entry = renderEntry(id);\n // A page-kind component answers with a whole document, which a page inside the root layout cannot be.\n // Relative on purpose: Next prefixes basePath onto a \"/\"-rooted redirect, and the browser resolves this one.\n if (entry && pages[entry.componentId]) redirect(\\`render-page?id=\\${encodeURIComponent(id!)}\\`);\n const Component = entry ? registry[entry.componentId] : undefined;\n if (!entry || !Component) notFound();\n // The marker the runtime page checks before acknowledging: a 404 or an error page never carries it.\n return (\n <>\n {kinds[entry.componentId] === \"section\"\n ? <Component blockId=\"bcms-preview\" overrides={entry.props} page={{}} />\n : <Component {...entry.props} />}\n <template data-bcms-preview-render=\"1\" />\n </>\n );\n}\n`);\n const importUser = userConfig ? `import user from \"./${relative(root, userConfig)}\";` : \"const user = {};\";\n writeFileSync(join(root, wrapperName), `${importUser}\n\n// No frame-ancestors here: next.config headers are fixed at build time, and the dashboard origin the\n// render frame must allow is runtime configuration. The platform's proxy sets it for this whole prefix.\nconst RENDER_HEADERS = [\n { key: \"referrer-policy\", value: \"no-referrer\" },\n { key: \"cache-control\", value: \"no-store\" },\n];\n\nexport default async function betterCMSComponentPreviewConfig(phase, context) {\n const resolved = typeof user === \"function\" ? await user(phase, context) : user;\n const userHeaders = resolved.headers;\n return {\n ...resolved,\n output: \"standalone\",\n basePath: ${JSON.stringify(PREVIEW_BASE)},\n async headers() {\n const own = typeof userHeaders === \"function\" ? await userHeaders() : [];\n return [...own, { source: \"/__bcms/render\", headers: RENDER_HEADERS }];\n },\n };\n}\n`);\n rmSync(join(root, \".next\"), { recursive: true, force: true });\n run(root, bin(root, \"next\"), [\"build\"]);\n } finally {\n rmSync(gen, { recursive: true, force: true });\n rmSync(join(root, wrapperName), { force: true });\n if (configName && userConfig && existsSync(userConfig)) renameSync(userConfig, join(root, configName));\n }\n\n const standalone = join(root, \".next\", \"standalone\");\n if (!existsSync(join(standalone, \"server.js\"))) fail(\"next build produced no standalone server\");\n const app = join(out, \"app\");\n mkdirSync(app, { recursive: true });\n cpSync(standalone, app, { recursive: true, verbatimSymlinks: true });\n if (existsSync(join(root, \".next\", \"static\"))) cpSync(join(root, \".next\", \"static\"), join(app, \".next\", \"static\"), { recursive: true });\n if (existsSync(join(root, \"public\"))) cpSync(join(root, \"public\"), join(app, \"public\"), { recursive: true });\n writeFileSync(join(out, \"bcms-runtime.json\"), `${JSON.stringify({ kind: \"node\", dir: \"app\", entry: \"server.js\" })}\\n`);\n}\n\nexport function buildPreviewRuntime(input: { root: string; manifestPath: string; out: string }) {\n const root = resolve(input.root);\n const out = resolve(input.out);\n const entries = validateManifest(root, readJson<Manifest>(resolve(input.manifestPath)));\n const framework = detectFramework(root);\n\n rmSync(out, { recursive: true, force: true });\n mkdirSync(out, { recursive: true });\n const restore = snapshot(root, MUTATED_BY_BUILD);\n try {\n if (framework === \"astro\") buildAstro(root, entries, out);\n else buildNext(root, entries, out);\n } finally {\n restore();\n }\n return {\n framework,\n out,\n components: entries.map((e) => e.id),\n kinds: Object.fromEntries(entries.map((e) => [e.id, e.source.kind ?? \"file\"])) as Record<string, SourceKind>,\n };\n}\n","/**\n * `bcms-preview validate` — validates components in CI with nothing configured in the repository.\n *\n * Run by `.github/workflows/bcms-component-validation.yml`, which BetterCMS commits and dispatches. One run\n * validates one component or a batch of them, and builds once either way: fetch the manifest, build a preview\n * runtime from the app as it is, package and upload that runtime, start it and one browser — then, for each\n * component in turn, render it with its default props at every native viewport, check brand tokens and the\n * console, claim its request and complete it.\n *\n * 🔴 NOTHING FAILS SILENTLY. A component whose checks fail is still COMPLETED — failed evidence is a\n * result the dashboard shows, with the failing checks. Anything that prevents a result (no source file\n * recorded, a build that breaks, a runtime that never starts, no browser) FAILS the request with a named\n * code and the reason, so the panel says what happened instead of waiting for the request to expire. In a\n * batch one component's failure is reported for that component and the rest carry on; a failure that\n * prevents every result (the build, the runtime, the upload) is reported for every component.\n */\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { mkdtempSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { createServer } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { Browser } from \"playwright\";\nimport { buildPreviewRuntime, CliFailure } from \"./build\";\n\nconst PREVIEW_ROUTE_BASE = \"/__bettercms/component-preview/__bcms\";\nconst RUNTIME_PATH = `${PREVIEW_ROUTE_BASE}/runtime`;\n\n/** Deadlines, so a hung API, app or browser fails the component it hangs instead of the whole 25-minute job. */\nconst API_TIMEOUT_MS = 60_000;\nconst LOCAL_FETCH_TIMEOUT_MS = 30_000;\nconst HEALTH_PROBE_TIMEOUT_MS = 5_000;\nconst RENDER_TIMEOUT_PER_VIEWPORT_MS = 90_000;\nconst BUNDLE_UPLOAD_TIMEOUT_MS = 5 * 60_000;\n/**\n * Ends well before the workflow's 25-minute job timeout — the clock starts only after checkout, install and `npx`\n * — so components not reached are reported, not killed.\n */\nexport const DEFAULT_BATCH_BUDGET_MS = 15 * 60_000;\n\nexport type Viewport = { name: string; width: number; height: number };\n/** One component to validate: what the dispatch names for it. */\nexport type BatchItem = { requestId: string; componentId: string; familyKey: string; nativeViewports: Viewport[] };\ntype RequestTarget = {\n componentId: string;\n componentVersion: number;\n candidateId: string;\n familyKey: string;\n familyContractHash: string;\n schemaHash: string;\n brandContractHash: string;\n dependenciesHash: string;\n commitSha: string;\n adapterHash: string;\n familyManifestHash: string;\n nativeViewports: Viewport[];\n};\ntype Claim = { request: RequestTarget; claimCapability: string };\nexport type Manifest = {\n components: {\n id: string;\n /** `{ path, export, kind? }` for a file or section; `{ kind: \"page\", route, … }` for a placement or layout section. */\n source: Record<string, unknown>;\n defaultProps: Record<string, unknown>;\n /** On an explicitly recorded source: the page this component would render from without it. */\n fallback?: { route: string };\n }[];\n brandTokenNames: string[];\n};\nexport type RenderResult = {\n results: { name: string; width: number; height: number; status: \"baseline-missing\"; candidateDigest: string }[];\n consoleErrors: number;\n runtimeErrors: number;\n missingTokens: string[];\n problems: string[];\n};\nexport type Api = <T>(path: string, init?: { method?: string; body?: unknown; claim?: string }) => Promise<T>;\n/** The built, packaged and started runtime every component in the run renders through. */\nexport type PreparedRuntime = {\n kinds: Record<string, string>;\n bundle: Buffer;\n storeProps(componentId: string, props: Record<string, unknown>, signal: AbortSignal): Promise<string>;\n render(renderId: string, viewports: Viewport[], tokenNames: string[], options: { section: boolean }, signal: AbortSignal): Promise<RenderResult>;\n /** The app server's own error lines so far — a component's are the ones logged while it rendered. */\n serverErrorCount(): number;\n serverErrorsSince(mark: number): string[];\n close(): Promise<void>;\n};\nexport type BatchContext = {\n projectId: string;\n commitSha: string;\n previewOrigin: string;\n run: { providerRunId: string; providerRunAttempt: number; providerRunUrl: string; workflowRef: string };\n};\nexport type BatchDeps = {\n api: Api;\n prepare(manifest: Manifest): Promise<PreparedRuntime>;\n putBundle(uploadUrl: string, bytes: Buffer): Promise<{ ok: boolean; status: number }>;\n /** This runner's version, stamped on the bundle it registers so a later runtime refresh can tell stale ones apart. */\n runtimeVersion?: string;\n log?(line: string): void;\n error?(line: string): void;\n /** Clock, budget and step deadlines; defaults are the constants above. Overridden by tests. */\n now?(): number;\n budgetMs?: number;\n timeouts?: { propsMs?: number; renderPerViewportMs?: number; apiMs?: number };\n};\n\n/** Runs `run` with a deadline: past it the signal aborts and the step fails with a message naming it. */\nasync function bounded<T>(what: string, ms: number, run: (signal: AbortSignal) => Promise<T>): Promise<T> {\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n const limit = ms >= 1000 ? `${Math.round(ms / 1000)} seconds` : `${ms} ms`;\n reject(new ValidationFailure(\"COMPONENT_VALIDATION_STEP_TIMEOUT\", `${what} did not finish within ${limit}.`));\n }, ms);\n });\n try {\n return await Promise.race([run(controller.signal), expired]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport class ValidationFailure extends Error {\n constructor(readonly code: string, message: string) {\n super(message);\n this.name = \"ValidationFailure\";\n }\n}\n\nfunction required(name: string, env: Record<string, string | undefined> = process.env): string {\n const value = env[name]?.trim();\n if (!value) throw new CliFailure(`${name} is not set. This command runs inside the BetterCMS component validation workflow.`);\n return value;\n}\n\nconst isViewport = (value: unknown): value is Viewport =>\n !!value && typeof value === \"object\"\n && typeof (value as Viewport).name === \"string\"\n && Number.isFinite((value as Viewport).width)\n && Number.isFinite((value as Viewport).height);\n\nconst isBatchItem = (value: unknown): value is BatchItem => {\n if (!value || typeof value !== \"object\") return false;\n const item = value as Record<string, unknown>;\n return [\"requestId\", \"componentId\", \"familyKey\"].every((key) => typeof item[key] === \"string\" && (item[key] as string).trim() !== \"\")\n && Array.isArray(item.nativeViewports) && item.nativeViewports.length > 0 && item.nativeViewports.every(isViewport);\n};\n\nconst invalidBatch = (detail: string) => new CliFailure(`COMPONENT_VALIDATION_BATCH_INVALID: ${detail}`);\n\n/**\n * What this run validates. `BCMS_BATCH` (the dispatch's `batch`, JSON) names several components; a dispatch\n * without one — `toJSON` of an absent key is `null` — names one through the single-component variables, which is\n * every dispatch a BetterCMS backend made before batches existed.\n */\nexport function resolveBatch(env: Record<string, string | undefined> = process.env): BatchItem[] {\n const raw = env.BCMS_BATCH?.trim();\n if (raw && raw !== \"null\") {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw invalidBatch(\"BCMS_BATCH is not valid JSON.\");\n }\n if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(isBatchItem)) {\n throw invalidBatch(\"BCMS_BATCH must be a non-empty array of { requestId, componentId, familyKey, nativeViewports }.\");\n }\n if (new Set(parsed.map((item) => item.requestId)).size !== parsed.length) {\n throw invalidBatch(\"BCMS_BATCH names the same request twice.\");\n }\n return parsed;\n }\n const requestId = required(\"BCMS_REQUEST_ID\", env);\n const componentId = required(\"BCMS_COMPONENT_ID\", env);\n const familyKey = required(\"BCMS_FAMILY_KEY\", env);\n let nativeViewports: unknown;\n try {\n nativeViewports = JSON.parse(required(\"BCMS_NATIVE_VIEWPORTS\", env));\n } catch (error) {\n if (error instanceof CliFailure) throw error;\n throw invalidBatch(\"BCMS_NATIVE_VIEWPORTS is not valid JSON.\");\n }\n const item = { requestId, componentId, familyKey, nativeViewports };\n if (!isBatchItem(item)) throw invalidBatch(\"BCMS_NATIVE_VIEWPORTS must be a non-empty array of { name, width, height }.\");\n return [item];\n}\n\nconst sha256 = (data: string | Buffer) => createHash(\"sha256\").update(data).digest(\"hex\");\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n return `{${Object.keys(value as Record<string, unknown>).sort()\n .map((key) => `${JSON.stringify(key)}:${canonical((value as Record<string, unknown>)[key])}`).join(\",\")}}`;\n }\n return JSON.stringify(value);\n}\n\nconst toCliFailure = (error: unknown) =>\n new CliFailure(`${error instanceof ValidationFailure ? error.code : \"COMPONENT_VALIDATION_FAILED\"}: ${(error as Error).message.slice(0, 2000)}`);\n\n/**\n * Validates every component in `batch` against one build. Returns which components were reported as completed\n * and which failed; `exitCode` is 1 when any component could not produce a result (a completion whose checks\n * failed is still a result). Throws only when nothing could be validated at all, after reporting every\n * component's failure.\n */\nexport async function runValidationBatch(batch: BatchItem[], ctx: BatchContext, deps: BatchDeps) {\n const now = deps.now ?? Date.now;\n // Counted from the start, so the build and the upload spend the same budget the job timeout does.\n const deadline = now() + (deps.budgetMs ?? DEFAULT_BATCH_BUDGET_MS);\n const propsMs = deps.timeouts?.propsMs ?? LOCAL_FETCH_TIMEOUT_MS;\n const renderPerViewportMs = deps.timeouts?.renderPerViewportMs ?? RENDER_TIMEOUT_PER_VIEWPORT_MS;\n const apiMs = deps.timeouts?.apiMs ?? API_TIMEOUT_MS;\n const seconds = (ms: number) => `${Math.ceil(Math.max(ms, 0) / 1000)}s`;\n const log = deps.log ?? ((line: string) => console.log(line));\n const logError = deps.error ?? ((line: string) => console.error(line));\n const requestPath = (item: BatchItem) =>\n `/api/v1/projects/${ctx.projectId}/component-implementation/implementation-requests/${item.requestId}`;\n const completed: string[] = [];\n const failed: string[] = [];\n\n /**\n * 🔴 CLAIMED LAST, NOT FIRST. A claim credential lives minutes, and `complete` refuses an expired one.\n * Claiming before a framework build, a browser install and a render meant every real run finished with\n * a credential that had already lapsed — and the request sat \"running\" until it expired. Everything slow\n * happens first; each component's claim is followed only by its completion.\n */\n const claim = (item: BatchItem) => deps.api<Claim>(`${requestPath(item)}/claim`, {\n method: \"POST\",\n body: {\n componentId: item.componentId,\n commitSha: ctx.commitSha,\n adapter: {\n protocol: \"bcms-component-runtime-v1\",\n kind: \"project-route\",\n path: RUNTIME_PATH,\n familyKey: item.familyKey,\n previewOrigin: ctx.previewOrigin,\n nativeViewports: item.nativeViewports,\n },\n providerRunId: ctx.run.providerRunId,\n providerRunAttempt: ctx.run.providerRunAttempt,\n providerRunUrl: ctx.run.providerRunUrl,\n workflowRef: ctx.run.workflowRef,\n // The server caps this at the request's own expiry and at ten minutes.\n credentialExpiresAt: new Date(Date.now() + 10 * 60_000 - 5_000).toISOString(),\n },\n });\n\n // A failure before the claim is still reported: claim, then fail at once, so the dashboard names the reason\n // instead of showing \"running\" until the request expires.\n const report = async (item: BatchItem, held: Claim | null, error: unknown) => {\n const code = error instanceof ValidationFailure ? error.code : \"COMPONENT_VALIDATION_FAILED\";\n const message = (error as Error).message.slice(0, 2000);\n failed.push(item.componentId);\n logError(`bcms-preview: ${code}: ${message} (component ${item.componentId})`);\n const reported = held ?? await claim(item).catch((claimError) => {\n logError(`bcms-preview: could not claim request ${item.requestId} to report the failure: ${(claimError as Error).message}`);\n return null;\n });\n if (!reported) return;\n await deps.api(`${requestPath(item)}/fail`, {\n method: \"POST\",\n claim: reported.claimCapability,\n body: { componentId: item.componentId, errorCode: code, errorMessage: message },\n }).catch((reportError) => logError(`bcms-preview: could not report the failure: ${(reportError as Error).message}`));\n };\n\n let manifest: Manifest;\n try {\n // `kinds=page`: this validator builds page-kind entries. A 0.2.0 validator never asks, and never gets one.\n manifest = await deps.api<Manifest>(`/api/v1/projects/${ctx.projectId}/component-preview/manifest?kinds=page`);\n } catch (error) {\n for (const item of batch) await report(item, null, error);\n throw toCliFailure(error);\n }\n\n // A recorded file that fails while the component also renders from its page: the fix is to drop the file.\n // Known before the build, so a file that does not even build carries it too.\n const hintFor = (componentId: string) => {\n const entry = manifest.components.find((c) => c.id === componentId);\n return entry?.fallback && (entry.source as { kind?: unknown }).kind !== \"page\"\n ? [`Clear the recorded source: this component renders from page ${entry.fallback.route} without one.`]\n : [];\n };\n\n const pending: BatchItem[] = [];\n for (const item of batch) {\n if (manifest.components.some((c) => c.id === item.componentId)) {\n pending.push(item);\n } else {\n await report(item, null, new ValidationFailure(\n \"COMPONENT_SOURCE_NOT_RECORDED\",\n \"No file is recorded and this component is neither placed on a page nor used in the layout, so there is nothing to render. Place it, add it to the layout, or record its file.\",\n ));\n }\n }\n if (pending.length === 0) return { completed, failed, exitCode: 1 as const };\n\n let runtime: PreparedRuntime | null = null;\n try {\n runtime = await deps.prepare(manifest);\n // Uploaded before any claim: the upload needs only the key, and validated evidence pointing at a runtime\n // nobody can start renders nothing.\n const upload = await deps.api<{ uploadUrl: string; uploadKey: string }>(`/api/v1/projects/${ctx.projectId}/artifacts/upload-url`, { method: \"POST\" });\n const put = await deps.putBundle(upload.uploadUrl, runtime.bundle);\n if (!put.ok) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED\", `Storage refused the preview bundle (HTTP ${put.status}).`);\n }\n await deps.api(`/api/v1/projects/${ctx.projectId}/component-preview/bundles`, {\n method: \"POST\",\n body: {\n commitSha: ctx.commitSha,\n uploadKey: upload.uploadKey,\n checksum: `sha256:${sha256(runtime.bundle)}`,\n sizeBytes: runtime.bundle.byteLength,\n ...(deps.runtimeVersion ? { runtimeVersion: deps.runtimeVersion } : {}),\n },\n });\n } catch (error) {\n await runtime?.close().catch(() => {});\n for (const item of pending) {\n const hint = error instanceof ValidationFailure && error.code === \"COMPONENT_PREVIEW_BUILD_FAILED\" ? hintFor(item.componentId) : [];\n await report(item, null, hint.length ? new ValidationFailure((error as ValidationFailure).code, [(error as Error).message, ...hint].join(\" \")) : error);\n }\n throw toCliFailure(error);\n }\n\n const ready = runtime;\n try {\n for (const item of pending) {\n // Started only when this component's own worst case fits: props, every viewport's render, a claim and a\n // completion. One that does not fit is reported now; a smaller one after it may still fit.\n const worstCase = propsMs + renderPerViewportMs * item.nativeViewports.length + 2 * apiMs;\n const left = deadline - now();\n if (left < worstCase) {\n await report(item, null, new ValidationFailure(\n \"COMPONENT_VALIDATION_BATCH_TIMEOUT\",\n `The validation batch did not have enough time left for this component (needs up to ${seconds(worstCase)}, ${seconds(left)} left). Request validation again.`,\n ));\n continue;\n }\n const entry = manifest.components.find((c) => c.id === item.componentId)!;\n const hint = hintFor(item.componentId);\n let held: Claim | null = null;\n try {\n const mark = ready.serverErrorCount();\n const renderId = await bounded(\n `The preview runtime's props endpoint for ${item.componentId}`,\n propsMs,\n (signal) => ready.storeProps(item.componentId, entry.defaultProps, signal),\n );\n // The viewports the dispatch declared are exactly the ones the claim records as the adapter's.\n const render = await bounded(\n `Rendering ${item.componentId}`,\n renderPerViewportMs * item.nativeViewports.length,\n (signal) => ready.render(\n renderId,\n item.nativeViewports,\n manifest.brandTokenNames,\n // A page-kind render lifts a section too, and stamps its root.\n { section: ready.kinds[item.componentId] !== \"file\" },\n signal,\n ),\n );\n /**\n * The app's own server errors (`TypeError: Cannot read properties of undefined`) are the real reason a\n * render fails — the browser only sees \"500\". The first few logged while this component rendered are\n * kept for its evidence so the panel can say what broke.\n */\n const serverErrors = ready.serverErrorsSince(mark).slice(0, 5);\n\n held = await claim(item);\n const target = held.request;\n const checks = {\n brandKit: {\n status: render.missingTokens.length === 0 ? \"passed\" : \"failed\",\n contractHash: target.brandContractHash,\n missingTokens: render.missingTokens,\n },\n runtime: {\n status: render.runtimeErrors === 0 && render.consoleErrors === 0 ? \"passed\" : \"failed\",\n runtimeErrors: render.runtimeErrors,\n consoleErrors: render.consoleErrors,\n // Only on a failure, and bounded: the server's own error lines first (the real cause), then what the\n // browser saw. The database stores them and the panel shows the first one.\n ...(render.runtimeErrors + render.consoleErrors > 0\n ? { problems: [...hint, ...serverErrors.map((line) => `server: ${line}`), ...render.problems].slice(0, 10).map((line) => line.slice(0, 200)) }\n : {}),\n },\n visual: { status: \"baseline-missing\", reviewRequired: true, viewports: render.results },\n };\n\n const evidenceDigest = `sha256:${sha256(canonical({ requestId: item.requestId, commitSha: target.commitSha, checks }))}`;\n await deps.api(`${requestPath(item)}/complete`, {\n method: \"POST\",\n claim: held.claimCapability,\n body: {\n componentId: target.componentId,\n candidateId: target.candidateId,\n componentVersion: target.componentVersion,\n familyKey: target.familyKey,\n familyContractHash: target.familyContractHash,\n schemaHash: target.schemaHash,\n brandContractHash: target.brandContractHash,\n dependenciesHash: target.dependenciesHash,\n commitSha: target.commitSha,\n adapterHash: target.adapterHash,\n familyManifestHash: target.familyManifestHash,\n nativeViewports: target.nativeViewports,\n checks,\n evidenceDigest,\n },\n });\n completed.push(item.componentId);\n\n const passed = checks.brandKit.status === \"passed\" && checks.runtime.status === \"passed\";\n log(`bcms-preview: validation ${passed ? \"PASSED\" : \"FAILED\"} for ${item.componentId}`);\n if (!passed) {\n if (render.missingTokens.length) log(` brand tokens used but not defined: ${render.missingTokens.join(\", \")}`);\n for (const problem of [...hint, ...render.problems]) log(` ${problem}`);\n }\n } catch (error) {\n await report(item, held, error);\n }\n }\n } finally {\n await ready.close().catch(() => {});\n }\n return { completed, failed, exitCode: failed.length > 0 ? (1 as const) : (0 as const) };\n}\n\nfunction freePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => {\n const address = server.address();\n const port = typeof address === \"object\" && address ? address.port : 0;\n server.close(() => resolve(port));\n });\n });\n}\n\nasync function waitForOk(url: string, timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n try {\n if ((await fetch(url, { signal: AbortSignal.timeout(HEALTH_PROBE_TIMEOUT_MS) })).ok) return true;\n } catch {\n // not up yet\n }\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n\n/** Install Chromium for the bundled Playwright. On a Linux CI runner, with its system dependencies. */\nfunction ensureBrowser() {\n const require = createRequire(import.meta.url);\n const cli = join(dirname(require.resolve(\"playwright/package.json\")), \"cli.js\");\n const args = [cli, \"install\", \"chromium\"];\n if (process.platform === \"linux\" && process.env.CI) args.push(\"--with-deps\");\n const result = spawnSync(process.execPath, args, { stdio: \"inherit\" });\n if (result.status !== 0) {\n throw new ValidationFailure(\"COMPONENT_VALIDATION_BROWSER_UNAVAILABLE\", \"A headless browser could not be installed on this runner.\");\n }\n}\n\nexport async function renderInBrowser(browser: Browser, url: string, viewports: Viewport[], tokenNames: string[], options: { section: boolean }, signal?: AbortSignal): Promise<RenderResult> {\n let consoleErrors = 0;\n let runtimeErrors = 0;\n const missingTokens = new Set<string>();\n const results: RenderResult[\"results\"] = [];\n const problems: string[] = [];\n for (const viewport of viewports) {\n // Past its deadline the step has already failed; do not keep opening pages for it.\n if (signal?.aborted) break;\n const page = await browser.newPage({ viewport: { width: viewport.width, height: viewport.height } });\n // 🔴 A page stuck in goto/evaluate/screenshot past its deadline keeps running in the shared browser, and the\n // app errors it causes would land in the NEXT component's evidence. Closing it ends the stuck call.\n const onAbort = () => {\n page.close().catch(() => {});\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (signal?.aborted) onAbort();\n try {\n page.on(\"console\", (message) => {\n if (message.type() === \"error\") {\n consoleErrors += 1;\n problems.push(`${viewport.name} console: ${message.text().slice(0, 200)}`);\n }\n });\n page.on(\"pageerror\", (error) => {\n runtimeErrors += 1;\n problems.push(`${viewport.name} error: ${error.message.slice(0, 200)}`);\n });\n const response = await page.goto(url, { waitUntil: \"load\", timeout: 45_000 });\n await page.waitForLoadState(\"networkidle\", { timeout: 15_000 }).catch(() => {});\n const rendered = await page.locator(\"[data-bcms-preview-render]\").count();\n if (!response?.ok() || rendered === 0) {\n runtimeErrors += 1;\n problems.push(`${viewport.name}: the component page did not render (HTTP ${response?.status() ?? \"none\"})`);\n } else if (options.section && (await page.locator(\"[data-bcms-block]\").count()) === 0) {\n // The codemod stamps data-bcms-block on every section root, and the editor resolves a section's\n // fields by walking up to it: a section without one renders but cannot be edited.\n runtimeErrors += 1;\n problems.push(`${viewport.name}: the section rendered without its [data-bcms-block] root`);\n }\n /**\n * A token is MISSING only when the rendered page uses it and it resolves to nothing. `--bcms-*` are\n * guaranteed on pages BetterCMS renders itself, not in a customer's framework build, so asking\n * \"is every token defined?\" would fail every starter while saying nothing about the component. The\n * question worth a failure is \"does this component reference a brand token the app never defines?\"\n * — a component that will render unstyled on the live site. Cross-origin stylesheets cannot be read\n * and are skipped.\n */\n const missing = await page.evaluate((names: string[]) => {\n const referenced = new Set<string>();\n const scan = (text: string) => {\n for (const match of text.matchAll(/var\\(\\s*(--[A-Za-z0-9_-]+)/g)) referenced.add(match[1]!);\n };\n for (const sheet of Array.from(document.styleSheets)) {\n try {\n for (const rule of Array.from(sheet.cssRules)) scan(rule.cssText);\n } catch {\n // cross-origin sheet\n }\n }\n document.querySelectorAll(\"[style]\").forEach((element) => scan(element.getAttribute(\"style\") ?? \"\"));\n const style = getComputedStyle(document.documentElement);\n return names.filter((name) => referenced.has(name) && !style.getPropertyValue(name).trim());\n }, tokenNames);\n for (const token of missing) missingTokens.add(token);\n const png = await page.screenshot({ fullPage: true });\n results.push({\n name: viewport.name,\n width: viewport.width,\n height: viewport.height,\n // No baseline exists for a first validation. The database requires this exact shape for it:\n // no baseline or diff digest, and the check marked as needing review.\n status: \"baseline-missing\",\n candidateDigest: `sha256:${sha256(png)}`,\n });\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n await page.close().catch(() => {});\n }\n }\n return { results, consoleErrors, runtimeErrors, missingTokens: [...missingTokens].sort(), problems };\n}\n\nexport async function validateComponent() {\n const apiUrl = required(\"BCMS_API_URL\");\n const apiKey = required(\"BCMS_API_KEY\");\n // A refresh dispatch names no request: read first, or resolveBatch would demand one.\n const refresh = resolveRefresh();\n const batch = refresh ? [] : resolveBatch();\n const ctx: BatchContext = {\n projectId: required(\"BCMS_PROJECT_ID\"),\n commitSha: required(\"BCMS_COMMIT_SHA\"),\n previewOrigin: required(\"BCMS_PREVIEW_ORIGIN\"),\n run: {\n providerRunId: required(\"BCMS_RUN_ID\"),\n providerRunAttempt: Number(process.env.BCMS_RUN_ATTEMPT) || 1,\n providerRunUrl: required(\"BCMS_RUN_URL\"),\n workflowRef: required(\"BCMS_WORKFLOW_REF\"),\n },\n };\n\n const api: Api = async <T>(path: string, init: { method?: string; body?: unknown; claim?: string } = {}): Promise<T> => {\n let response: Response;\n let text: string;\n try {\n response = await fetch(new URL(path, apiUrl), {\n method: init.method ?? \"GET\",\n headers: {\n authorization: `Bearer ${apiKey}`,\n \"content-type\": \"application/json\",\n ...(init.claim ? { \"x-bcms-component-claim\": init.claim } : {}),\n },\n ...(init.body === undefined ? {} : { body: JSON.stringify(init.body) }),\n signal: AbortSignal.timeout(API_TIMEOUT_MS),\n });\n text = await response.text();\n } catch (error) {\n const name = (error as Error).name;\n if (name === \"TimeoutError\" || name === \"AbortError\") {\n throw new ValidationFailure(\"COMPONENT_VALIDATION_API_TIMEOUT\", `${init.method ?? \"GET\"} ${path} did not answer within ${API_TIMEOUT_MS / 1000} seconds.`);\n }\n throw error;\n }\n let parsed: { data?: unknown; error?: unknown; message?: unknown } | null = null;\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = null;\n }\n if (!response.ok) {\n const code = typeof parsed?.error === \"string\" && /^[A-Z][A-Z0-9_]*$/.test(parsed.error) ? parsed.error : `API_HTTP_${response.status}`;\n const detail = typeof parsed?.message === \"string\" ? parsed.message : typeof parsed?.error === \"string\" ? parsed.error : text.slice(0, 300);\n throw new ValidationFailure(code, `${init.method ?? \"GET\"} ${path} answered ${response.status}: ${detail}`);\n }\n return ((parsed && \"data\" in parsed ? parsed.data : parsed) ?? {}) as T;\n };\n\n const work = mkdtempSync(join(tmpdir(), \"bcms-validate-\"));\n\n const prepare = async (manifest: Manifest): Promise<PreparedRuntime> => {\n const manifestPath = join(work, \"manifest.json\");\n writeFileSync(manifestPath, JSON.stringify({ components: manifest.components.map(({ id, source, fallback }) => ({ id, source, ...(fallback ? { fallback } : {}) })) }));\n const out = join(work, \"runtime\");\n let built: ReturnType<typeof buildPreviewRuntime>;\n try {\n built = buildPreviewRuntime({ root: process.cwd(), manifestPath, out });\n } catch (error) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUILD_FAILED\", `The preview build failed: ${(error as Error).message}`);\n }\n\n // Packed before the runtime starts, so the bundle is exactly the tree that was built.\n const tarball = join(work, \"bundle.tgz\");\n if (spawnSync(\"tar\", [\"-czf\", tarball, \"-C\", out, \".\"], { stdio: \"inherit\" }).status !== 0) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_PACK_FAILED\", \"The preview runtime could not be packaged.\");\n }\n const bundle = readFileSync(tarball);\n\n const runtimeManifest = JSON.parse(readFileSync(join(out, \"bcms-runtime.json\"), \"utf8\")) as { dir: string; entry: string };\n const port = await freePort();\n const validatorKey = randomBytes(32).toString(\"base64url\");\n const local = `http://127.0.0.1:${port}`;\n // 🔴 The customer's code runs in this process tree. It gets no BetterCMS API key.\n const { BCMS_API_KEY: _withheld, ...inherited } = process.env;\n const child = spawn(process.execPath, [join(out, runtimeManifest.dir, runtimeManifest.entry)], {\n cwd: join(out, runtimeManifest.dir),\n env: {\n ...inherited,\n NODE_ENV: \"production\",\n PORT: String(port),\n HOST: \"127.0.0.1\",\n HOSTNAME: \"127.0.0.1\",\n BCMS_API_URL: apiUrl,\n BCMS_DASHBOARD_ORIGIN: local,\n BCMS_PREVIEW_ORIGIN: local,\n BCMS_PREVIEW_VALIDATOR_KEY: validatorKey,\n },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n // Still echoed to the CI log; every line that looks like an error is kept (bounded) so each component's\n // evidence can carry the ones logged while it rendered.\n const serverErrors: string[] = [];\n const collect = (stream: NodeJS.WriteStream) => (chunk: Buffer) => {\n stream.write(chunk);\n for (const line of chunk.toString(\"utf8\").split(\"\\n\")) {\n const clean = line.replace(/\\x1b\\[[0-9;]*m/g, \"\").trim();\n if (serverErrors.length < 500 && /\\b(error|exception)\\b/i.test(clean)) serverErrors.push(clean.slice(0, 200));\n }\n };\n child.stdout?.on(\"data\", collect(process.stdout));\n child.stderr?.on(\"data\", collect(process.stderr));\n\n let browser: Browser | null = null;\n try {\n if (!(await waitForOk(`${local}${PREVIEW_ROUTE_BASE}/health`, 60_000))) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_RUNTIME_DID_NOT_START\", \"The preview runtime did not start within 60 seconds.\");\n }\n ensureBrowser();\n const { chromium } = await import(\"playwright\");\n browser = await chromium.launch();\n } catch (error) {\n child.kill();\n throw error;\n }\n const shared = browser;\n\n return {\n kinds: built.kinds,\n bundle,\n storeProps: async (componentId, props, signal) => {\n const stored = await fetch(`${local}${PREVIEW_ROUTE_BASE}/props`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-bcms-validator-key\": validatorKey },\n body: JSON.stringify({ componentId, props }),\n signal,\n });\n if (!stored.ok) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_RUNTIME_REFUSED\", `The preview runtime refused the component (HTTP ${stored.status}).`);\n }\n return ((await stored.json()) as { id: string }).id;\n },\n render: (renderId, viewports, tokenNames, options, signal) =>\n renderInBrowser(shared, `${local}${PREVIEW_ROUTE_BASE}/render?id=${encodeURIComponent(renderId)}`, viewports, tokenNames, options, signal),\n serverErrorCount: () => serverErrors.length,\n serverErrorsSince: (mark) => serverErrors.slice(mark),\n close: async () => {\n child.kill();\n await shared.close().catch(() => {});\n },\n };\n };\n\n const putBundle: BatchDeps[\"putBundle\"] = async (uploadUrl, bytes) => {\n try {\n const put = await fetch(uploadUrl, {\n method: \"PUT\",\n body: new Uint8Array(bytes),\n headers: { \"content-type\": \"application/gzip\" },\n signal: AbortSignal.timeout(BUNDLE_UPLOAD_TIMEOUT_MS),\n });\n return { ok: put.ok, status: put.status };\n } catch (error) {\n const name = (error as Error).name;\n if (name !== \"TimeoutError\" && name !== \"AbortError\") throw error;\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED\", `Storage did not accept the preview bundle within ${BUNDLE_UPLOAD_TIMEOUT_MS / 60_000} minutes.`);\n }\n };\n const runtimeVersion = runnerVersion();\n\n const budget = Number(process.env.BCMS_BATCH_BUDGET_MS);\n try {\n if (refresh) {\n await runRuntimeRefresh(refresh, ctx, { api, prepare, putBundle, runtimeVersion });\n return;\n }\n const result = await runValidationBatch(batch, ctx, {\n api,\n prepare,\n putBundle,\n runtimeVersion,\n budgetMs: Number.isFinite(budget) && budget > 0 ? budget : DEFAULT_BATCH_BUDGET_MS,\n });\n if (batch.length > 1) {\n console.log(`bcms-preview: ${result.completed.length} of ${batch.length} components completed, ${result.failed.length} could not be validated`);\n }\n if (result.exitCode) process.exitCode = 1;\n } finally {\n rmSync(work, { recursive: true, force: true });\n }\n}\n\n/** This runner's own version, from its package.json (`src/` and `dist/` both sit one level below it). */\nfunction runnerVersion(): string | undefined {\n try {\n const version = (createRequire(import.meta.url)(\"../package.json\") as { version?: unknown }).version;\n return typeof version === \"string\" ? version : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport type RefreshItem = { componentId: string; familyKey: string; nativeViewports: Viewport[] };\n/** A runtime refresh: the components validated on the checked-out commit, rebuilt and re-rendered with this runner. */\nexport type RefreshPlan = { refreshId: string; items: RefreshItem[] };\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst isRefreshItem = (value: unknown): value is RefreshItem => {\n if (!value || typeof value !== \"object\") return false;\n const item = value as Record<string, unknown>;\n return [\"componentId\", \"familyKey\"].every((key) => typeof item[key] === \"string\" && (item[key] as string).trim() !== \"\")\n && Array.isArray(item.nativeViewports) && item.nativeViewports.length > 0 && item.nativeViewports.every(isViewport);\n};\n\n/** `BCMS_REFRESH` (the dispatch's `refresh`, JSON), or null for a validation run — `toJSON` of an absent key is `null`. */\nexport function resolveRefresh(env: Record<string, string | undefined> = process.env): RefreshPlan | null {\n const raw = env.BCMS_REFRESH?.trim();\n if (!raw || raw === \"null\") return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new CliFailure(\"COMPONENT_PREVIEW_REFRESH_INVALID: BCMS_REFRESH is not valid JSON.\");\n }\n const plan = parsed as Partial<RefreshPlan> | null;\n if (!plan || typeof plan.refreshId !== \"string\" || !UUID.test(plan.refreshId)\n || !Array.isArray(plan.items) || plan.items.length === 0 || !plan.items.every(isRefreshItem)) {\n throw new CliFailure(\"COMPONENT_PREVIEW_REFRESH_INVALID: BCMS_REFRESH must be { refreshId, items: [{ componentId, familyKey, nativeViewports }] }.\");\n }\n return { refreshId: plan.refreshId, items: plan.items };\n}\n\n/**\n * Rebuild this commit's preview runtime with this runner and replace its bundle — ONLY when every component validated\n * on the commit still renders cleanly through it (the same brand-token and runtime checks a validation passes).\n *\n * 🔴 NO REQUEST IS CLAIMED OR COMPLETED: the components' evidence stands whatever happens here. Any failure is reported\n * against the refresh, and the bundle that was serving keeps serving. Rendered before uploading, the reverse of a\n * validation, because an upload here replaces a runtime that works.\n */\nexport async function runRuntimeRefresh(\n plan: RefreshPlan,\n ctx: Pick<BatchContext, \"projectId\" | \"commitSha\">,\n deps: BatchDeps,\n): Promise<{ refreshed: true }> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const logError = deps.error ?? ((line: string) => console.error(line));\n const propsMs = deps.timeouts?.propsMs ?? LOCAL_FETCH_TIMEOUT_MS;\n const renderPerViewportMs = deps.timeouts?.renderPerViewportMs ?? RENDER_TIMEOUT_PER_VIEWPORT_MS;\n const base = `/api/v1/projects/${ctx.projectId}`;\n\n const fail = async (error: unknown): Promise<never> => {\n const code = error instanceof ValidationFailure ? error.code : \"COMPONENT_PREVIEW_REFRESH_FAILED\";\n const message = (error as Error).message.slice(0, 2000);\n logError(`bcms-preview: ${code}: ${message} (runtime refresh ${plan.refreshId})`);\n await deps.api(`${base}/component-preview/refreshes/${plan.refreshId}/fail`, {\n method: \"POST\",\n body: { errorCode: code, errorMessage: message },\n }).catch((reportError) => logError(`bcms-preview: could not report the refresh failure: ${(reportError as Error).message}`));\n throw new CliFailure(`${code}: ${message}`);\n };\n\n let manifest: Manifest;\n try {\n manifest = await deps.api<Manifest>(`${base}/component-preview/manifest?kinds=page`);\n } catch (error) {\n return fail(error);\n }\n const missing = plan.items.filter((item) => !manifest.components.some((c) => c.id === item.componentId)).map((item) => item.componentId);\n if (missing.length > 0) {\n return fail(new ValidationFailure(\n \"COMPONENT_SOURCE_NOT_RECORDED\",\n `Nothing to render for ${missing.join(\", \")}: no file is recorded and it is neither placed on a page nor used in the layout. Validate it again.`,\n ));\n }\n // Only the components validated on this commit: one added since may not exist in this commit's tree.\n const listed = new Set(plan.items.map((item) => item.componentId));\n const scoped: Manifest = { ...manifest, components: manifest.components.filter((c) => listed.has(c.id)) };\n\n let runtime: PreparedRuntime;\n try {\n runtime = await deps.prepare(scoped);\n } catch (error) {\n return fail(error);\n }\n const ready = runtime;\n try {\n const problems: string[] = [];\n for (const item of plan.items) {\n const entry = scoped.components.find((c) => c.id === item.componentId)!;\n try {\n const renderId = await bounded(\n `The preview runtime's props endpoint for ${item.componentId}`,\n propsMs,\n (signal) => ready.storeProps(item.componentId, entry.defaultProps, signal),\n );\n const render = await bounded(\n `Rendering ${item.componentId}`,\n renderPerViewportMs * item.nativeViewports.length,\n (signal) => ready.render(renderId, item.nativeViewports, scoped.brandTokenNames, { section: ready.kinds[item.componentId] !== \"file\" }, signal),\n );\n const lines = [\n ...(render.missingTokens.length ? [`brand tokens used but not defined: ${render.missingTokens.join(\", \")}`] : []),\n ...(render.runtimeErrors + render.consoleErrors > 0\n ? (render.problems.length ? render.problems : [`${render.runtimeErrors + render.consoleErrors} runtime or console error(s)`])\n : []),\n ];\n if (lines.length > 0) problems.push(`${item.componentId}: ${lines.slice(0, 3).map((line) => line.slice(0, 200)).join(\"; \")}`);\n else log(`bcms-preview: runtime refresh renders ${item.componentId}`);\n } catch (error) {\n problems.push(`${item.componentId}: ${(error as Error).message.slice(0, 200)}`);\n }\n }\n if (problems.length > 0) {\n return fail(new ValidationFailure(\n \"COMPONENT_PREVIEW_REFRESH_RENDER_FAILED\",\n `Kept the current runtime: ${problems.length} of ${plan.items.length} component(s) did not render cleanly with this runner. ${problems.join(\" | \")}`,\n ));\n }\n try {\n const upload = await deps.api<{ uploadUrl: string; uploadKey: string }>(`${base}/artifacts/upload-url`, { method: \"POST\" });\n const put = await deps.putBundle(upload.uploadUrl, ready.bundle);\n if (!put.ok) {\n throw new ValidationFailure(\"COMPONENT_PREVIEW_BUNDLE_UPLOAD_FAILED\", `Storage refused the preview bundle (HTTP ${put.status}).`);\n }\n await deps.api(`${base}/component-preview/bundles`, {\n method: \"POST\",\n body: {\n commitSha: ctx.commitSha,\n uploadKey: upload.uploadKey,\n checksum: `sha256:${sha256(ready.bundle)}`,\n sizeBytes: ready.bundle.byteLength,\n refreshId: plan.refreshId,\n ...(deps.runtimeVersion ? { runtimeVersion: deps.runtimeVersion } : {}),\n },\n });\n } catch (error) {\n return fail(error);\n }\n log(`bcms-preview: runtime refreshed for ${plan.items.length} component(s) at ${ctx.commitSha}`);\n return { refreshed: true };\n } finally {\n await ready.close().catch(() => {});\n }\n}\n","/**\n * bcms-preview\n *\n * bcms-preview build --manifest <file> --out <dir> [--cwd <dir>]\n * bcms-preview validate (in CI; configured entirely by BCMS_* environment variables)\n */\nimport { buildPreviewRuntime, CliFailure } from \"./build\";\nimport { validateComponent } from \"./validate\";\n\nfunction arg(name: string): string | undefined {\n const index = process.argv.indexOf(`--${name}`);\n return index === -1 ? undefined : process.argv[index + 1];\n}\n\nasync function main() {\n const command = process.argv[2];\n if (command === \"build\") {\n const manifestPath = arg(\"manifest\");\n const out = arg(\"out\");\n if (!manifestPath || !out) throw new CliFailure(\"usage: bcms-preview build --manifest <file> --out <dir> [--cwd <dir>]\");\n console.log(JSON.stringify(buildPreviewRuntime({ root: arg(\"cwd\") ?? process.cwd(), manifestPath, out })));\n return;\n }\n if (command === \"validate\") {\n await validateComponent();\n return;\n }\n throw new CliFailure(\"usage: bcms-preview <build|validate>\");\n}\n\n/**\n * One handler for every failure, and no `process.exit`: writes to a piped stderr are asynchronous, so\n * exiting right after the write dropped the message and CI showed a failed step with no reason.\n */\nmain().catch((error) => {\n console.error(`bcms-preview: ${error instanceof CliFailure ? error.message : (error as Error).stack ?? String(error)}`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["require","spawnSync","readFileSync","rmSync","writeFileSync","createRequire","dirname","join","run","item","resolve","require","createRequire","join","dirname","spawnSync","writeFileSync","readFileSync","rmSync","fail"]}
@@ -1 +1,2 @@
1
- "use strict";(()=>{function U(e){let o=new ArrayBuffer(e.byteLength);return new Uint8Array(o).set(e),o}function P(e){let{protocol:o,...t}=e;return{...t,runtimeProtocol:o,nativeViewports:e.nativeViewports.map(n=>({...n}))}}function O(e){if(e===null||typeof e=="boolean"||typeof e=="string")return JSON.stringify(e);if(typeof e=="number"){if(!Number.isFinite(e))throw new TypeError("Canonical JSON only supports finite numbers");if(Object.is(e,-0))return"0";let o=JSON.stringify(e),t=/^(-?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(o);if(!t)return o;let[,n,r,c="",m]=t,a=`${r}${c}`,d=r.length+Number(m);return d<=0?`${n}0.${"0".repeat(-d)}${a}`:d>=a.length?`${n}${a}${"0".repeat(d-a.length)}`:`${n}${a.slice(0,d)}.${a.slice(d)}`}if(Array.isArray(e))return`[${e.map(o=>{try{return O(o)}catch{return"null"}}).join(",")}]`;if(e&&typeof e=="object"){let o=Object.entries(e).filter(([,n])=>n!==void 0&&typeof n!="function").sort(([n],[r])=>n<r?-1:n>r?1:0),t=[];for(let[n,r]of o)try{t.push(`${JSON.stringify(n)}:${O(r)}`)}catch{}return`{${t.join(",")}}`}throw new TypeError("Unsupported canonical JSON value")}async function x(e){let o=new TextEncoder().encode(O(e)),t=await crypto.subtle.digest("SHA-256",U(o));return`sha256:${[...new Uint8Array(t)].map(r=>r.toString(16).padStart(2,"0")).join("")}`}var f="bcms-component-preview/2";function L(e){let{claims:o,dashboardOrigin:t,onProps:n,onStatus:r=()=>{},onError:c=()=>{},retryIntervalMs:m=400,maxAnnounces:a=10,ackDeadlineMs:d=250}=e,S=P(o),u=null,k=!1,I=0,M=0,h=null,l=s=>{u?.postMessage({protocol:f,binding:S,...s})},E=()=>{h!==null&&clearInterval(h),h=null};if(typeof window>"u"||window.parent===window)return r({kind:"not-embedded",dashboardOrigin:t}),{dispose:()=>{}};let v=()=>{if(!k){if(I>=a){E(),console.warn(`[bcms] no BetterCMS dashboard answered at ${t}. If the dashboard is on another origin, dashboardOrigin is misconfigured.`),r({kind:"unanswered",dashboardOrigin:t});return}I+=1,window.parent.postMessage({protocol:f,kind:"runtime:ready",binding:S},t)}},H=async s=>{let i=s.data;if(i?.protocol!==f||i.kind!=="props")return;let p=i.propsRevision;if(typeof p!="number"||p<=M)return;let C=await x(i.props);if(C!==i.propsHash){l({kind:"runtime:error",error:{code:"PROPS_HASH_MISMATCH",message:"Props did not match their hash."}});return}M=p;try{await n(i.props)}catch(K){console.error("[bcms] component render failed:",K),l({kind:"runtime:error",error:{code:"RENDER_FAILED",message:"The component could not be rendered."}});return}let R=!1,_=()=>{R||(R=!0,l({kind:"props:ack",propsRevision:p,propsHash:C}))};requestAnimationFrame(()=>requestAnimationFrame(_)),setTimeout(_,d)},N=s=>{if(s.origin!==t){let C=s.data;s.source===window.parent&&C?.kind==="runtime:connect"&&console.warn(`[bcms] a BetterCMS dashboard at ${s.origin} tried to connect, but dashboardOrigin is ${t}. Refusing \u2014 set dashboardOrigin to ${s.origin} if that is your dashboard.`);return}if(s.source!==window.parent)return;let i=s.data;if(i?.protocol!==f||i.kind!=="runtime:connect")return;let p=s.ports[0];p&&(k=!0,E(),u=p,u.onmessage=H,u.start?.(),r({kind:"connected"}),l({kind:"runtime:connected"}))},T=s=>{let i={code:"RUNTIME_ERROR",message:String(s.message).slice(0,300)};c(i),l({kind:"runtime:error",error:i})},A=s=>{let i={code:"UNHANDLED_REJECTION",message:String(s.reason).slice(0,300)};c(i),l({kind:"runtime:error",error:i})};return r({kind:"connecting",dashboardOrigin:t}),window.addEventListener("message",N),window.addEventListener("error",T),window.addEventListener("unhandledrejection",A),v(),h=setInterval(v,m),{dispose:()=>{E(),window.removeEventListener("message",N),window.removeEventListener("error",T),window.removeEventListener("unhandledrejection",A),u?.close(),u=null,k=!1}}}function B(e){typeof window>"u"||window.parent===window||window.parent.postMessage({protocol:f,kind:"runtime:refused",cause:e.cause},e.dashboardOrigin)}var F=15e3,b=document.getElementById("bcms-status"),g=document.getElementById("bcms-frame"),y=JSON.parse(document.getElementById("bcms-preview-config").textContent),w=e=>{b.textContent=e,b.hidden=!1},D=(e,o)=>fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(o),credentials:"omit",cache:"no-store"}),J=50;function $(){try{let e=g.contentDocument;return!e||e.readyState==="loading"||e.location.href==="about:blank"?!1:!!e.querySelector("[data-bcms-preview-render]")}catch{return!1}}function V(e){return new Promise((o,t)=>{let n=!1,r=a=>{if(!n){if(n=!0,clearInterval(m),clearTimeout(c),g.onload=null,a){t(a);return}b.hidden=!0,g.hidden=!1,o()}},c=setTimeout(()=>r(new Error("render timed out")),F),m=setInterval(()=>{$()&&r()},J);g.onload=()=>r($()?void 0:new Error("the render page did not render (blocked, not found, or failed)")),g.src=`${y.routes.render}?id=${encodeURIComponent(e)}`})}async function j(){let e=new URL(location.href).searchParams.get("bcmsSession");history.replaceState(null,"",location.pathname);let t=await(await D(y.routes.session,{token:e})).json().catch(()=>null);if(!t||!t.ok){let n=t&&!t.ok&&t.cause==="keys-unreachable"?"keys-unreachable":"session-refused";B({dashboardOrigin:y.dashboardOrigin,cause:n}),w("This preview session was refused. The runtime log records why.");return}L({claims:t.claims,dashboardOrigin:y.dashboardOrigin,onProps:async n=>{let r=await D(y.routes.props,{renderKey:t.renderKey,props:n});if(!r.ok)throw new Error(`props were refused (HTTP ${r.status})`);let{id:c}=await r.json();await V(c)},onStatus:n=>{n.kind!=="connected"&&(n.kind==="connecting"?w("Connecting to BetterCMS\u2026"):n.kind==="unanswered"?w(`${n.dashboardOrigin} did not answer.`):w("This page is meant to be opened from BetterCMS."))}})}j().catch(e=>{console.error("[bcms-preview]",e),w("The preview could not start. The browser console records why.")});})();
1
+ "use strict";(()=>{function z(e){let n=new ArrayBuffer(e.byteLength);return new Uint8Array(n).set(e),n}function L(e){let{protocol:n,...r}=e;return{...r,runtimeProtocol:n,nativeViewports:e.nativeViewports.map(t=>({...t}))}}function O(e){if(e===null||typeof e=="boolean"||typeof e=="string")return JSON.stringify(e);if(typeof e=="number"){if(!Number.isFinite(e))throw new TypeError("Canonical JSON only supports finite numbers");if(Object.is(e,-0))return"0";let n=JSON.stringify(e),r=/^(-?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(n);if(!r)return n;let[,t,o,c="",m]=r,a=`${o}${c}`,d=o.length+Number(m);return d<=0?`${t}0.${"0".repeat(-d)}${a}`:d>=a.length?`${t}${a}${"0".repeat(d-a.length)}`:`${t}${a.slice(0,d)}.${a.slice(d)}`}if(Array.isArray(e))return`[${e.map(n=>{try{return O(n)}catch{return"null"}}).join(",")}]`;if(e&&typeof e=="object"){let n=Object.entries(e).filter(([,t])=>t!==void 0&&typeof t!="function").sort(([t],[o])=>t<o?-1:t>o?1:0),r=[];for(let[t,o]of n)try{r.push(`${JSON.stringify(t)}:${O(o)}`)}catch{}return`{${r.join(",")}}`}throw new TypeError("Unsupported canonical JSON value")}async function $(e){let n=new TextEncoder().encode(O(e)),r=await crypto.subtle.digest("SHA-256",z(n));return`sha256:${[...new Uint8Array(r)].map(o=>o.toString(16).padStart(2,"0")).join("")}`}var B=/^(chrome-extension|moz-extension|safari-web-extension|safari-extension):\/\//i,X=/^at .*?\(?([a-z][a-z0-9+.-]*:\/\/[^\s()]+?):\d+(?::\d+)?\)?$/i,Y=/@([a-z][a-z0-9+.-]*:\/\/[^\s()]+?):\d+(?::\d+)?$/i;function D(e){if(!e)return[];let n=[];for(let r of e.split(`
2
+ `)){let t=r.trim(),o=t.startsWith("at ")?X.exec(t):Y.exec(t);o?.[1]&&n.push(o[1])}return n}var K=e=>e.every(n=>B.test(n));function b(e){let n=e?.stack;return typeof n=="string"?n:void 0}function H(e,n){return!e||!B.test(e)?!1:K(D(n))}function F(e){let n=D(e);return n.length>0&&K(n)}var f="bcms-component-preview/2";function U(e){let{claims:n,dashboardOrigin:r,onProps:t,onStatus:o=()=>{},onError:c=()=>{},retryIntervalMs:m=400,maxAnnounces:a=10,ackDeadlineMs:d=250}=e,I=L(n),p=null,k=!1,M=0,N=0,h=null,l=s=>{p?.postMessage({protocol:f,binding:I,...s})},C=()=>{h!==null&&clearInterval(h),h=null};if(typeof window>"u"||window.parent===window)return o({kind:"not-embedded",dashboardOrigin:r}),{dispose:()=>{}};let v=()=>{if(!k){if(M>=a){C(),console.warn(`[bcms] no BetterCMS dashboard answered at ${r}. If the dashboard is on another origin, dashboardOrigin is misconfigured.`),o({kind:"unanswered",dashboardOrigin:r});return}M+=1,window.parent.postMessage({protocol:f,kind:"runtime:ready",binding:I},r)}},W=async s=>{let i=s.data;if(i?.protocol!==f||i.kind!=="props")return;let u=i.propsRevision;if(typeof u!="number"||u<=N)return;let E=await $(i.props);if(E!==i.propsHash){l({kind:"runtime:error",error:{code:"PROPS_HASH_MISMATCH",message:"Props did not match their hash."}});return}N=u;try{await t(i.props)}catch(G){console.error("[bcms] component render failed:",G),l({kind:"runtime:error",error:{code:"RENDER_FAILED",message:"The component could not be rendered."}});return}let x=!1,P=()=>{x||(x=!0,l({kind:"props:ack",propsRevision:u,propsHash:E}))};requestAnimationFrame(()=>requestAnimationFrame(P)),setTimeout(P,d)},T=s=>{if(s.origin!==r){let E=s.data;s.source===window.parent&&E?.kind==="runtime:connect"&&console.warn(`[bcms] a BetterCMS dashboard at ${s.origin} tried to connect, but dashboardOrigin is ${r}. Refusing \u2014 set dashboardOrigin to ${s.origin} if that is your dashboard.`);return}if(s.source!==window.parent)return;let i=s.data;if(i?.protocol!==f||i.kind!=="runtime:connect")return;let u=s.ports[0];u&&(k=!0,C(),p=u,p.onmessage=W,p.start?.(),o({kind:"connected"}),l({kind:"runtime:connected"}))},A=s=>console.warn(`[bcms] ignored an error from a browser extension: ${String(s).slice(0,300)}`),R=s=>{if(H(s.filename,b(s.error)))return A(s.message);let i={code:"RUNTIME_ERROR",message:String(s.message).slice(0,300)};c(i),l({kind:"runtime:error",error:i})},_=s=>{if(F(b(s.reason)))return A(s.reason);let i={code:"UNHANDLED_REJECTION",message:String(s.reason).slice(0,300)};c(i),l({kind:"runtime:error",error:i})};return o({kind:"connecting",dashboardOrigin:r}),window.addEventListener("message",T),window.addEventListener("error",R),window.addEventListener("unhandledrejection",_),v(),h=setInterval(v,m),{dispose:()=>{C(),window.removeEventListener("message",T),window.removeEventListener("error",R),window.removeEventListener("unhandledrejection",_),p?.close(),p=null,k=!1}}}function V(e){typeof window>"u"||window.parent===window||window.parent.postMessage({protocol:f,kind:"runtime:refused",cause:e.cause},e.dashboardOrigin)}var q=15e3,S=document.getElementById("bcms-status"),g=document.getElementById("bcms-frame"),y=JSON.parse(document.getElementById("bcms-preview-config").textContent),w=e=>{S.textContent=e,S.hidden=!1},J=(e,n)=>fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),credentials:"omit",cache:"no-store"}),Z=50;function j(){try{let e=g.contentDocument;return!e||e.readyState==="loading"||e.location.href==="about:blank"?!1:!!e.querySelector("[data-bcms-preview-render]")}catch{return!1}}function Q(e){return new Promise((n,r)=>{let t=!1,o=a=>{if(!t){if(t=!0,clearInterval(m),clearTimeout(c),g.onload=null,a){r(a);return}S.hidden=!0,g.hidden=!1,n()}},c=setTimeout(()=>o(new Error("render timed out")),q),m=setInterval(()=>{j()&&o()},Z);g.onload=()=>o(j()?void 0:new Error("the render page did not render (blocked, not found, or failed)")),g.src=`${y.routes.render}?id=${encodeURIComponent(e)}`})}async function ee(){let e=new URL(location.href).searchParams.get("bcmsSession");history.replaceState(null,"",location.pathname);let r=await(await J(y.routes.session,{token:e})).json().catch(()=>null);if(!r||!r.ok){let t=r&&!r.ok&&r.cause==="keys-unreachable"?"keys-unreachable":"session-refused";V({dashboardOrigin:y.dashboardOrigin,cause:t}),w("This preview session was refused. The runtime log records why.");return}U({claims:r.claims,dashboardOrigin:y.dashboardOrigin,onProps:async t=>{let o=await J(y.routes.props,{renderKey:r.renderKey,props:t});if(!o.ok)throw new Error(`props were refused (HTTP ${o.status})`);let{id:c}=await o.json();await Q(c)},onStatus:t=>{t.kind!=="connected"&&(t.kind==="connecting"?w("Connecting to BetterCMS\u2026"):t.kind==="unanswered"?w(`${t.dashboardOrigin} did not answer.`):w("This page is meant to be opened from BetterCMS."))}})}ee().catch(e=>{console.error("[bcms-preview]",e),w("The preview could not start. The browser console records why.")});})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/preview-runtime",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Zero-config BetterCMS component previews: builds a preview runtime for Next.js and Astro apps and validates components in CI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "prepublishOnly": "bun run build"
24
24
  },
25
25
  "dependencies": {
26
- "@bettercms-ai/component-output": "^0.2.0",
26
+ "@bettercms-ai/component-output": "^0.2.1",
27
27
  "playwright": "^1.55.0"
28
28
  },
29
29
  "devDependencies": {