@hyperframes/studio-server 0.7.107 → 0.7.108
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 +24 -19
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -352,7 +352,7 @@ import {
|
|
|
352
352
|
mkdirSync as mkdirSync3,
|
|
353
353
|
unlinkSync as unlinkSync2,
|
|
354
354
|
rmSync as rmSync2,
|
|
355
|
-
statSync,
|
|
355
|
+
statSync as statSync2,
|
|
356
356
|
renameSync,
|
|
357
357
|
readdirSync as readdirSync4
|
|
358
358
|
} from "fs";
|
|
@@ -406,14 +406,17 @@ function isAudioFile(name) {
|
|
|
406
406
|
|
|
407
407
|
// src/helpers/waveform.ts
|
|
408
408
|
import { spawn } from "child_process";
|
|
409
|
-
import { existsSync as existsSync2, writeFileSync, mkdirSync } from "fs";
|
|
409
|
+
import { existsSync as existsSync2, writeFileSync, mkdirSync, statSync } from "fs";
|
|
410
410
|
import { join as join3 } from "path";
|
|
411
411
|
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
|
|
412
412
|
var SAMPLE_RATE = 4e3;
|
|
413
413
|
var PEAK_COUNT = 4e3;
|
|
414
414
|
var WAVEFORM_CACHE_VERSION = "v2";
|
|
415
|
-
function buildWaveformCacheKey(assetPath) {
|
|
416
|
-
|
|
415
|
+
function buildWaveformCacheKey(assetPath, fingerprint) {
|
|
416
|
+
const name = assetPath.replace(/[/\\]/g, "_");
|
|
417
|
+
if (!fingerprint) return `${WAVEFORM_CACHE_VERSION}_${name}.json`;
|
|
418
|
+
const stamp = `${fingerprint.size}-${Math.round(fingerprint.mtimeMs)}`;
|
|
419
|
+
return `${WAVEFORM_CACHE_VERSION}_${name}_${stamp}.json`;
|
|
417
420
|
}
|
|
418
421
|
function computePeaks(floats, count) {
|
|
419
422
|
const step = floats.length / count;
|
|
@@ -473,8 +476,9 @@ function decodeAudioPeaks(audioPath) {
|
|
|
473
476
|
async function generateWaveformCache(projectDir, assetPath) {
|
|
474
477
|
const audioPath = join3(projectDir, assetPath);
|
|
475
478
|
if (!existsSync2(audioPath)) return;
|
|
479
|
+
const stats = statSync(audioPath);
|
|
476
480
|
const cacheDir = join3(projectDir, ".waveform-cache");
|
|
477
|
-
const cachePath = join3(cacheDir, buildWaveformCacheKey(assetPath));
|
|
481
|
+
const cachePath = join3(cacheDir, buildWaveformCacheKey(assetPath, stats));
|
|
478
482
|
if (existsSync2(cachePath)) return;
|
|
479
483
|
const peaks = await decodeAudioPeaks(audioPath);
|
|
480
484
|
mkdirSync(cacheDir, { recursive: true });
|
|
@@ -2426,7 +2430,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
2426
2430
|
api.delete("/projects/:id/files/*", async (c) => {
|
|
2427
2431
|
const res = await resolveProjectFile(c, adapter, { mustExist: true });
|
|
2428
2432
|
if ("error" in res) return res.error;
|
|
2429
|
-
const stat =
|
|
2433
|
+
const stat = statSync2(res.absPath);
|
|
2430
2434
|
const backup = snapshotBeforeWrite(res.project.dir, res.absPath);
|
|
2431
2435
|
if (backup.error) console.warn(`Failed to create backup for ${res.filePath}: ${backup.error}`);
|
|
2432
2436
|
if (stat.isDirectory()) {
|
|
@@ -3023,7 +3027,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
3023
3027
|
}
|
|
3024
3028
|
|
|
3025
3029
|
// src/routes/preview.ts
|
|
3026
|
-
import { existsSync as existsSync6, readFileSync as readFileSync8, statSync as
|
|
3030
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
|
|
3027
3031
|
import { join as join8, resolve as resolve4 } from "path";
|
|
3028
3032
|
import { createHash as createHash3 } from "crypto";
|
|
3029
3033
|
import { injectScriptsIntoHtml, stripEmbeddedRuntimeScripts as stripEmbeddedRuntimeScripts2 } from "@hyperframes/core/compiler";
|
|
@@ -3573,7 +3577,7 @@ ${runtimeTag}`;
|
|
|
3573
3577
|
c.req.path.replace(`/projects/${project.id}/preview/comp/`, "").split("?")[0] ?? ""
|
|
3574
3578
|
);
|
|
3575
3579
|
const compFile = resolveWithinProject(project.dir, compPath);
|
|
3576
|
-
if (!compFile || !existsSync6(compFile) || !
|
|
3580
|
+
if (!compFile || !existsSync6(compFile) || !statSync3(compFile).isFile()) {
|
|
3577
3581
|
return c.text("not found", 404);
|
|
3578
3582
|
}
|
|
3579
3583
|
const etag = `"comp:v2:${compPath}:${signature}${variablesEtagSalt(vars.raw)}"`;
|
|
@@ -3612,7 +3616,7 @@ ${runtimeTag}`;
|
|
|
3612
3616
|
if (!file) {
|
|
3613
3617
|
return c.text("not found", 404);
|
|
3614
3618
|
}
|
|
3615
|
-
const stat = existsSync6(file) ?
|
|
3619
|
+
const stat = existsSync6(file) ? statSync3(file) : null;
|
|
3616
3620
|
if (!stat?.isFile()) {
|
|
3617
3621
|
return c.text("not found", 404);
|
|
3618
3622
|
}
|
|
@@ -3724,7 +3728,7 @@ function registerLintRoutes(api, adapter) {
|
|
|
3724
3728
|
|
|
3725
3729
|
// src/routes/render.ts
|
|
3726
3730
|
import { streamSSE } from "hono/streaming";
|
|
3727
|
-
import { existsSync as existsSync7, readFileSync as readFileSync10, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync5, statSync as
|
|
3731
|
+
import { existsSync as existsSync7, readFileSync as readFileSync10, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
3728
3732
|
import { join as join10 } from "path";
|
|
3729
3733
|
import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/parsers";
|
|
3730
3734
|
import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
|
|
@@ -3922,7 +3926,7 @@ function registerRenderRoutes(api, adapter) {
|
|
|
3922
3926
|
if (!existsSync7(rendersDir)) return c.json({ renders: [] });
|
|
3923
3927
|
const files = readdirSync5(rendersDir).filter((f) => f.endsWith(".mp4") || f.endsWith(".webm") || f.endsWith(".mov")).map((f) => {
|
|
3924
3928
|
const fp = join10(rendersDir, f);
|
|
3925
|
-
const stat =
|
|
3929
|
+
const stat = statSync4(fp);
|
|
3926
3930
|
const rid = f.replace(/\.(mp4|webm|mov)$/, "");
|
|
3927
3931
|
const metaPath = join10(rendersDir, `${rid}.meta.json`);
|
|
3928
3932
|
let status = "complete";
|
|
@@ -3967,7 +3971,7 @@ import {
|
|
|
3967
3971
|
readdirSync as readdirSync6,
|
|
3968
3972
|
renameSync as renameSync2,
|
|
3969
3973
|
rmSync as rmSync3,
|
|
3970
|
-
statSync as
|
|
3974
|
+
statSync as statSync5,
|
|
3971
3975
|
unlinkSync as unlinkSync4,
|
|
3972
3976
|
writeFileSync as writeFileSync6
|
|
3973
3977
|
} from "fs";
|
|
@@ -4090,7 +4094,7 @@ function pruneThumbnailCache(cacheDir, protectedPaths, now = Date.now()) {
|
|
|
4090
4094
|
if (!entry.isFile()) return [];
|
|
4091
4095
|
const path = join11(cacheDir, entry.name);
|
|
4092
4096
|
try {
|
|
4093
|
-
const stats =
|
|
4097
|
+
const stats = statSync5(path);
|
|
4094
4098
|
return [{ path, bytes: stats.size, mtimeMs: stats.mtimeMs }];
|
|
4095
4099
|
} catch {
|
|
4096
4100
|
return [];
|
|
@@ -4157,7 +4161,7 @@ function registerThumbnailRoutes(api, adapter) {
|
|
|
4157
4161
|
if (existsSync8(htmlFile)) {
|
|
4158
4162
|
const html = readFileSync11(htmlFile, "utf-8");
|
|
4159
4163
|
sourceKey = `_${createHash4("sha1").update(html).digest("hex").slice(0, 16)}`;
|
|
4160
|
-
sourceMtime = Math.round(
|
|
4164
|
+
sourceMtime = Math.round(statSync5(htmlFile).mtimeMs);
|
|
4161
4165
|
if (!vpWidth) {
|
|
4162
4166
|
const wMatch = html.match(/data-width=["'](\d+)["']/);
|
|
4163
4167
|
const hMatch = html.match(/data-height=["'](\d+)["']/);
|
|
@@ -4170,14 +4174,14 @@ function registerThumbnailRoutes(api, adapter) {
|
|
|
4170
4174
|
if (existsSync8(manualEditsFile)) {
|
|
4171
4175
|
const manualEditsContent = readFileSync11(manualEditsFile, "utf-8");
|
|
4172
4176
|
manualEditsKey = `_${createHash4("sha1").update(manualEditsContent).digest("hex").slice(0, 16)}`;
|
|
4173
|
-
sourceMtime = Math.max(sourceMtime, Math.round(
|
|
4177
|
+
sourceMtime = Math.max(sourceMtime, Math.round(statSync5(manualEditsFile).mtimeMs));
|
|
4174
4178
|
}
|
|
4175
4179
|
const motionFile = join11(project.dir, STUDIO_MOTION_PATH);
|
|
4176
4180
|
let motionKey = "";
|
|
4177
4181
|
if (existsSync8(motionFile)) {
|
|
4178
4182
|
const motionContent = readFileSync11(motionFile, "utf-8");
|
|
4179
4183
|
motionKey = `_${createHash4("sha1").update(motionContent).digest("hex").slice(0, 16)}`;
|
|
4180
|
-
sourceMtime = Math.max(sourceMtime, Math.round(
|
|
4184
|
+
sourceMtime = Math.max(sourceMtime, Math.round(statSync5(motionFile).mtimeMs));
|
|
4181
4185
|
}
|
|
4182
4186
|
const previewUrl = compPath === "index.html" ? `http://${c.req.header("host")}/api/projects/${project.id}/preview` : `http://${c.req.header("host")}/api/projects/${project.id}/preview/comp/${compPath}`;
|
|
4183
4187
|
const cacheDir = join11(project.dir, ".thumbnails");
|
|
@@ -4246,7 +4250,7 @@ function registerThumbnailRoutes(api, adapter) {
|
|
|
4246
4250
|
}
|
|
4247
4251
|
|
|
4248
4252
|
// src/routes/waveform.ts
|
|
4249
|
-
import { existsSync as existsSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6 } from "fs";
|
|
4253
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, statSync as statSync6 } from "fs";
|
|
4250
4254
|
import { join as join12 } from "path";
|
|
4251
4255
|
function registerWaveformRoutes(api, adapter) {
|
|
4252
4256
|
api.get("/projects/:id/waveform/*", async (c) => {
|
|
@@ -4256,9 +4260,10 @@ function registerWaveformRoutes(api, adapter) {
|
|
|
4256
4260
|
c.req.path.replace(`/projects/${project.id}/waveform/`, "").split("?")[0] ?? ""
|
|
4257
4261
|
);
|
|
4258
4262
|
const audioPath = join12(project.dir, assetPath);
|
|
4259
|
-
|
|
4263
|
+
const stats = statSync6(audioPath, { throwIfNoEntry: false });
|
|
4264
|
+
if (!stats) return c.json({ error: "file not found" }, 404);
|
|
4260
4265
|
const cacheDir = join12(project.dir, ".waveform-cache");
|
|
4261
|
-
const cachePath = join12(cacheDir, buildWaveformCacheKey(assetPath));
|
|
4266
|
+
const cachePath = join12(cacheDir, buildWaveformCacheKey(assetPath, stats));
|
|
4262
4267
|
if (existsSync9(cachePath)) {
|
|
4263
4268
|
try {
|
|
4264
4269
|
const peaks2 = JSON.parse(readFileSync12(cachePath, "utf-8"));
|