Skip to content

refactor: extract @hyperframes/studio-server from core#1757

Merged
miguel-heygen merged 5 commits into
mainfrom
refactor/extract-studio-server
Jun 27, 2026
Merged

refactor: extract @hyperframes/studio-server from core#1757
miguel-heygen merged 5 commits into
mainfrom
refactor/extract-studio-server

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extracts the studio preview server — the studio-api Hono routes, helpers, and server wiring — out of @hyperframes/core/src/studio-api/ into a new @hyperframes/studio-server package.

Part of #1749: pulls the HTTP/preview server out of core so an embedder can mount the studio backend without depending on the entire core surface, and so core stops carrying a web server it doesn't need at render time.

Part 3 of 3 — stacks on #1755 (@hyperframes/parsers). Independent of Part 2 (lint); merge A first, then B and C in either order.

What moves

Source moved out of core (src/studio-api/) ~9,100 LOC removed
New package source ~5,700 LOC
Files in new package 49
Tests carried over 201 passing

This includes the route handlers (files, thumbnail, mutation endpoints), the source-mutation helpers, and the server bootstrap.

Bundle footprint

Artifact Size
dist/ (unpacked) 592 KB
npm tarball (packed) 124 KB (19 files)

How @hyperframes/core changes

packages/core/src/studio-api/index.ts becomes a @deprecated re-export stub pointing at the new package, so @hyperframes/core/studio-api imports keep resolving.

The notable wrinkle: this creates an intentional circular workspace dependency.

@hyperframes/core  ──(stub re-export)──▶  @hyperframes/studio-server
@hyperframes/studio-server  ──(real usage)──▶  @hyperframes/core

core re-exports studio-server for back-compat, while studio-server genuinely consumes core's types/compiler. tsup handles it by marking both @hyperframes/* packages external during each build, so neither bundles the other — the cycle exists only in the module graph, never in the emitted output. core picks up @hyperframes/studio-server as a dependency; studio-server depends on core + parsers + hono + linkedom + postcss.

Design notes

  • The studio routing test (thumbnail.test.ts) moves with the routes from packages/core to packages/studio-server; the preview-regression workflow is updated to point at the new location.
  • "bun" export condition before "node" (same convention as the rest of the stack) keeps the dev loop build-free while Node/tsx/Docker resolve built dist/.

Test plan

  • bun run --filter @hyperframes/studio-server test — 201 tests pass
  • bun run --cwd packages/cli test — 1045 tests pass
  • bun run build — full monorepo build succeeds (circular dep resolves cleanly)
  • Preview parity + regression shards pass on CI
  • Fallow audit passes on CI

miguel-heygen commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@miguel-heygen miguel-heygen force-pushed the refactor/extract-studio-server branch 3 times, most recently from dcce528 to 79649b6 Compare June 27, 2026 03:15
terencecho
terencecho previously approved these changes Jun 27, 2026

@terencecho terencecho 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.

Clean, well-executed extraction. The circular workspace dep is the most interesting risk on paper, but it's structured safely — happy to ship.

Verified

  • Circular dep is safe. Both studio-server/tsup.config.ts:14 and core's tsup pipeline rely on tsup's default-externalize-deps-from-package.json behavior (same pattern as sibling parsers/lint). studio-server/package.json:90 declares @hyperframes/core in deps → tsup emits a runtime import rather than bundling. The cycle is deepcore/src/index.ts doesn't import studio-api at top level, and studio-server/src/index.ts doesn't directly import @hyperframes/core at top level either — so ESM lazy module eval breaks it before either side initializes. Bun-dev resolves both to src/... but the same depth saves it.
  • Backwards-compat stubs complete. Core's package.json still declares ./studio-api, ./studio-api/screenshot-clip, ./studio-api/manual-edits-render-script, ./studio-api/studio-motion-render-script, ./studio-api/draft-markers, ./studio-api/finite-mutation. Each corresponding packages/core/src/studio-api/helpers/<file>.ts is a 2-line export * from "@hyperframes/studio-server/<sub>" stub. Old imports continue to resolve.
  • No silent route drop. packages/studio-server/src/createStudioApi.ts registers 10 routes (projects/storyboard/files/preview/lint/render/thumbnail/waveform/fonts/registry) — identical to master's packages/core/src/studio-api/createStudioApi.ts. Verified line-by-line.
  • CLI mount sig preserved. cli/src/server/studioServer.ts:242-258 just swaps the import path (@hyperframes/core/studio-api@hyperframes/studio-server); the createStudioApi(adapter) call shape is unchanged.
  • Test relocation parity. preview-regression.yml:86 correctly updated to bun run --cwd packages/studio-server test -- src/routes/thumbnail.test.ts. Workflow also builds @hyperframes/studio-server before core (line 80). Dockerfile.test:78,93 mirrors this.
  • Stack-base: gh pr diff 1757 is the studio-server delta only — no parser-package leakage.
  • Dependency hygiene: studio-server/package.json:90-96 has core + parsers + hono + linkedom + postcss + postcss-selector-parser. Core picks up @hyperframes/studio-server at packages/core/package.json:357. CLI / producer / studio all updated. set-version.ts:25 + publish.yml:128 add studio-server to the version-sync + publish order (parsers → studio-server → core) — correct given the cycle.

Non-blocking polish

  • Stale consumer imports on the deprecated path. cli/src/utils/staticProjectServer.ts:4, cli/src/commands/play.ts:110, studio/src/hooks/gsapScriptCommitHelpers.ts:1, studio/src/hooks/useDomEditCommits.ts, studio/src/hooks/useGsapScriptCommits.ts, studio/src/hooks/useGestureRecording.ts, cli/src/commands/present.ts all still import from @hyperframes/core/studio-api/*. These resolve via the stubs and work, but a bulk-migrate (either in this PR or as a follow-up issue) would lock in the new package name and let the stubs be deleted in a future round.
  • Build-order asymmetry. Workflow builds studio-server before core even though core depends on studio-server. tsup's dts generation resolves types via "types": "./src/index.ts" so it works — but a one-line comment in the workflow noting why this order is correct (it's not topological — the "types" condition rescues it) would help the next person who touches it.

— Review by tai (pr-review)

@miguel-heygen miguel-heygen changed the base branch from refactor/extract-parsers to graphite-base/1757 June 27, 2026 04:46
Moves all studio-api routes, helpers, and Hono server wiring from
packages/core/src/studio-api/ into a new standalone packages/studio-server
package (@hyperframes/studio-server).

Core keeps thin re-export stubs at @hyperframes/core/studio-api and the
subpath helpers (screenshot-clip, draft-markers, etc.) for backward
compatibility. Consumer imports (cli studioServer, vite adapter/config,
producer htmlCompiler, studio manualEditsTypes) are updated to import from
@hyperframes/studio-server directly.

Also exports rewriteInlineStyleAssetUrls from @hyperframes/core root (was
in compiler/rewriteSubCompPaths.ts but not re-exported), required by
@hyperframes/studio-server/helpers/subComposition.

Removes postcss-selector-parser from @hyperframes/core dependencies (moved
to @hyperframes/studio-server which owns the routes that used it).

Depends on @hyperframes/parsers (PR #1755).
@miguel-heygen miguel-heygen force-pushed the refactor/extract-studio-server branch from 79649b6 to 99ceace Compare June 27, 2026 04:47
@graphite-app graphite-app Bot changed the base branch from graphite-base/1757 to main June 27, 2026 04:47
@graphite-app graphite-app Bot dismissed terencecho’s stale review June 27, 2026 04:47

The base branch was changed.

@miguel-heygen miguel-heygen force-pushed the refactor/extract-studio-server branch from 99ceace to dd33a4a Compare June 27, 2026 04:47
… smoke

Studio's vite.config.ts imports @hyperframes/studio-server, which resolves
via its "node" export condition to built dist. The Test and studio-load-smoke
jobs only built parsers + core, so esbuild's config load failed to resolve the
package entry. Build studio-server too.
sourceMutation moved from core's studio-api to @hyperframes/studio-server;
the test still imported the deleted core path. This was masked while studio's
vite.config failed to load (couldn't resolve studio-server); now that the
config loads, the test runs and the stale import surfaced.
…io-server

# Conflicts:
#	.fallowrc.jsonc
#	.github/workflows/preview-regression.yml
#	.github/workflows/publish.yml
#	Dockerfile.test
#	bun.lock
#	package.json
#	packages/cli/tsup.config.ts
#	packages/producer/package.json
#	scripts/set-version.ts
@miguel-heygen miguel-heygen merged commit 7a4853d into main Jun 27, 2026
14 checks passed
@miguel-heygen miguel-heygen deleted the refactor/extract-studio-server branch June 27, 2026 05:24
miguel-heygen added a commit that referenced this pull request Jun 27, 2026
New docs pages for the three packages extracted from core (#1755, #1756,
#1757), wired into the Packages nav after @hyperframes/core. Each covers
when-to-use, exports, and API with cross-links. Core's parser/lint sections
now point at the dedicated packages and its Related Packages lists all three.
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