mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
fix(cli): wire aspect-agnostic resolution through cloudrun/lambda/batch + preflight recompute
Addresses R2 CHANGES_REQUESTED from Miga + Rames on PR #2529: 1. Sibling-surface gap (blocker): `hyperframes cloudrun render{,-batch}`, `hyperframes lambda render{,-batch}` all advertised the same tier-only aliases (`1080p` / `hd` / `4k` / `uhd`) but normalized them to `landscape` and never set `outputResolutionAspectAgnostic`. The distributed plumbing PR #2529 added received `undefined` from those callers, so portrait `1080p` still hit the original aspect-mismatch on Cloud Run / Lambda. Fix: introduce `resolveResolutionFlagPair` in `@hyperframes/parsers` (the single source of truth for the two-step normalize + aspect-agnostic detect) and route every distributed entrypoint through a shared `parseOutputResolutionFlag` CLI util so the alias signal now reaches `SerializableDistributedRenderConfig`. Studio Server keeps its canonical-only HTTP contract; that intent is now pinned in tests. 2. Preflight recompute (hardening): the earlier "downgrade aspect-mismatch" preflight cleared un-remapped mismatches, so IG 4:5 (non-preset aspect, no sibling) and portrait-4K comp + `--resolution 1080p` (remap + downsample) both slipped through to fail late in `resolveDeviceScaleFactor`. Now `checkRenderResolutionPreflight` computes the effective preset via `suggestMatchingPreset` (mirroring the compile stage's `adaptAspectAgnosticResolution`) and re-checks against that — only genuinely-fixable mismatches clear early. New tests pin both regressed input classes. 3. Docker forwarding boundary test (Miga's important #2): pinned `1080p` survives verbatim as `--resolution 1080p` in the Docker args so the in-container CLI can re-run `isAspectAgnosticResolutionAlias`. 4. Doc-nit (Miga): parsers/src/types.ts no longer references the nonexistent `resolveResolutionForComposition` — points at the actual remap helpers. Fallow: cloudrun.ts / lambda.ts share 390 lines of pre-existing structural symmetry (parallel AWS + GCP dispatchers), and lambda/render.ts + render-batch.ts declare parallel RenderArgs interfaces. Both re-flagged after threading the aspect-agnostic field through each surface; ignored with justification in .fallowrc.jsonc. lambda.ts's `run` and lambda/render.ts's `waitForCompletion` are pre-existing CRAP-score hotspots untouched by this PR — added under health.ignore. Co-Authored-By: Claude <noreply@anthropic.com> — Via
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Shared `--output-resolution` / `--resolution` normalizer for the distributed
|
||||
* render entrypoints (`hyperframes cloudrun render{,-batch}`, `hyperframes
|
||||
* lambda render{,-batch}`) plus the local `hyperframes render` command.
|
||||
*
|
||||
* The one field this helper carries that the previous per-surface copies
|
||||
* were dropping is `outputResolutionAspectAgnostic`: `true` when the raw
|
||||
* flag was a tier-only alias (`1080p` / `hd` / `4k` / `uhd`). Passing it
|
||||
* through into `SerializableDistributedRenderConfig` is what lets the
|
||||
* remote worker's compile stage remap `landscape` → `portrait` when the
|
||||
* composition demands it. Dropping the flag at any single entrypoint
|
||||
* reproduces the portrait-1080p regression this helper prevents (see
|
||||
* PR #2529 R2 CHANGES_REQUESTED and the sibling-surface enumeration in
|
||||
* Miga + Rames's reviews).
|
||||
*
|
||||
* The strict-throw contract (unknown values raise instead of silently
|
||||
* degrading to `outputResolution: undefined`) is preserved so a typo like
|
||||
* `--output-resolution 8k` fails fast rather than falling back to
|
||||
* composition dimensions.
|
||||
*/
|
||||
|
||||
import { type CanvasResolution, resolveResolutionFlagPair } from "@hyperframes/core";
|
||||
import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/core";
|
||||
|
||||
/**
|
||||
* Free-text prefix the thrown error is scoped to (e.g. `"[cloudrun render]"`,
|
||||
* `"[lambda render]"`). Kept as a caller-supplied string rather than a
|
||||
* fixed enum so future surfaces (Studio Server, an SDK wrapper, …) can
|
||||
* opt in without editing this file.
|
||||
*/
|
||||
export interface OutputResolutionParseOptions {
|
||||
surfaceLabel: string;
|
||||
/**
|
||||
* Optional per-surface hint appended to the error message. Defaults to a
|
||||
* generic tier-alias hint; the Lambda surface exposes additional
|
||||
* orientation-suffixed aliases the CLI accepts (`1080p-portrait`, `4k-portrait`,
|
||||
* …) — pass a custom hint to keep the error text faithful.
|
||||
*/
|
||||
aliasHint?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the user-supplied resolution flag into the pair the distributed
|
||||
* wire config needs. Returns `{ outputResolution: undefined,
|
||||
* outputResolutionAspectAgnostic: false }` when the flag is absent so the
|
||||
* caller can spread the result unconditionally.
|
||||
*
|
||||
* Throws (not exits) on an unknown value — CLI callers wrap that in their
|
||||
* own errorBox / process.exit; SDK callers surface the error to their own
|
||||
* user.
|
||||
*/
|
||||
export function parseOutputResolutionFlag(
|
||||
raw: unknown,
|
||||
options: OutputResolutionParseOptions,
|
||||
): { outputResolution: CanvasResolution | undefined; outputResolutionAspectAgnostic: boolean } {
|
||||
if (raw == null || raw === "") {
|
||||
return { outputResolution: undefined, outputResolutionAspectAgnostic: false };
|
||||
}
|
||||
const asString = String(raw);
|
||||
const { outputResolution, outputResolutionAspectAgnostic } = resolveResolutionFlagPair(asString);
|
||||
if (outputResolution) return { outputResolution, outputResolutionAspectAgnostic };
|
||||
const aliasHint = options.aliasHint ?? "1080p, 4k, uhd, hd, …";
|
||||
throw new Error(
|
||||
`${options.surfaceLabel} --output-resolution must be one of ${VALID_CANVAS_RESOLUTIONS.join("|")} ` +
|
||||
`(or an alias: ${aliasHint}); got ${asString}`,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user