Skip to content

refactor(studio): wire vite.config.ts to shared studio API module#115

Merged
miguel-heygen merged 1 commit intomainfrom
refactor/studio-use-shared-api
Mar 28, 2026
Merged

refactor(studio): wire vite.config.ts to shared studio API module#115
miguel-heygen merged 1 commit intomainfrom
refactor/studio-use-shared-api

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen commented Mar 28, 2026

Summary

  • Replaces ~850 lines of inline route handlers in vite.config.ts with the shared createStudioApi(adapter) module
  • Implements StudioApiAdapter for the Vite dev server context (SSR-loaded bundler/linter, producer HTTP proxy, Puppeteer thumbnails)
  • Bridges Hono fetch() to Vite's Connect middleware with streaming support for SSE

Now both consumers (CLI + studio) use the same shared API module, ensuring feature parity.

Test plan

  • pnpm --filter @hyperframes/studio dev starts correctly
  • Home page shows project grid with thumbnails
  • Preview plays with correct fonts/animations
  • Sub-composition drill-down works
  • Lint modal shows findings
  • File read/write works in code editor
  • Render queue works (requires producer server)

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

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

Review: refactor(studio): wire vite.config.ts to shared studio API module

What was done well

This is a clean, impactful refactor. The PR replaces ~727 lines of inline route-handler code with a well-structured adapter pattern that delegates to the shared createStudioApi(adapter) module. Key strengths:

  • Excellent separation of concerns. Host-specific logic (Puppeteer browser management, Vite SSR module loading, producer-server proxying) stays in vite.config.ts via the StudioApiAdapter, while routing, path validation (isSafePath), file walking, sub-composition HTML building, and MIME detection all live in the shared module where they belong.

  • The Hono-to-Connect bridge is clean. bridgeHonoResponse() correctly streams the response body (critical for SSE progress events) and handles the no-body case. The request-side bridge properly reads the body for non-GET/HEAD methods and forwards headers.

  • The /api prefix stripping is correct. url.pathname = url.pathname.slice(4) strips /api so that shared routes like /projects, /projects/:id/preview, etc. match correctly. This was verified against the route definitions.

  • Lazy initialization pattern is preserved. Both the bundler (getBundler) and the Hono app (getApi) are lazily loaded via Vite's SSR module loader, which correctly resolves TypeScript imports for @hyperframes/core/studio-api and @hyperframes/core/compiler.

  • CI is fully green -- typecheck, lint, format, build, and all test suites pass.

Issues

None critical or blocking.

Minor observations / suggestions

  1. rendersDir ignores its argument. The interface defines rendersDir(project: ResolvedProject): string but the adapter implements rendersDir: () => resolve(dataDir, "../renders"). This works due to TypeScript's structural typing (fewer params assignable to more params), and in this context all projects share the same renders directory, so it is correct behavior. Just noting it as something future readers might find surprising -- a comment like // All projects share a single renders dir in dev mode would help.

  2. _api local type annotation. let _api: { fetch: (req: Request) => Promise<Response> } | null = null is a structural duck-type for Hono. This is a fine choice since it avoids importing Hono directly into the Vite config (Hono is loaded via SSR), but if @hyperframes/core/studio-api ever exported a StudioApi type alias, it would be cleaner to use that.

  3. Thumbnail caching moved to the shared module. The old code cached thumbnails to disk in the Vite handler; now the shared thumbnail.ts route handles the disk cache while the adapter's generateThumbnail just does the Puppeteer screenshot. This is a good separation. The adapter's in-flight dedup via _thumbnailInflight correctly prevents parallel Puppeteer pages for the same frame, and the shared route handles the disk layer. No issue here, just confirming it was reviewed.

  4. Body reading for POST/PUT. The body is read as a UTF-8 string for all non-GET/HEAD requests. This is fine for the current API surface (JSON bodies and text file content), but would need revisiting if binary uploads (e.g., asset upload) are added in the future.

  5. Error handling in bridgeHonoResponse. The catch {} on reader errors is appropriate for client disconnects, but swallows all errors silently. Consider logging at debug level if you add structured logging later.

Verdict

Approve. This is a well-executed refactor that achieves its stated goal -- both CLI and studio now consume the same shared API module. The adapter cleanly encapsulates Vite-specific concerns, the bridge handles streaming correctly, and no functionality appears to be lost or broken. The observations above are all suggestions for future improvement, not blockers.

Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

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

Review: refactor(studio): wire vite.config.ts to shared studio API module

Clean extraction. The Vite config correctly consumes the shared API module via SSR lazy-loading. ~727 lines of inline route handlers replaced with a ~308-line adapter.

What looks good

  • Request/response bridging handles both streaming (SSE) and non-streaming responses correctly via bridgeHonoResponse
  • Adapter implementation delegates to createStudioApi(adapter) with proper duck-typing of Hono's .fetch() — no unnecessary indirection
  • No breaking changes — routes, paths, and behavior are functionally equivalent to the old inline implementation
  • CI passes (typecheck, lint, build, all test suites)

Minor suggestions (non-blocking)

  • rendersDir parameter could be derived from projectDir instead of passed separately
  • Silent error swallowing in the bridge function could log to debug
  • Body-reading assumes text-only — binary payloads would need .arrayBuffer()

Verdict

Approved. No critical or important issues.

@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from f0692ed to 9c1ebaa Compare March 28, 2026 17:17
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from bdb4434 to cd8b974 Compare March 28, 2026 17:17
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch 2 times, most recently from 206f2c6 to 89e22ef Compare March 28, 2026 17:26
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from cd8b974 to c67943e Compare March 28, 2026 17:26
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 89e22ef to e051b17 Compare March 28, 2026 17:40
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from c67943e to 1a49a4d Compare March 28, 2026 17:40
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from e051b17 to 3f65cce Compare March 28, 2026 17:47
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 1a49a4d to 1e531f2 Compare March 28, 2026 17:47
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 3f65cce to d99cfca Compare March 28, 2026 18:00
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 1e531f2 to 9660e75 Compare March 28, 2026 18:00
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from d99cfca to 964ebd7 Compare March 28, 2026 18:04
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch 2 times, most recently from 8242e33 to 643c61a Compare March 28, 2026 18:05
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 964ebd7 to 4bba2f0 Compare March 28, 2026 18:05
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 643c61a to 646266f Compare March 28, 2026 18:12
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 4bba2f0 to 989bd8f Compare March 28, 2026 18:12
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 33105f1 to 22c2c84 Compare March 28, 2026 19:37
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch 2 times, most recently from faccb37 to 229f62d Compare March 28, 2026 19:43
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 22c2c84 to 43966ba Compare March 28, 2026 19:43
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 229f62d to 31701fe Compare March 28, 2026 19:48
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 43966ba to 494d4e7 Compare March 28, 2026 19:48
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 31701fe to 69a4de3 Compare March 28, 2026 19:53
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 494d4e7 to ef5282c Compare March 28, 2026 19:53
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 69a4de3 to 8a2af77 Compare March 28, 2026 19:58
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from ef5282c to 3a49a8e Compare March 28, 2026 19:58
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 8a2af77 to 029329e Compare March 28, 2026 19:59
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch 2 times, most recently from 6f7590e to a46c170 Compare March 28, 2026 20:09
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch 2 times, most recently from 9356f4e to 37bbab3 Compare March 28, 2026 20:30
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from a46c170 to b3904ee Compare March 28, 2026 20:30
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch from 37bbab3 to a57d95f Compare March 28, 2026 20:50
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from b3904ee to 438a377 Compare March 28, 2026 20:50
@miguel-heygen miguel-heygen force-pushed the refactor/shared-studio-api branch 2 times, most recently from 99f4d36 to 644ad12 Compare March 28, 2026 21:09
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 438a377 to 4a0e7bb Compare March 28, 2026 21:09
@miguel-heygen miguel-heygen changed the base branch from refactor/shared-studio-api to graphite-base/115 March 28, 2026 21:28
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from 4a0e7bb to da9e21f Compare March 28, 2026 21:28
@graphite-app graphite-app bot changed the base branch from graphite-base/115 to main March 28, 2026 21:28
Replace ~850 lines of inline route handlers with the shared
`createStudioApi(adapter)` module from @hyperframes/core/studio-api.

The Vite adapter implements StudioApiAdapter with:
- Multi-project listing with session resolution
- SSR-loaded bundler and linter (via server.ssrLoadModule)
- Producer HTTP proxy for rendering
- Puppeteer thumbnail generation with inflight dedup
- File watcher → HMR bridge

Hono fetch is bridged to Vite's Connect middleware with streaming
support for SSE endpoints (render progress).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@miguel-heygen miguel-heygen force-pushed the refactor/studio-use-shared-api branch from da9e21f to e3e431b Compare March 28, 2026 21:28
@miguel-heygen miguel-heygen merged commit b11edbf into main Mar 28, 2026
14 of 15 checks passed
Copy link
Copy Markdown
Collaborator Author

Merge activity

@miguel-heygen miguel-heygen deleted the refactor/studio-use-shared-api branch April 6, 2026 23:24
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