@hyperframes/studio-server 0.8.50 → 0.8.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -290,77 +290,14 @@ function registerProjectRoutes(api, adapter) {
290
290
  });
291
291
  }
292
292
 
293
- // src/routes/storyboard.ts
294
- import { existsSync, readFileSync as readFileSync2 } from "fs";
295
- import {
296
- parseStoryboard,
297
- SCRIPT_FILENAME,
298
- STORYBOARD_FILENAME
299
- } from "@hyperframes/core/storyboard";
300
- function resolveFrames(projectDir, frames) {
301
- return frames.map((frame) => {
302
- let srcExists = false;
303
- if (frame.src) {
304
- const abs = resolveWithinProject(projectDir, frame.src);
305
- srcExists = abs ? existsSync(abs) : false;
306
- }
307
- return { ...frame, srcExists };
308
- });
309
- }
310
- function readScript(projectDir) {
311
- const abs = resolveWithinProject(projectDir, SCRIPT_FILENAME);
312
- if (abs && existsSync(abs)) {
313
- try {
314
- return { exists: true, path: SCRIPT_FILENAME, content: readFileSync2(abs, "utf-8") };
315
- } catch {
316
- }
317
- }
318
- return { exists: false, path: SCRIPT_FILENAME, content: "" };
319
- }
320
- function registerStoryboardRoutes(api, adapter) {
321
- api.get("/projects/:id/storyboard", async (c) => {
322
- const resolved = await resolveProjectAndSignature(adapter, c.req.param("id"));
323
- if (!resolved) return c.json({ error: "not found" }, 404);
324
- const { project, signature } = resolved;
325
- const abs = resolveWithinProject(project.dir, STORYBOARD_FILENAME);
326
- if (!abs || !existsSync(abs)) {
327
- return c.json({
328
- exists: false,
329
- path: STORYBOARD_FILENAME,
330
- globals: { extra: {} },
331
- frames: [],
332
- warnings: [],
333
- script: readScript(project.dir),
334
- signature
335
- });
336
- }
337
- let source;
338
- try {
339
- source = readFileSync2(abs, "utf-8");
340
- } catch {
341
- return c.json({ error: "failed to read storyboard" }, 500);
342
- }
343
- const manifest = parseStoryboard(source);
344
- return c.json({
345
- exists: true,
346
- path: STORYBOARD_FILENAME,
347
- globals: manifest.globals,
348
- frames: resolveFrames(project.dir, manifest.frames),
349
- warnings: manifest.warnings,
350
- script: readScript(project.dir),
351
- signature
352
- });
353
- });
354
- }
355
-
356
293
  // src/routes/files.ts
357
294
  import { bodyLimit } from "hono/body-limit";
358
295
  import {
359
296
  closeSync,
360
- existsSync as existsSync4,
297
+ existsSync as existsSync3,
361
298
  ftruncateSync,
362
299
  openSync,
363
- readFileSync as readFileSync5,
300
+ readFileSync as readFileSync4,
364
301
  writeFileSync as writeFileSync4,
365
302
  writeSync,
366
303
  mkdirSync as mkdirSync3,
@@ -421,7 +358,7 @@ function isAudioFile(name) {
421
358
  // src/helpers/waveform.ts
422
359
  import { spawn } from "child_process";
423
360
  import {
424
- existsSync as existsSync2,
361
+ existsSync,
425
362
  writeFileSync,
426
363
  mkdirSync,
427
364
  lstatSync as lstatSync2,
@@ -498,11 +435,11 @@ function decodeAudioPeaks(audioPath) {
498
435
  }
499
436
  async function generateWaveformCache(projectDir, assetPath) {
500
437
  const audioPath = join3(projectDir, assetPath);
501
- if (!existsSync2(audioPath)) return;
438
+ if (!existsSync(audioPath)) return;
502
439
  const stats = statSync(audioPath);
503
440
  const cacheDir = join3(projectDir, ".waveform-cache");
504
441
  const cachePath = join3(cacheDir, buildWaveformCacheKey(assetPath, stats));
505
- if (isWaveformCacheDirectory(cacheDir) && existsSync2(cachePath)) return;
442
+ if (isWaveformCacheDirectory(cacheDir) && existsSync(cachePath)) return;
506
443
  const peaks = await decodeAudioPeaks(audioPath);
507
444
  writeWaveformCache(cachePath, peaks);
508
445
  }
@@ -584,7 +521,7 @@ function validateUploadedMediaBuffer(fileName, buffer, runner = spawnSync) {
584
521
  }
585
522
 
586
523
  // src/helpers/backupJournal.ts
587
- import { mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
524
+ import { mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
588
525
  import { Buffer as Buffer2 } from "buffer";
589
526
  import { join as join5, relative as relative2 } from "path";
590
527
  var DEFAULT_KEEP_PER_FILE = 10;
@@ -603,7 +540,7 @@ function backupPathForResponse(projectDir, backupPath) {
603
540
  function snapshotBeforeWrite(projectDir, absPath, options = {}) {
604
541
  if (!isSafePath(projectDir, absPath)) return { backupPath: null };
605
542
  try {
606
- const content = readFileSync3(absPath);
543
+ const content = readFileSync2(absPath);
607
544
  const relativePath = relative2(projectDir, absPath);
608
545
  const backupDir = join5(projectDir, ".hyperframes", "backup");
609
546
  mkdirSync2(backupDir, { recursive: true });
@@ -625,7 +562,7 @@ function nextBackupPath(backupDir, backupKey) {
625
562
  let counter = 2;
626
563
  while (true) {
627
564
  try {
628
- readFileSync3(candidate);
565
+ readFileSync2(candidate);
629
566
  } catch (error) {
630
567
  if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
631
568
  return candidate;
@@ -722,7 +659,7 @@ import {
722
659
  import { parseHTML as parseHTML2 } from "linkedom";
723
660
 
724
661
  // src/helpers/compositionInsertion.ts
725
- import { existsSync as existsSync3, readFileSync as readFileSync4, realpathSync } from "fs";
662
+ import { existsSync as existsSync2, readFileSync as readFileSync3, realpathSync } from "fs";
726
663
  import { randomUUID as randomUUID2 } from "crypto";
727
664
  import { dirname as dirname2, relative as relative3, resolve as resolve2, sep as sep2 } from "path";
728
665
  import { parseHTML } from "linkedom";
@@ -757,7 +694,7 @@ function canonicalProjectPath(projectDir, candidate) {
757
694
  if (!candidate) {
758
695
  throw new CompositionInsertionError("Composition source escapes the project", 400);
759
696
  }
760
- if (!existsSync3(candidate)) {
697
+ if (!existsSync2(candidate)) {
761
698
  throw new CompositionInsertionError("Composition source was not found", 404);
762
699
  }
763
700
  const canonical = realpathSync(candidate);
@@ -794,7 +731,7 @@ function validateDependencyGraph(projectDir, targetAbs, sourceAbs) {
794
731
  }
795
732
  if (visited.has(file)) return;
796
733
  visiting.add(file);
797
- const source = readFileSync4(file, "utf-8");
734
+ const source = readFileSync3(file, "utf-8");
798
735
  const { document } = compositionRoot(source);
799
736
  for (const host of descendants(document, "[data-composition-src]")) {
800
737
  const dependency = host.getAttribute("data-composition-src");
@@ -858,7 +795,7 @@ function insertCompositionIntoSource(input) {
858
795
  const targetAbs = canonicalProjectFile(input.projectDir, input.targetPath);
859
796
  const sourceAbs = canonicalProjectFile(input.projectDir, input.sourcePath);
860
797
  validateDependencyGraph(input.projectDir, targetAbs, sourceAbs);
861
- const source = readFileSync4(sourceAbs, "utf-8");
798
+ const source = readFileSync3(sourceAbs, "utf-8");
862
799
  const sourceComposition = compositionRoot(source).root;
863
800
  const duration = positiveAttribute(
864
801
  sourceComposition,
@@ -988,7 +925,7 @@ async function resolveProjectPath(c, adapter, pathPrefix, opts) {
988
925
  if (!absPath) {
989
926
  return { error: c.json({ error: "forbidden" }, 403) };
990
927
  }
991
- if (opts?.mustExist && !existsSync4(absPath)) {
928
+ if (opts?.mustExist && !existsSync3(absPath)) {
992
929
  return { error: c.json({ error: "not found" }, 404) };
993
930
  }
994
931
  return { project, filePath, absPath };
@@ -1056,7 +993,7 @@ function commitElementPatchBatches(projectDir, batches, writeFile = writeFileSyn
1056
993
  resolvedPaths.add(absPath);
1057
994
  let before;
1058
995
  try {
1059
- before = readFileSync5(absPath, "utf-8");
996
+ before = readFileSync4(absPath, "utf-8");
1060
997
  } catch {
1061
998
  return { error: "not-found", sourceFile: batch.sourceFile };
1062
999
  }
@@ -1196,7 +1133,7 @@ async function parseMutationBody(c) {
1196
1133
  }
1197
1134
  function ensureDir(filePath) {
1198
1135
  const dir = dirname3(filePath);
1199
- if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
1136
+ if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true });
1200
1137
  }
1201
1138
  function generateCopyPath(projectDir, originalPath) {
1202
1139
  const ext = originalPath.includes(".") ? "." + originalPath.split(".").pop() : "";
@@ -1205,7 +1142,7 @@ function generateCopyPath(projectDir, originalPath) {
1205
1142
  const cleanBase = copyMatch ? base.slice(0, -copyMatch[0].length) : base;
1206
1143
  let num = copyMatch ? copyMatch[1] ? parseInt(copyMatch[1]) + 1 : 2 : 1;
1207
1144
  let candidate = num === 1 ? `${cleanBase} (copy)${ext}` : `${cleanBase} (copy ${num})${ext}`;
1208
- while (existsSync4(resolve3(projectDir, candidate))) {
1145
+ while (existsSync3(resolve3(projectDir, candidate))) {
1209
1146
  num++;
1210
1147
  candidate = `${cleanBase} (copy ${num})${ext}`;
1211
1148
  }
@@ -1233,7 +1170,7 @@ function updateReferences(projectDir, oldPath, newPath) {
1233
1170
  let updatedCount = 0;
1234
1171
  for (const file of textFiles) {
1235
1172
  if (!isSafePath(projectDir, file)) continue;
1236
- const content = readFileSync5(file, "utf-8");
1173
+ const content = readFileSync4(file, "utf-8");
1237
1174
  if (!content.includes(oldPath)) continue;
1238
1175
  const updated = content.split(oldPath).join(newPath);
1239
1176
  if (updated !== content) {
@@ -1507,7 +1444,7 @@ function containsRawGsapExpression(value) {
1507
1444
  return Object.values(value).some(containsRawGsapExpression);
1508
1445
  }
1509
1446
  async function prepareGsapMutationScript(c, res, firstMutation) {
1510
- const beforeHtml = readFileSync5(res.absPath, "utf-8");
1447
+ const beforeHtml = readFileSync4(res.absPath, "utf-8");
1511
1448
  let html = beforeHtml;
1512
1449
  let block = extractGsapScriptBlock(html);
1513
1450
  if (!block && (firstMutation.type === "add" || firstMutation.type === "add-with-keyframes")) {
@@ -1574,7 +1511,7 @@ async function applyGsapMutations(c, res, mutations) {
1574
1511
  const changed = block.scriptText !== initialScript;
1575
1512
  const newHtml = changed ? block.replaceScript(block.scriptText) : html;
1576
1513
  let backupPath = null;
1577
- if (readFileSync5(res.absPath, "utf-8") !== beforeHtml) {
1514
+ if (readFileSync4(res.absPath, "utf-8") !== beforeHtml) {
1578
1515
  return c.json({ error: "file changed during GSAP mutation", conflict: true }, 409);
1579
1516
  }
1580
1517
  if (changed) {
@@ -2335,9 +2272,9 @@ async function processUploadedFiles(formData, targetDir, projectDir) {
2335
2272
  const base = dotIdx > 0 ? name.slice(0, dotIdx) : name;
2336
2273
  const MAX_COPY_INDEX = 1e4;
2337
2274
  let n = 1;
2338
- if (existsSync4(finalPath)) {
2275
+ if (existsSync3(finalPath)) {
2339
2276
  n = 2;
2340
- while (n < MAX_COPY_INDEX && existsSync4(resolve3(targetDir, `${base} (${n})${ext}`))) n++;
2277
+ while (n < MAX_COPY_INDEX && existsSync3(resolve3(targetDir, `${base} (${n})${ext}`))) n++;
2341
2278
  if (n >= MAX_COPY_INDEX) {
2342
2279
  skipped.push(name);
2343
2280
  continue;
@@ -2389,13 +2326,13 @@ function registerFileRoutes(api, adapter) {
2389
2326
  api.get("/projects/:id/files/*", async (c) => {
2390
2327
  const res = await resolveProjectFile(c, adapter);
2391
2328
  if ("error" in res) return res.error;
2392
- if (!existsSync4(res.absPath)) {
2329
+ if (!existsSync3(res.absPath)) {
2393
2330
  if (c.req.query("optional") === "1") {
2394
2331
  return c.json({ filename: res.filePath, content: "" });
2395
2332
  }
2396
2333
  return c.json({ error: "not found" }, 404);
2397
2334
  }
2398
- const content = readFileSync5(res.absPath);
2335
+ const content = readFileSync4(res.absPath);
2399
2336
  const version = fileContentVersion(content);
2400
2337
  c.header("ETag", version);
2401
2338
  return c.json({ filename: res.filePath, content: content.toString("utf-8"), version });
@@ -2409,7 +2346,7 @@ function registerFileRoutes(api, adapter) {
2409
2346
  if (expectedVersion === null && !createOnly) {
2410
2347
  let currentContent = null;
2411
2348
  try {
2412
- currentContent = readFileSync5(res.absPath);
2349
+ currentContent = readFileSync4(res.absPath);
2413
2350
  } catch (error) {
2414
2351
  if (!error || typeof error !== "object" || !("code" in error) || error.code !== "ENOENT") {
2415
2352
  throw error;
@@ -2435,7 +2372,7 @@ function registerFileRoutes(api, adapter) {
2435
2372
  if (!error || typeof error !== "object" || !("code" in error) || error.code !== "EEXIST") {
2436
2373
  throw error;
2437
2374
  }
2438
- const currentContent = readFileSync5(res.absPath);
2375
+ const currentContent = readFileSync4(res.absPath);
2439
2376
  return c.json(
2440
2377
  {
2441
2378
  error: "file conflict",
@@ -2470,7 +2407,7 @@ function registerFileRoutes(api, adapter) {
2470
2407
  );
2471
2408
  }
2472
2409
  try {
2473
- const currentContent = readFileSync5(fd);
2410
+ const currentContent = readFileSync4(fd);
2474
2411
  const currentVersion = fileContentVersion(currentContent);
2475
2412
  if (expectedVersion !== currentVersion) {
2476
2413
  return c.json(
@@ -2543,7 +2480,7 @@ function registerFileRoutes(api, adapter) {
2543
2480
  }
2544
2481
  let before;
2545
2482
  try {
2546
- before = readFileSync5(ctx.absPath, "utf-8");
2483
+ before = readFileSync4(ctx.absPath, "utf-8");
2547
2484
  } catch (error) {
2548
2485
  if (!error || typeof error !== "object" || !("code" in error) || error.code !== "ENOENT") {
2549
2486
  throw error;
@@ -2595,12 +2532,12 @@ function registerFileRoutes(api, adapter) {
2595
2532
  api.post("/projects/:id/file-mutations/remove-element/*", async (c) => {
2596
2533
  const ctx = await resolveFileMutationContext(c, adapter, "remove-element");
2597
2534
  if ("error" in ctx) return ctx.error;
2598
- if (!existsSync4(ctx.absPath)) {
2535
+ if (!existsSync3(ctx.absPath)) {
2599
2536
  return c.json({ error: "not found" }, 404);
2600
2537
  }
2601
2538
  const parsed = await parseMutationBody(c);
2602
2539
  if ("error" in parsed) return parsed.error;
2603
- const originalContent = readFileSync5(ctx.absPath, "utf-8");
2540
+ const originalContent = readFileSync4(ctx.absPath, "utf-8");
2604
2541
  return writeIfChanged(
2605
2542
  c,
2606
2543
  ctx.project.dir,
@@ -2613,7 +2550,7 @@ function registerFileRoutes(api, adapter) {
2613
2550
  api.post("/projects/:id/file-mutations/remove-elements/*", async (c) => {
2614
2551
  const ctx = await resolveFileMutationContext(c, adapter, "remove-elements");
2615
2552
  if ("error" in ctx) return ctx.error;
2616
- if (!existsSync4(ctx.absPath)) {
2553
+ if (!existsSync3(ctx.absPath)) {
2617
2554
  return c.json({ error: "not found" }, 404);
2618
2555
  }
2619
2556
  const body = await c.req.json().catch(() => null);
@@ -2621,7 +2558,7 @@ function registerFileRoutes(api, adapter) {
2621
2558
  if (!Array.isArray(targets) || targets.length === 0) {
2622
2559
  return c.json({ error: "targets required" }, 400);
2623
2560
  }
2624
- const originalContent = readFileSync5(ctx.absPath, "utf-8");
2561
+ const originalContent = readFileSync4(ctx.absPath, "utf-8");
2625
2562
  let next = originalContent;
2626
2563
  for (const target of targets) {
2627
2564
  next = removeElementFromHtml(next, target);
@@ -2654,7 +2591,7 @@ function registerFileRoutes(api, adapter) {
2654
2591
  seen.add(absPath);
2655
2592
  let before;
2656
2593
  try {
2657
- before = readFileSync5(absPath, "utf-8");
2594
+ before = readFileSync4(absPath, "utf-8");
2658
2595
  } catch {
2659
2596
  return c.json({ error: `not found: ${file.path}` }, 404);
2660
2597
  }
@@ -2681,7 +2618,7 @@ function registerFileRoutes(api, adapter) {
2681
2618
  prepared.push(folded);
2682
2619
  }
2683
2620
  for (const file of prepared) {
2684
- const current = readFileSync5(file.absPath, "utf-8");
2621
+ const current = readFileSync4(file.absPath, "utf-8");
2685
2622
  if (current !== file.before) {
2686
2623
  return c.json(
2687
2624
  {
@@ -2723,7 +2660,7 @@ function registerFileRoutes(api, adapter) {
2723
2660
  const conflicts = [];
2724
2661
  for (const file of written.reverse()) {
2725
2662
  try {
2726
- const current = readFileSync5(file.absPath, "utf-8");
2663
+ const current = readFileSync4(file.absPath, "utf-8");
2727
2664
  if (current !== file.after) {
2728
2665
  conflicts.push(file.path);
2729
2666
  continue;
@@ -2771,7 +2708,7 @@ function registerFileRoutes(api, adapter) {
2771
2708
  const fallbackTiming = typeof parsed.body.elementStart === "number" && typeof parsed.body.elementDuration === "number" ? { start: parsed.body.elementStart, duration: parsed.body.elementDuration } : void 0;
2772
2709
  let originalContent;
2773
2710
  try {
2774
- originalContent = readFileSync5(ctx.absPath, "utf-8");
2711
+ originalContent = readFileSync4(ctx.absPath, "utf-8");
2775
2712
  } catch {
2776
2713
  return c.json({ error: "not found" }, 404);
2777
2714
  }
@@ -2827,7 +2764,7 @@ function registerFileRoutes(api, adapter) {
2827
2764
  }
2828
2765
  let originalContent;
2829
2766
  try {
2830
- originalContent = readFileSync5(ctx.absPath, "utf-8");
2767
+ originalContent = readFileSync4(ctx.absPath, "utf-8");
2831
2768
  } catch {
2832
2769
  return c.json({ error: "not found" }, 404);
2833
2770
  }
@@ -2928,7 +2865,7 @@ function registerFileRoutes(api, adapter) {
2928
2865
  }
2929
2866
  let originalContent;
2930
2867
  try {
2931
- originalContent = readFileSync5(ctx.absPath, "utf-8");
2868
+ originalContent = readFileSync4(ctx.absPath, "utf-8");
2932
2869
  } catch {
2933
2870
  return c.json({ error: "not found" }, 404);
2934
2871
  }
@@ -2983,7 +2920,7 @@ function registerFileRoutes(api, adapter) {
2983
2920
  ).map((entry) => ({ target: entry.target, track: entry.track }));
2984
2921
  let originalContent;
2985
2922
  try {
2986
- originalContent = readFileSync5(ctx.absPath, "utf-8");
2923
+ originalContent = readFileSync4(ctx.absPath, "utf-8");
2987
2924
  } catch {
2988
2925
  return c.json({ error: "not found" }, 404);
2989
2926
  }
@@ -3012,7 +2949,7 @@ function registerFileRoutes(api, adapter) {
3012
2949
  if ("error" in parsed) return parsed.error;
3013
2950
  let content;
3014
2951
  try {
3015
- content = readFileSync5(ctx.absPath, "utf-8");
2952
+ content = readFileSync4(ctx.absPath, "utf-8");
3016
2953
  } catch {
3017
2954
  return c.json({ exists: false });
3018
2955
  }
@@ -3030,7 +2967,7 @@ function registerFileRoutes(api, adapter) {
3030
2967
  if (!newAbs) {
3031
2968
  return c.json({ error: "forbidden" }, 403);
3032
2969
  }
3033
- if (existsSync4(newAbs)) {
2970
+ if (existsSync3(newAbs)) {
3034
2971
  return c.json({ error: "already exists" }, 409);
3035
2972
  }
3036
2973
  ensureDir(newAbs);
@@ -3046,7 +2983,7 @@ function registerFileRoutes(api, adapter) {
3046
2983
  return c.json({ error: "path required" }, 400);
3047
2984
  }
3048
2985
  const srcAbs = resolveWithinProject(project.dir, body.path);
3049
- if (!srcAbs || !existsSync4(srcAbs)) {
2986
+ if (!srcAbs || !existsSync3(srcAbs)) {
3050
2987
  return c.json({ error: "not found" }, 404);
3051
2988
  }
3052
2989
  const copyPath = generateCopyPath(project.dir, body.path);
@@ -3055,7 +2992,7 @@ function registerFileRoutes(api, adapter) {
3055
2992
  return c.json({ error: "forbidden" }, 403);
3056
2993
  }
3057
2994
  ensureDir(destAbs);
3058
- writeFileSync4(destAbs, readFileSync5(srcAbs));
2995
+ writeFileSync4(destAbs, readFileSync4(srcAbs));
3059
2996
  return c.json({ ok: true, path: copyPath }, 201);
3060
2997
  });
3061
2998
  const MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
@@ -3071,7 +3008,7 @@ function registerFileRoutes(api, adapter) {
3071
3008
  const subDir = c.req.query("dir") ?? "";
3072
3009
  const targetDir = subDir ? resolveWithinProject(project.dir, subDir) : project.dir;
3073
3010
  if (!targetDir) return c.json({ error: "forbidden" }, 403);
3074
- if (subDir && !existsSync4(targetDir)) mkdirSync3(targetDir, { recursive: true });
3011
+ if (subDir && !existsSync3(targetDir)) mkdirSync3(targetDir, { recursive: true });
3075
3012
  const formData = await c.req.formData();
3076
3013
  const result = await processUploadedFiles(formData, targetDir, project.dir);
3077
3014
  return c.json(
@@ -3085,7 +3022,7 @@ function registerFileRoutes(api, adapter) {
3085
3022
  mustExist: true
3086
3023
  });
3087
3024
  if ("error" in res) return res.error;
3088
- const html = readFileSync5(res.absPath, "utf-8");
3025
+ const html = readFileSync4(res.absPath, "utf-8");
3089
3026
  const block = extractGsapScriptBlock(html);
3090
3027
  if (!block) {
3091
3028
  return c.json({
@@ -3144,7 +3081,7 @@ function registerFileRoutes(api, adapter) {
3144
3081
  if (!body || typeof body.expected !== "string" || typeof body.restore !== "string") {
3145
3082
  return c.json({ error: "expected and restore contents required" }, 400);
3146
3083
  }
3147
- const current = readFileSync5(res.absPath, "utf-8");
3084
+ const current = readFileSync4(res.absPath, "utf-8");
3148
3085
  if (current !== body.expected) {
3149
3086
  return c.json({ ok: true, restored: false, conflict: true });
3150
3087
  }
@@ -3154,7 +3091,7 @@ function registerFileRoutes(api, adapter) {
3154
3091
  }
3155
3092
 
3156
3093
  // src/routes/preview.ts
3157
- import { createReadStream, existsSync as existsSync6, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
3094
+ import { createReadStream, existsSync as existsSync5, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
3158
3095
  import { Readable } from "stream";
3159
3096
  import { join as join8, resolve as resolve4 } from "path";
3160
3097
  import { createHash as createHash3 } from "crypto";
@@ -3162,7 +3099,7 @@ import { injectScriptsIntoHtml, stripEmbeddedRuntimeScripts as stripEmbeddedRunt
3162
3099
  import { isWithinProjectRoot } from "@hyperframes/parsers/asset-resolution";
3163
3100
 
3164
3101
  // src/helpers/subComposition.ts
3165
- import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
3102
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
3166
3103
  import { join as join7 } from "path";
3167
3104
  import { parseHTML as parseHTML3 } from "linkedom";
3168
3105
  import {
@@ -3175,7 +3112,7 @@ function isFullHtmlDocument(html) {
3175
3112
  return /^\s*(?:<!doctype\s|<html[\s>])/i.test(html);
3176
3113
  }
3177
3114
  function rewriteRelativePaths(root, compPath, projectDir) {
3178
- const assetExists = (path) => existsSync5(join7(projectDir, path));
3115
+ const assetExists = (path) => existsSync4(join7(projectDir, path));
3179
3116
  rewriteAssetPaths(
3180
3117
  root.querySelectorAll("[src], [href]"),
3181
3118
  compPath,
@@ -3273,8 +3210,8 @@ function tagRootCompositionFile(bodyHtml, compPath) {
3273
3210
  }
3274
3211
  function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref, rawOverride) {
3275
3212
  const compFile = join7(projectDir, compPath);
3276
- if (!existsSync5(compFile)) return null;
3277
- const rawComp = rawOverride ?? readFileSync6(compFile, "utf-8");
3213
+ if (!existsSync4(compFile)) return null;
3214
+ const rawComp = rawOverride ?? readFileSync5(compFile, "utf-8");
3278
3215
  let compHeadContent = "";
3279
3216
  let rewrittenContent;
3280
3217
  let htmlAttrs = "";
@@ -3306,8 +3243,8 @@ function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref, raw
3306
3243
  rewrittenContent = tagRootCompositionFile(rewrittenContent, compPath);
3307
3244
  const indexPath = join7(projectDir, "index.html");
3308
3245
  let headContent = "";
3309
- if (existsSync5(indexPath)) {
3310
- const indexHtml = readFileSync6(indexPath, "utf-8");
3246
+ if (existsSync4(indexPath)) {
3247
+ const indexHtml = readFileSync5(indexPath, "utf-8");
3311
3248
  const headMatch = indexHtml.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
3312
3249
  headContent = headMatch?.[1] ?? "";
3313
3250
  }
@@ -3351,7 +3288,7 @@ import {
3351
3288
  fstatSync,
3352
3289
  ftruncateSync as ftruncateSync2,
3353
3290
  openSync as openSync2,
3354
- readFileSync as readFileSync7,
3291
+ readFileSync as readFileSync6,
3355
3292
  writeFileSync as writeFileSync5,
3356
3293
  writeSync as writeSync2
3357
3294
  } from "fs";
@@ -3361,7 +3298,7 @@ function persistHfIdsIfNeeded(filePath, html) {
3361
3298
  const idsAfter = (normalized.match(/\bdata-hf-id=/g) ?? []).length;
3362
3299
  if (idsAfter > idsBefore) {
3363
3300
  try {
3364
- const current = readFileSync7(filePath, "utf-8");
3301
+ const current = readFileSync6(filePath, "utf-8");
3365
3302
  if (current === html) {
3366
3303
  writeFileSync5(filePath, normalized, "utf-8");
3367
3304
  }
@@ -3389,7 +3326,7 @@ function stampFileHfIds(filePath) {
3389
3326
  if (fd === null) return null;
3390
3327
  try {
3391
3328
  if (!fstatSync(fd).isFile()) return null;
3392
- const html = readFileSync7(fd, "utf-8");
3329
+ const html = readFileSync6(fd, "utf-8");
3393
3330
  const normalized = ensureHfIds(html);
3394
3331
  const idsBefore = (html.match(/\bdata-hf-id=/g) ?? []).length;
3395
3332
  const idsAfter = (normalized.match(/\bdata-hf-id=/g) ?? []).length;
@@ -3449,9 +3386,9 @@ ${html}`;
3449
3386
  }
3450
3387
  function readStudioMotionManifestContent(projectDir) {
3451
3388
  const manifestPath = join8(projectDir, STUDIO_MOTION_PATH);
3452
- if (!existsSync6(manifestPath)) return "";
3389
+ if (!existsSync5(manifestPath)) return "";
3453
3390
  try {
3454
- return readFileSync8(manifestPath, "utf-8");
3391
+ return readFileSync7(manifestPath, "utf-8");
3455
3392
  } catch {
3456
3393
  return "";
3457
3394
  }
@@ -3595,16 +3532,16 @@ async function transformPreviewHtml(html, adapter, project, activeCompositionPat
3595
3532
  }
3596
3533
  function resolveProjectMainHtml(projectDir, projectId) {
3597
3534
  const indexPath = join8(projectDir, "index.html");
3598
- if (existsSync6(indexPath)) {
3535
+ if (existsSync5(indexPath)) {
3599
3536
  return {
3600
- html: readFileSync8(indexPath, "utf-8"),
3537
+ html: readFileSync7(indexPath, "utf-8"),
3601
3538
  compositionPath: "index.html"
3602
3539
  };
3603
3540
  }
3604
3541
  const blockHtmlPath = join8(projectDir, `${projectId}.html`);
3605
- if (existsSync6(blockHtmlPath)) {
3542
+ if (existsSync5(blockHtmlPath)) {
3606
3543
  return {
3607
- html: readFileSync8(blockHtmlPath, "utf-8"),
3544
+ html: readFileSync7(blockHtmlPath, "utf-8"),
3608
3545
  compositionPath: `${projectId}.html`
3609
3546
  };
3610
3547
  }
@@ -3709,7 +3646,7 @@ ${runtimeTag}`;
3709
3646
  c.req.path.replace(`/projects/${project.id}/preview/comp/`, "").split("?")[0] ?? ""
3710
3647
  );
3711
3648
  const compFile = resolveWithinProject(project.dir, compPath);
3712
- if (!compFile || !existsSync6(compFile) || !statSync3(compFile).isFile()) {
3649
+ if (!compFile || !existsSync5(compFile) || !statSync3(compFile).isFile()) {
3713
3650
  return c.text("not found", 404);
3714
3651
  }
3715
3652
  const compPathHash = createHash3("sha1").update(compPath).digest("hex");
@@ -3749,7 +3686,7 @@ ${runtimeTag}`;
3749
3686
  if (!file) {
3750
3687
  return c.text("not found", 404);
3751
3688
  }
3752
- const stat = existsSync6(file) ? statSync3(file) : null;
3689
+ const stat = existsSync5(file) ? statSync3(file) : null;
3753
3690
  if (!stat?.isFile()) {
3754
3691
  return c.text("not found", 404);
3755
3692
  }
@@ -3798,7 +3735,7 @@ ${runtimeTag}`;
3798
3735
  }
3799
3736
  servedContentType = PROXY_VARIANT_CONFIG[proxyVariant].contentType;
3800
3737
  }
3801
- const textBuffer = isText ? Buffer.from(readFileSync8(file, "utf-8"), "utf-8") : null;
3738
+ const textBuffer = isText ? Buffer.from(readFileSync7(file, "utf-8"), "utf-8") : null;
3802
3739
  const totalSize = textBuffer ? textBuffer.length : statSync3(servedPath).size;
3803
3740
  const bodyFor = (start, end) => textBuffer ? new Uint8Array(textBuffer.subarray(start, end + 1)) : (
3804
3741
  // Node's web stream type and the DOM one do not overlap for tsc on
@@ -3842,7 +3779,7 @@ ${runtimeTag}`;
3842
3779
  }
3843
3780
 
3844
3781
  // src/routes/lint.ts
3845
- import { readFileSync as readFileSync9 } from "fs";
3782
+ import { readFileSync as readFileSync8 } from "fs";
3846
3783
  import { join as join9 } from "path";
3847
3784
  async function collectProjectFindings(adapter, projectDir) {
3848
3785
  const findings = [];
@@ -3861,7 +3798,7 @@ async function lintUncoveredHtml(adapter, projectDir, htmlFiles, coveredFiles) {
3861
3798
  const findings = [];
3862
3799
  for (const file of htmlFiles) {
3863
3800
  if (coveredFiles.has(file)) continue;
3864
- const content = readFileSync9(join9(projectDir, file), "utf-8");
3801
+ const content = readFileSync8(join9(projectDir, file), "utf-8");
3865
3802
  const result = await adapter.lint(content, { filePath: file, isSubComposition: true });
3866
3803
  for (const finding of result?.findings ?? []) {
3867
3804
  findings.push({ ...finding, file });
@@ -3894,7 +3831,7 @@ function registerLintRoutes(api, adapter) {
3894
3831
 
3895
3832
  // src/routes/render.ts
3896
3833
  import { streamSSE } from "hono/streaming";
3897
- import { existsSync as existsSync7, readFileSync as readFileSync10, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
3834
+ import { existsSync as existsSync6, readFileSync as readFileSync9, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
3898
3835
  import { join as join10 } from "path";
3899
3836
  import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/parsers";
3900
3837
  import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
@@ -3961,7 +3898,7 @@ function registerRenderRoutes(api, adapter) {
3961
3898
  const now = /* @__PURE__ */ new Date();
3962
3899
  const jobId = `${project.id}_${formatRenderOutputTimestamp(now)}`;
3963
3900
  const rendersDir = adapter.rendersDir(project);
3964
- if (!existsSync7(rendersDir)) mkdirSync4(rendersDir, { recursive: true });
3901
+ if (!existsSync6(rendersDir)) mkdirSync4(rendersDir, { recursive: true });
3965
3902
  const ext = FORMAT_EXT[format] ?? ".mp4";
3966
3903
  const outputPath = join10(rendersDir, `${jobId}${ext}`);
3967
3904
  const jobState = adapter.startRender({
@@ -4027,12 +3964,12 @@ function registerRenderRoutes(api, adapter) {
4027
3964
  api.get("/render/:jobId/view", (c) => {
4028
3965
  const { jobId } = c.req.param();
4029
3966
  const job = renderJobs.get(jobId);
4030
- if (!job?.outputPath || !existsSync7(job.outputPath)) {
3967
+ if (!job?.outputPath || !existsSync6(job.outputPath)) {
4031
3968
  return c.json({ error: "not found" }, 404);
4032
3969
  }
4033
3970
  const contentType = renderContentType(job.outputPath);
4034
3971
  const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
4035
- const content = readFileSync10(job.outputPath);
3972
+ const content = readFileSync9(job.outputPath);
4036
3973
  return new Response(content, {
4037
3974
  headers: {
4038
3975
  "Content-Type": contentType,
@@ -4045,12 +3982,12 @@ function registerRenderRoutes(api, adapter) {
4045
3982
  api.get("/render/:jobId/download", (c) => {
4046
3983
  const { jobId } = c.req.param();
4047
3984
  const job = renderJobs.get(jobId);
4048
- if (!job?.outputPath || !existsSync7(job.outputPath)) {
3985
+ if (!job?.outputPath || !existsSync6(job.outputPath)) {
4049
3986
  return c.json({ error: "not found" }, 404);
4050
3987
  }
4051
3988
  const contentType = renderContentType(job.outputPath);
4052
3989
  const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
4053
- const content = readFileSync10(job.outputPath);
3990
+ const content = readFileSync9(job.outputPath);
4054
3991
  return new Response(content, {
4055
3992
  headers: {
4056
3993
  "Content-Type": contentType,
@@ -4065,7 +4002,7 @@ function registerRenderRoutes(api, adapter) {
4065
4002
  const dir = state.outputPath.replace(/\/[^/]+$/, "");
4066
4003
  for (const ext of [".mp4", ".webm", ".mov", ".meta.json"]) {
4067
4004
  const fp = join10(dir, `${jobId}${ext}`);
4068
- if (existsSync7(fp)) unlinkSync3(fp);
4005
+ if (existsSync6(fp)) unlinkSync3(fp);
4069
4006
  }
4070
4007
  break;
4071
4008
  }
@@ -4081,9 +4018,9 @@ function registerRenderRoutes(api, adapter) {
4081
4018
  const rendersDir = adapter.rendersDir(project);
4082
4019
  const fp = resolveWithinProject(rendersDir, filename);
4083
4020
  if (!fp) return c.json({ error: "forbidden" }, 403);
4084
- if (!existsSync7(fp)) return c.json({ error: "not found" }, 404);
4021
+ if (!existsSync6(fp)) return c.json({ error: "not found" }, 404);
4085
4022
  const contentType = renderContentType(fp);
4086
- const content = readFileSync10(fp);
4023
+ const content = readFileSync9(fp);
4087
4024
  return new Response(content, {
4088
4025
  headers: {
4089
4026
  "Content-Type": contentType,
@@ -4097,7 +4034,7 @@ function registerRenderRoutes(api, adapter) {
4097
4034
  const project = await adapter.resolveProject(c.req.param("id"));
4098
4035
  if (!project) return c.json({ error: "not found" }, 404);
4099
4036
  const rendersDir = adapter.rendersDir(project);
4100
- if (!existsSync7(rendersDir)) return c.json({ renders: [] });
4037
+ if (!existsSync6(rendersDir)) return c.json({ renders: [] });
4101
4038
  const files = readdirSync5(rendersDir).filter((f) => f.endsWith(".mp4") || f.endsWith(".webm") || f.endsWith(".mov")).map((f) => {
4102
4039
  const fp = join10(rendersDir, f);
4103
4040
  const stat = statSync4(fp);
@@ -4105,10 +4042,10 @@ function registerRenderRoutes(api, adapter) {
4105
4042
  const metaPath = join10(rendersDir, `${rid}.meta.json`);
4106
4043
  let status = "complete";
4107
4044
  let durationMs;
4108
- if (existsSync7(metaPath)) {
4045
+ if (existsSync6(metaPath)) {
4109
4046
  try {
4110
- const meta = JSON.parse(readFileSync10(metaPath, "utf-8"));
4111
- if (meta.status === "failed" && !existsSync7(fp)) status = "failed";
4047
+ const meta = JSON.parse(readFileSync9(metaPath, "utf-8"));
4048
+ if (meta.status === "failed" && !existsSync6(fp)) status = "failed";
4112
4049
  if (meta.durationMs) durationMs = meta.durationMs;
4113
4050
  } catch {
4114
4051
  }
@@ -4139,9 +4076,9 @@ function registerRenderRoutes(api, adapter) {
4139
4076
 
4140
4077
  // src/routes/thumbnail.ts
4141
4078
  import {
4142
- existsSync as existsSync8,
4079
+ existsSync as existsSync7,
4143
4080
  mkdirSync as mkdirSync5,
4144
- readFileSync as readFileSync11,
4081
+ readFileSync as readFileSync10,
4145
4082
  readdirSync as readdirSync6,
4146
4083
  renameSync as renameSync3,
4147
4084
  rmSync as rmSync4,
@@ -4259,12 +4196,11 @@ var thumbnailGenerationCoordinator = new ThumbnailGenerationCoordinator(1);
4259
4196
  var THUMBNAIL_CACHE_VERSION = "v4";
4260
4197
  var THUMBNAIL_MAX_OUTPUT_WIDTH = 240;
4261
4198
  var THUMBNAIL_MAX_OUTPUT_HEIGHT = 135;
4262
- var STORYBOARD_MAX_OUTPUT_DIMENSION = 1080;
4263
4199
  var THUMBNAIL_CACHE_MAX_BYTES = 512 * 1024 * 1024;
4264
4200
  var THUMBNAIL_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
4265
4201
  var prunedCacheDirs = /* @__PURE__ */ new Set();
4266
4202
  function pruneThumbnailCache(cacheDir, protectedPaths, now = Date.now()) {
4267
- if (!existsSync8(cacheDir)) return;
4203
+ if (!existsSync7(cacheDir)) return;
4268
4204
  const files = readdirSync6(cacheDir, { withFileTypes: true }).flatMap((entry) => {
4269
4205
  if (!entry.isFile()) return [];
4270
4206
  const path = join11(cacheDir, entry.name);
@@ -4325,7 +4261,7 @@ function registerThumbnailRoutes(api, adapter) {
4325
4261
  const format = url.searchParams.get("format") === "png" ? "png" : "jpeg";
4326
4262
  const contentType = format === "png" ? "image/png" : "image/jpeg";
4327
4263
  const requestedOutput = url.searchParams.get("output");
4328
- const outputMode = requestedOutput === "source" ? "source" : requestedOutput === "storyboard" ? "storyboard" : requestedOutput !== "preview" && format === "png" ? "source" : "preview";
4264
+ const outputMode = requestedOutput === "source" || requestedOutput !== "preview" && format === "png" ? "source" : "preview";
4329
4265
  const rawSelectorIndex = Number.parseInt(url.searchParams.get("selectorIndex") || "0", 10);
4330
4266
  const selectorIndex = Number.isFinite(rawSelectorIndex) && rawSelectorIndex > 0 ? rawSelectorIndex : void 0;
4331
4267
  const urlVersion = url.searchParams.get("v") || "";
@@ -4334,8 +4270,8 @@ function registerThumbnailRoutes(api, adapter) {
4334
4270
  let sourceMtime = 0;
4335
4271
  let sourceKey = "";
4336
4272
  const htmlFile = join11(project.dir, compPath);
4337
- if (existsSync8(htmlFile)) {
4338
- const html = readFileSync11(htmlFile, "utf-8");
4273
+ if (existsSync7(htmlFile)) {
4274
+ const html = readFileSync10(htmlFile, "utf-8");
4339
4275
  sourceKey = `_${createHash4("sha1").update(html).digest("hex").slice(0, 16)}`;
4340
4276
  sourceMtime = Math.round(statSync5(htmlFile).mtimeMs);
4341
4277
  if (!vpWidth) {
@@ -4347,15 +4283,15 @@ function registerThumbnailRoutes(api, adapter) {
4347
4283
  }
4348
4284
  const manualEditsFile = join11(project.dir, STUDIO_MANUAL_EDITS_PATH);
4349
4285
  let manualEditsKey = "";
4350
- if (existsSync8(manualEditsFile)) {
4351
- const manualEditsContent = readFileSync11(manualEditsFile, "utf-8");
4286
+ if (existsSync7(manualEditsFile)) {
4287
+ const manualEditsContent = readFileSync10(manualEditsFile, "utf-8");
4352
4288
  manualEditsKey = `_${createHash4("sha1").update(manualEditsContent).digest("hex").slice(0, 16)}`;
4353
4289
  sourceMtime = Math.max(sourceMtime, Math.round(statSync5(manualEditsFile).mtimeMs));
4354
4290
  }
4355
4291
  const motionFile = join11(project.dir, STUDIO_MOTION_PATH);
4356
4292
  let motionKey = "";
4357
- if (existsSync8(motionFile)) {
4358
- const motionContent = readFileSync11(motionFile, "utf-8");
4293
+ if (existsSync7(motionFile)) {
4294
+ const motionContent = readFileSync10(motionFile, "utf-8");
4359
4295
  motionKey = `_${createHash4("sha1").update(motionContent).digest("hex").slice(0, 16)}`;
4360
4296
  sourceMtime = Math.max(sourceMtime, Math.round(statSync5(motionFile).mtimeMs));
4361
4297
  }
@@ -4364,11 +4300,7 @@ function registerThumbnailRoutes(api, adapter) {
4364
4300
  const selectorKey = selector ? `_${selector.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 80)}_${selectorIndex ?? 0}` : "";
4365
4301
  const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
4366
4302
  const projectSignatureKey = `_${createHash4("sha1").update(projectSignature).digest("hex").slice(0, 16)}`;
4367
- const outputScale = outputMode === "source" ? 1 : outputMode === "storyboard" ? Math.min(
4368
- 1,
4369
- STORYBOARD_MAX_OUTPUT_DIMENSION / compW,
4370
- STORYBOARD_MAX_OUTPUT_DIMENSION / compH
4371
- ) : Math.min(1, THUMBNAIL_MAX_OUTPUT_WIDTH / compW, THUMBNAIL_MAX_OUTPUT_HEIGHT / compH);
4303
+ const outputScale = outputMode === "source" ? 1 : Math.min(1, THUMBNAIL_MAX_OUTPUT_WIDTH / compW, THUMBNAIL_MAX_OUTPUT_HEIGHT / compH);
4372
4304
  const outputWidth = Math.max(1, Math.round(compW * outputScale));
4373
4305
  const outputHeight = Math.max(1, Math.round(compH * outputScale));
4374
4306
  const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}${projectSignatureKey}${manualEditsKey}${motionKey}${sourceKey}_${format}_${outputMode}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${outputWidth}x${outputHeight}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.${format === "png" ? "png" : "jpg"}`;
@@ -4380,8 +4312,8 @@ function registerThumbnailRoutes(api, adapter) {
4380
4312
  /* @__PURE__ */ new Set([...thumbnailGenerationCoordinator.protectedKeys(), cachePath])
4381
4313
  );
4382
4314
  }
4383
- if (existsSync8(cachePath)) {
4384
- return new Response(new Uint8Array(readFileSync11(cachePath)), {
4315
+ if (existsSync7(cachePath)) {
4316
+ return new Response(new Uint8Array(readFileSync10(cachePath)), {
4385
4317
  headers: { "Content-Type": contentType, "Cache-Control": "no-cache" }
4386
4318
  });
4387
4319
  }
@@ -4410,7 +4342,7 @@ function registerThumbnailRoutes(api, adapter) {
4410
4342
  if (!afterGeneration || afterGeneration.project.dir !== project.dir || afterGeneration.signature !== projectSignature || freshSignature !== projectSignature) {
4411
4343
  return generated;
4412
4344
  }
4413
- if (!existsSync8(cacheDir)) mkdirSync5(cacheDir, { recursive: true });
4345
+ if (!existsSync7(cacheDir)) mkdirSync5(cacheDir, { recursive: true });
4414
4346
  writeThumbnailAtomically(cachePath, generated);
4415
4347
  return generated;
4416
4348
  }
@@ -4436,7 +4368,7 @@ function registerThumbnailRoutes(api, adapter) {
4436
4368
  }
4437
4369
 
4438
4370
  // src/routes/waveform.ts
4439
- import { existsSync as existsSync9, readFileSync as readFileSync12, statSync as statSync6 } from "fs";
4371
+ import { existsSync as existsSync8, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
4440
4372
  import { join as join12 } from "path";
4441
4373
  function registerWaveformRoutes(api, adapter) {
4442
4374
  api.get("/projects/:id/waveform/*", async (c) => {
@@ -4451,8 +4383,8 @@ function registerWaveformRoutes(api, adapter) {
4451
4383
  const cacheDir = join12(project.dir, ".waveform-cache");
4452
4384
  const cachePath = join12(cacheDir, buildWaveformCacheKey(assetPath, stats));
4453
4385
  try {
4454
- if (isWaveformCacheDirectory(cacheDir) && existsSync9(cachePath)) {
4455
- const peaks2 = JSON.parse(readFileSync12(cachePath, "utf-8"));
4386
+ if (isWaveformCacheDirectory(cacheDir) && existsSync8(cachePath)) {
4387
+ const peaks2 = JSON.parse(readFileSync11(cachePath, "utf-8"));
4456
4388
  return c.json({ peaks: peaks2 });
4457
4389
  }
4458
4390
  } catch {
@@ -4735,7 +4667,7 @@ function registerSelectionRoutes(api, adapter) {
4735
4667
 
4736
4668
  // src/routes/media.ts
4737
4669
  import { streamSSE as streamSSE2 } from "hono/streaming";
4738
- import { existsSync as existsSync10, mkdirSync as mkdirSync6 } from "fs";
4670
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
4739
4671
  import { basename as basename2, dirname as dirname4, extname as extname2, join as join13 } from "path";
4740
4672
  var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
4741
4673
  ".mp4",
@@ -4773,7 +4705,7 @@ function uniqueAssetPath(projectDir, assetPath) {
4773
4705
  const ext = extname2(assetPath);
4774
4706
  const withoutExt = assetPath.slice(0, -ext.length);
4775
4707
  let candidate = assetPath;
4776
- for (let index = 2; existsSync10(join13(projectDir, candidate)); index++) {
4708
+ for (let index = 2; existsSync9(join13(projectDir, candidate)); index++) {
4777
4709
  candidate = `${withoutExt}-${index}${ext}`;
4778
4710
  }
4779
4711
  return candidate;
@@ -4824,7 +4756,7 @@ function registerMediaRoutes(api, adapter, options = {}) {
4824
4756
  }
4825
4757
  const filePath = resolveWithinProject(project.dir, assetPath);
4826
4758
  if (!filePath) return c.json({ error: "forbidden" }, 403);
4827
- if (!existsSync10(filePath)) return c.json({ error: "media not found" }, 404);
4759
+ if (!existsSync9(filePath)) return c.json({ error: "media not found" }, 404);
4828
4760
  return c.json({ path: assetPath, metadata: await readMediaMetadata(filePath) });
4829
4761
  });
4830
4762
  api.post(
@@ -4846,7 +4778,7 @@ function registerMediaRoutes(api, adapter, options = {}) {
4846
4778
  }
4847
4779
  const inputPath = resolveWithinProject(project.dir, inputAssetPath);
4848
4780
  if (!inputPath) return c.json({ error: "forbidden" }, 403);
4849
- if (!existsSync10(inputPath)) return c.json({ error: "input media not found" }, 404);
4781
+ if (!existsSync9(inputPath)) return c.json({ error: "input media not found" }, 404);
4850
4782
  const inputIsVideo = isVideoPath(inputAssetPath);
4851
4783
  const inputIsImage = isImagePath(inputAssetPath);
4852
4784
  if (!inputIsVideo && !inputIsImage) {
@@ -4938,14 +4870,14 @@ function registerMediaRoutes(api, adapter, options = {}) {
4938
4870
  }
4939
4871
 
4940
4872
  // src/routes/globalAssets.ts
4941
- import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
4873
+ import { existsSync as existsSync10, readFileSync as readFileSync12 } from "fs";
4942
4874
  import { homedir } from "os";
4943
4875
  import { join as join14 } from "path";
4944
4876
  function readGlobalAssets(home = homedir()) {
4945
4877
  const manifestPath = join14(home, ".media", "manifest.jsonl");
4946
- if (!existsSync11(manifestPath)) return [];
4878
+ if (!existsSync10(manifestPath)) return [];
4947
4879
  const out = [];
4948
- for (const line of readFileSync13(manifestPath, "utf8").split("\n")) {
4880
+ for (const line of readFileSync12(manifestPath, "utf8").split("\n")) {
4949
4881
  if (!line.trim()) continue;
4950
4882
  try {
4951
4883
  const rec = JSON.parse(line);
@@ -4966,7 +4898,6 @@ function registerGlobalAssetRoutes(api) {
4966
4898
  function createStudioApi(adapter) {
4967
4899
  const api = new Hono();
4968
4900
  registerProjectRoutes(api, adapter);
4969
- registerStoryboardRoutes(api, adapter);
4970
4901
  registerFileRoutes(api, adapter);
4971
4902
  registerPreviewRoutes(api, adapter);
4972
4903
  registerLintRoutes(api, adapter);