Plan reads the account's Lambda concurrency when a render sets none, and
the handler tests left that client to its default, so a machine with AWS
credentials made a real GetAccountSettings call. Every handler call in the
file now gets a stub that refuses, and a guard fails any test that sends
through a real Lambda or S3 client.
* perf(aws-lambda): run chunks through a Distributed Map to lift the 40-chunk cap
The inline Map runs at most 40 chunk renders at once. Both state machine
definitions (CDK and SAM) now use a Distributed Map with STANDARD child
executions, capped at the function's reserved concurrency so chunks past it
queue instead of being throttled. Progress reads each chunk's child
execution history so frames, cost and chunk errors still show up.
* fix(aws-lambda): retry Lambda throttles for minutes and stop on oversized chunks
A throttled task used to burn its four catch-all retries in about 30 s.
It now gets its own jittered backoff of several minutes, because another
render on the same function can still hold the reserved slots. Plan
treats CHUNK_EXCEEDS_WORKER_TIMEOUT as terminal in both definitions.
* chore(aws-lambda): trim stack comments to keep the comment share flat
* fix(aws-lambda): keep render --wait working at hundreds of chunks
Progress polls read the chunk Map Run's counts (one DescribeMapRun) instead of
every child execution's history, take exact chunk frames and cost from the Map
output once it exits, and read failed children only when the counts show a
failure. The SDK client retries throttled calls up to 8 times with backoff.
* feat(aws-lambda): size each render's concurrency to the account instead of a fixed 8
* fix(lambda): keep the concurrency SDK external in published modules
* fix(cli): keep an existing stack's reserved concurrency on redeploy
Redeploying without --concurrency sent ReservedConcurrency=-1, which
removed the cap of 8 that earlier CLI versions reserved by default and
stopped recording it in the state file. The override is now left out
when the flag is omitted, so SAM keeps the stack's current value (a new
stack still gets the template's unreserved default). The state file
records the deployed value, and deploy prints the kept reservation.
* fix(aws-lambda): keep progress working for callers without DescribeMapRun
Callers whose IAM policy came from an earlier `lambda policies user`
lack states:DescribeMapRun, so reading a running Distributed Map threw
AccessDeniedException out of `lambda progress` and `render --wait`
while the render itself went on to succeed. getRenderProgress now
catches only that error around the map-run read, returns the parent
snapshot (status, plan and assemble progress) and adds a warning to
re-apply the policy, which both commands print. Other errors still
throw.
* fix(cli): let the documented deploy policy drop a reserved concurrency
When a redeploy removes a function's reserved concurrency, CloudFormation
calls lambda:DeleteFunctionConcurrency. The policy printed by
`lambda policies role|user` granted only PutFunctionConcurrency, so the
update failed and rolled back. Grant it, and pin it with
states:DescribeMapRun in the required-actions test.
* fix(aws-lambda): read smoke chunk hashes from the Distributed Map output
With chunks in a Distributed Map, their task results live in child
executions, so the smoke gate's chunk-hash check found 0 chunks in the
parent history and failed every v1/v2 comparison. Read Chunks[] from the
RenderChunks / RenderChunksV2 MapStateExited output instead, as
getRenderProgress does. The stack this script deploys only has the
Distributed Map, so the inline-Map path is gone.
* fix(producer): cap a pinned chunk size at the worker concurrency, not 16
With --chunk-size or --target-chunk-frames and no --max-parallel-chunks,
the plan still capped the render at 16 chunks however many workers the
account allowed, so --chunk-size 30 on a 60 s render gave 16 chunks of
113 frames. The cap is now one wave across the worker concurrency, as
the --max-parallel-chunks docs say; 16 remains when the concurrency is
unknown.
* feat(cli): remove a stack's reserved concurrency with --concurrency=none
Since an omitted --concurrency now keeps the stack's reservation, there
was no CLI way back to the unreserved default. --concurrency=none sends
ReservedConcurrency=-1, the state file records the stack as unreserved
and deploy says the reservation was removed. Positive N and an omitted
flag behave as before; any other value is rejected instead of being
silently ignored.
* chore(aws-lambda): raise the package size budget for account-sized concurrency
Measured with pnpm@10.17.1 pack after rebasing on main with the S3 assembly change: 67,763 packed / 244,685 unpacked; the budget is the check's own 5% headroom over that.
* perf(producer): assemble chunks that carry audio under one faststart index
Reads each chunk's moov, merges the sample tables into one moov at the front, and writes
the chunks' mdat payloads after it unchanged: the same bytes storage can copy into place.
The assembler no longer needs the plan audio for such plans.
* perf(aws-lambda): build the final mp4 inside S3 with its index up front
The Lambda plan asks chunks to carry their audio. Assemble writes the faststart header as
part 1 of a multipart upload and copies each chunk's mdat payload with UploadPartCopy, so
the video bytes never pass through the function; any failure aborts the upload.
* fix(engine): a chunk's first frame shows its own time, not the composition's opening frame
* fix(producer): stitch silent AAC tails and clean failed outputs
* fix(producer): open stitched chunks read-only with an explicit mode
* chore(aws-lambda): raise the package size budget for S3-side MP4 assembly
handler.js and index.js each bundle the new S3 stitch code (+5,550 bytes apiece) and s3Stitch.d.ts adds 970: +3,479 packed and +12,070 unpacked over main, measured with the CI pack. The budget rises by exactly that delta.
* fix(aws-lambda): v1 plans give chunks their audio too, so both protocols match
* perf(producer): plans whose chunks carry audio encode it once, at the frames' exact length
* test(producer): terminate the plan audio ffprobe argv like every other probe
* perf(producer): assemble in one pass and keep its disk use under one output copy
The distributed assembler joined the chunks into a full-size file, muxed the
audio into a second one and rewrote that again for faststart, so local disk
peaked near four copies of the video and a 30-minute 1080p render came close
to Lambda's 10 GB /tmp. The join, audio mux and faststart now run as one
ffmpeg pass over the concat demuxer; the audio pad/trim takes its frame count
from the chunks. Video and audio packets are unchanged. Assemble and the
Lambda assemble handler log per-stage timings.
* refactor(producer): split assemble into plan check, cfr re-encode and final write
Keeps assemble under the complexity gate and drops an orphaned doc comment in chunkEncoder. No behaviour change.
The integer rates Lambda and Cloud Run accept were written out by hand in
about 25 places across core, engine, producer, the adapters and the CLI.
They now come from DISTRIBUTED_FPS / DistributedFps / isDistributedFps in
@hyperframes/core. Engine config snapshots accept 25 like the rest.
Lambda and Cloud Run renders refused 25 fps although it is an integer
rate like 24, 30 and 60, and PAL footage is 25 fps. The distributed fps
set is now {24, 25, 30, 60} in the producer's config validation, the
plan v2 manifest, the render request mapping, the Lambda and Cloud Run
event types, the CLI's lambda and cloudrun commands and the regression
harnesses.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(build): ship NodeNext-resolvable declarations from every package
tsc copies relative specifiers verbatim, so packages whose sources use
bundler-style extensionless imports (core, inspector) published .d.ts files
that a module/moduleResolution nodenext consumer cannot resolve. Core already
rewrote its emitted JavaScript for this, but not its declarations.
Move that rewrite to scripts/rewrite-relative-import-extensions.mjs, make it
cover .d.ts too (adding .js or /index.js, and failing the build when a
declaration import has no declaration), and run it after every tsc emit:
core, engine, sdk, producer, aws-lambda, gcp-cloud-run and inspector.
verify:packed-manifests now typechecks the clean packed consumer with
skipLibCheck false and type-only imports of every typed subpath, so an
unresolvable import inside a published declaration fails the gate and is
attributed to its package.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore(ci): allow the moved core rewrite-esm-extensions script deletion
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* ci: rebuild the edit-accuracy bench when the import-extension rewriter changes
The package builds now run scripts/rewrite-relative-import-extensions.mjs, so main's
edit_accuracy paths filter has to include it (check-edit-accuracy-filter test).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore: release v0.8.159
* chore: v0.8.159 notes list the first-frame fix
* chore: v0.8.159 notes list the sandboxed GPU check fix
* chore: v0.8.159 notes list the hidden-scene fix and the offline font test
* chore: release v0.8.154
* ci: give the studio test job fifteen minutes
The queue run installs and builds inside the same ten minute cap.
It was still inside the studio tests when that cap cancelled the job.
* chore: release v0.8.152
* docs(changelog): correct the v0.8.152 release notes
The summary overstated snapshot retention, history turns, and video state.
It also left out the new artifact paths and nullable keyframe times.
* perf(packages): ship npm packages without source maps and guard their size in CI
No package or consumer reads the published source maps, so they are no
longer built. The CLI copies only the studio app it serves instead of the
whole studio dist. verify:packed-manifests now holds every published package
to a size budget that ratchets down, and CI rejects pull requests that add a
large binary outside LFS.
* fix(ci): large-binary check reads every filename and fails on git errors
* ci: run only Build when a skill bundled into the CLI changes
* fix(ci): size guards also catch type changes, odd file names, unreadable blobs and bad budgets
* fix(ci): large-binary check reads blobs by id and skips submodules
* fix(ci): exempt only exact registry copies under docs/public/catalog
* test(ci): cover the staged catalog-copy exemption; drop the local-only override hint in CI
* fix(ci): producer budget follows its slimmed package; size checks name their real cause
* test(aws-lambda): compare every CDK Lambda payload against the SAM template
#5259 shipped because CDK drops null-valued payload fields when it renders the
state machine, so the construct's source and its deployed definition disagreed
with nothing to notice. This test reads all six Lambda task payloads from the
synthesized definition and requires each to equal the SAM template's, reading
`States.StringToJson('null')` as the null it sends. A field dropped or renamed
on either side now fails CI, not just AssembleV2's audio.
Refs #5259
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(aws-lambda): discover Lambda tasks for the payload parity check
The parity test took its tasks from helpers that name six states, so a seventh
Lambda task on either side would be skipped and the check would stay green.
It now walks both definitions, Map and Parallel processors included, collects
every lambda:invoke task by name, requires the two name sets to match, then
compares each payload.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(aws-lambda): key discovered Lambda tasks by their nested state path
Keying tasks by state name let two branches that each hold a RenderChunk
collapse into one entry, so the other's payload went unchecked. Tasks are now
keyed by path (a Map processor as `Map/`, a Parallel branch as `Parallel/<i>/`),
and a regression test keeps two same-named branch tasks apart.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>