mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(render): surface structured outcomes (#2153)
This commit is contained in:
@@ -80,7 +80,7 @@ vi.mock("../utils/producer.js", () => ({
|
||||
}),
|
||||
createRenderJob: vi.fn((config: Record<string, unknown>) => {
|
||||
producerState.createdJobs.push(config);
|
||||
return { config, progress: 100 };
|
||||
return { config, progress: 100, outcome: "completed", warnings: [] };
|
||||
}),
|
||||
executeRenderJob: vi.fn(async (job: Record<string, unknown>) => producerState.executeImpl(job)),
|
||||
})),
|
||||
@@ -413,6 +413,35 @@ describe("renderLocal browser GPU config", () => {
|
||||
expect(producerState.createdJobs[0]?.debug).toBe(true);
|
||||
});
|
||||
|
||||
it("defaults to best-effort readiness", async () => {
|
||||
await renderLocal("/tmp/project", "/tmp/out.mp4", {
|
||||
fps: { num: 30, den: 1 },
|
||||
quality: "standard",
|
||||
format: "mp4",
|
||||
gpu: false,
|
||||
browserGpuMode: "software",
|
||||
hdrMode: "auto",
|
||||
quiet: true,
|
||||
});
|
||||
|
||||
expect(producerState.createdJobs[0]?.strictness).toBe("best-effort");
|
||||
});
|
||||
|
||||
it("forwards an explicit strict readiness opt-in", async () => {
|
||||
await renderLocal("/tmp/project", "/tmp/out.mp4", {
|
||||
fps: { num: 30, den: 1 },
|
||||
quality: "standard",
|
||||
format: "mp4",
|
||||
gpu: false,
|
||||
browserGpuMode: "software",
|
||||
hdrMode: "auto",
|
||||
quiet: true,
|
||||
bestEffort: false,
|
||||
});
|
||||
|
||||
expect(producerState.createdJobs[0]?.strictness).toBe("strict");
|
||||
});
|
||||
|
||||
it("omits variables from createRenderJob when not provided", async () => {
|
||||
await renderLocal("/tmp/project", "/tmp/out.mp4", {
|
||||
fps: { num: 30, den: 1 },
|
||||
|
||||
@@ -267,6 +267,12 @@ export default defineCommand({
|
||||
"Write full render diagnostics and keep intermediate artifacts under the producer .debug directory.",
|
||||
default: false,
|
||||
},
|
||||
"best-effort": {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Allow output with structured capture-readiness warnings (default). Use --no-best-effort to fail on missing or unready media.",
|
||||
default: true,
|
||||
},
|
||||
strict: {
|
||||
type: "boolean",
|
||||
description: "Fail render on lint errors",
|
||||
@@ -622,6 +628,7 @@ export default defineCommand({
|
||||
const browserGpuMode = resolveBrowserGpuForCli(useDocker, browserGpuArg);
|
||||
const quiet = args.quiet ?? false;
|
||||
const debug = args.debug ?? false;
|
||||
const bestEffort = args["best-effort"] ?? true;
|
||||
const batchJson = args.json ?? false;
|
||||
const effectiveQuiet = quiet || (batchPath != null && batchJson);
|
||||
const strictAll = args["strict-all"] ?? false;
|
||||
@@ -902,6 +909,7 @@ export default defineCommand({
|
||||
protocolTimeout,
|
||||
playerReadyTimeout,
|
||||
debug,
|
||||
bestEffort,
|
||||
exitAfterComplete: false,
|
||||
throwOnError: true,
|
||||
skipFeedback: true,
|
||||
@@ -960,6 +968,7 @@ export default defineCommand({
|
||||
videoFrameFormat,
|
||||
quiet,
|
||||
debug,
|
||||
bestEffort,
|
||||
variables,
|
||||
entryFile,
|
||||
outputResolution,
|
||||
@@ -988,6 +997,7 @@ export default defineCommand({
|
||||
quiet,
|
||||
browserPath,
|
||||
debug,
|
||||
bestEffort,
|
||||
variables,
|
||||
entryFile,
|
||||
outputResolution,
|
||||
@@ -1006,6 +1016,8 @@ export default defineCommand({
|
||||
export interface SingleRenderResult {
|
||||
durationMs?: number;
|
||||
renderTimeMs: number;
|
||||
outcome?: "completed" | "completed_with_warnings";
|
||||
warnings?: Array<{ code: string; message: string }>;
|
||||
}
|
||||
|
||||
export function renderLintContinuationHint(strictErrors: boolean): string {
|
||||
@@ -1036,6 +1048,7 @@ interface RenderOptions {
|
||||
videoFrameFormat?: VideoFrameFormat;
|
||||
quiet: boolean;
|
||||
debug?: boolean;
|
||||
bestEffort?: boolean;
|
||||
browserPath?: string;
|
||||
variables?: Record<string, unknown>;
|
||||
entryFile?: string;
|
||||
@@ -1370,6 +1383,7 @@ async function renderDocker(
|
||||
outputResolution: options.outputResolution,
|
||||
pageSideCompositing: options.pageSideCompositing,
|
||||
debug: options.debug,
|
||||
bestEffort: options.bestEffort,
|
||||
experimentalFastCapture: options.experimentalFastCapture,
|
||||
pageNavigationTimeoutMs: options.pageNavigationTimeoutMs,
|
||||
},
|
||||
@@ -1490,6 +1504,7 @@ export async function renderLocal(
|
||||
entryFile: options.entryFile,
|
||||
outputResolution: options.outputResolution,
|
||||
debug: options.debug,
|
||||
strictness: options.bestEffort === false ? "strict" : "best-effort",
|
||||
});
|
||||
|
||||
const onProgress = options.quiet
|
||||
@@ -1515,6 +1530,11 @@ export async function renderLocal(
|
||||
|
||||
maybeConsumeDeParallelRouterTrial(deParallelRouterTrialArmed, job, options.quiet);
|
||||
const elapsed = Date.now() - startTime;
|
||||
if (job.outcome === "completed_with_warnings") {
|
||||
for (const warning of job.warnings) {
|
||||
console.warn(c.warn(` [${warning.code}] ${warning.message}`));
|
||||
}
|
||||
}
|
||||
trackRenderMetrics(job, elapsed, options, false);
|
||||
printRenderComplete(
|
||||
outputPath,
|
||||
@@ -1534,7 +1554,14 @@ export async function renderLocal(
|
||||
const durationMs = job.perfSummary
|
||||
? Math.round(job.perfSummary.compositionDurationSeconds * 1000)
|
||||
: undefined;
|
||||
return { renderTimeMs: elapsed, durationMs };
|
||||
const outcome =
|
||||
job.outcome === "completed_with_warnings" ? "completed_with_warnings" : "completed";
|
||||
return {
|
||||
renderTimeMs: elapsed,
|
||||
durationMs,
|
||||
outcome,
|
||||
warnings: job.warnings.map((warning) => ({ code: warning.code, message: warning.message })),
|
||||
};
|
||||
}
|
||||
|
||||
type UnrefableTimer = {
|
||||
|
||||
@@ -280,6 +280,7 @@ describe("studioRenderTelemetry", () => {
|
||||
progress: 25,
|
||||
currentStage: "Starting frame capture",
|
||||
createdAt: new Date(),
|
||||
warnings: [],
|
||||
errorDetails: {
|
||||
message: "Navigation timeout of 60000 ms exceeded",
|
||||
elapsedMs: 60_001,
|
||||
|
||||
@@ -172,6 +172,7 @@ describe("buildDockerRunArgs", () => {
|
||||
videoFrameFormat: "png",
|
||||
quiet: true,
|
||||
debug: true,
|
||||
bestEffort: false,
|
||||
entryFile: "compositions/intro.html",
|
||||
experimentalFastCapture: true,
|
||||
},
|
||||
@@ -191,6 +192,7 @@ describe("buildDockerRunArgs", () => {
|
||||
expect(args).toContain("png");
|
||||
expect(args).toContain("--quiet");
|
||||
expect(args).toContain("--debug");
|
||||
expect(args).toContain("--no-best-effort");
|
||||
expect(args).toContain("--gpu");
|
||||
expect(args).toContain("--no-browser-gpu");
|
||||
expect(args).toContain("--hdr");
|
||||
@@ -199,6 +201,21 @@ describe("buildDockerRunArgs", () => {
|
||||
expect(args).toContain("--experimental-fast-capture");
|
||||
});
|
||||
|
||||
it("forwards only an explicit strict-readiness opt-in", () => {
|
||||
const compatible = buildDockerRunArgs({
|
||||
...FIXED_INPUT,
|
||||
options: { ...BASE, bestEffort: true },
|
||||
});
|
||||
expect(compatible).not.toContain("--best-effort");
|
||||
expect(compatible).not.toContain("--no-best-effort");
|
||||
|
||||
const strict = buildDockerRunArgs({
|
||||
...FIXED_INPUT,
|
||||
options: { ...BASE, bestEffort: false },
|
||||
});
|
||||
expect(strict).toContain("--no-best-effort");
|
||||
});
|
||||
|
||||
it("forwards --experimental-fast-capture only when enabled", () => {
|
||||
const on = buildDockerRunArgs({
|
||||
...FIXED_INPUT,
|
||||
|
||||
@@ -51,6 +51,7 @@ export interface DockerRenderOptions {
|
||||
videoFrameFormat?: "auto" | "jpg" | "png";
|
||||
quiet: boolean;
|
||||
debug?: boolean;
|
||||
bestEffort?: boolean;
|
||||
variables?: Record<string, unknown>;
|
||||
entryFile?: string;
|
||||
/** Output resolution preset (e.g. "landscape-4k"). Forwarded as `--resolution`. */
|
||||
@@ -136,6 +137,9 @@ export function buildDockerRunArgs(input: DockerRunArgsInput): string[] {
|
||||
: []),
|
||||
...(options.quiet ? ["--quiet"] : []),
|
||||
...(options.debug ? ["--debug"] : []),
|
||||
// The in-container CLI is best-effort by default. Only forward the
|
||||
// explicit strict opt-in so Docker and local renders cannot drift.
|
||||
...(options.bestEffort === false ? ["--no-best-effort"] : []),
|
||||
...(options.gpu ? ["--gpu"] : []),
|
||||
...(options.browserGpu ? [] : ["--no-browser-gpu"]),
|
||||
...(options.hdrMode === "force-hdr" ? ["--hdr"] : []),
|
||||
|
||||
Reference in New Issue
Block a user