@hyperframes/studio-server 0.8.206 → 0.8.208
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/{chunk-OSZE5WT3.js → chunk-WAMZ2Z5O.js} +26 -30
- package/dist/{chunk-2GPN2OSU.js → chunk-ZR3T4TKU.js} +51 -2
- package/dist/helpers/encoderOptions.d.ts +8 -1
- package/dist/helpers/encoderOptions.js +3 -1
- package/dist/helpers/mediaProxyPreview.d.ts +1 -1
- package/dist/history/index.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +63 -12
- package/dist/{mediaProxyPreview-DeICCYb5.d.ts → mediaProxyPreview-DIEtpLJo.d.ts} +3 -0
- package/package.json +3 -3
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "fs";
|
|
21
21
|
import { homedir } from "os";
|
|
22
22
|
import { dirname as dirname5, isAbsolute as isAbsolute5, join as join8, relative as relative5, resolve as resolve7, sep as sep5 } from "path";
|
|
23
|
-
import { replaceFileAtomically as
|
|
23
|
+
import { replaceFileAtomically as replaceFileAtomically6 } from "@hyperframes/core/atomic-file";
|
|
24
24
|
|
|
25
25
|
// src/helpers/fileVersion.ts
|
|
26
26
|
import { createHash, randomUUID } from "crypto";
|
|
@@ -103,22 +103,15 @@ var consumeFileWriteReceipt = identifyFileWrite;
|
|
|
103
103
|
// src/helpers/renderOutputs.ts
|
|
104
104
|
import { readFileSync as readFileSync2 } from "fs";
|
|
105
105
|
import { isAbsolute, relative, resolve, sep } from "path";
|
|
106
|
-
import { replaceFileAtomically } from "@hyperframes/core/atomic-file";
|
|
106
|
+
import { replaceFileAtomically as replaceFileAtomically2 } from "@hyperframes/core/atomic-file";
|
|
107
107
|
|
|
108
108
|
// src/history/ownerLock.ts
|
|
109
109
|
import { spawnSync } from "child_process";
|
|
110
110
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
111
|
-
import {
|
|
112
|
-
linkSync,
|
|
113
|
-
mkdirSync,
|
|
114
|
-
readFileSync,
|
|
115
|
-
renameSync,
|
|
116
|
-
rmSync,
|
|
117
|
-
statSync,
|
|
118
|
-
writeFileSync
|
|
119
|
-
} from "fs";
|
|
111
|
+
import { linkSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
|
|
120
112
|
import { uptime } from "os";
|
|
121
113
|
import { join } from "path";
|
|
114
|
+
import { replaceFileAtomically } from "@hyperframes/core/atomic-file";
|
|
122
115
|
var HistoryBusyError = class extends Error {
|
|
123
116
|
constructor(pid, url) {
|
|
124
117
|
super(`This project's history is open in another process (pid ${pid}).`);
|
|
@@ -258,9 +251,7 @@ function evictDeadOwner(file) {
|
|
|
258
251
|
}
|
|
259
252
|
function advertise(urlFile, url) {
|
|
260
253
|
if (!url) return rmSync(urlFile, { force: true });
|
|
261
|
-
|
|
262
|
-
writeFileSync(draft, JSON.stringify({ pid: process.pid, url }));
|
|
263
|
-
renameSync(draft, urlFile);
|
|
254
|
+
replaceFileAtomically(urlFile, JSON.stringify({ pid: process.pid, url }));
|
|
264
255
|
}
|
|
265
256
|
function servedBy(file, urlFile, pid) {
|
|
266
257
|
try {
|
|
@@ -294,7 +285,12 @@ async function takeHistoryOwnership(home, waitMs, url) {
|
|
|
294
285
|
if (next === "claimed") break;
|
|
295
286
|
if (next === "wait") await new Promise((settle) => setTimeout(settle, 50));
|
|
296
287
|
}
|
|
297
|
-
|
|
288
|
+
try {
|
|
289
|
+
advertise(urlFile, url);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
releaseOwn(file);
|
|
292
|
+
throw error;
|
|
293
|
+
}
|
|
298
294
|
let held = true;
|
|
299
295
|
return () => {
|
|
300
296
|
if (held && servedBy(file, urlFile, process.pid)) rmSync(urlFile, { force: true });
|
|
@@ -344,7 +340,7 @@ async function registerRenderOutput(projectDir, output) {
|
|
|
344
340
|
const release = await takeHistoryOwnership(lock, 5e3);
|
|
345
341
|
try {
|
|
346
342
|
const paths = [.../* @__PURE__ */ new Set([...readRenderOutputs(projectDir), path])].sort();
|
|
347
|
-
|
|
343
|
+
replaceFileAtomically2(registry, JSON.stringify({ version: 1, paths }) + "\n", 420);
|
|
348
344
|
} finally {
|
|
349
345
|
release();
|
|
350
346
|
}
|
|
@@ -528,7 +524,7 @@ function createProjectSignature(projectDir, excluding = /* @__PURE__ */ new Set(
|
|
|
528
524
|
|
|
529
525
|
// src/history/blobStore.ts
|
|
530
526
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
531
|
-
import { constants, createReadStream, createWriteStream, renameSync
|
|
527
|
+
import { constants, createReadStream, createWriteStream, renameSync } from "fs";
|
|
532
528
|
import { copyFile, mkdir, readdir, readFile, rename, rm, stat } from "fs/promises";
|
|
533
529
|
import { dirname, join as join2 } from "path";
|
|
534
530
|
import { pipeline } from "stream/promises";
|
|
@@ -558,7 +554,7 @@ async function cloneOrCopy(from, to, beforeReplace) {
|
|
|
558
554
|
try {
|
|
559
555
|
await copyFile(from, temp, constants.COPYFILE_FICLONE);
|
|
560
556
|
beforeReplace?.();
|
|
561
|
-
|
|
557
|
+
renameSync(temp, to);
|
|
562
558
|
} catch (error) {
|
|
563
559
|
await rm(temp, { force: true });
|
|
564
560
|
throw error;
|
|
@@ -703,7 +699,7 @@ function uncopiedOnlyHashes(log, sizeOf) {
|
|
|
703
699
|
|
|
704
700
|
// src/history/pruneHistories.ts
|
|
705
701
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
706
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as
|
|
702
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
707
703
|
import { lstat, readdir as readdir2, rm as rm2 } from "fs/promises";
|
|
708
704
|
import { tmpdir } from "os";
|
|
709
705
|
import { dirname as dirname2, join as join4 } from "path";
|
|
@@ -712,7 +708,7 @@ import { dirname as dirname2, join as join4 } from "path";
|
|
|
712
708
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
713
709
|
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync4, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
714
710
|
import { basename, join as join3, resolve as resolve3 } from "path";
|
|
715
|
-
import { replaceFileAtomically as
|
|
711
|
+
import { replaceFileAtomically as replaceFileAtomically3 } from "@hyperframes/core/atomic-file";
|
|
716
712
|
var ID_PATH = join3(".hyperframes", "history-id");
|
|
717
713
|
var ID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
718
714
|
var isHistoryId = (name) => ID_SHAPE.test(name);
|
|
@@ -775,7 +771,7 @@ var HistoryIdError = class extends Error {
|
|
|
775
771
|
function recordProject(historyDir, dir, folder) {
|
|
776
772
|
const record = { dir, ino: folder.ino, born: folder.birthtimeMs, dev: folder.dev };
|
|
777
773
|
mkdirSync2(historyDir, { recursive: true });
|
|
778
|
-
|
|
774
|
+
replaceFileAtomically3(join3(historyDir, "project.json"), JSON.stringify(record), 420);
|
|
779
775
|
}
|
|
780
776
|
|
|
781
777
|
// src/history/pruneHistories.ts
|
|
@@ -867,7 +863,7 @@ function recheckAndMoveAway(historyRoot, id, { now, dryRun, tempDir }) {
|
|
|
867
863
|
if (projectDir === null) return null;
|
|
868
864
|
if (dryRun) return { projectDir, trash: null };
|
|
869
865
|
const trash = join4(historyRoot, `${PRUNED_PREFIX}${id}-${randomUUID5()}`);
|
|
870
|
-
|
|
866
|
+
renameSync2(home, trash);
|
|
871
867
|
return { projectDir, trash };
|
|
872
868
|
}
|
|
873
869
|
function abandonedProject(home, id, now, tempDir) {
|
|
@@ -926,9 +922,9 @@ function pruneGoneProjectHistoriesDaily(historyRoot, now, { onError, budgetMs }
|
|
|
926
922
|
|
|
927
923
|
// src/history/videoState.ts
|
|
928
924
|
import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
|
|
929
|
-
import { createReadStream as createReadStream2, existsSync as existsSync2, readFileSync as readFileSync8, renameSync as
|
|
925
|
+
import { createReadStream as createReadStream2, existsSync as existsSync2, readFileSync as readFileSync8, renameSync as renameSync3, statSync as statSync4 } from "fs";
|
|
930
926
|
import { isAbsolute as isAbsolute4, join as join7, resolve as resolve6 } from "path";
|
|
931
|
-
import { replaceFileAtomically as
|
|
927
|
+
import { replaceFileAtomically as replaceFileAtomically4 } from "@hyperframes/core/atomic-file";
|
|
932
928
|
|
|
933
929
|
// src/history/artifactCleanup.ts
|
|
934
930
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -1327,11 +1323,11 @@ async function updateState(dir, update) {
|
|
|
1327
1323
|
state = readState(dir);
|
|
1328
1324
|
} catch (error) {
|
|
1329
1325
|
if (!(error instanceof SyntaxError)) throw error;
|
|
1330
|
-
|
|
1326
|
+
renameSync3(statePath(dir), `${statePath(dir)}.invalid-${randomUUID6()}`);
|
|
1331
1327
|
state = emptyState();
|
|
1332
1328
|
}
|
|
1333
1329
|
update(state);
|
|
1334
|
-
|
|
1330
|
+
replaceFileAtomically4(statePath(dir), JSON.stringify(state, null, 2) + "\n", 420);
|
|
1335
1331
|
} finally {
|
|
1336
1332
|
release();
|
|
1337
1333
|
}
|
|
@@ -1534,7 +1530,7 @@ async function finishSnapshotRun(projectDir, path) {
|
|
|
1534
1530
|
// src/history/historyLog.ts
|
|
1535
1531
|
import { closeSync as closeSync3, constants as constants4, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync9, writeSync as writeSync2 } from "fs";
|
|
1536
1532
|
import { dirname as dirname4 } from "path";
|
|
1537
|
-
import { replaceFileAtomically as
|
|
1533
|
+
import { replaceFileAtomically as replaceFileAtomically5 } from "@hyperframes/core/atomic-file";
|
|
1538
1534
|
var START = "start";
|
|
1539
1535
|
function parseRecord(line) {
|
|
1540
1536
|
try {
|
|
@@ -1596,7 +1592,7 @@ function writeLog(file, log) {
|
|
|
1596
1592
|
...[...log.pins].map((id) => ({ type: "pin", id, pinned: true }))
|
|
1597
1593
|
];
|
|
1598
1594
|
mkdirSync4(dirname4(file), { recursive: true });
|
|
1599
|
-
|
|
1595
|
+
replaceFileAtomically5(file, records2.map((r) => `${JSON.stringify(r)}
|
|
1600
1596
|
`).join(""), 420);
|
|
1601
1597
|
}
|
|
1602
1598
|
function applyEntry(manifest2, entry, side) {
|
|
@@ -1966,7 +1962,7 @@ var Engine = class {
|
|
|
1966
1962
|
const file = join8(this.home, "adopting.json");
|
|
1967
1963
|
if (!this.adopting.size) return rmSync3(file, { force: true });
|
|
1968
1964
|
mkdirSync5(this.home, { recursive: true });
|
|
1969
|
-
|
|
1965
|
+
replaceFileAtomically6(file, JSON.stringify([...this.adopting.keys()]), 420);
|
|
1970
1966
|
}
|
|
1971
1967
|
async adopt(file, sweptAt) {
|
|
1972
1968
|
try {
|
|
@@ -2018,7 +2014,7 @@ var Engine = class {
|
|
|
2018
2014
|
saveStatCache() {
|
|
2019
2015
|
const files = JSON.stringify(Object.fromEntries(this.tracked));
|
|
2020
2016
|
mkdirSync5(this.home, { recursive: true });
|
|
2021
|
-
|
|
2017
|
+
replaceFileAtomically6(join8(this.home, "stat.json"), files, 420);
|
|
2022
2018
|
}
|
|
2023
2019
|
/**
|
|
2024
2020
|
* Takes in every write since the last sweep and files each change to its writer. ponytail: always the whole
|
|
@@ -29,10 +29,46 @@ function parseRateControl(body, format) {
|
|
|
29
29
|
if (isSet(body.videoBitrate)) return parseVideoBitrate(body.videoBitrate);
|
|
30
30
|
return { ok: true, options: {} };
|
|
31
31
|
}
|
|
32
|
+
function parseKeyframeInterval(value) {
|
|
33
|
+
if (typeof value !== "number" || !(value > 0)) {
|
|
34
|
+
return { ok: false, error: "keyframeIntervalSeconds must be a positive number of seconds" };
|
|
35
|
+
}
|
|
36
|
+
return { ok: true, options: { keyframeIntervalSeconds: value } };
|
|
37
|
+
}
|
|
38
|
+
function parseBitrateField(name, value) {
|
|
39
|
+
if (typeof value !== "string" || !VIDEO_BITRATE.test(value)) {
|
|
40
|
+
return { ok: false, error: `${name} must look like "8M", "5000k" or "8000000"` };
|
|
41
|
+
}
|
|
42
|
+
return { ok: true, options: { [name]: value } };
|
|
43
|
+
}
|
|
44
|
+
var DELIVERY_FIELDS = [
|
|
45
|
+
["keyframeIntervalSeconds", parseKeyframeInterval],
|
|
46
|
+
["maxBitrate", (value) => parseBitrateField("maxBitrate", value)],
|
|
47
|
+
["bufferSize", (value) => parseBitrateField("bufferSize", value)]
|
|
48
|
+
];
|
|
49
|
+
function parseDelivery(body, format) {
|
|
50
|
+
const present = DELIVERY_FIELDS.filter(([name]) => isSet(body[name]));
|
|
51
|
+
if (present.length === 0) return { ok: true, options: {} };
|
|
52
|
+
if (format !== "mp4") {
|
|
53
|
+
return { ok: false, error: "keyframeIntervalSeconds and maxBitrate apply to mp4 renders" };
|
|
54
|
+
}
|
|
55
|
+
if (isSet(body.bufferSize) && !isSet(body.maxBitrate)) {
|
|
56
|
+
return { ok: false, error: "bufferSize requires maxBitrate" };
|
|
57
|
+
}
|
|
58
|
+
const options = {};
|
|
59
|
+
for (const [name, parse] of present) {
|
|
60
|
+
const parsed = parse(body[name]);
|
|
61
|
+
if (!parsed.ok) return parsed;
|
|
62
|
+
Object.assign(options, parsed.options);
|
|
63
|
+
}
|
|
64
|
+
return { ok: true, options };
|
|
65
|
+
}
|
|
32
66
|
function parseEncoderOptions(body, format) {
|
|
33
67
|
const rate = parseRateControl(body, format);
|
|
34
68
|
if (!rate.ok) return rate;
|
|
35
|
-
const
|
|
69
|
+
const delivery = parseDelivery(body, format);
|
|
70
|
+
if (!delivery.ok) return delivery;
|
|
71
|
+
const options = { ...rate.options, ...delivery.options };
|
|
36
72
|
if (isSet(body.gifLoop)) {
|
|
37
73
|
if (typeof body.gifLoop !== "number" || !Number.isInteger(body.gifLoop) || body.gifLoop < 0 || body.gifLoop > 65535) {
|
|
38
74
|
return { ok: false, error: "gifLoop must be an integer from 0 to 65535" };
|
|
@@ -56,7 +92,20 @@ function parseEncoderOptions(body, format) {
|
|
|
56
92
|
}
|
|
57
93
|
return { ok: true, options };
|
|
58
94
|
}
|
|
95
|
+
function encoderJobOptions(opts) {
|
|
96
|
+
const { crf, videoBitrate, keyframeIntervalSeconds, maxBitrate, bufferSize } = opts;
|
|
97
|
+
return {
|
|
98
|
+
...crf !== void 0 ? { crf } : {},
|
|
99
|
+
...videoBitrate ? { videoBitrate } : {},
|
|
100
|
+
...keyframeIntervalSeconds !== void 0 ? { keyframeIntervalSeconds } : {},
|
|
101
|
+
...maxBitrate ? { maxBitrate } : {},
|
|
102
|
+
...bufferSize ? { bufferSize } : {},
|
|
103
|
+
...opts.videoFrameFormat ? { videoFrameFormat: opts.videoFrameFormat } : {},
|
|
104
|
+
...opts.hdrMode ? { hdrMode: opts.hdrMode } : {}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
59
107
|
|
|
60
108
|
export {
|
|
61
|
-
parseEncoderOptions
|
|
109
|
+
parseEncoderOptions,
|
|
110
|
+
encoderJobOptions
|
|
62
111
|
};
|
|
@@ -6,6 +6,9 @@ interface EncoderOptions {
|
|
|
6
6
|
videoBitrate?: string;
|
|
7
7
|
videoFrameFormat?: (typeof VIDEO_FRAME_FORMATS)[number];
|
|
8
8
|
hdrMode?: (typeof HDR_MODES)[number];
|
|
9
|
+
keyframeIntervalSeconds?: number;
|
|
10
|
+
maxBitrate?: string;
|
|
11
|
+
bufferSize?: string;
|
|
9
12
|
}
|
|
10
13
|
interface EncoderOptionsBody {
|
|
11
14
|
gifLoop?: unknown;
|
|
@@ -13,6 +16,9 @@ interface EncoderOptionsBody {
|
|
|
13
16
|
videoBitrate?: unknown;
|
|
14
17
|
videoFrameFormat?: unknown;
|
|
15
18
|
hdrMode?: unknown;
|
|
19
|
+
keyframeIntervalSeconds?: unknown;
|
|
20
|
+
maxBitrate?: unknown;
|
|
21
|
+
bufferSize?: unknown;
|
|
16
22
|
}
|
|
17
23
|
type Parsed = {
|
|
18
24
|
ok: true;
|
|
@@ -23,5 +29,6 @@ type Parsed = {
|
|
|
23
29
|
};
|
|
24
30
|
/** Explicit encoder overrides from a render request. MOV (ProRes) takes no rate control. */
|
|
25
31
|
declare function parseEncoderOptions(body: EncoderOptionsBody, format: string): Parsed;
|
|
32
|
+
declare function encoderJobOptions(opts: EncoderOptions): Omit<EncoderOptions, "gifLoop">;
|
|
26
33
|
|
|
27
|
-
export { type EncoderOptionsBody, parseEncoderOptions };
|
|
34
|
+
export { type EncoderOptionsBody, encoderJobOptions, parseEncoderOptions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '@hyperframes/core';
|
|
2
|
-
export { a as PreviewApiAdapter, P as PreviewDocumentStore, i as injectMediaCodecMap, f as injectMediaCodecMapIntoHtml, g as isAutoProxyEnabled, p as proxyEtagSalt, r as resolvePreviewMediaCodecProbeCache } from '../mediaProxyPreview-
|
|
2
|
+
export { a as PreviewApiAdapter, P as PreviewDocumentStore, i as injectMediaCodecMap, f as injectMediaCodecMapIntoHtml, g as isAutoProxyEnabled, p as proxyEtagSalt, r as resolvePreviewMediaCodecProbeCache } from '../mediaProxyPreview-DIEtpLJo.js';
|
|
3
3
|
import './mediaCodecMap.js';
|
|
4
4
|
import 'sharp';
|
|
5
5
|
import '@hyperframes/parsers';
|
package/dist/history/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-
|
|
3
|
-
export { L as LintResult, a as PreviewApiAdapter, R as RenderJobState, b as ResolvedProject, c as StudioSelectionResponse, d as StudioSelectionSnapshot, e as StudioSelectionTextField } from './mediaProxyPreview-
|
|
2
|
+
import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-DIEtpLJo.js';
|
|
3
|
+
export { L as LintResult, a as PreviewApiAdapter, R as RenderJobState, b as ResolvedProject, c as StudioSelectionResponse, d as StudioSelectionSnapshot, e as StudioSelectionTextField } from './mediaProxyPreview-DIEtpLJo.js';
|
|
4
4
|
export { C as ClosedWindow, D as DEFAULT_HISTORY_ROOT, S as HISTORY_START, H as HistoryClosedError, a as HistoryEntry, b as HistoryEntrySide, c as HistoryFileChange, d as HistoryListItem, e as HistoryRefusedError, f as HistoryResult, g as HistoryTarget, h as HistoryWho, i as HistoryWindow, M as MAX_WINDOW_IDLE_MS, P as ProjectHistory, j as ProjectHistoryOptions, k as ProjectHistoryView, U as UNDO_MODES, l as UndoMode, o as openProjectHistory, r as readProjectHistory } from './projectHistory-C18HDvac.js';
|
|
5
5
|
export { ArtifactCapture, ArtifactInput, ArtifactRecord, HistoryBusyError, HistoryIdError, ProjectHistoryRecord, PrunedHistory, ReclaimedHistory, RenderRecord, VideoState, artifactDirectory, beginArtifactCapture, finishSnapshotRun, forgetRecordedArtifacts, historyCache, listProjectHistories, pruneGoneProjectHistories, reclaimUncopiedBlobs, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput, retainSnapshotOutput } from './history/index.js';
|
|
6
6
|
export { CACHE_DIR_NAME as PROXY_CACHE_DIR_NAME } from './helpers/proxyTranscoder.js';
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from "./chunk-FJBJJURY.js";
|
|
25
25
|
import {
|
|
26
26
|
parseEncoderOptions
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-ZR3T4TKU.js";
|
|
28
28
|
import {
|
|
29
29
|
DEFAULT_HISTORY_ROOT,
|
|
30
30
|
DELETED_VERSION,
|
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
resolveProjectSignature,
|
|
63
63
|
retainSnapshotOutput,
|
|
64
64
|
settledFileTag
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-WAMZ2Z5O.js";
|
|
66
66
|
import {
|
|
67
67
|
clearElementScreenshotIsolation,
|
|
68
68
|
getElementScreenshotClip
|
|
@@ -3902,8 +3902,51 @@ import {
|
|
|
3902
3902
|
normalizeGsapBaseUrl,
|
|
3903
3903
|
normalizeGsapLocalRoot
|
|
3904
3904
|
} from "@hyperframes/core/gsap-cdn";
|
|
3905
|
-
import { findStartTags as
|
|
3905
|
+
import { findStartTags as findStartTags4, injectTagsAtHeadStart as injectTagsAtHeadStart2 } from "@hyperframes/core/compiler/html-document";
|
|
3906
3906
|
import { isWithinProjectRoot } from "@hyperframes/parsers/asset-resolution";
|
|
3907
|
+
|
|
3908
|
+
// src/helpers/rootImportMap.ts
|
|
3909
|
+
import { findStartTags as findStartTags2, injectTagsAtHeadStart } from "@hyperframes/core/compiler/html-document";
|
|
3910
|
+
var ROOT_PATH = /^\/(?!\/)/;
|
|
3911
|
+
var IMPORT_MAP_TYPE = /\btype\s*=\s*["']?importmap["']?(?=[\s/>])/i;
|
|
3912
|
+
function findImportMap(html) {
|
|
3913
|
+
for (const at of findStartTags2(html, "script")) {
|
|
3914
|
+
const open2 = /^<script\b[^>]*>/i.exec(html.slice(at));
|
|
3915
|
+
if (!open2 || !IMPORT_MAP_TYPE.test(open2[0])) continue;
|
|
3916
|
+
const start = at + open2[0].length;
|
|
3917
|
+
const end = html.toLowerCase().indexOf("</script", start);
|
|
3918
|
+
if (end !== -1) return { start, end, json: html.slice(start, end) };
|
|
3919
|
+
}
|
|
3920
|
+
return null;
|
|
3921
|
+
}
|
|
3922
|
+
function withRootImportMap(html, base) {
|
|
3923
|
+
const ours = { "/": base, [base]: base };
|
|
3924
|
+
const own = findImportMap(html);
|
|
3925
|
+
if (!own)
|
|
3926
|
+
return injectTagsAtHeadStart(
|
|
3927
|
+
html,
|
|
3928
|
+
`<script type="importmap">${JSON.stringify({ imports: ours })}</script>`
|
|
3929
|
+
);
|
|
3930
|
+
let map;
|
|
3931
|
+
try {
|
|
3932
|
+
map = JSON.parse(own.json);
|
|
3933
|
+
} catch {
|
|
3934
|
+
return html;
|
|
3935
|
+
}
|
|
3936
|
+
if (!map || typeof map !== "object") return html;
|
|
3937
|
+
const under = (path) => ROOT_PATH.test(path) && !path.startsWith(base) ? base + path.slice(1) : path;
|
|
3938
|
+
const moved = (entries = {}) => Object.fromEntries(
|
|
3939
|
+
Object.entries(entries).map(([key, target]) => [key, under(String(target))])
|
|
3940
|
+
);
|
|
3941
|
+
const merged = { ...map, imports: { ...ours, ...moved(map.imports) } };
|
|
3942
|
+
if (map.scopes)
|
|
3943
|
+
merged.scopes = Object.fromEntries(
|
|
3944
|
+
Object.entries(map.scopes).map(([scope, entries]) => [under(scope), moved(entries)])
|
|
3945
|
+
);
|
|
3946
|
+
return html.slice(0, own.start) + JSON.stringify(merged) + html.slice(own.end);
|
|
3947
|
+
}
|
|
3948
|
+
|
|
3949
|
+
// src/routes/preview.ts
|
|
3907
3950
|
import { ensureHfIds as ensureHfIds2 } from "@hyperframes/parsers/hf-ids";
|
|
3908
3951
|
|
|
3909
3952
|
// src/helpers/previewReads.ts
|
|
@@ -4037,7 +4080,7 @@ function injectPreviewVariables(html, values) {
|
|
|
4037
4080
|
}
|
|
4038
4081
|
|
|
4039
4082
|
// src/helpers/lazyPreviewImages.ts
|
|
4040
|
-
import { findStartTags as
|
|
4083
|
+
import { findStartTags as findStartTags3 } from "@hyperframes/core/compiler/html-document";
|
|
4041
4084
|
import { parseHTML as parseHTML6 } from "linkedom";
|
|
4042
4085
|
import { STUDIO_PREVIEW_LAZY_ATTR } from "@hyperframes/core/studio-preview-mark";
|
|
4043
4086
|
function startsAfterZero(el) {
|
|
@@ -4050,7 +4093,7 @@ var hasLoading = (img) => Array.from(img.attributes).some((attr) => attr.name.to
|
|
|
4050
4093
|
function lazyPreviewImages(html) {
|
|
4051
4094
|
if (!/<!doctype|<html[\s>]/i.test(html)) return html;
|
|
4052
4095
|
const images = [...parseHTML6(html).document.querySelectorAll("img")];
|
|
4053
|
-
const tags =
|
|
4096
|
+
const tags = findStartTags3(html, "img");
|
|
4054
4097
|
if (tags.length !== images.length) return html;
|
|
4055
4098
|
const parts = [];
|
|
4056
4099
|
let from = 0;
|
|
@@ -4136,7 +4179,7 @@ function injectMotionPathPluginIfNeeded(html, baseUrl) {
|
|
|
4136
4179
|
}
|
|
4137
4180
|
function findGsapCoreScript(html) {
|
|
4138
4181
|
const scripts = [...parseHTML7(html).document.querySelectorAll("script")];
|
|
4139
|
-
const starts =
|
|
4182
|
+
const starts = findStartTags4(html, "script");
|
|
4140
4183
|
if (starts.length !== scripts.length) return null;
|
|
4141
4184
|
const at = scripts.findIndex(
|
|
4142
4185
|
(script) => isGsapCoreUrl(lowerCaseAttributes(script).get("src") ?? "")
|
|
@@ -4242,16 +4285,16 @@ var PREVIEW_CAPTURE_PARAM = "hf-capture";
|
|
|
4242
4285
|
var EARLY_ERRORS_SCRIPT = `<script>(function(){var seen=window.${STUDIO_PREVIEW_ERRORS}=[];
|
|
4243
4286
|
addEventListener("error",function(e){seen.push(e.message||String(e))});})();</script>`;
|
|
4244
4287
|
function injectStudioPreviewAugmentations(html, adapter, projectDir, activeCompositionPath, options) {
|
|
4245
|
-
const marked = options.capture ?
|
|
4288
|
+
const marked = options.capture ? injectTagsAtHeadStart2(
|
|
4246
4289
|
html,
|
|
4247
4290
|
`<meta name="${STUDIO_PREVIEW_MARK_META}" content="${STUDIO_PREVIEW_CAPTURE_MODE}">`
|
|
4248
|
-
) :
|
|
4291
|
+
) : injectTagsAtHeadStart2(
|
|
4249
4292
|
lazyPreviewImages(html),
|
|
4250
4293
|
`<meta name="${STUDIO_PREVIEW_MARK_META}">${EARLY_ERRORS_SCRIPT}`
|
|
4251
4294
|
);
|
|
4252
4295
|
const withFallback = injectGsapCdnFallback(
|
|
4253
4296
|
injectProjectSignature(
|
|
4254
|
-
|
|
4297
|
+
injectTagsAtHeadStart2(
|
|
4255
4298
|
marked,
|
|
4256
4299
|
`<meta name="${GSAP_BASE_URL_META}" content="${escapeGsapUrl(options.gsapBaseUrl)}">`
|
|
4257
4300
|
),
|
|
@@ -4307,7 +4350,11 @@ var PREVIEW_BUNDLE_OPTIONS = {
|
|
|
4307
4350
|
sceneParts: true
|
|
4308
4351
|
};
|
|
4309
4352
|
var previewBaseHref = (projectId) => `/api/projects/${encodeURIComponent(projectId)}/preview/`;
|
|
4310
|
-
var withPreviewBase = (html, projectId) =>
|
|
4353
|
+
var withPreviewBase = (html, projectId) => {
|
|
4354
|
+
const base = previewBaseHref(projectId);
|
|
4355
|
+
const mapped = withRootImportMap(html, base);
|
|
4356
|
+
return hasBaseElement(mapped) ? mapped : injectTagsAtHeadStart2(mapped, `<base href="${base}">`);
|
|
4357
|
+
};
|
|
4311
4358
|
function resolvePreviewGsapBaseUrl(adapter) {
|
|
4312
4359
|
const configured = process.env.HYPERFRAMES_GSAP_BASE_URL;
|
|
4313
4360
|
if (configured?.trim() || !adapter.gsapLocalRoot) {
|
|
@@ -4482,6 +4529,7 @@ ${etag}`;
|
|
|
4482
4529
|
gsapBaseUrl
|
|
4483
4530
|
);
|
|
4484
4531
|
if (!html) return c.text("not found", 404);
|
|
4532
|
+
html = withRootImportMap(html, baseHref);
|
|
4485
4533
|
recordPreviewReferences(project.dir, html);
|
|
4486
4534
|
html = ensureHfIds2(await transformPreviewHtml(html, adapter, project, compPath));
|
|
4487
4535
|
html = injectStudioPreviewAugmentations(html, adapter, project.dir, compPath, {
|
|
@@ -6672,9 +6720,12 @@ function registerHistoryRoutes(api, adapter) {
|
|
|
6672
6720
|
}
|
|
6673
6721
|
|
|
6674
6722
|
// src/helpers/previewErrorPage.ts
|
|
6675
|
-
import {
|
|
6723
|
+
import {
|
|
6724
|
+
refusedPreviewMessage,
|
|
6725
|
+
STUDIO_PREVIEW_ERRORS as STUDIO_PREVIEW_ERRORS2
|
|
6726
|
+
} from "@hyperframes/core/studio-preview-mark";
|
|
6676
6727
|
function previewErrorPage(status) {
|
|
6677
|
-
const message =
|
|
6728
|
+
const message = refusedPreviewMessage(status);
|
|
6678
6729
|
return `<!doctype html><meta charset="utf-8"><script>window.${STUDIO_PREVIEW_ERRORS2}=[${JSON.stringify(message)}]</script><p>${message}</p>`;
|
|
6679
6730
|
}
|
|
6680
6731
|
|
|
@@ -167,6 +167,9 @@ interface StudioApiAdapter {
|
|
|
167
167
|
gifLoop?: number;
|
|
168
168
|
crf?: number;
|
|
169
169
|
videoBitrate?: string;
|
|
170
|
+
keyframeIntervalSeconds?: number;
|
|
171
|
+
maxBitrate?: string;
|
|
172
|
+
bufferSize?: string;
|
|
170
173
|
videoFrameFormat?: "auto" | "jpg" | "png";
|
|
171
174
|
hdrMode?: "auto" | "force-hdr" | "force-sdr";
|
|
172
175
|
jobId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio-server",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.208",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"linkedom": "^0.18.12",
|
|
85
85
|
"postcss": "^8.5.8",
|
|
86
86
|
"postcss-selector-parser": "^7.1.2",
|
|
87
|
-
"@hyperframes/
|
|
88
|
-
"@hyperframes/
|
|
87
|
+
"@hyperframes/core": "0.8.208",
|
|
88
|
+
"@hyperframes/parsers": "0.8.208"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@types/node": "^25.0.10",
|