Skip to content

feat(studio): host apps can import the render queue from the package - #4184

Merged
miguel-heygen merged 2 commits into
mainfrom
feat/studio-export-render-queue
Sep 19, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
feat/studio-export-render-queue

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

Host apps that mount Studio pieces in-tree can now import the render queue from @hyperframes/studio instead of copying it.

What is exported

  • RenderQueue (the props-based panel) and RenderQueueProps, CompositionDimensions
  • useRenderQueue, with RenderJob, ResolutionPreset, StartRenderOptions, FfmpegStatus
  • getPersistedRenderSettings, persistRenderSettings, PersistedRenderSettings

All through the existing "." entry in packages/studio/src/index.ts, the same way the ask-agent flow was exported. No new subpath, so package-subpaths.json and the packed-manifest check are unaffected.

What is not exported, on purpose

RenderQueuePanel and StudioShellProvider. The panel reads a 14-field shell context (project id, toast, undo/redo, iframe refs, render queue and more); exporting it would commit the package to that whole shape. A host wires useRenderQueue into RenderQueue directly.

Test

renderQueueExports.test.tsx imports everything by package name, mounts RenderQueue with a host-supplied job and round-trips the persisted settings. It fails on main (the imports are undefined) and passes here.

Before

before

After

after

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at 090c5b56. Small and well-built — approving.

The "fails on main" claim holds, and for the right reason

The test imports from @hyperframes/studio by package name rather than by relative path, so it goes through the declared export map instead of reaching around it. On main none of RenderQueue, useRenderQueue, getPersistedRenderSettings or persistRenderSettings are in src/index.ts, so the module fails to provide those named exports and the file fails to load. That is the export surface being pinned, not something incidental to it.

It also resolves to the right thing. package.json maps exports["."].import and types to ./src/index.ts, so in the workspace the test exercises the file this PR actually changes — no build step in between, and no chance of grading a stale dist. And the published path does not diverge: tsup.config.ts builds index from that same src/index.ts with dts: true, so dist/index.js and dist/index.d.ts pick the new exports up on their own. Nothing to add for the publish surface.

The test runs: vite.config.ts sets only exclude and setupFiles under test, so vitest's default include applies and src/renderQueueExports.test.tsx matches it. The assertions discriminate — expect(el.textContent).toContain("host-render.mp4") is a real mount through createRoot, and the settings check is a genuine write-then-read round trip rather than a shape assertion.

Export surface checked at source

Every re-exported symbol exists where the barrel says it does: RenderJob, ResolutionPreset, StartRenderOptions, useRenderQueue in useRenderQueue.ts; PersistedRenderSettings, getPersistedRenderSettings, persistRenderSettings in renderSettings.ts; FfmpegStatus in useFfmpegStatus.ts; RenderQueue at RenderQueue.tsx:423.

CompositionDimensions was already exported at RenderQueue.tsx:13, so the one-line export added to RenderQueueProps is the only source change needed. That is the correct minimal edit.

Nit — one type in the public props is still private

RenderQueueProps is public now, and three of the four types it references came with it: RenderJob, CompositionDimensions and FfmpegStatus are all exported and re-exported. The fourth is not. StartRenderHandler (RenderQueue.tsx:18) is a bare type with no export, and it is the type of onStartRender (:31).

This compiles and publishes fine — tsup's declaration build emits it as a local in the rolled-up .d.ts, and structural typing means a host can pass a function literal. What a host cannot do is name it: const onStartRender: StartRenderHandler = ... is unavailable, so they either inline the four-parameter signature themselves or reach for ComponentProps<typeof RenderQueue>["onStartRender"]. Since ResolutionPreset is already re-exported, every piece needed to hand-rewrite the alias is public — just not the alias.

Worth the same one-word fix that RenderQueueProps got, because the PR's stated goal is a host importing this instead of copying it, and a host that wires up a real render handler is the first one to hit it.

The test cannot catch this: onStartRender={vi.fn()} is assignable to anything, so it proves the export resolves and the component mounts, not that the type surface is usable for a real handler.

Not a blocker. Approving at 090c5b56.

— Rames

@miguel-heygen
miguel-heygen merged commit fd020ca into main Sep 19, 2026
49 checks passed
@miguel-heygen
miguel-heygen deleted the feat/studio-export-render-queue branch September 19, 2026 17:21
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.

2 participants