{"record":{"id":"c393540c019d6d73","repo":"heygen-com/hyperframes","slug":"missing-contrast-audit-browser-script","errorCode":null,"errorMessage":"Missing contrast audit browser script","messagePattern":"Missing contrast audit browser script","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/cli/src/commands/validate.ts","lineNumber":326,"sourceCode":"        if (typeof restore === \"function\") (restore as () => void)();\n      });\n    }\n  }\n\n  return results;\n}\n\nfunction loadContrastAuditScript(): string {\n  const candidates = [\n    join(__dirname, \"contrast-audit.browser.js\"),\n    join(__dirname, \"commands\", \"contrast-audit.browser.js\"),\n  ];\n\n  for (const candidate of candidates) {\n    if (existsSync(candidate)) return readFileSync(candidate, \"utf-8\");\n  }\n\n  throw new Error(\"Missing contrast audit browser script\");\n}\n\n/**\n * Pull the `missing_or_empty_sub_composition` lint findings out of a\n * `lintProject` result and shape them as `ConsoleEntry`s. Extracted as a\n * pure function so it's testable without a headless browser or a real\n * project directory — see validate.test.ts.\n */\nexport function extractCompositionErrorsFromLint(\n  lintResult: Pick<ProjectLintResult, \"results\">,\n): ConsoleEntry[] {\n  return lintResult.results\n    .flatMap((r) => r.result.findings)\n    .filter((f) => f.code === \"missing_or_empty_sub_composition\" && f.severity === \"error\")\n    .map((f) => ({ level: \"error\" as const, text: f.message }));\n}\n\n// Match the render pipeline: localize remote <img>/<video>/<audio>/@font-face","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/validate.ts#L308-L344","documentation":"Thrown by loadContrastAuditScript when neither candidate location for the bundled contrast-audit.browser.js exists. This file is a build artifact injected into the headless browser to run WCAG contrast checks during `hyperframes check`; its absence means the CLI package is missing compiled assets.","triggerScenarios":"validate's contrast audit path calls loadContrastAuditScript, which tries join(__dirname,'contrast-audit.browser.js') and join(__dirname,'commands','contrast-audit.browser.js'). Both existsSync checks fail → throw at validate.ts:326.","commonSituations":"Running from a source tree without building; a corrupted/partial npm install that stripped JS assets; an over-pruned Docker image; referencing a forked CLI that didn't ship the browser bundle.","solutions":["Reinstall the CLI from a clean state: `npm i -g hyperframes@latest`","If running from source, build first: `bun run build` to emit the browser bundle","Verify the file exists under the installed commands/ directory","Run a non-contrast subset of checks as a temporary workaround"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nfunction contrastScriptPresent(): boolean {\n  return [join(__dirname, \"contrast-audit.browser.js\"),\n          join(__dirname, \"commands\", \"contrast-audit.browser.js\")]\n    .some(existsSync);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install the CLI cleanly from the official tarball so build assets ship","Run `bun run build` from source before validate","Don't prune the package's compiled browser bundles"],"tags":["validate","wcag","contrast","packaging","corrupted-install"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}