MCPcopy Create free account
hub / github.com/heygen-com/hyperframes / validateInBrowser

Function validateInBrowser

packages/cli/src/commands/validate.ts:198–305  ·  view source on GitHub ↗
(
  project: ProjectDir,
  opts: { timeout?: number; contrast?: boolean },
)

Source from the content-addressed store, hash-verified

196}
197
198async function validateInBrowser(
199 project: ProjectDir,
200 opts: { timeout?: number; contrast?: boolean },
201): Promise<{ errors: ConsoleEntry[]; warnings: ConsoleEntry[]; contrast?: ContrastEntry[] }> {
202 const projectDir = project.dir;
203 const { bundleToSingleHtml } = await import("@hyperframes/core/compiler");
204 const { ensureBrowser } = await import("../browser/manager.js");
205 const { serveStaticProjectHtml } = await import("../utils/staticProjectServer.js");
206 const { lintProject } = await import("../utils/lintProject.js");
207
208 // Fail fast on missing/empty/unparsable data-composition-src references
209 // before spending time bundling and launching a browser. The bundler
210 // (bundleToSingleHtml → inlineSubCompositions) is intentionally tolerant of
211 // these — it skips the broken scene and keeps going, silently, with only a
212 // console.warn — so validate would otherwise report "No console errors"
213 // for a project that renders a materially broken video. Surface it as a
214 // real validate failure instead.
215 const lintResult = await lintProject(projectDir);
216 const compositionErrors = extractCompositionErrorsFromLint(lintResult);
217
218 // `bundleToSingleHtml` now inlines the runtime IIFE by default, so the
219 // previous post-bundle regex substitution (which matched `src="..."` on the
220 // runtime tag) is no longer needed — there's no `src` attribute to match.
221 const html = await bundleToSingleHtml(projectDir);
222
223 const server = await serveStaticProjectHtml(projectDir, html);
224
225 const errors: ConsoleEntry[] = [...compositionErrors];
226 const warnings: ConsoleEntry[] = [];
227 let contrast: ContrastEntry[] | undefined;
228 const viewport = resolveCompositionViewportFromHtml(html);
229
230 try {
231 const browser = await ensureBrowser();
232 const puppeteer = await import("puppeteer-core");
233 const { buildChromeArgs, analyzeClipMediaFit } = await import("@hyperframes/engine");
234 const browserGpuMode =
235 process.env.PRODUCER_BROWSER_GPU_MODE === "software" ? "software" : "hardware";
236 const chromeBrowser = await puppeteer.default.launch({
237 headless: true,
238 executablePath: browser.executablePath,
239 args: buildChromeArgs({ ...viewport, captureMode: "screenshot" }, { browserGpuMode }),
240 });
241
242 const page = await chromeBrowser.newPage();
243 await page.setViewport(viewport);
244
245 page.on("console", (msg) => {
246 const type = msg.type();
247 const loc = msg.location();
248 const text = msg.text();
249 if (type === "error") {
250 if (text.startsWith("Failed to load resource")) return;
251 errors.push({ level: "error", text, url: loc.url, line: loc.lineNumber });
252 } else if (type === "warn") {
253 warnings.push({ level: "warning", text, url: loc.url, line: loc.lineNumber });
254 }
255 });

Callers 1

runFunction · 0.85

Calls 13

lintProjectFunction · 0.85
bundleToSingleHtmlFunction · 0.85
serveStaticProjectHtmlFunction · 0.85
ensureBrowserFunction · 0.85
buildChromeArgsFunction · 0.85
auditClipDurationsFunction · 0.85
runContrastAuditFunction · 0.70
onMethod · 0.65
closeMethod · 0.65

Tested by

no test coverage detected