/** * Helpers shared between the distributed activity scripts (`plan.ts`, * `renderChunk.ts`, `assemble.ts`). Kept module-local so the public surface * stays just the three activity functions plus their result types. */ import { execFile as execFileCallback } from "node:child_process"; import { dirname, join } from "node:path"; import { existsSync, readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { promisify } from "node:util"; import { type Fps } from "@hyperframes/core"; import { type VideoElement, type VideoFrameFormat, type VideoMetadata } from "@hyperframes/engine"; import { type RenderConfig, type RenderJob, createRenderJob } from "../renderOrchestrator.js"; import { defaultLogger, type ProducerLogger } from "../../logger.js"; /** * Output container formats the distributed pipeline supports end-to-end. * Single source of truth for the format union — `plan()`, `renderChunk()`, * `assemble()`, the aws-lambda handler, and the harness all derive from * this type. Adding a new format starts here. */ export type DistributedFormat = "mp4" | "mov" | "png-sequence" | "webm"; /** * Filename of the per-video extraction manifest written by `plan()` into * `/meta/` and consumed by `renderChunk()` to rebuild the * BeforeCaptureHook that injects pre-extracted frames into the page. * Absence is fine — compositions with no `