From a18fc04bf40552e75faa1896a47d280eba386b9f Mon Sep 17 00:00:00 2001 From: James Date: Sun, 17 May 2026 21:43:46 +0000 Subject: [PATCH] =?UTF-8?q?fix(producer):=20break=20aws-lambda=E2=86=94pro?= =?UTF-8?q?ducer=20build=20cycle=20for=20lambda-local=20harness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The aws-lambda publish-readiness changes earlier in this PR moved aws-lambda's types from `./src/index.ts` → `./dist/index.d.ts`. That flipped producer's emit pass from "always works" to "needs aws-lambda built first," because producer's `regression-harness-lambda-local.ts` imports `@hyperframes/aws-lambda{,/handler}`. aws-lambda's own emit pass in turn imports `@hyperframes/producer{,/distributed}` → circular build dependency, so neither side can emit declarations in a single pass. CI's first run on this PR failed Build, Typecheck, CLI smoke, windows tests, and every perf job for this reason. Fix: extract the public surface of `regression-harness-lambda-local.ts` into a new types-only file that has no aws-lambda imports, point `regression-harness.ts` at that types file, and exclude `regression-harness-lambda-local.ts` from producer's tsconfig `include`. The implementation file is still loaded at runtime via `tsx` (lambda-local mode runs the harness through tsx, not from producer's dist/), so the runtime contract is unchanged — producer's tsc just no longer has to type-check it. - `regression-harness-lambda-local-types.ts` (new): exports `RunLambdaLocalInput` + `RunLambdaLocalRender` with zero aws-lambda imports. - `regression-harness-lambda-local.ts`: re-exports `RunLambdaLocalInput` from the new types file (so the public name stays stable for any future direct imports). - `regression-harness.ts`: drops the `typeof import("...")` trick and uses the explicit `RunLambdaLocalRender` signature for the dynamically-loaded function. - `tsconfig.json`: excludes `src/regression-harness-lambda-local.ts` so producer's emit pass never resolves `@hyperframes/aws-lambda`. Verified: bun run build # full root build green bun run verify:packed-manifests # all packages publish-safe --- .../regression-harness-lambda-local-types.ts | 37 +++++++++++++++++++ .../src/regression-harness-lambda-local.ts | 25 +------------ packages/producer/src/regression-harness.ts | 17 +++++++-- packages/producer/tsconfig.json | 8 +++- 4 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 packages/producer/src/regression-harness-lambda-local-types.ts diff --git a/packages/producer/src/regression-harness-lambda-local-types.ts b/packages/producer/src/regression-harness-lambda-local-types.ts new file mode 100644 index 000000000..bb021951a --- /dev/null +++ b/packages/producer/src/regression-harness-lambda-local-types.ts @@ -0,0 +1,37 @@ +/** + * Public-facing types for `./regression-harness-lambda-local.ts`. + * + * Kept in its own file because the implementation imports + * `@hyperframes/aws-lambda`, which can't be resolved by producer's + * tsc emit pass until aws-lambda's own dist/ is built. Splitting the + * types out lets producer's regression harness reference the lambda + * adapter's shape without pulling the aws-lambda graph into producer's + * type-check pass. + */ + +/** Inputs for {@link runLambdaLocalRender}. Same contract as `runDistributedSimulatedRender`. */ +export interface RunLambdaLocalInput { + projectDir: string; + tempRoot: string; + renderedOutputPath: string; + fps: 24 | 30 | 60; + /** + * Width/height from the fixture's renderConfig. Forwarded directly to + * the Lambda event so this mode catches drift if the handler ever + * starts honouring `Config.width/height` for canvas sizing rather + * than reading the composition's `data-width`/`data-height`. The + * `distributed-simulated` mode hardcodes 1920×1080 because it + * bypasses the event-serialization boundary; lambda-local goes + * through it, which is the whole point. + */ + width: number; + height: number; + format: "mp4" | "mov" | "png-sequence"; + codec?: "h264" | "h265"; + chunkSize?: number; + maxParallelChunks?: number; + variables?: Record; +} + +/** Public signature of the dynamically-loaded `runLambdaLocalRender`. */ +export type RunLambdaLocalRender = (input: RunLambdaLocalInput) => Promise; diff --git a/packages/producer/src/regression-harness-lambda-local.ts b/packages/producer/src/regression-harness-lambda-local.ts index b731ac35d..b1c342e62 100644 --- a/packages/producer/src/regression-harness-lambda-local.ts +++ b/packages/producer/src/regression-harness-lambda-local.ts @@ -46,29 +46,8 @@ import type { SerializableDistributedRenderConfig, } from "@hyperframes/aws-lambda"; -/** Inputs for {@link runLambdaLocalRender}. Same contract as `runDistributedSimulatedRender`. */ -export interface RunLambdaLocalInput { - projectDir: string; - tempRoot: string; - renderedOutputPath: string; - fps: 24 | 30 | 60; - /** - * Width/height from the fixture's renderConfig. Forwarded directly to - * the Lambda event so this mode catches drift if the handler ever - * starts honouring `Config.width/height` for canvas sizing rather - * than reading the composition's `data-width`/`data-height`. The - * `distributed-simulated` mode hardcodes 1920×1080 because it - * bypasses the event-serialization boundary; lambda-local goes - * through it, which is the whole point. - */ - width: number; - height: number; - format: "mp4" | "mov" | "png-sequence"; - codec?: "h264" | "h265"; - chunkSize?: number; - maxParallelChunks?: number; - variables?: Record; -} +export type { RunLambdaLocalInput } from "./regression-harness-lambda-local-types.js"; +import type { RunLambdaLocalInput } from "./regression-harness-lambda-local-types.js"; const FAKE_BUCKET = "harness-lambda-local"; diff --git a/packages/producer/src/regression-harness.ts b/packages/producer/src/regression-harness.ts index 5b9d3c153..9d413a79d 100644 --- a/packages/producer/src/regression-harness.ts +++ b/packages/producer/src/regression-harness.ts @@ -37,10 +37,19 @@ import { // In Dockerfile.test the workspace copy of aws-lambda's src isn't present, // so a static import here would fail at module-load time even when // running `--mode=in-process`. Load it on demand instead. -async function loadLambdaLocalRender(): Promise< - typeof import("./regression-harness-lambda-local.js").runLambdaLocalRender -> { - const mod = await import("./regression-harness-lambda-local.js"); +// +// The signature is typed via `RunLambdaLocalRender` (in its own types-only +// file) instead of `typeof import(...)` so producer's tsc doesn't have to +// type-check the implementation. The implementation imports +// `@hyperframes/aws-lambda`, whose types come from `dist/index.d.ts` after +// aws-lambda's build runs — a chicken-and-egg with producer's tsc that +// would otherwise fail the whole-repo build. +import type { RunLambdaLocalRender } from "./regression-harness-lambda-local-types.js"; + +async function loadLambdaLocalRender(): Promise { + const mod = (await import("./regression-harness-lambda-local.js")) as { + runLambdaLocalRender: RunLambdaLocalRender; + }; return mod.runLambdaLocalRender; } diff --git a/packages/producer/tsconfig.json b/packages/producer/tsconfig.json index cbe56306a..4e876a30f 100644 --- a/packages/producer/tsconfig.json +++ b/packages/producer/tsconfig.json @@ -20,5 +20,11 @@ } }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "src/**/*.test.ts", "src/**/__test_utils__/**"] + "exclude": [ + "node_modules", + "dist", + "src/**/*.test.ts", + "src/**/__test_utils__/**", + "src/regression-harness-lambda-local.ts" + ] }