fix: give the HyperFrames capture process the Distribution resolver its parent has - #209
Conversation
resolve hooks registered by bin/hypit.mjs are process-local, so the HyperFrames capture child, which Node starts directly, saw neither @hypit/* nor the machine packages those modules declare. Only a contributor checkout hid this: pnpm links each workspace package into its own node_modules, while a packed Distribution ships none, so local rendering failed there with ERR_MODULE_NOT_FOUND on @hypit/hyperframes before it reached @hyperframes/engine. Preload the same resolution environment in that child and cover it with a test that starts outside the workspace.
|
Thank you for the report and the fix. Reproduced on the published 0.1.10 distribution. It ships Adding On the relative cross-package imports: Passing the preload as a Linux and Windows checks pass. Merging. |
Closes #207
What this fixes
bin/hypit.mjsinstalls two resolution hooks withmodule.registerHooks. Those hooks are process-local, andcapture-process.tsstarts its render child with Node directly:That child therefore saw
tsxbut neither@hypit/*nor the machine packages the Distribution's own modules declare. The child's runtime graph needs both —render.tsimports@hypit/hyperframes/project,@hypit/media,@hypit/media-execution,@hypit/render-hyperframesand@hypit/runtime, andopaque-capture.tsimports@hyperframes/engine.A contributor checkout hides this completely: pnpm links every workspace package into each package's own
node_modules, so plain Node resolution succeeds and the bug is invisible. A packed Distribution shipspackages/*/src/**/*with zeronode_modulesentries and zero symlinks (verified againstnpm run pack:distribution's tarball), so local rendering failed there withThe change
Preload a 5-line bootstrap that installs the same two resolvers the launcher installs, resolving the Distribution root from
HYPIT_DISTRIBUTION_ROOT(published bybin/hypit.mjs:23and inherited) with the sameimport.meta.dirname-relative fallback thatpackages/video-cli/src/distribution.ts:17already uses. No new environment variable, noNODE_PATH, no junction, nonode_modulespatch, no hard-coded path.Why the bootstrap lives in the provider
packages/package-loader-nodeownsinstallDistributionPackageResolution, but it cannot importhypitHostPackageRootfrom@hypit/runtime-host-node— that package already depends onpackage-loader-node, so it would be a dependency cycle.provider-hyperframes-localalready declares both packages, so the bootstrap sits next to the spawn it explains. Only relative specifiers can be used, since the module is evaluated before any hook exists.Happy to move it if maintainers prefer another home — the constraint is just "somewhere that can see both packages without a cycle".
Relationship to the existing pattern
packages/video-cli/src/distribution.ts:58-68already solves this class of problem for the Runtime Worker by re-entering the launcher (workerLaunch.args = [installedLauncher]). This is the same idea applied to the one child that does not go through the launcher. I did not extract a shared helper because the two call sites do not share a fixed relative depth, and the duplication is 5 lines.Test evidence
New case in
packages/provider-hyperframes-local/test/capture-process.test.ts. It starts outside the checkout, where nothing above the entry declares@hypit/hyperframes, and has three arms:ERR_MODULE_NOT_FOUND.stageHyperframesProject.runCaptureProcessitself, proving the entry point passes the preload.$ node --import tsx --test packages/provider-hyperframes-local/test/capture-process.test.ts ok 1 - a stuck renderer and its detached child both stop before the call rejects ok 2 - a capture process resolves Distribution packages without workspace links ok 3 - renderer stdout and stderr diagnostics are drained before reporting success # tests 3 · pass 3 · fail 0It fails on the unmodified spawn, with the production error verbatim:
$ git stash push -- packages/provider-hyperframes-local/src/capture-process.ts $ node --import tsx --test …capture-process.test.ts not ok 2 - a capture process resolves Distribution packages without workspace links HyperFrames process exited before completion: Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@hypit/hyperframes' imported from <tmp>/hypit-capture-resolution-…/worker.mjs $ git stash popEnd-to-end acceptance on a real packed Distribution
Exported MP4:
mov,mp4, 2 streams,h264 High 540x960 30/1 240 frames 8.000 s+aac LC 48000 Hz stereo 8.000 s, fullffmpeg -f null -decode with zero errors.Preloaded resolution inside that install (probe placed where
opaque-capture.tslives,cwd= the project,NODE_PATHunset,HYPIT_DISTRIBUTION_ROOTunset):Zero occurrences of the checkout path anywhere in the installed Distribution, and the only symlink under the install is npm's own project-local example package. So this is genuinely running the packaged artifact, not falling back to a source tree.
Verification
pnpm check(repo-widetsc --noEmit) — passes on this branch.node --import tsx --test packages/provider-hyperframes-local/test/*.test.ts→ 19 tests, 15 pass, 0 fail, 4 skipped (skips are behind the browser-test opt-in flag).pnpm test— unchanged; the single failure is the pre-existing WindowsEPERMsymlink case incompiler-node, same as on pristinemain.This PR is independent of the
optionalDependenciesfont fix (#206); the two touch disjoint files and I verified each branch against pristinemainseparately.