MCPcopy Create free account
hub / github.com/heygen-com/hyperframes / createStudioServer

Function createStudioServer

packages/cli/src/server/studioServer.ts:278–724  ·  view source on GitHub ↗
(options: StudioServerOptions)

Source from the content-addressed store, hash-verified

276}
277
278export function createStudioServer(options: StudioServerOptions): StudioServer {
279 const { projectDir, projectName } = options;
280 const projectId = projectName || basename(projectDir);
281 const studioDir = resolveDistDir();
282 const runtimePath = resolveRuntimePath();
283 const watcher = createProjectWatcher(projectDir);
284
285 // ── CLI adapter for the shared studio API ──────────────────────────────
286
287 const project: ResolvedProject = { id: projectId, dir: projectDir, title: projectId };
288 let cachedProjectSignature: string | null = null;
289 watcher.addListener(() => {
290 cachedProjectSignature = null;
291 });
292
293 const adapter: StudioApiAdapter = {
294 listProjects: () => [project],
295
296 resolveProject: (id: string) => (id === projectId ? project : null),
297
298 async bundle(dir: string): Promise<string | null> {
299 try {
300 const { bundleToSingleHtml } = await import("@hyperframes/core/compiler");
301 // Studio dev server: ask the bundler for an empty `src=""` placeholder so
302 // we can point it at our hot-reloadable local runtime endpoint. Inlining
303 // ~150 KB of runtime body on every preview render would defeat browser
304 // caching across composition edits.
305 let html = await bundleToSingleHtml(dir, { runtime: "placeholder" });
306 html = html.replace(
307 'data-hyperframes-preview-runtime="1" src=""',
308 'data-hyperframes-preview-runtime="1" src="/api/runtime.js"',
309 );
310 return html;
311 } catch (err) {
312 console.error("[studio] Bundle failed:", err);
313 return null;
314 }
315 },
316
317 async transformPreviewHtml({ html, project }) {
318 const { injectDeterministicFontFaces } =
319 await import("../../../producer/src/services/deterministicFonts.js");
320 const { prepareAnimatedGifInputs } =
321 await import("../../../producer/src/services/animatedGifPrep.js");
322 const { downloadToTemp } = await import("../../../producer/src/utils/urlDownloader.js");
323 const gifOutputDir = join(project.dir, ".hyperframes", "prepared-assets", "gif");
324 const gifDownloadDir = join(project.dir, ".hyperframes", "prepared-assets", "downloads");
325 const prepared = await prepareAnimatedGifInputs(html, {
326 projectDir: project.dir,
327 downloadDir: gifDownloadDir,
328 outputDir: gifOutputDir,
329 outputSrcPrefix: ".hyperframes/prepared-assets/gif",
330 cacheDir: gifOutputDir,
331 sourceAssets: await downloadRemoteGifImageSources(html, gifDownloadDir, downloadToTemp),
332 });
333 return injectDeterministicFontFaces(prepared.html);
334 },
335

Callers 1

runEmbeddedModeFunction · 0.85

Calls 14

createStudioApiFunction · 0.90
basenameFunction · 0.85
resolveDistDirFunction · 0.85
createProjectWatcherFunction · 0.85
findFFmpegFunction · 0.85
getFFmpegInstallHintFunction · 0.85
resolveFunction · 0.85
buildStudioHeadScriptsFunction · 0.85
buildRuntimeEnvScriptFunction · 0.85
addListenerMethod · 0.80
getMethod · 0.80

Tested by

no test coverage detected