@hyperframes/studio-server 0.8.117 → 0.8.119
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 +69 -28
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3258,6 +3258,7 @@ import {
|
|
|
3258
3258
|
stripEmbeddedRuntimeScripts as stripEmbeddedRuntimeScripts2
|
|
3259
3259
|
} from "@hyperframes/core/compiler";
|
|
3260
3260
|
import { STUDIO_PREVIEW_MARK_META } from "@hyperframes/core/studio-preview-mark";
|
|
3261
|
+
import { gsapCdnDist as gsapCdnDist2, motionPathPluginUrl } from "@hyperframes/core/gsap-cdn";
|
|
3261
3262
|
import { injectTagsAtHeadStart } from "@hyperframes/core/compiler/html-document";
|
|
3262
3263
|
import { isWithinProjectRoot } from "@hyperframes/parsers/asset-resolution";
|
|
3263
3264
|
|
|
@@ -3272,6 +3273,7 @@ import {
|
|
|
3272
3273
|
} from "@hyperframes/core";
|
|
3273
3274
|
import { stripEmbeddedRuntimeScripts } from "@hyperframes/core/compiler";
|
|
3274
3275
|
import { isFullHtmlDocument } from "@hyperframes/core/compiler/html-document";
|
|
3276
|
+
import { gsapCdnDist } from "@hyperframes/core/gsap-cdn";
|
|
3275
3277
|
function rewriteRelativePaths(root, compPath, projectDir) {
|
|
3276
3278
|
const assetExists = (path) => existsSync4(join6(projectDir, path));
|
|
3277
3279
|
rewriteAssetPaths(
|
|
@@ -3421,7 +3423,7 @@ ${compHeadContent}`;
|
|
|
3421
3423
|
}
|
|
3422
3424
|
if (!headContent.includes("gsap")) {
|
|
3423
3425
|
headContent += `
|
|
3424
|
-
<script src="
|
|
3426
|
+
<script src="${gsapCdnDist()}gsap.min.js"></script>`;
|
|
3425
3427
|
}
|
|
3426
3428
|
const htmlOpen = htmlAttrs ? `<html ${htmlAttrs}>` : "<html>";
|
|
3427
3429
|
const bodyOpen = bodyAttrs ? `<body ${bodyAttrs}>` : "<body>";
|
|
@@ -3572,10 +3574,9 @@ function lazyPreviewImages(html) {
|
|
|
3572
3574
|
|
|
3573
3575
|
// src/routes/preview.ts
|
|
3574
3576
|
var PROJECT_SIGNATURE_META = "hyperframes-project-signature";
|
|
3575
|
-
var
|
|
3576
|
-
var
|
|
3577
|
-
var
|
|
3578
|
-
var GSAP_MOTION_PATH_CDN_SCRIPT = `<script src="https://cdn.jsdelivr.net/npm/gsap@${GSAP_CDN_VERSION}/dist/MotionPathPlugin.min.js"></script>`;
|
|
3577
|
+
var GSAP_CDN_SCRIPT = `<script src="${gsapCdnDist2()}gsap.min.js"></script>`;
|
|
3578
|
+
var GSAP_CUSTOM_EASE_CDN_SCRIPT = `<script src="${gsapCdnDist2()}CustomEase.min.js"></script>`;
|
|
3579
|
+
var GSAP_MOTION_PATH_CDN_SCRIPT = `<script src="${motionPathPluginUrl()}"></script>`;
|
|
3579
3580
|
function injectProjectSignature(html, signature) {
|
|
3580
3581
|
const tag = `<meta name="${PROJECT_SIGNATURE_META}" content="${signature}">`;
|
|
3581
3582
|
if (html.includes(`name="${PROJECT_SIGNATURE_META}"`)) {
|
|
@@ -3632,8 +3633,8 @@ function injectMotionPathPluginIfNeeded(html) {
|
|
|
3632
3633
|
const gsapScript = /<script\b[^>]*\bsrc=["'][^"']*\/gsap(\.min)?\.js["'][^>]*>\s*<\/script>/i;
|
|
3633
3634
|
const match = html.match(gsapScript);
|
|
3634
3635
|
if (match) {
|
|
3635
|
-
const version = match[0].match(/gsap@([\d.]+)/)?.[1]
|
|
3636
|
-
const pluginTag = `<script src="
|
|
3636
|
+
const version = match[0].match(/gsap@([\d.]+)/)?.[1];
|
|
3637
|
+
const pluginTag = `<script src="${motionPathPluginUrl(version)}"></script>`;
|
|
3637
3638
|
const end = html.indexOf(match[0]) + match[0].length;
|
|
3638
3639
|
return html.slice(0, end) + "\n" + pluginTag + html.slice(end);
|
|
3639
3640
|
}
|
|
@@ -3665,7 +3666,7 @@ function injectStudioMotionScript(html, projectDir, activeCompositionPath) {
|
|
|
3665
3666
|
var GSAP_FALLBACK_ATTR = "data-hf-gsap-fallback";
|
|
3666
3667
|
var GSAP_CDN_FALLBACK_SCRIPT = `<script ${GSAP_FALLBACK_ATTR}>
|
|
3667
3668
|
(function(){
|
|
3668
|
-
var cdnBase="
|
|
3669
|
+
var cdnBase="${gsapCdnDist2()}";
|
|
3669
3670
|
var loaded={};
|
|
3670
3671
|
function loadFallback(file){
|
|
3671
3672
|
if(loaded[file])return loaded[file];
|
|
@@ -4890,10 +4891,14 @@ function registerWaveformRoutes(api, adapter) {
|
|
|
4890
4891
|
|
|
4891
4892
|
// src/routes/freezeFrame.ts
|
|
4892
4893
|
import { execFile } from "child_process";
|
|
4893
|
-
import {
|
|
4894
|
-
import { dirname as dirname5, join as join13, relative as relative4, sep as sep2 } from "path";
|
|
4894
|
+
import { readFileSync as readFileSync11, rmSync as rmSync5, statSync as statSync8 } from "fs";
|
|
4895
|
+
import { basename as basename2, dirname as dirname5, join as join13, relative as relative4, sep as sep2 } from "path";
|
|
4895
4896
|
import { findFfBinary as findFfBinary3 } from "@hyperframes/parsers/ff-binaries";
|
|
4896
|
-
import {
|
|
4897
|
+
import {
|
|
4898
|
+
atomicTempPath,
|
|
4899
|
+
createFileAtomically as createFileAtomically2,
|
|
4900
|
+
replaceFileAtomically as replaceFileAtomically3
|
|
4901
|
+
} from "@hyperframes/core/atomic-file";
|
|
4897
4902
|
|
|
4898
4903
|
// src/helpers/freezeFrame.ts
|
|
4899
4904
|
import { createHash as createHash5, randomBytes } from "crypto";
|
|
@@ -4918,7 +4923,22 @@ function freezeFrameMediaTime(input) {
|
|
|
4918
4923
|
return input.mediaStart + sourceTimeAt(rate, Math.max(0, input.playhead - input.clipStart));
|
|
4919
4924
|
}
|
|
4920
4925
|
function freezeExtractArgs(src, mediaTime, output) {
|
|
4921
|
-
return [
|
|
4926
|
+
return [
|
|
4927
|
+
"-y",
|
|
4928
|
+
"-ss",
|
|
4929
|
+
String(round3(mediaTime)),
|
|
4930
|
+
"-i",
|
|
4931
|
+
src,
|
|
4932
|
+
"-frames:v",
|
|
4933
|
+
"1",
|
|
4934
|
+
"-c:v",
|
|
4935
|
+
"png",
|
|
4936
|
+
"-f",
|
|
4937
|
+
"image2",
|
|
4938
|
+
"-update",
|
|
4939
|
+
"1",
|
|
4940
|
+
output
|
|
4941
|
+
];
|
|
4922
4942
|
}
|
|
4923
4943
|
var randomStillToken = () => randomBytes(4).toString("hex");
|
|
4924
4944
|
function freezeStillFileName(clipId, playhead, token = randomStillToken()) {
|
|
@@ -5091,15 +5111,38 @@ function readExpected(absPath, expectedVersion) {
|
|
|
5091
5111
|
}
|
|
5092
5112
|
return fileContentVersion(content) === expectedVersion ? { content } : { error: "file conflict", status: 409 };
|
|
5093
5113
|
}
|
|
5094
|
-
function
|
|
5114
|
+
function readFrame(path) {
|
|
5115
|
+
try {
|
|
5116
|
+
return readFileSync11(path);
|
|
5117
|
+
} catch (error) {
|
|
5118
|
+
if (error.code === "ENOENT") return null;
|
|
5119
|
+
throw error;
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
function publishStill(path, frame) {
|
|
5095
5123
|
try {
|
|
5096
|
-
|
|
5124
|
+
createFileAtomically2(path, frame);
|
|
5097
5125
|
return true;
|
|
5098
5126
|
} catch (error) {
|
|
5099
5127
|
if (error.code === "EEXIST") return false;
|
|
5100
5128
|
throw error;
|
|
5101
5129
|
}
|
|
5102
5130
|
}
|
|
5131
|
+
async function extractThenPublishWhole(extract, mediaPath, mediaTime, imagePath) {
|
|
5132
|
+
const unseenByHistory = atomicTempPath(imagePath);
|
|
5133
|
+
try {
|
|
5134
|
+
const extracted = await extract(freezeExtractArgs(mediaPath, mediaTime, unseenByHistory));
|
|
5135
|
+
const frame = extracted.ok ? readFrame(unseenByHistory) : null;
|
|
5136
|
+
if (!frame?.length) {
|
|
5137
|
+
const reason = extracted.ok ? "no frame at this time" : extracted.error ?? "ffmpeg failed";
|
|
5138
|
+
return { error: `Could not extract the frame: ${reason}`, status: 500 };
|
|
5139
|
+
}
|
|
5140
|
+
if (publishStill(imagePath, frame)) return null;
|
|
5141
|
+
return { error: `freeze still already exists: ${basename2(imagePath)}`, status: 409 };
|
|
5142
|
+
} finally {
|
|
5143
|
+
rmSync5(unseenByHistory, { force: true });
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5103
5146
|
async function extractStill(projectDir, absPath, source, playhead, tools) {
|
|
5104
5147
|
const fileDir = dirname5(absPath);
|
|
5105
5148
|
const mediaPath = pinWithinProject(projectDir, relative4(projectDir, join13(fileDir, source.src)));
|
|
@@ -5111,15 +5154,13 @@ async function extractStill(projectDir, absPath, source, playhead, tools) {
|
|
|
5111
5154
|
if (!imagePath || dirname5(imagePath) !== freezeDir) {
|
|
5112
5155
|
return { error: `forbidden freeze path: ${fileName}`, status: 403 };
|
|
5113
5156
|
}
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
return { error: `Could not extract the frame: ${reason}`, status: 500 };
|
|
5122
|
-
}
|
|
5157
|
+
const failed = await extractThenPublishWhole(
|
|
5158
|
+
tools.extract,
|
|
5159
|
+
mediaPath,
|
|
5160
|
+
source.mediaTime,
|
|
5161
|
+
imagePath
|
|
5162
|
+
);
|
|
5163
|
+
if (failed) return failed;
|
|
5123
5164
|
const depth = relative4(projectDir, fileDir).split(sep2).filter(Boolean).length;
|
|
5124
5165
|
const stillPath = `${FREEZE_DIR.join("/")}/${fileName}`;
|
|
5125
5166
|
return { imageSrc: `${"../".repeat(depth)}${stillPath}`, stillPath, imagePath };
|
|
@@ -5408,7 +5449,7 @@ function registerPeakRoutes(api, adapter, decode = decodePeakMap) {
|
|
|
5408
5449
|
}
|
|
5409
5450
|
|
|
5410
5451
|
// src/routes/fonts.ts
|
|
5411
|
-
import { closeSync as
|
|
5452
|
+
import { closeSync as closeSync3, constants, fstatSync as fstatSync3, openSync as openSync3, readSync } from "fs";
|
|
5412
5453
|
import {
|
|
5413
5454
|
collectFontFileEntries,
|
|
5414
5455
|
fontDirectories,
|
|
@@ -5515,7 +5556,7 @@ function registerFontRoutes(api) {
|
|
|
5515
5556
|
if (!located) return c.json({ error: "font not found" }, 404);
|
|
5516
5557
|
let fd;
|
|
5517
5558
|
try {
|
|
5518
|
-
fd =
|
|
5559
|
+
fd = openSync3(located.path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
5519
5560
|
} catch {
|
|
5520
5561
|
return c.json({ error: "font file not accessible" }, 404);
|
|
5521
5562
|
}
|
|
@@ -5537,7 +5578,7 @@ function registerFontRoutes(api) {
|
|
|
5537
5578
|
} catch {
|
|
5538
5579
|
return c.json({ error: "failed to read font file" }, 500);
|
|
5539
5580
|
} finally {
|
|
5540
|
-
|
|
5581
|
+
closeSync3(fd);
|
|
5541
5582
|
}
|
|
5542
5583
|
});
|
|
5543
5584
|
}
|
|
@@ -5674,7 +5715,7 @@ function registerSelectionRoutes(api, adapter) {
|
|
|
5674
5715
|
// src/routes/media.ts
|
|
5675
5716
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
5676
5717
|
import { existsSync as existsSync10 } from "fs";
|
|
5677
|
-
import { basename as
|
|
5718
|
+
import { basename as basename3, dirname as dirname6, extname, join as join15, posix } from "path";
|
|
5678
5719
|
var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5679
5720
|
".mp4",
|
|
5680
5721
|
".mov",
|
|
@@ -5704,7 +5745,7 @@ function containsNullByte(path) {
|
|
|
5704
5745
|
return path.includes("\0");
|
|
5705
5746
|
}
|
|
5706
5747
|
function slugFileBase(path) {
|
|
5707
|
-
const name =
|
|
5748
|
+
const name = basename3(path, extname(path)).replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
5708
5749
|
return name || "media";
|
|
5709
5750
|
}
|
|
5710
5751
|
function uniqueAssetPath(projectDir, assetPath, taken) {
|