fix(producer): validate render request engine snapshots

This commit is contained in:
James
2026-07-17 16:22:23 -04:00
parent 25dd4cc8c0
commit fc4e9a6c0e
5 changed files with 238 additions and 5 deletions
+200
View File
@@ -317,6 +317,206 @@ export const DEFAULT_CONFIG: EngineConfig = {
debug: false,
};
const OPTIONAL_ENGINE_CONFIG_FIELDS = [
"chromePath",
"expectedChromiumMajor",
"pageSideCompositingAutoDisabled",
"forceScreenshotExplicitlyOptedOut",
"streamingEncodeAutoDisabledOnWin32Compound",
"runtimeManifestPath",
"extractCacheDir",
] as const;
const BOOLEAN_ENGINE_CONFIG_FIELDS = [
"disableGpu",
"enableBrowserPool",
"forceScreenshot",
"staticFrameDedup",
"useDrawElement",
"enableDrawElementWorkerEncode",
"lowMemoryMode",
"enablePageSideCompositing",
"enableChunkedEncode",
"enableStreamingEncode",
"hdrAutoDetect",
"verifyRuntime",
"debug",
] as const;
const POSITIVE_NUMBER_ENGINE_CONFIG_FIELDS = [
"coresPerWorker",
"browserTimeout",
"protocolTimeout",
"chunkSizeFrames",
"ffmpegEncodeTimeout",
"ffmpegProcessTimeout",
"ffmpegStreamingTimeout",
"frameDataUriCacheLimit",
"frameDataUriCacheBytesLimitMb",
"playerReadyTimeout",
"renderReadyTimeout",
"pageNavigationTimeout",
"extractCacheMaxBytes",
] as const;
const ENUM_ENGINE_CONFIG_FIELDS = {
fps: [24, 30, 60],
quality: ["draft", "standard", "high"],
format: ["jpeg", "png"],
browserGpuMode: ["software", "hardware", "auto"],
} as const;
function isPlainObject(value: unknown): value is Record<string, unknown> {
return (
typeof value === "object" &&
value !== null &&
!Array.isArray(value) &&
[Object.prototype, null].includes(Object.getPrototypeOf(value))
);
}
function assertEngineConfigNumber(
config: Record<string, unknown>,
field: string,
min: number,
integer = false,
): void {
const value = config[field];
if (
typeof value !== "number" ||
!Number.isFinite(value) ||
value < min ||
(integer && !Number.isInteger(value))
) {
throw new Error(
`Engine config ${field} must be a ${integer ? "finite integer" : "finite number"} >= ${min}`,
);
}
}
function assertEngineConfigEnum(
config: Record<string, unknown>,
field: string,
values: readonly unknown[],
): void {
if (!values.includes(config[field])) throw new Error(`Engine config ${field} is invalid`);
}
function validateRequiredEngineConfigFields(config: Record<string, unknown>): void {
const requiredFields = Object.keys(DEFAULT_CONFIG);
for (const field of requiredFields) {
if (!Object.hasOwn(config, field)) {
throw new Error(`Engine config snapshot is missing required field ${field}`);
}
}
const allowedFields = new Set([...requiredFields, ...OPTIONAL_ENGINE_CONFIG_FIELDS]);
for (const field of Object.keys(config)) {
if (!allowedFields.has(field))
throw new Error(`Engine config snapshot has unknown field ${field}`);
}
}
function validateEngineConfigScalars(config: Record<string, unknown>): void {
for (const [field, values] of Object.entries(ENUM_ENGINE_CONFIG_FIELDS)) {
assertEngineConfigEnum(config, field, values);
}
assertEngineConfigNumber(config, "jpegQuality", 0);
if (typeof config.jpegQuality === "number" && config.jpegQuality > 100) {
throw new Error("Engine config jpegQuality must be <= 100");
}
}
function validateEngineConfigParallelism(config: Record<string, unknown>): void {
if (
config.concurrency !== "auto" &&
(typeof config.concurrency !== "number" ||
!Number.isInteger(config.concurrency) ||
config.concurrency < 1)
) {
throw new Error("Engine config concurrency must be a positive integer or auto");
}
assertEngineConfigNumber(config, "coresPerWorker", 0);
for (const field of ["minParallelFrames", "largeRenderThreshold"] as const) {
assertEngineConfigNumber(config, field, 0, true);
}
}
function validateEngineConfigVp9(config: Record<string, unknown>): void {
if (
typeof config.vp9CpuUsed !== "number" ||
!Number.isInteger(config.vp9CpuUsed) ||
config.vp9CpuUsed < -8 ||
config.vp9CpuUsed > 8
) {
throw new Error("Engine config vp9CpuUsed must be an integer in [-8, 8]");
}
}
function validateEngineConfigRuntime(config: Record<string, unknown>): void {
for (const field of BOOLEAN_ENGINE_CONFIG_FIELDS) {
if (typeof config[field] !== "boolean")
throw new Error(`Engine config ${field} must be a boolean`);
}
for (const field of POSITIVE_NUMBER_ENGINE_CONFIG_FIELDS) {
assertEngineConfigNumber(config, field, 1, field === "frameDataUriCacheLimit");
}
assertEngineConfigNumber(config, "streamingEncodeMaxDurationSeconds", 0);
assertEngineConfigNumber(config, "audioGain", 0);
}
function validateEngineConfigHdr(config: Record<string, unknown>): void {
const { hdr } = config;
if (
hdr !== false &&
(!isPlainObject(hdr) ||
Object.keys(hdr).length !== 1 ||
(hdr.transfer !== "hlg" && hdr.transfer !== "pq"))
) {
throw new Error("Engine config hdr must be false or an hlg/pq transfer object");
}
}
function validateOptionalEngineConfigFields(config: Record<string, unknown>): void {
for (const field of ["chromePath", "runtimeManifestPath", "extractCacheDir"] as const) {
if (
config[field] !== undefined &&
(typeof config[field] !== "string" || config[field].length === 0)
) {
throw new Error(`Engine config ${field} must be a non-empty string`);
}
}
if (config.expectedChromiumMajor !== undefined) {
assertEngineConfigNumber(config, "expectedChromiumMajor", 1, true);
}
for (const field of [
"pageSideCompositingAutoDisabled",
"forceScreenshotExplicitlyOptedOut",
"streamingEncodeAutoDisabledOnWin32Compound",
] as const) {
if (config[field] !== undefined && typeof config[field] !== "boolean") {
throw new Error(`Engine config ${field} must be a boolean`);
}
}
}
/**
* Validate a complete EngineConfig crossing a JSON wire boundary.
*
* `resolveConfig()` intentionally accepts partial programmatic overrides, but
* a serialized render request stores a resolved snapshot. Accepting a partial
* snapshot would skip the orchestrator's `resolveConfig()` fallback entirely.
*/
export function validateEngineConfigSnapshot(value: unknown): asserts value is EngineConfig {
if (!isPlainObject(value)) throw new Error("Engine config snapshot must be a plain object");
validateRequiredEngineConfigFields(value);
validateEngineConfigScalars(value);
validateEngineConfigParallelism(value);
validateEngineConfigVp9(value);
validateEngineConfigRuntime(value);
validateEngineConfigHdr(value);
validateOptionalEngineConfigFields(value);
}
/**
* Reference canvas area for the baseline `protocolTimeout`: 1080p. A single CDP
* call (`Runtime.callFunctionOn` seek+paint, or `Page.captureScreenshot`)
+1
View File
@@ -48,6 +48,7 @@ export type {
// ── Configuration ──────────────────────────────────────────────────────────────
export {
resolveConfig,
validateEngineConfigSnapshot,
DEFAULT_CONFIG,
scaleProtocolTimeoutForComposition,
shouldClampToScreenshotForConcreteGpu,
@@ -174,6 +174,35 @@ describe("RenderRequest", () => {
).toThrow("distributed.width");
});
it("requires complete and valid engine config snapshots on both wire paths", () => {
const value = request();
for (const engineConfig of [
{},
{ ...value.options.engineConfig, protocolTimeout: "forever" },
{ ...value.options.engineConfig, browserGpuMode: "turbo" },
]) {
expect(() =>
parseRenderRequest({ ...value, options: { ...value.options, engineConfig } }),
).toThrow("Engine config");
}
for (const engineConfig of [
{},
{ ...value.options.engineConfig, protocolTimeout: "forever" },
{ ...value.options.engineConfig, browserGpuMode: "turbo" },
]) {
const distributed = distributedConfigFromRequest(value);
(distributed as { engineConfig: unknown }).engineConfig = engineConfig;
expect(() =>
renderRequestFromDistributedConfig({
projectDir: value.projectDir,
outputPath: value.outputPath,
config: distributed,
}),
).toThrow("Engine config");
}
});
it("validates the reverse distributed adapter at the wire boundary", () => {
const distributed = distributedConfigFromRequest(request());
distributed.width = 1921;
+2 -3
View File
@@ -1,6 +1,7 @@
import {
isVideoFrameFormat,
resolveConfig,
validateEngineConfigSnapshot,
type EngineConfig,
type VideoFrameFormat,
} from "@hyperframes/engine";
@@ -176,9 +177,7 @@ function assertRequestOptionScalars(options: Record<string, unknown>): void {
}
function assertRequestOptionObjects(options: Record<string, unknown>): void {
if (!isPlainObject(options.engineConfig)) {
throw new Error("Render request must contain a resolved engineConfig snapshot");
}
validateEngineConfigSnapshot(options.engineConfig);
if (options.variables !== undefined && !isPlainObject(options.variables)) {
throw new Error("Render request variables must be a JSON object");
}
@@ -17,7 +17,11 @@
* needs the actual planner.
*/
import { VIDEO_FRAME_FORMATS, isVideoFrameFormat } from "@hyperframes/engine";
import {
VIDEO_FRAME_FORMATS,
isVideoFrameFormat,
validateEngineConfigSnapshot,
} from "@hyperframes/engine";
import { type DistributedFormat } from "./shared.js";
import { type DistributedRenderConfig } from "./plan.js";
@@ -204,7 +208,7 @@ export function validateDistributedRenderConfig(
validateVariablesPayload(config.variables);
}
if (config.engineConfig !== undefined) {
walkVariables(config.engineConfig, "config.engineConfig", new WeakSet());
validateEngineConfigSnapshot(config.engineConfig);
}
return config;