Skip to content

fix(cli): a media file referenced by its filesystem path goes into the cloud archive - #7381

Merged
miguel-heygen merged 3 commits into
mainfrom
dcloudpro/localize-absolute-media
Nov 7, 2026
Merged

miguel-heygen merged 3 commits into
mainfrom
dcloudpro/localize-absolute-media

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

What

hyperframes cloud render now puts a media file that a composition references by its filesystem path (src="/Users/me/Music/song.mp3") into the upload archive, the way it already does for ../media/song.mp3: the file is copied under _ext/ and the reference is rewritten. A reference to a project file by its absolute path is rewritten to the file's path inside the archive.

Why

A leading / is a filesystem path to the local renderer (htmlCompiler.ts resolves it as one), so such a project renders with its audio locally. The archive builder treated every leading-/ reference as a site URL and left it alone, the file was never uploaded, and the cloud renderer refuses a path starting with / (distributed/shared.ts:188). The render is then blocked with audio_processing_failed: Source not found for audio element ... and the CLI never warned.

How

tryResolveExternal in utils/publishProject.ts now resolves a single-leading-/ reference as a filesystem path: outside the project and present on disk it is archived under _ext/ (the existing addExternalAsset); inside the project it is rewritten to its archive path. A Windows drive-letter path (C:\\...) counts as a filesystem path too (path.isAbsolute). A reference that does not exist on disk (a root-relative site URL such as /assets/x.png) is left as written, as before.

Test plan

  • utils/publishProject.absolutePath.test.ts: an absolute path outside the project is archived under _ext/ and rewritten; one inside is rewritten to its project path; a missing one is left alone. fails without the fix: the first two fail on main (the reference and the archive are unchanged).

  • The publishProject suites pass (80 tests), on Linux.

  • Real check through the archive builder: an audio src of an absolute path outside the project gave an archive of index.html and hyperframes.json only before, and _ext/media/song.mp3 with src="_ext/media/song.mp3" after. Local render of the same project is unchanged (audio present).

  • Unit tests added/updated

  • Manual testing performed

  • Documentation updated (not applicable)

  • Comments follow CONTRIBUTING.md "Comments"

Not exercised: a real cloud render of the archive, CSS url() with an absolute path (it goes through the same function, not separately tested), the #fragment/?query kept after the archive path is tested for HTML only, a real Windows run beyond CI (the new tests use join of the temp folders, so they take the drive-letter form there).

@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 90 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

Unstable (2)

  • seqrotatenudge-none-pct-r0-root-z100: tracking 0.03, pressJump 0, drop 0, reload 3.03, render 0.04, renderKey -, undo false, teleport true / tracking 0.03, pressJump 0, drop 0, reload 0, render 0.08, renderKey -, undo true, teleport true / tracking 0.03, pressJump 0, drop 0, reload 0, render 0.08, renderKey -, undo true, teleport true
  • seqplainkeys-none-px-r0-root-z100: tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo false, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 1 important · 0 nits · head 9c48060b

Checked

Checked the fails without the fix: claim: with main's publishProject.ts, the first two cases in publishProject.absolutePath.test.ts fail and the third passes. On this head, the publishProject suites pass (80 passed, 2 skipped). The returned archive path goes through referenceFrom, so a sub-composition at comp/c.html gets ../media/a.mp3 (probed). A root-relative URL that isn't on disk is still left as written. CI not read: this identity can't read check-runs.

if (isPathInside(absPath, ctx.absProjectDir)) {
includeReferencedProjectFile(ctx, absPath, rawPath, requireOnDisk);
return null;
return filesystemPath ? relativeToProject(ctx, absPath) : null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

important: an in-project absolute path with a fragment or query gets the suffix encoded into the filename. I probed src="<project>/media/a.mp3#t=1" and it comes out as media/a.mp3%23t%3D1, a file that isn't in the archive, so the cloud render still can't find the audio. Media fragments (#t=) are common on <audio>/<video>. This isn't a regression: on main the absolute path also fails in the cloud. To fix it, split off ?…/#… before relativeToProject and append it after, with a case in publishProject.absolutePath.test.ts. The outside-project branch is unaffected, because existsSync misses and leaves the reference as written.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixed in aa5f2ed: the ?…/#… suffix is cut before resolving and re-appended to the archive path. The new test fails against 9c48060's publishProject.ts and passes now.

@miguel-heygen
miguel-heygen force-pushed the dcloudpro/localize-absolute-media branch from 9c48060 to aa5f2ed Compare November 7, 2026 21:07

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 1 resolved, 0 open, 0 new · 9c48060 → aa5f2ed

Rebased onto main (#7376/#7377/#7380). The PR's own patch is still only publishProject.ts plus its test. Relative references don't take the suffix cut (filesystemPath only). publishProject suites: 81 passed, 2 skipped.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 resolved, 0 open, 0 new · aa5f2ed → f8cdaa9

path.isAbsolute is the same as startsWith("/") on POSIX. On win32 it also accepts C:\…, C:/… and UNC, and rejects https:, data: and drive-relative C:rel. This matches the two windows-latest failures on aa5f2ed (job 128529378310: the inside-project and #fragment cases left C:\Users\… unrewritten). publishProject suites pass on Linux (81 passed, 2 skipped). Windows CI on this head is still running.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit e0c11bf Nov 7, 2026
131 checks passed
@miguel-heygen
miguel-heygen deleted the dcloudpro/localize-absolute-media branch November 7, 2026 22:09
@miguel-heygen miguel-heygen mentioned this pull request Nov 7, 2026
3 of 5 tasks
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 9, 2026
Port the adopted upstream fixes from f5bde95 to the current upstream tip:
heygen-com#7375 multipart cloud upload, heygen-com#7382 minParallelChunks, heygen-com#7349 HLG header SEI,
heygen-com#7369 skip unmounted compositions in lint/check, heygen-com#7381 filesystem-path media
in the cloud archive, heygen-com#7383 Safari cut-point pre-roll revert, heygen-com#7373 clock
steering between audio time updates, heygen-com#7384 injector test isolation, heygen-com#7378
preview seek retention, heygen-com#7390 virtual timer schedule per worker, heygen-com#7394 CDN
script failure naming, heygen-com#7395 menu row radius, heygen-com#7119 decode timeout caller
test, heygen-com#7397 authored tween order, heygen-com#7402 capture page clip loading, heygen-com#7412 muted
video audio track at cuts, heygen-com#6150 template root variable test, heygen-com#7442 held tail
seek once.

Deliberate local differences: heygen-com#7067's audio-start hold is not carried into
clock.ts, mountedSources comes from heygen-com#6827 as a helper only, cloud/_gen/types.ts
omits the image-request types the fork does not generate, and the lint
symlink test skips through symlinkOrSkip where the account cannot create links.

Co-Authored-By: Claude Sonnet <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant