@hyperframes/studio-server 0.8.140 → 0.8.142

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
@@ -17,7 +17,7 @@ import {
17
17
  splitElementInHtml,
18
18
  unwrapElementsFromHtml,
19
19
  wrapElementsInHtml
20
- } from "./chunk-CLWFZQUU.js";
20
+ } from "./chunk-JJ4N3PXT.js";
21
21
  import {
22
22
  isCompositionSource,
23
23
  stampProjectHfIds
@@ -64,7 +64,7 @@ import {
64
64
  isAutoProxyEnabled,
65
65
  proxyEtagSalt,
66
66
  resolvePreviewMediaCodecProbeCache
67
- } from "./chunk-G7FEKQ32.js";
67
+ } from "./chunk-5VCIZYUE.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-6RFZWPPN.js";
78
+ } from "./chunk-QP7LKFU2.js";
79
79
  import {
80
80
  PROXY_VARIANT_CONFIG,
81
81
  decideMediaProxyEligibility,
@@ -3615,6 +3615,7 @@ import {
3615
3615
  STUDIO_PREVIEW_MARK_META,
3616
3616
  STUDIO_PREVIEW_ERRORS
3617
3617
  } from "@hyperframes/core/studio-preview-mark";
3618
+ import { PREVIEW_PROXY_BOX_PARAM, parsePreviewProxyBox } from "@hyperframes/core";
3618
3619
  import { gsapCdnDist as gsapCdnDist2, motionPathPluginUrl } from "@hyperframes/core/gsap-cdn";
3619
3620
  import { findStartTags as findStartTags2, injectTagsAtHeadStart } from "@hyperframes/core/compiler/html-document";
3620
3621
  import { isWithinProjectRoot } from "@hyperframes/parsers/asset-resolution";
@@ -4189,6 +4190,11 @@ ${etag}`;
4189
4190
  const contentType = getMimeType(subPath);
4190
4191
  const isText = /\.(html|css|js|json|svg|txt|md|cube)$/i.test(subPath);
4191
4192
  const proxyParam = c.req.query("hf-proxy");
4193
+ const boxParam = c.req.query(PREVIEW_PROXY_BOX_PARAM);
4194
+ const proxyBox = boxParam === void 0 ? void 0 : parsePreviewProxyBox(boxParam);
4195
+ if (proxyBox === null || proxyBox && proxyParam === void 0) {
4196
+ return c.text("not found", 404);
4197
+ }
4192
4198
  let proxyVariant;
4193
4199
  if (proxyParam !== void 0) {
4194
4200
  if (!isProxyVariantRequest(proxyParam) || !contentType.startsWith("video/") || !isAutoProxyEnabled(adapter)) {
@@ -4206,7 +4212,7 @@ ${etag}`;
4206
4212
  }
4207
4213
  }
4208
4214
  const tag = settledFileTag(stat2);
4209
- const etag = tag && `"${tag}${proxyEtagSalt(proxyVariant)}"`;
4215
+ const etag = tag && `"${tag}${proxyEtagSalt(proxyVariant, proxyBox)}"`;
4210
4216
  const cacheHeaders = isText ? { "Cache-Control": "no-store" } : { "Cache-Control": "private, no-cache", ...etag && { ETag: etag } };
4211
4217
  if (!isText && etag) {
4212
4218
  const ifNoneMatch = c.req.header("If-None-Match");
@@ -4218,7 +4224,7 @@ ${etag}`;
4218
4224
  let servedContentType = contentType;
4219
4225
  if (proxyVariant !== void 0) {
4220
4226
  try {
4221
- servedPath = await waitForProxy(resolveProxy(project.dir, file, proxyVariant), 0);
4227
+ servedPath = await waitForProxy(resolveProxy(project.dir, file, proxyVariant, proxyBox), 0);
4222
4228
  } catch (err) {
4223
4229
  if (err instanceof ProxyWaitTimeoutError) {
4224
4230
  return c.text("media proxy is being made", 202, {
@@ -4333,10 +4339,25 @@ function registerLintRoutes(api, adapter) {
4333
4339
  // src/routes/render.ts
4334
4340
  import { streamSSE } from "hono/streaming";
4335
4341
  import { existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
4336
- import { join as join10 } from "path";
4342
+ import { dirname as dirname5, join as join10 } from "path";
4337
4343
  import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/parsers";
4338
4344
  import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
4339
4345
  var VALID_RESOLUTIONS = new Set(VALID_CANVAS_RESOLUTIONS);
4346
+ var RENDER_MIME = {
4347
+ ".mp4": "video/mp4",
4348
+ ".webm": "video/webm",
4349
+ ".mov": "video/quicktime"
4350
+ };
4351
+ var RENDER_EXTENSIONS = Object.keys(RENDER_MIME);
4352
+ var RENDER_ARTIFACT_EXTENSIONS = [...RENDER_EXTENSIONS, ".meta.json"];
4353
+ function resolveRenderArtifacts(directories, jobId) {
4354
+ const artifacts = [...new Set(directories)].filter(existsSync6).flatMap(
4355
+ (directory) => RENDER_ARTIFACT_EXTENSIONS.map(
4356
+ (extension) => resolveWithinProject(directory, `${jobId}${extension}`)
4357
+ )
4358
+ );
4359
+ return artifacts.every((path) => path !== null) ? artifacts : null;
4360
+ }
4340
4361
  function contentDispositionHeader(disposition, filename) {
4341
4362
  const fallback = filename.replace(/[^\x20-\x7e]|["\\]/g, "_");
4342
4363
  const encoded = encodeURIComponent(filename).replace(
@@ -4454,12 +4475,6 @@ function registerRenderRoutes(api, adapter) {
4454
4475
  }
4455
4476
  return c.json({ status: job.status });
4456
4477
  });
4457
- const RENDER_MIME = {
4458
- ".mp4": "video/mp4",
4459
- ".webm": "video/webm",
4460
- ".mov": "video/quicktime"
4461
- };
4462
- const RENDER_EXTENSIONS = Object.keys(RENDER_MIME);
4463
4478
  const isPlainFile = (path) => {
4464
4479
  try {
4465
4480
  return lstatSync3(path).isFile();
@@ -4505,17 +4520,22 @@ function registerRenderRoutes(api, adapter) {
4505
4520
  }
4506
4521
  });
4507
4522
  });
4508
- api.delete("/render/:jobId", (c) => {
4523
+ async function renderDirectories(jobId) {
4524
+ const outputPath = renderJobs.get(jobId)?.outputPath;
4525
+ if (outputPath) return [dirname5(outputPath)];
4526
+ const projects = await adapter.listProjects();
4527
+ return projects.map((project) => adapter.rendersDir(project));
4528
+ }
4529
+ api.delete("/render/:jobId", async (c) => {
4509
4530
  const { jobId } = c.req.param();
4510
- for (const [, state] of renderJobs) {
4511
- if (state.id === jobId && state.outputPath) {
4512
- const dir = state.outputPath.replace(/\/[^/]+$/, "");
4513
- for (const ext of [".mp4", ".webm", ".mov", ".meta.json"]) {
4514
- const fp = join10(dir, `${jobId}${ext}`);
4515
- if (existsSync6(fp)) unlinkSync3(fp);
4516
- }
4517
- break;
4518
- }
4531
+ if (jobId.includes("/") || jobId.includes("\\") || jobId.includes("\0")) {
4532
+ return c.json({ error: "forbidden" }, 403);
4533
+ }
4534
+ const directories = await renderDirectories(jobId);
4535
+ const artifacts = resolveRenderArtifacts(directories, jobId);
4536
+ if (!artifacts) return c.json({ error: "forbidden" }, 403);
4537
+ for (const path of artifacts) {
4538
+ if (existsSync6(path)) unlinkSync3(path);
4519
4539
  }
4520
4540
  renderJobs.delete(jobId);
4521
4541
  return c.json({ deleted: true });
@@ -5059,7 +5079,7 @@ function registerWaveformRoutes(api, adapter) {
5059
5079
  // src/routes/freezeFrame.ts
5060
5080
  import { execFile } from "child_process";
5061
5081
  import { readFileSync as readFileSync11, rmSync as rmSync5, statSync as statSync8 } from "fs";
5062
- import { basename as basename2, dirname as dirname5, join as join13, relative as relative4, sep as sep2 } from "path";
5082
+ import { basename as basename2, dirname as dirname6, join as join13, relative as relative4, sep as sep2 } from "path";
5063
5083
  import { findFfBinary as findFfBinary3 } from "@hyperframes/parsers/ff-binaries";
5064
5084
  import {
5065
5085
  atomicTempPath,
@@ -5306,14 +5326,14 @@ async function extractThenPublishWhole(extract, mediaPath, mediaTime, imagePath)
5306
5326
  }
5307
5327
  }
5308
5328
  async function extractStill(projectDir, absPath, source, playhead, tools) {
5309
- const fileDir = dirname5(absPath);
5329
+ const fileDir = dirname6(absPath);
5310
5330
  const mediaPath = pinWithinProject(projectDir, relative4(projectDir, join13(fileDir, source.src)));
5311
5331
  if (!mediaPath) return { error: `forbidden media path: ${source.src}`, status: 403 };
5312
5332
  const freezeDir = join13(projectDir, ...FREEZE_DIR);
5313
5333
  const fileName = freezeStillFileName(source.id, playhead, tools.stillToken());
5314
5334
  mkdirWithinProject(projectDir, freezeDir);
5315
5335
  const imagePath = pinWithinProject(projectDir, join13(...FREEZE_DIR, fileName));
5316
- if (!imagePath || dirname5(imagePath) !== freezeDir) {
5336
+ if (!imagePath || dirname6(imagePath) !== freezeDir) {
5317
5337
  return { error: `forbidden freeze path: ${fileName}`, status: 403 };
5318
5338
  }
5319
5339
  const failed = await extractThenPublishWhole(
@@ -5877,7 +5897,7 @@ function registerSelectionRoutes(api, adapter) {
5877
5897
  // src/routes/media.ts
5878
5898
  import { streamSSE as streamSSE2 } from "hono/streaming";
5879
5899
  import { existsSync as existsSync10 } from "fs";
5880
- import { basename as basename3, dirname as dirname6, extname, join as join15, posix } from "path";
5900
+ import { basename as basename3, dirname as dirname7, extname, join as join15, posix } from "path";
5881
5901
  var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
5882
5902
  ".mp4",
5883
5903
  ".mov",
@@ -6033,8 +6053,8 @@ function registerMediaRoutes(api, adapter, options = {}) {
6033
6053
  return c.json({ error: "forbidden" }, 403);
6034
6054
  }
6035
6055
  }
6036
- mkdirWithinProject(project.dir, dirname6(outputPath));
6037
- if (backgroundOutputPath) mkdirWithinProject(project.dir, dirname6(backgroundOutputPath));
6056
+ mkdirWithinProject(project.dir, dirname7(outputPath));
6057
+ if (backgroundOutputPath) mkdirWithinProject(project.dir, dirname7(backgroundOutputPath));
6038
6058
  const jobId = makeJobId(project.id, mediaJobs);
6039
6059
  const state = adapter.startBackgroundRemoval({
6040
6060
  project,