@hyperframes/studio-server 0.8.137 → 0.8.139

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.
@@ -2,12 +2,12 @@ import {
2
2
  PROXY_VARIANT_CONFIG,
3
3
  probeFirstFrameColour,
4
4
  probeMediaMetadata
5
- } from "./chunk-I3DRHG52.js";
5
+ } from "./chunk-74JVVCWL.js";
6
6
  import {
7
7
  mkdirWithinProject,
8
8
  realProjectRoot,
9
9
  realpath
10
- } from "./chunk-TTWLTYSQ.js";
10
+ } from "./chunk-DTKK7TKL.js";
11
11
 
12
12
  // src/helpers/proxyTranscoder.ts
13
13
  import { spawn } from "child_process";
@@ -481,4 +481,4 @@ export {
481
481
  proxyActivityMark,
482
482
  resolveProxy
483
483
  };
484
- //# sourceMappingURL=chunk-YOBWV2CY.js.map
484
+ //# sourceMappingURL=chunk-6RFZWPPN.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  realpath
3
- } from "./chunk-TTWLTYSQ.js";
3
+ } from "./chunk-DTKK7TKL.js";
4
4
 
5
5
  // src/helpers/mediaCodecMap.ts
6
6
  import { existsSync, statSync } from "fs";
@@ -346,4 +346,4 @@ export {
346
346
  probeAssetCodec,
347
347
  scanProjectMediaCodecMap
348
348
  };
349
- //# sourceMappingURL=chunk-I3DRHG52.js.map
349
+ //# sourceMappingURL=chunk-74JVVCWL.js.map
@@ -2,7 +2,7 @@ import {
2
2
  isInHiddenOrVendorDir,
3
3
  mkdirWithinProject,
4
4
  walkDir
5
- } from "./chunk-TTWLTYSQ.js";
5
+ } from "./chunk-DTKK7TKL.js";
6
6
 
7
7
  // src/helpers/hfIdPersist.ts
8
8
  import { ensureHfIds } from "@hyperframes/parsers/hf-ids";
@@ -95,4 +95,4 @@ export {
95
95
  stampProjectHfIds,
96
96
  stampFileHfIds
97
97
  };
98
- //# sourceMappingURL=chunk-7ON477WG.js.map
98
+ //# sourceMappingURL=chunk-DG2VOIGR.js.map
@@ -1,16 +1,26 @@
1
+ import {
2
+ STUDIO_MANUAL_EDITS_PATH
3
+ } from "./chunk-6XMC64FJ.js";
4
+ import {
5
+ STUDIO_MOTION_PATH
6
+ } from "./chunk-4ETS2LXI.js";
7
+
1
8
  // src/helpers/safePath.ts
2
9
  import { basename, dirname, isAbsolute, join, relative, sep } from "path";
3
10
  import { readdirSync } from "fs";
4
- import { realpath, resolveWithinProject } from "@hyperframes/core/safe-path";
11
+ import { realpath, resolveWithinProject as resolveInProject } from "@hyperframes/core/safe-path";
5
12
  import {
6
13
  folderGone,
7
14
  isProjectRootMissing,
8
15
  isSafePath,
9
16
  mkdirWithinProject,
10
17
  realpath as realpath2,
11
- realProjectRoot,
12
- resolveWithinProject as resolveWithinProject2
18
+ realProjectRoot
13
19
  } from "@hyperframes/core/safe-path";
20
+ function resolveWithinProject(base, relativePath) {
21
+ const resolved = resolveInProject(base, relativePath);
22
+ return resolved && !isPrivateProjectFile(base, resolved) ? resolved : null;
23
+ }
14
24
  function realFilePath(filePath) {
15
25
  try {
16
26
  return realpath(filePath);
@@ -19,6 +29,18 @@ function realFilePath(filePath) {
19
29
  return dir === filePath ? filePath : join(realFilePath(dir), basename(filePath));
20
30
  }
21
31
  }
32
+ var STUDIO_FILES = /* @__PURE__ */ new Set([STUDIO_MOTION_PATH, STUDIO_MANUAL_EDITS_PATH]);
33
+ var STUDIO_FOLDERS = [".hyperframes/prepared-assets", ".hyperframes/requests"];
34
+ function isPrivateProjectPath(relPath) {
35
+ const path = relPath.toLowerCase();
36
+ return (path === ".hyperframes" || path.startsWith(".hyperframes/")) && !STUDIO_FILES.has(path) && !STUDIO_FOLDERS.some((folder) => path === folder || path.startsWith(`${folder}/`));
37
+ }
38
+ function isPrivateProjectFile(projectDir, filePath) {
39
+ const rel = (from, to) => relative(from, to).split(sep).join("/");
40
+ return [rel(projectDir, filePath), rel(realFilePath(projectDir), realFilePath(filePath))].some(
41
+ isPrivateProjectPath
42
+ );
43
+ }
22
44
  function pinWithinProject(base, relativePath) {
23
45
  const checked = resolveWithinProject(base, relativePath);
24
46
  if (!checked) return null;
@@ -64,7 +86,10 @@ function walkDir(dir, prefix = "") {
64
86
  }
65
87
 
66
88
  export {
89
+ resolveWithinProject,
67
90
  realFilePath,
91
+ isPrivateProjectPath,
92
+ isPrivateProjectFile,
68
93
  pinWithinProject,
69
94
  isInHiddenOrVendorDir,
70
95
  walkDir,
@@ -73,7 +98,6 @@ export {
73
98
  isSafePath,
74
99
  mkdirWithinProject,
75
100
  realpath2 as realpath,
76
- realProjectRoot,
77
- resolveWithinProject2 as resolveWithinProject
101
+ realProjectRoot
78
102
  };
79
- //# sourceMappingURL=chunk-TTWLTYSQ.js.map
103
+ //# sourceMappingURL=chunk-DTKK7TKL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers/safePath.ts"],"sourcesContent":["import { basename, dirname, isAbsolute, join, relative, sep } from \"node:path\";\nimport { readdirSync, type Dirent } from \"node:fs\";\nimport { realpath, resolveWithinProject as resolveInProject } from \"@hyperframes/core/safe-path\";\nimport { STUDIO_MANUAL_EDITS_PATH } from \"./manualEditsRenderScript.js\";\nimport { STUDIO_MOTION_PATH } from \"./studioMotionRenderScript.js\";\n\n// `isSafePath` lives at the package root so non-studio-api layers (compiler,\n// CLI, engine) can share it without a backwards dependency on studio-api.\n// Re-exported here for back-compat with existing `../helpers/safePath.js` imports.\nexport {\n folderGone,\n isProjectRootMissing,\n isSafePath,\n mkdirWithinProject,\n realpath,\n realProjectRoot,\n} from \"@hyperframes/core/safe-path\";\n\n/** Core's `resolveWithinProject`, closed to the desktop app's private files for every route a request path reaches. */\nexport function resolveWithinProject(base: string, relativePath: string): string | null {\n const resolved = resolveInProject(base, relativePath);\n return resolved && !isPrivateProjectFile(base, resolved) ? resolved : null;\n}\n\n/** The real path; for a path not there (yet, or any more), the nearest existing folder's real path plus the rest. */\nexport function realFilePath(filePath: string): string {\n try {\n return realpath(filePath);\n } catch {\n const dir = dirname(filePath);\n return dir === filePath ? filePath : join(realFilePath(dir), basename(filePath));\n }\n}\n\n// `.hyperframes/` holds the desktop app's and the CLI's own records (a hand-off, chat history, read marks): no route\n// reaches any of it, the folder itself included, but Studio's own files and the app's request pictures.\nconst STUDIO_FILES = new Set([STUDIO_MOTION_PATH, STUDIO_MANUAL_EDITS_PATH]);\nconst STUDIO_FOLDERS = [\".hyperframes/prepared-assets\", \".hyperframes/requests\"];\n\n/** For a project-relative path with `/` separators. */\nexport function isPrivateProjectPath(relPath: string): boolean {\n const path = relPath.toLowerCase();\n return (\n (path === \".hyperframes\" || path.startsWith(\".hyperframes/\")) &&\n !STUDIO_FILES.has(path) &&\n !STUDIO_FOLDERS.some((folder) => path === folder || path.startsWith(`${folder}/`))\n );\n}\n\nexport function isPrivateProjectFile(projectDir: string, filePath: string): boolean {\n const rel = (from: string, to: string) => relative(from, to).split(sep).join(\"/\");\n return [rel(projectDir, filePath), rel(realFilePath(projectDir), realFilePath(filePath))].some(\n isPrivateProjectPath,\n );\n}\n\n/**\n * `resolveWithinProject` with every link inside the project resolved now, so a write to the result lands on the\n * file checked here even if a link on the way is retargeted before the write.\n */\nexport function pinWithinProject(base: string, relativePath: string): string | null {\n const checked = resolveWithinProject(base, relativePath);\n if (!checked) return null;\n const inside = relative(realFilePath(base), realFilePath(checked));\n const escapes = inside === \"..\" || inside.startsWith(`..${sep}`) || isAbsolute(inside);\n return escapes ? null : join(base, inside);\n}\n\nconst IGNORE_DIRS = new Set([\n \".thumbnails\",\n \".transcode-cache\",\n \".waveform-cache\",\n \"node_modules\",\n \".git\",\n]);\n\nfunction shouldIgnoreDir(rel: string): boolean {\n return rel === \".hyperframes/backup\";\n}\n\n/**\n * True when any directory segment of a relative path is a dot-directory or\n * node_modules. Projects that vendor tooling assets under dot-directories\n * (.hyperframes/, .cache/, …) ship example/preset HTML that must not surface\n * as project compositions or studio lint targets (#1384). The file tree is\n * deliberately not filtered — this only gates discovery.\n */\nexport function isInHiddenOrVendorDir(relPath: string): boolean {\n const segments = relPath.split(\"/\");\n return segments.slice(0, -1).some((seg) => seg.startsWith(\".\") || seg === \"node_modules\");\n}\n\nconst UNREADABLE_DIR_CODES = new Set([\"EACCES\", \"EPERM\", \"ENOENT\", \"ENOTDIR\"]);\n\n/** Recursively walk a directory and return relative file paths. A subfolder that is unreadable\n * or removed mid-walk is skipped; any other failure, or an unreadable `dir` itself, throws. */\nexport function walkDir(dir: string, prefix = \"\"): string[] {\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (!prefix || !code || !UNREADABLE_DIR_CODES.has(code)) throw err;\n return [];\n }\n const files: string[] = [];\n for (const entry of entries) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (IGNORE_DIRS.has(entry.name) || shouldIgnoreDir(rel)) continue;\n if (entry.isDirectory()) {\n files.push(...walkDir(join(dir, entry.name), rel));\n } else {\n files.push(rel);\n }\n }\n return files;\n}\n"],"mappings":"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","names":["realpath"]}
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  PROXY_PARAMS_VERSION,
3
3
  resolveProxy
4
- } from "./chunk-YOBWV2CY.js";
4
+ } from "./chunk-6RFZWPPN.js";
5
5
  import {
6
6
  createMediaCodecProbeCache,
7
7
  proxyVariantFor,
8
8
  recordProxyPrewarm,
9
9
  scanProjectMediaCodecMap,
10
10
  shouldPrewarmProxy
11
- } from "./chunk-I3DRHG52.js";
11
+ } from "./chunk-74JVVCWL.js";
12
12
 
13
13
  // src/helpers/mediaProxyPreview.ts
14
14
  import { resolve } from "path";
@@ -63,4 +63,4 @@ export {
63
63
  injectMediaCodecMapIntoHtml,
64
64
  injectMediaCodecMap
65
65
  };
66
- //# sourceMappingURL=chunk-WK3ZL3SN.js.map
66
+ //# sourceMappingURL=chunk-G7FEKQ32.js.map
@@ -2,7 +2,7 @@ import {
2
2
  isSafePath,
3
3
  mkdirWithinProject,
4
4
  realFilePath
5
- } from "./chunk-TTWLTYSQ.js";
5
+ } from "./chunk-DTKK7TKL.js";
6
6
 
7
7
  // src/history/projectHistory.ts
8
8
  import { randomUUID as randomUUID6 } from "crypto";
@@ -1750,4 +1750,4 @@ export {
1750
1750
  openProjectHistory,
1751
1751
  historyCache
1752
1752
  };
1753
- //# sourceMappingURL=chunk-36F5I56K.js.map
1753
+ //# sourceMappingURL=chunk-K3H6HTVC.js.map
@@ -2,8 +2,10 @@ import {
2
2
  isCompositionSource,
3
3
  stampFileHfIds,
4
4
  stampProjectHfIds
5
- } from "../chunk-7ON477WG.js";
6
- import "../chunk-TTWLTYSQ.js";
5
+ } from "../chunk-DG2VOIGR.js";
6
+ import "../chunk-DTKK7TKL.js";
7
+ import "../chunk-6XMC64FJ.js";
8
+ import "../chunk-4ETS2LXI.js";
7
9
  export {
8
10
  isCompositionSource,
9
11
  stampFileHfIds,
@@ -13,8 +13,10 @@ import {
13
13
  resolveProxyVariantRequest,
14
14
  scanProjectMediaCodecMap,
15
15
  shouldPrewarmProxy
16
- } from "../chunk-I3DRHG52.js";
17
- import "../chunk-TTWLTYSQ.js";
16
+ } from "../chunk-74JVVCWL.js";
17
+ import "../chunk-DTKK7TKL.js";
18
+ import "../chunk-6XMC64FJ.js";
19
+ import "../chunk-4ETS2LXI.js";
18
20
  export {
19
21
  BROWSER_HOSTILE_CODECS,
20
22
  PROXY_VARIANT_CONFIG,
@@ -4,10 +4,12 @@ import {
4
4
  isAutoProxyEnabled,
5
5
  proxyEtagSalt,
6
6
  resolvePreviewMediaCodecProbeCache
7
- } from "../chunk-WK3ZL3SN.js";
8
- import "../chunk-YOBWV2CY.js";
9
- import "../chunk-I3DRHG52.js";
10
- import "../chunk-TTWLTYSQ.js";
7
+ } from "../chunk-G7FEKQ32.js";
8
+ import "../chunk-6RFZWPPN.js";
9
+ import "../chunk-74JVVCWL.js";
10
+ import "../chunk-DTKK7TKL.js";
11
+ import "../chunk-6XMC64FJ.js";
12
+ import "../chunk-4ETS2LXI.js";
11
13
  export {
12
14
  injectMediaCodecMap,
13
15
  injectMediaCodecMapIntoHtml,
@@ -14,9 +14,11 @@ import {
14
14
  proxyActivityMark,
15
15
  resolveProxy,
16
16
  waitForProxy
17
- } from "../chunk-YOBWV2CY.js";
18
- import "../chunk-I3DRHG52.js";
19
- import "../chunk-TTWLTYSQ.js";
17
+ } from "../chunk-6RFZWPPN.js";
18
+ import "../chunk-74JVVCWL.js";
19
+ import "../chunk-DTKK7TKL.js";
20
+ import "../chunk-6XMC64FJ.js";
21
+ import "../chunk-4ETS2LXI.js";
20
22
  export {
21
23
  CACHE_DIR_NAME,
22
24
  DEFAULT_PROXY_WAIT_TIMEOUT_MS,
@@ -1,7 +1,12 @@
1
- export { folderGone, isProjectRootMissing, isSafePath, mkdirWithinProject, realProjectRoot, realpath, resolveWithinProject } from '@hyperframes/core/safe-path';
1
+ export { folderGone, isProjectRootMissing, isSafePath, mkdirWithinProject, realProjectRoot, realpath } from '@hyperframes/core/safe-path';
2
2
 
3
+ /** Core's `resolveWithinProject`, closed to the desktop app's private files for every route a request path reaches. */
4
+ declare function resolveWithinProject(base: string, relativePath: string): string | null;
3
5
  /** The real path; for a path not there (yet, or any more), the nearest existing folder's real path plus the rest. */
4
6
  declare function realFilePath(filePath: string): string;
7
+ /** For a project-relative path with `/` separators. */
8
+ declare function isPrivateProjectPath(relPath: string): boolean;
9
+ declare function isPrivateProjectFile(projectDir: string, filePath: string): boolean;
5
10
  /**
6
11
  * `resolveWithinProject` with every link inside the project resolved now, so a write to the result lands on the
7
12
  * file checked here even if a link on the way is retargeted before the write.
@@ -19,4 +24,4 @@ declare function isInHiddenOrVendorDir(relPath: string): boolean;
19
24
  * or removed mid-walk is skipped; any other failure, or an unreadable `dir` itself, throws. */
20
25
  declare function walkDir(dir: string, prefix?: string): string[];
21
26
 
22
- export { isInHiddenOrVendorDir, pinWithinProject, realFilePath, walkDir };
27
+ export { isInHiddenOrVendorDir, isPrivateProjectFile, isPrivateProjectPath, pinWithinProject, realFilePath, resolveWithinProject, walkDir };
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  folderGone,
3
3
  isInHiddenOrVendorDir,
4
+ isPrivateProjectFile,
5
+ isPrivateProjectPath,
4
6
  isProjectRootMissing,
5
7
  isSafePath,
6
8
  mkdirWithinProject,
@@ -10,10 +12,14 @@ import {
10
12
  realpath,
11
13
  resolveWithinProject,
12
14
  walkDir
13
- } from "../chunk-TTWLTYSQ.js";
15
+ } from "../chunk-DTKK7TKL.js";
16
+ import "../chunk-6XMC64FJ.js";
17
+ import "../chunk-4ETS2LXI.js";
14
18
  export {
15
19
  folderGone,
16
20
  isInHiddenOrVendorDir,
21
+ isPrivateProjectFile,
22
+ isPrivateProjectPath,
17
23
  isProjectRootMissing,
18
24
  isSafePath,
19
25
  mkdirWithinProject,
@@ -10,8 +10,10 @@ import {
10
10
  listProjectHistories,
11
11
  openProjectHistory,
12
12
  pruneGoneProjectHistories
13
- } from "../chunk-36F5I56K.js";
14
- import "../chunk-TTWLTYSQ.js";
13
+ } from "../chunk-K3H6HTVC.js";
14
+ import "../chunk-DTKK7TKL.js";
15
+ import "../chunk-6XMC64FJ.js";
16
+ import "../chunk-4ETS2LXI.js";
15
17
  export {
16
18
  DEFAULT_HISTORY_ROOT,
17
19
  START as HISTORY_START,
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  import {
22
22
  isCompositionSource,
23
23
  stampProjectHfIds
24
- } from "./chunk-7ON477WG.js";
24
+ } from "./chunk-DG2VOIGR.js";
25
25
  import {
26
26
  DEFAULT_HISTORY_ROOT,
27
27
  DELETED_VERSION,
@@ -47,7 +47,7 @@ import {
47
47
  resolveProjectAndSignature,
48
48
  resolveProjectSignature,
49
49
  settledFileTag
50
- } from "./chunk-36F5I56K.js";
50
+ } from "./chunk-K3H6HTVC.js";
51
51
  import {
52
52
  clearElementScreenshotIsolation,
53
53
  getElementScreenshotClip
@@ -64,7 +64,7 @@ import {
64
64
  isAutoProxyEnabled,
65
65
  proxyEtagSalt,
66
66
  resolvePreviewMediaCodecProbeCache
67
- } from "./chunk-WK3ZL3SN.js";
67
+ } from "./chunk-G7FEKQ32.js";
68
68
  import {
69
69
  CACHE_DIR_NAME,
70
70
  PROXY_PENDING_RETRY_AFTER_SECONDS,
@@ -75,7 +75,7 @@ import {
75
75
  proxyActivityMark,
76
76
  resolveProxy,
77
77
  waitForProxy
78
- } from "./chunk-YOBWV2CY.js";
78
+ } from "./chunk-6RFZWPPN.js";
79
79
  import {
80
80
  PROXY_VARIANT_CONFIG,
81
81
  decideMediaProxyEligibility,
@@ -84,10 +84,12 @@ import {
84
84
  probeMediaMetadata,
85
85
  recordProxyRequest,
86
86
  resolveProxyVariantRequest
87
- } from "./chunk-I3DRHG52.js";
87
+ } from "./chunk-74JVVCWL.js";
88
88
  import {
89
89
  folderGone,
90
90
  isInHiddenOrVendorDir,
91
+ isPrivateProjectFile,
92
+ isPrivateProjectPath,
91
93
  isProjectRootMissing,
92
94
  isSafePath,
93
95
  mkdirWithinProject,
@@ -96,7 +98,7 @@ import {
96
98
  realpath,
97
99
  resolveWithinProject,
98
100
  walkDir
99
- } from "./chunk-TTWLTYSQ.js";
101
+ } from "./chunk-DTKK7TKL.js";
100
102
  import {
101
103
  STUDIO_MANUAL_EDITS_PATH,
102
104
  createStudioManualEditsRenderBodyScript,
@@ -149,7 +151,7 @@ function registerProjectRoutes(api, adapter) {
149
151
  api.get("/projects/:id", async (c) => {
150
152
  const project = await adapter.resolveProject(c.req.param("id"));
151
153
  if (!project) return c.json({ error: "not found" }, 404);
152
- const files = walkDir(project.dir);
154
+ const files = walkDir(project.dir).filter((file) => !isPrivateProjectPath(file));
153
155
  const compositions = await filterCompositionFiles(project.dir, files);
154
156
  return c.json({ id: project.id, dir: project.dir, title: project.title, files, compositions });
155
157
  });
@@ -1572,7 +1574,7 @@ function updateReferences(projectDir, oldPath, newPath, isDirectory) {
1572
1574
  const rewrite = referenceRewriter(oldPath, newPath, isDirectory, projectPaths(projectDir));
1573
1575
  let updatedCount = 0;
1574
1576
  for (const file of textFiles) {
1575
- if (!isSafePath(projectDir, file)) continue;
1577
+ if (!isSafePath(projectDir, file) || isPrivateProjectFile(projectDir, file)) continue;
1576
1578
  const content = readableText(file);
1577
1579
  if (content === null) continue;
1578
1580
  const updated = rewrite(content);
@@ -1922,7 +1924,7 @@ function clipRetimeOf(mutation) {
1922
1924
  function retimeRun(script, run, root) {
1923
1925
  const live = run.filter((slot) => slot !== "no-op");
1924
1926
  const retimed = retimeClipTweensInScript(script, live, root);
1925
- const synced = syncPositionHoldsBeforeKeyframes(retimed.script);
1927
+ const synced = syncPositionHoldsBeforeKeyframes(retimed.script, script);
1926
1928
  let next = 0;
1927
1929
  const changed = run.map((slot) => slot !== "no-op" && retimed.changed[next++]);
1928
1930
  if (synced !== retimed.script) changed[changed.length - 1] = true;
@@ -2716,7 +2718,7 @@ async function processUploadedFiles(formData, targetDir, projectDir) {
2716
2718
  finalName = `${base} (${n})${ext}`;
2717
2719
  finalPath = resolve2(targetDir, finalName);
2718
2720
  }
2719
- if (!isSafePath(projectDir, finalPath)) continue;
2721
+ if (!isSafePath(projectDir, finalPath) || isPrivateProjectFile(projectDir, finalPath)) continue;
2720
2722
  const buffer = Buffer.from(await value.arrayBuffer());
2721
2723
  const validation = validateUploadedMediaBuffer(finalName, buffer);
2722
2724
  if (!validation.ok) {
@@ -3609,7 +3611,10 @@ import {
3609
3611
  insertRuntimeTag,
3610
3612
  stripEmbeddedRuntimeScripts as stripEmbeddedRuntimeScripts2
3611
3613
  } from "@hyperframes/core/compiler";
3612
- import { STUDIO_PREVIEW_MARK_META } from "@hyperframes/core/studio-preview-mark";
3614
+ import {
3615
+ STUDIO_PREVIEW_MARK_META,
3616
+ STUDIO_PREVIEW_ERRORS
3617
+ } from "@hyperframes/core/studio-preview-mark";
3613
3618
  import { gsapCdnDist as gsapCdnDist2, motionPathPluginUrl } from "@hyperframes/core/gsap-cdn";
3614
3619
  import { findStartTags as findStartTags2, injectTagsAtHeadStart } from "@hyperframes/core/compiler/html-document";
3615
3620
  import { isWithinProjectRoot } from "@hyperframes/parsers/asset-resolution";
@@ -3904,15 +3909,17 @@ var GSAP_CDN_FALLBACK_SCRIPT = `<script ${GSAP_FALLBACK_ATTR}>
3904
3909
  if(loaded[file])return loaded[file];
3905
3910
  return loaded[file]=new Promise(function(ok,fail){
3906
3911
  var s=document.createElement("script");
3907
- s.src=cdnBase+file;s.onload=ok;s.onerror=fail;
3912
+ s.src=cdnBase+file;s.hfGsapFallback=true;s.onload=ok;s.onerror=fail;
3908
3913
  document.head.appendChild(s);
3909
3914
  });
3910
3915
  }
3911
3916
  document.addEventListener("error",function(e){
3912
3917
  var t=e.target;
3913
- if(!t||t.tagName!=="SCRIPT"||!t.src)return;
3918
+ if(!t||t.tagName!=="SCRIPT"||!t.src||t.hfGsapFallback)return;
3914
3919
  var m=t.src.match(/gsap[^/]*\\/dist\\/(.+\\.js)/);
3915
- if(m)loadFallback(m[1]);
3920
+ if(m)loadFallback(m[1]).catch(function(){
3921
+ reportError(new Error("GSAP could not load from "+t.src+" or "+cdnBase+m[1]+", so this preview's animations will not play."));
3922
+ });
3916
3923
  },true);
3917
3924
  })();
3918
3925
  </script>`;
@@ -3944,8 +3951,13 @@ function previewVariablesFromRequest(rawVariables) {
3944
3951
  return { raw: rawVariables, values: parse2.values };
3945
3952
  }
3946
3953
  var PREVIEW_CAPTURE_PARAM = "hf-capture";
3954
+ var EARLY_ERRORS_SCRIPT = `<script>(function(){var seen=window.${STUDIO_PREVIEW_ERRORS}=[];
3955
+ addEventListener("error",function(e){seen.push(e.message||String(e))});})();</script>`;
3947
3956
  function injectStudioPreviewAugmentations(html, adapter, projectDir, activeCompositionPath, capture) {
3948
- const marked = capture ? html : injectTagsAtHeadStart(lazyPreviewImages(html), `<meta name="${STUDIO_PREVIEW_MARK_META}">`);
3957
+ const marked = capture ? html : injectTagsAtHeadStart(
3958
+ lazyPreviewImages(html),
3959
+ `<meta name="${STUDIO_PREVIEW_MARK_META}">${EARLY_ERRORS_SCRIPT}`
3960
+ );
3949
3961
  return injectStudioMotionScript(
3950
3962
  injectMotionPathPluginIfNeeded(
3951
3963
  injectGsapCdnFallback(
@@ -4166,7 +4178,7 @@ ${etag}`;
4166
4178
  const subPath = requestSubPath(c.req.url, "projects/:id/preview");
4167
4179
  const candidate = resolve4(project.dir, subPath);
4168
4180
  const file = isWithinProjectRoot(project.dir, candidate) ? candidate : null;
4169
- if (!file) {
4181
+ if (!file || isPrivateProjectFile(project.dir, file)) {
4170
4182
  return c.text("not found", 404);
4171
4183
  }
4172
4184
  recordPreviewRead(project.dir, file);
@@ -4320,7 +4332,7 @@ function registerLintRoutes(api, adapter) {
4320
4332
 
4321
4333
  // src/routes/render.ts
4322
4334
  import { streamSSE } from "hono/streaming";
4323
- import { existsSync as existsSync6, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
4335
+ import { existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
4324
4336
  import { join as join10 } from "path";
4325
4337
  import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/parsers";
4326
4338
  import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
@@ -4448,6 +4460,13 @@ function registerRenderRoutes(api, adapter) {
4448
4460
  ".mov": "video/quicktime"
4449
4461
  };
4450
4462
  const RENDER_EXTENSIONS = Object.keys(RENDER_MIME);
4463
+ const isPlainFile = (path) => {
4464
+ try {
4465
+ return lstatSync3(path).isFile();
4466
+ } catch {
4467
+ return false;
4468
+ }
4469
+ };
4451
4470
  function renderContentType(filePath) {
4452
4471
  const ext = RENDER_EXTENSIONS.find((e) => filePath.endsWith(e));
4453
4472
  return (ext && RENDER_MIME[ext]) ?? "video/mp4";
@@ -4455,7 +4474,7 @@ function registerRenderRoutes(api, adapter) {
4455
4474
  api.get("/render/:jobId/view", (c) => {
4456
4475
  const { jobId } = c.req.param();
4457
4476
  const job = renderJobs.get(jobId);
4458
- if (!job?.outputPath || !existsSync6(job.outputPath)) {
4477
+ if (!job?.outputPath || !isPlainFile(job.outputPath)) {
4459
4478
  return c.json({ error: "not found" }, 404);
4460
4479
  }
4461
4480
  const contentType = renderContentType(job.outputPath);
@@ -4473,7 +4492,7 @@ function registerRenderRoutes(api, adapter) {
4473
4492
  api.get("/render/:jobId/download", (c) => {
4474
4493
  const { jobId } = c.req.param();
4475
4494
  const job = renderJobs.get(jobId);
4476
- if (!job?.outputPath || !existsSync6(job.outputPath)) {
4495
+ if (!job?.outputPath || !isPlainFile(job.outputPath)) {
4477
4496
  return c.json({ error: "not found" }, 404);
4478
4497
  }
4479
4498
  const contentType = renderContentType(job.outputPath);
@@ -4508,7 +4527,7 @@ function registerRenderRoutes(api, adapter) {
4508
4527
  if (!filename) return c.json({ error: "missing filename" }, 400);
4509
4528
  const rendersDir = adapter.rendersDir(project);
4510
4529
  const fp = resolveWithinProject(rendersDir, filename);
4511
- if (!fp) return c.json({ error: "forbidden" }, 403);
4530
+ if (!fp || isPrivateProjectFile(project.dir, fp)) return c.json({ error: "forbidden" }, 403);
4512
4531
  if (!existsSync6(fp)) return c.json({ error: "not found" }, 404);
4513
4532
  const contentType = renderContentType(fp);
4514
4533
  const content = readFileSync8(fp);
@@ -4526,8 +4545,10 @@ function registerRenderRoutes(api, adapter) {
4526
4545
  if (!project) return c.json({ error: "not found" }, 404);
4527
4546
  const rendersDir = adapter.rendersDir(project);
4528
4547
  if (!existsSync6(rendersDir)) return c.json({ renders: [] });
4529
- const files = readdirSync3(rendersDir).filter((f) => f.endsWith(".mp4") || f.endsWith(".webm") || f.endsWith(".mov")).map((f) => {
4530
- const fp = join10(rendersDir, f);
4548
+ const files = readdirSync3(rendersDir).filter((f) => f.endsWith(".mp4") || f.endsWith(".webm") || f.endsWith(".mov")).flatMap((f) => {
4549
+ const fp = resolveWithinProject(rendersDir, f);
4550
+ return fp && !isPrivateProjectFile(project.dir, fp) ? [{ f, fp }] : [];
4551
+ }).map(({ f, fp }) => {
4531
4552
  const stat2 = statSync5(fp);
4532
4553
  const rid = f.replace(/\.(mp4|webm|mov)$/, "");
4533
4554
  const metaPath = join10(rendersDir, `${rid}.meta.json`);
@@ -4546,6 +4567,7 @@ function registerRenderRoutes(api, adapter) {
4546
4567
  return {
4547
4568
  id: rid,
4548
4569
  filename: f,
4570
+ path: fp,
4549
4571
  size: stat2.size,
4550
4572
  createdAt: stat2.mtimeMs,
4551
4573
  status,
@@ -4559,12 +4581,12 @@ function registerRenderRoutes(api, adapter) {
4559
4581
  id: file.id,
4560
4582
  status: file.status,
4561
4583
  progress: 100,
4562
- outputPath: join10(rendersDir, file.filename),
4584
+ outputPath: file.path,
4563
4585
  createdAt: file.createdAt
4564
4586
  });
4565
4587
  }
4566
4588
  }
4567
- return c.json({ renders: files });
4589
+ return c.json({ renders: files.map(({ path: _path, ...render }) => render) });
4568
4590
  });
4569
4591
  }
4570
4592