hyperframes 0.4.4 → 0.4.6
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/cli.js
CHANGED
|
@@ -54,7 +54,7 @@ var VERSION;
|
|
|
54
54
|
var init_version = __esm({
|
|
55
55
|
"src/version.ts"() {
|
|
56
56
|
"use strict";
|
|
57
|
-
VERSION = true ? "0.4.
|
|
57
|
+
VERSION = true ? "0.4.6" : "0.0.0-dev";
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
|
|
@@ -6245,7 +6245,15 @@ function runSkillsAdd(repo) {
|
|
|
6245
6245
|
return new Promise((resolve35, reject) => {
|
|
6246
6246
|
const child = spawn("npx", ["skills", "add", repo, "--all"], {
|
|
6247
6247
|
stdio: "inherit",
|
|
6248
|
-
timeout: 12e4
|
|
6248
|
+
timeout: 12e4,
|
|
6249
|
+
// GH #316 — the upstream `skills` CLI shells out to `git clone`.
|
|
6250
|
+
// When Git's clone-hook protection is active (shipped on by
|
|
6251
|
+
// default in 2.45.1, reverted in 2.45.2, still present on many
|
|
6252
|
+
// corporate and CI setups), any globally-registered
|
|
6253
|
+
// `git lfs install` post-checkout hook aborts the clone. The
|
|
6254
|
+
// `repo` reaching this function is hardcoded in SOURCES below
|
|
6255
|
+
// — no user input reaches the spawn — so opting out here is safe.
|
|
6256
|
+
env: { ...process.env, GIT_CLONE_PROTECTION_ACTIVE: "0" }
|
|
6249
6257
|
});
|
|
6250
6258
|
child.on("close", (code, signal) => {
|
|
6251
6259
|
if (code === 0) resolve35();
|
|
@@ -10507,10 +10515,10 @@ function compareDocumentPosition(nodeA, nodeB) {
|
|
|
10507
10515
|
function uniqueSort(nodes) {
|
|
10508
10516
|
nodes = nodes.filter((node, i2, arr) => !arr.includes(node, i2 + 1));
|
|
10509
10517
|
nodes.sort((a, b) => {
|
|
10510
|
-
const
|
|
10511
|
-
if (
|
|
10518
|
+
const relative5 = compareDocumentPosition(a, b);
|
|
10519
|
+
if (relative5 & DocumentPosition.PRECEDING) {
|
|
10512
10520
|
return -1;
|
|
10513
|
-
} else if (
|
|
10521
|
+
} else if (relative5 & DocumentPosition.FOLLOWING) {
|
|
10514
10522
|
return 1;
|
|
10515
10523
|
}
|
|
10516
10524
|
return 0;
|
|
@@ -20930,6 +20938,15 @@ function isFontResourceError(type, text, locationUrl) {
|
|
|
20930
20938
|
`${locationUrl} ${text}`
|
|
20931
20939
|
);
|
|
20932
20940
|
}
|
|
20941
|
+
async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100) {
|
|
20942
|
+
const deadline = Date.now() + timeoutMs;
|
|
20943
|
+
while (Date.now() < deadline) {
|
|
20944
|
+
const ready = Boolean(await page.evaluate(expression));
|
|
20945
|
+
if (ready) return true;
|
|
20946
|
+
await new Promise((resolve35) => setTimeout(resolve35, intervalMs));
|
|
20947
|
+
}
|
|
20948
|
+
return Boolean(await page.evaluate(expression));
|
|
20949
|
+
}
|
|
20933
20950
|
async function initializeSession(session) {
|
|
20934
20951
|
const { page, serverUrl } = session;
|
|
20935
20952
|
page.on("console", (msg) => {
|
|
@@ -20959,14 +20976,26 @@ async function initializeSession(session) {
|
|
|
20959
20976
|
if (session.captureMode === "screenshot") {
|
|
20960
20977
|
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 6e4 });
|
|
20961
20978
|
const pageReadyTimeout2 = session.config?.playerReadyTimeout ?? DEFAULT_CONFIG2.playerReadyTimeout;
|
|
20962
|
-
await
|
|
20979
|
+
const pageReady2 = await pollPageExpression(
|
|
20980
|
+
page,
|
|
20963
20981
|
`!!(window.__hf && typeof window.__hf.seek === "function" && window.__hf.duration > 0)`,
|
|
20964
|
-
|
|
20982
|
+
pageReadyTimeout2
|
|
20965
20983
|
);
|
|
20966
|
-
|
|
20984
|
+
if (!pageReady2) {
|
|
20985
|
+
throw new Error(
|
|
20986
|
+
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout2}ms. Page must expose window.__hf = { duration, seek }.`
|
|
20987
|
+
);
|
|
20988
|
+
}
|
|
20989
|
+
const videosReady = await pollPageExpression(
|
|
20990
|
+
page,
|
|
20967
20991
|
`document.querySelectorAll("video").length === 0 || Array.from(document.querySelectorAll("video")).every(v => v.readyState >= 1)`,
|
|
20968
|
-
|
|
20992
|
+
pageReadyTimeout2
|
|
20969
20993
|
);
|
|
20994
|
+
if (!videosReady) {
|
|
20995
|
+
throw new Error(
|
|
20996
|
+
`[FrameCapture] video metadata not ready after ${pageReadyTimeout2}ms. Video elements must load metadata before capture starts.`
|
|
20997
|
+
);
|
|
20998
|
+
}
|
|
20970
20999
|
await page.evaluate(`document.fonts?.ready`);
|
|
20971
21000
|
session.isInitialized = true;
|
|
20972
21001
|
return;
|
|
@@ -24071,8 +24100,22 @@ function injectScriptsIntoHtml2(html, headScripts, bodyScripts, stripEmbedded) {
|
|
|
24071
24100
|
}
|
|
24072
24101
|
return html;
|
|
24073
24102
|
}
|
|
24103
|
+
function injectScriptsAtHeadStart(html, scripts) {
|
|
24104
|
+
if (scripts.length === 0) return html;
|
|
24105
|
+
const headTags = scripts.map((src) => `<script>${src}</script>`).join("\n");
|
|
24106
|
+
if (html.includes("<head")) {
|
|
24107
|
+
return html.replace(/<head\b[^>]*>/i, (match) => `${match}
|
|
24108
|
+
${headTags}`);
|
|
24109
|
+
}
|
|
24110
|
+
if (html.includes("<body")) {
|
|
24111
|
+
return html.replace("<body", () => `${headTags}
|
|
24112
|
+
<body`);
|
|
24113
|
+
}
|
|
24114
|
+
return headTags + "\n" + html;
|
|
24115
|
+
}
|
|
24074
24116
|
function createFileServer2(options) {
|
|
24075
24117
|
const { projectDir, compiledDir, port = 0, stripEmbeddedRuntime = true } = options;
|
|
24118
|
+
const preHeadScripts = options.preHeadScripts ?? [];
|
|
24076
24119
|
const headScripts = options.headScripts ?? [getVerifiedHyperframeRuntimeSource()];
|
|
24077
24120
|
const bodyScripts = options.bodyScripts ?? [RENDER_MODE_SCRIPT, HF_BRIDGE_SCRIPT];
|
|
24078
24121
|
const app = new Hono3();
|
|
@@ -24096,7 +24139,11 @@ function createFileServer2(options) {
|
|
|
24096
24139
|
if (ext === ".html") {
|
|
24097
24140
|
const rawHtml = readFileSync17(filePath, "utf-8");
|
|
24098
24141
|
const isIndex = relativePath === "index.html";
|
|
24099
|
-
|
|
24142
|
+
let html = rawHtml;
|
|
24143
|
+
if (preHeadScripts.length > 0) {
|
|
24144
|
+
html = injectScriptsAtHeadStart(html, preHeadScripts);
|
|
24145
|
+
}
|
|
24146
|
+
html = isIndex ? injectScriptsIntoHtml2(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
|
|
24100
24147
|
return c2.text(html, 200, { "Content-Type": contentType });
|
|
24101
24148
|
}
|
|
24102
24149
|
const content = readFileSync17(filePath);
|
|
@@ -24124,7 +24171,7 @@ function createFileServer2(options) {
|
|
|
24124
24171
|
});
|
|
24125
24172
|
});
|
|
24126
24173
|
}
|
|
24127
|
-
var MIME_TYPES3, RENDER_SEEK_MODE, RENDER_SEEK_DIAGNOSTICS, RENDER_SEEK_STEP, RENDER_SEEK_OFFSET_FRACTION, RENDER_MODE_SCRIPT, HF_BRIDGE_SCRIPT;
|
|
24174
|
+
var MIME_TYPES3, VIRTUAL_TIME_SHIM, RENDER_SEEK_MODE, RENDER_SEEK_DIAGNOSTICS, RENDER_SEEK_STEP, RENDER_SEEK_OFFSET_FRACTION, RENDER_MODE_SCRIPT, HF_BRIDGE_SCRIPT;
|
|
24128
24175
|
var init_fileServer2 = __esm({
|
|
24129
24176
|
"../producer/src/services/fileServer.ts"() {
|
|
24130
24177
|
"use strict";
|
|
@@ -24151,6 +24198,102 @@ var init_fileServer2 = __esm({
|
|
|
24151
24198
|
".ttf": "font/ttf",
|
|
24152
24199
|
".otf": "font/otf"
|
|
24153
24200
|
};
|
|
24201
|
+
VIRTUAL_TIME_SHIM = String.raw`(function() {
|
|
24202
|
+
if (window.__HF_VIRTUAL_TIME__) return;
|
|
24203
|
+
|
|
24204
|
+
var virtualNowMs = 0;
|
|
24205
|
+
var rafId = 1;
|
|
24206
|
+
var rafQueue = [];
|
|
24207
|
+
var OriginalDate = Date;
|
|
24208
|
+
var originalSetTimeout = window.setTimeout.bind(window);
|
|
24209
|
+
var originalClearTimeout = window.clearTimeout.bind(window);
|
|
24210
|
+
var originalSetInterval = window.setInterval.bind(window);
|
|
24211
|
+
var originalClearInterval = window.clearInterval.bind(window);
|
|
24212
|
+
var originalRequestAnimationFrame = window.requestAnimationFrame
|
|
24213
|
+
? window.requestAnimationFrame.bind(window)
|
|
24214
|
+
: null;
|
|
24215
|
+
var originalCancelAnimationFrame = window.cancelAnimationFrame
|
|
24216
|
+
? window.cancelAnimationFrame.bind(window)
|
|
24217
|
+
: null;
|
|
24218
|
+
|
|
24219
|
+
function flushAnimationFrame() {
|
|
24220
|
+
if (!rafQueue.length) return;
|
|
24221
|
+
var current = rafQueue.slice();
|
|
24222
|
+
rafQueue.length = 0;
|
|
24223
|
+
for (var i = 0; i < current.length; i++) {
|
|
24224
|
+
var entry = current[i];
|
|
24225
|
+
if (entry.cancelled) continue;
|
|
24226
|
+
try {
|
|
24227
|
+
entry.callback(virtualNowMs);
|
|
24228
|
+
} catch {}
|
|
24229
|
+
}
|
|
24230
|
+
}
|
|
24231
|
+
|
|
24232
|
+
function VirtualDate() {
|
|
24233
|
+
var args = Array.prototype.slice.call(arguments);
|
|
24234
|
+
if (!(this instanceof VirtualDate)) {
|
|
24235
|
+
return OriginalDate.apply(null, args.length ? args : [virtualNowMs]);
|
|
24236
|
+
}
|
|
24237
|
+
var instance = args.length ? new (Function.prototype.bind.apply(OriginalDate, [null].concat(args)))() : new OriginalDate(virtualNowMs);
|
|
24238
|
+
Object.setPrototypeOf(instance, VirtualDate.prototype);
|
|
24239
|
+
return instance;
|
|
24240
|
+
}
|
|
24241
|
+
|
|
24242
|
+
VirtualDate.prototype = OriginalDate.prototype;
|
|
24243
|
+
Object.setPrototypeOf(VirtualDate, OriginalDate);
|
|
24244
|
+
VirtualDate.now = function() { return virtualNowMs; };
|
|
24245
|
+
VirtualDate.parse = OriginalDate.parse.bind(OriginalDate);
|
|
24246
|
+
VirtualDate.UTC = OriginalDate.UTC.bind(OriginalDate);
|
|
24247
|
+
|
|
24248
|
+
try {
|
|
24249
|
+
Object.defineProperty(window, "Date", {
|
|
24250
|
+
configurable: true,
|
|
24251
|
+
writable: true,
|
|
24252
|
+
value: VirtualDate,
|
|
24253
|
+
});
|
|
24254
|
+
} catch {}
|
|
24255
|
+
|
|
24256
|
+
if (window.performance && typeof window.performance.now === "function") {
|
|
24257
|
+
try {
|
|
24258
|
+
Object.defineProperty(window.performance, "now", {
|
|
24259
|
+
configurable: true,
|
|
24260
|
+
value: function() { return virtualNowMs; },
|
|
24261
|
+
});
|
|
24262
|
+
} catch {}
|
|
24263
|
+
}
|
|
24264
|
+
|
|
24265
|
+
window.requestAnimationFrame = function(callback) {
|
|
24266
|
+
if (typeof callback !== "function") return 0;
|
|
24267
|
+
var entry = { id: rafId++, callback: callback, cancelled: false };
|
|
24268
|
+
rafQueue.push(entry);
|
|
24269
|
+
return entry.id;
|
|
24270
|
+
};
|
|
24271
|
+
window.cancelAnimationFrame = function(id) {
|
|
24272
|
+
for (var i = 0; i < rafQueue.length; i++) {
|
|
24273
|
+
if (rafQueue[i].id === id) {
|
|
24274
|
+
rafQueue[i].cancelled = true;
|
|
24275
|
+
}
|
|
24276
|
+
}
|
|
24277
|
+
};
|
|
24278
|
+
|
|
24279
|
+
window.__HF_VIRTUAL_TIME__ = {
|
|
24280
|
+
originalSetTimeout: originalSetTimeout,
|
|
24281
|
+
originalClearTimeout: originalClearTimeout,
|
|
24282
|
+
originalSetInterval: originalSetInterval,
|
|
24283
|
+
originalClearInterval: originalClearInterval,
|
|
24284
|
+
originalRequestAnimationFrame: originalRequestAnimationFrame,
|
|
24285
|
+
originalCancelAnimationFrame: originalCancelAnimationFrame,
|
|
24286
|
+
seekToTime: function(nextTimeMs) {
|
|
24287
|
+
var safeTimeMs = Math.max(0, Number(nextTimeMs) || 0);
|
|
24288
|
+
virtualNowMs = safeTimeMs;
|
|
24289
|
+
flushAnimationFrame();
|
|
24290
|
+
return virtualNowMs;
|
|
24291
|
+
},
|
|
24292
|
+
getTime: function() {
|
|
24293
|
+
return virtualNowMs;
|
|
24294
|
+
},
|
|
24295
|
+
};
|
|
24296
|
+
})();`;
|
|
24154
24297
|
RENDER_SEEK_MODE = process.env.PRODUCER_RUNTIME_RENDER_SEEK_MODE === "strict-boundary" ? "strict-boundary" : "preview-phase";
|
|
24155
24298
|
RENDER_SEEK_DIAGNOSTICS = process.env.PRODUCER_DEBUG_SEEK_DIAGNOSTICS === "true";
|
|
24156
24299
|
RENDER_SEEK_STEP = Math.max(
|
|
@@ -24162,6 +24305,10 @@ var init_fileServer2 = __esm({
|
|
|
24162
24305
|
Math.min(0.95, Number(process.env.PRODUCER_RUNTIME_RENDER_SEEK_OFFSET_FRACTION || 0.5))
|
|
24163
24306
|
);
|
|
24164
24307
|
RENDER_MODE_SCRIPT = `(function() {
|
|
24308
|
+
var __realSetTimeout =
|
|
24309
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalSetTimeout === "function"
|
|
24310
|
+
? window.__HF_VIRTUAL_TIME__.originalSetTimeout
|
|
24311
|
+
: window.setTimeout.bind(window);
|
|
24165
24312
|
var __seekMode = ${JSON.stringify(RENDER_SEEK_MODE)};
|
|
24166
24313
|
var __seekDiagnostics = ${RENDER_SEEK_DIAGNOSTICS ? "true" : "false"};
|
|
24167
24314
|
var __seekStep = ${RENDER_SEEK_STEP};
|
|
@@ -24255,23 +24402,56 @@ var init_fileServer2 = __esm({
|
|
|
24255
24402
|
window.__renderReady = true;
|
|
24256
24403
|
return;
|
|
24257
24404
|
}
|
|
24258
|
-
|
|
24405
|
+
__realSetTimeout(waitForPlayer, 50);
|
|
24259
24406
|
return;
|
|
24260
24407
|
}
|
|
24261
24408
|
if (installMediaFallbackPlayer()) {
|
|
24262
24409
|
return;
|
|
24263
24410
|
}
|
|
24264
|
-
|
|
24411
|
+
__realSetTimeout(waitForPlayer, 50);
|
|
24265
24412
|
}
|
|
24266
24413
|
waitForPlayer();
|
|
24267
24414
|
})();`;
|
|
24268
24415
|
HF_BRIDGE_SCRIPT = `(function() {
|
|
24416
|
+
var __realSetInterval =
|
|
24417
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalSetInterval === "function"
|
|
24418
|
+
? window.__HF_VIRTUAL_TIME__.originalSetInterval
|
|
24419
|
+
: window.setInterval.bind(window);
|
|
24420
|
+
var __realClearInterval =
|
|
24421
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalClearInterval === "function"
|
|
24422
|
+
? window.__HF_VIRTUAL_TIME__.originalClearInterval
|
|
24423
|
+
: window.clearInterval.bind(window);
|
|
24269
24424
|
function getDeclaredDuration() {
|
|
24270
24425
|
var root = document.querySelector('[data-composition-id]');
|
|
24271
24426
|
if (!root) return 0;
|
|
24272
24427
|
var d = Number(root.getAttribute('data-duration'));
|
|
24273
24428
|
return Number.isFinite(d) && d > 0 ? d : 0;
|
|
24274
24429
|
}
|
|
24430
|
+
function seekSameOriginChildFrames(frameWindow, nextTimeMs) {
|
|
24431
|
+
var frames;
|
|
24432
|
+
try {
|
|
24433
|
+
frames = frameWindow.frames;
|
|
24434
|
+
} catch (_error) {
|
|
24435
|
+
return;
|
|
24436
|
+
}
|
|
24437
|
+
if (!frames || typeof frames.length !== "number") return;
|
|
24438
|
+
for (var i = 0; i < frames.length; i++) {
|
|
24439
|
+
var childWindow = null;
|
|
24440
|
+
try {
|
|
24441
|
+
childWindow = frames[i];
|
|
24442
|
+
if (!childWindow || childWindow === frameWindow) continue;
|
|
24443
|
+
if (
|
|
24444
|
+
childWindow.__HF_VIRTUAL_TIME__ &&
|
|
24445
|
+
typeof childWindow.__HF_VIRTUAL_TIME__.seekToTime === "function"
|
|
24446
|
+
) {
|
|
24447
|
+
childWindow.__HF_VIRTUAL_TIME__.seekToTime(nextTimeMs);
|
|
24448
|
+
}
|
|
24449
|
+
} catch (_error) {
|
|
24450
|
+
continue;
|
|
24451
|
+
}
|
|
24452
|
+
seekSameOriginChildFrames(childWindow, nextTimeMs);
|
|
24453
|
+
}
|
|
24454
|
+
}
|
|
24275
24455
|
function bridge() {
|
|
24276
24456
|
var p = window.__player;
|
|
24277
24457
|
if (!p || typeof p.renderSeek !== "function" || typeof p.getDuration !== "function") {
|
|
@@ -24282,13 +24462,20 @@ var init_fileServer2 = __esm({
|
|
|
24282
24462
|
var d = p.getDuration();
|
|
24283
24463
|
return d > 0 ? d : getDeclaredDuration();
|
|
24284
24464
|
},
|
|
24285
|
-
seek: function(t) {
|
|
24465
|
+
seek: function(t) {
|
|
24466
|
+
p.renderSeek(t);
|
|
24467
|
+
var nextTimeMs = (Math.max(0, Number(t) || 0)) * 1000;
|
|
24468
|
+
if (window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.seekToTime === "function") {
|
|
24469
|
+
window.__HF_VIRTUAL_TIME__.seekToTime(nextTimeMs);
|
|
24470
|
+
}
|
|
24471
|
+
seekSameOriginChildFrames(window, nextTimeMs);
|
|
24472
|
+
},
|
|
24286
24473
|
};
|
|
24287
24474
|
return true;
|
|
24288
24475
|
}
|
|
24289
24476
|
if (bridge()) return;
|
|
24290
|
-
var iv =
|
|
24291
|
-
if (bridge())
|
|
24477
|
+
var iv = __realSetInterval(function() {
|
|
24478
|
+
if (bridge()) __realClearInterval(iv);
|
|
24292
24479
|
}, 50);
|
|
24293
24480
|
})();`;
|
|
24294
24481
|
}
|
|
@@ -24302,6 +24489,40 @@ var init_ffprobe2 = __esm({
|
|
|
24302
24489
|
}
|
|
24303
24490
|
});
|
|
24304
24491
|
|
|
24492
|
+
// ../producer/src/utils/paths.ts
|
|
24493
|
+
import { resolve as resolve13, basename, join as join27, relative as relative2, isAbsolute as isAbsolute3 } from "path";
|
|
24494
|
+
function isPathInside(childPath, parentPath) {
|
|
24495
|
+
const absChild = resolve13(childPath);
|
|
24496
|
+
const absParent = resolve13(parentPath);
|
|
24497
|
+
if (absChild === absParent) return true;
|
|
24498
|
+
const rel = relative2(absParent, absChild);
|
|
24499
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
|
|
24500
|
+
}
|
|
24501
|
+
function toExternalAssetKey(absPath) {
|
|
24502
|
+
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
24503
|
+
let normalised = absPath.replace(/\\/g, "/");
|
|
24504
|
+
normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
|
|
24505
|
+
normalised = normalised.replace(/^\/\/\?\//, "");
|
|
24506
|
+
normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
|
|
24507
|
+
normalised = normalised.replace(/^\/+/, "");
|
|
24508
|
+
normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
|
|
24509
|
+
return "hf-ext/" + normalised;
|
|
24510
|
+
}
|
|
24511
|
+
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
24512
|
+
const absoluteProjectDir = resolve13(projectDir);
|
|
24513
|
+
const projectName = basename(absoluteProjectDir);
|
|
24514
|
+
const resolvedOutputPath = outputPath ?? join27(rendersDir, `${projectName}.mp4`);
|
|
24515
|
+
const absoluteOutputPath = resolve13(resolvedOutputPath);
|
|
24516
|
+
return { absoluteProjectDir, absoluteOutputPath };
|
|
24517
|
+
}
|
|
24518
|
+
var DEFAULT_RENDERS_DIR;
|
|
24519
|
+
var init_paths = __esm({
|
|
24520
|
+
"../producer/src/utils/paths.ts"() {
|
|
24521
|
+
"use strict";
|
|
24522
|
+
DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve13(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
24523
|
+
}
|
|
24524
|
+
});
|
|
24525
|
+
|
|
24305
24526
|
// ../producer/src/utils/urlDownloader.ts
|
|
24306
24527
|
var init_urlDownloader2 = __esm({
|
|
24307
24528
|
"../producer/src/utils/urlDownloader.ts"() {
|
|
@@ -24365,7 +24586,7 @@ var init_fontData_generated = __esm({
|
|
|
24365
24586
|
// ../producer/src/services/deterministicFonts.ts
|
|
24366
24587
|
import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
|
|
24367
24588
|
import { homedir as homedir6 } from "os";
|
|
24368
|
-
import { join as
|
|
24589
|
+
import { join as join28 } from "path";
|
|
24369
24590
|
function normalizeFamilyName(family) {
|
|
24370
24591
|
return family.trim().replace(/^['"]|['"]$/g, "").trim().toLowerCase();
|
|
24371
24592
|
}
|
|
@@ -24476,14 +24697,14 @@ function fontSlug(familyName) {
|
|
|
24476
24697
|
return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
24477
24698
|
}
|
|
24478
24699
|
function fontCacheDir(slug) {
|
|
24479
|
-
const dir =
|
|
24700
|
+
const dir = join28(GOOGLE_FONTS_CACHE_DIR, slug);
|
|
24480
24701
|
if (!existsSync25(dir)) {
|
|
24481
24702
|
mkdirSync15(dir, { recursive: true });
|
|
24482
24703
|
}
|
|
24483
24704
|
return dir;
|
|
24484
24705
|
}
|
|
24485
24706
|
function cachedWoff2Path(slug, weight, style) {
|
|
24486
|
-
return
|
|
24707
|
+
return join28(fontCacheDir(slug), `${weight}-${style}.woff2`);
|
|
24487
24708
|
}
|
|
24488
24709
|
async function fetchGoogleFont(familyName) {
|
|
24489
24710
|
const slug = fontSlug(familyName);
|
|
@@ -24695,14 +24916,14 @@ var init_deterministicFonts = __esm({
|
|
|
24695
24916
|
poppins: "poppins",
|
|
24696
24917
|
"segoe ui": "roboto"
|
|
24697
24918
|
};
|
|
24698
|
-
GOOGLE_FONTS_CACHE_DIR =
|
|
24919
|
+
GOOGLE_FONTS_CACHE_DIR = join28(homedir6(), ".cache", "hyperframes", "fonts");
|
|
24699
24920
|
WOFF2_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
|
|
24700
24921
|
}
|
|
24701
24922
|
});
|
|
24702
24923
|
|
|
24703
24924
|
// ../producer/src/services/htmlCompiler.ts
|
|
24704
24925
|
import { readFileSync as readFileSync19, existsSync as existsSync26, mkdirSync as mkdirSync16 } from "fs";
|
|
24705
|
-
import { join as
|
|
24926
|
+
import { join as join29, dirname as dirname9, resolve as resolve14 } from "path";
|
|
24706
24927
|
import postcss from "postcss";
|
|
24707
24928
|
function dedupeElementsById(elements) {
|
|
24708
24929
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -24711,6 +24932,36 @@ function dedupeElementsById(elements) {
|
|
|
24711
24932
|
}
|
|
24712
24933
|
return Array.from(deduped.values());
|
|
24713
24934
|
}
|
|
24935
|
+
function stripJsComments(source) {
|
|
24936
|
+
return source.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
24937
|
+
}
|
|
24938
|
+
function detectRenderModeHints(html) {
|
|
24939
|
+
const reasons = [];
|
|
24940
|
+
const { document: document2 } = parseHTML(html);
|
|
24941
|
+
if (document2.querySelector("iframe")) {
|
|
24942
|
+
reasons.push({
|
|
24943
|
+
code: "iframe",
|
|
24944
|
+
message: "Detected <iframe> in the composition DOM. Nested iframe animation is routed through screenshot capture mode for compatibility."
|
|
24945
|
+
});
|
|
24946
|
+
}
|
|
24947
|
+
let scriptMatch;
|
|
24948
|
+
const scriptPattern = new RegExp(INLINE_SCRIPT_PATTERN.source, INLINE_SCRIPT_PATTERN.flags);
|
|
24949
|
+
while ((scriptMatch = scriptPattern.exec(html)) !== null) {
|
|
24950
|
+
const attrs = scriptMatch[1] || "";
|
|
24951
|
+
if (/\bsrc\s*=/i.test(attrs)) continue;
|
|
24952
|
+
const content = stripJsComments(scriptMatch[2] || "");
|
|
24953
|
+
if (!/requestAnimationFrame\s*\(/.test(content)) continue;
|
|
24954
|
+
reasons.push({
|
|
24955
|
+
code: "requestAnimationFrame",
|
|
24956
|
+
message: "Detected raw requestAnimationFrame() in an inline script. This render is routed through screenshot capture mode with virtual time enabled."
|
|
24957
|
+
});
|
|
24958
|
+
break;
|
|
24959
|
+
}
|
|
24960
|
+
return {
|
|
24961
|
+
recommendScreenshot: reasons.length > 0,
|
|
24962
|
+
reasons
|
|
24963
|
+
};
|
|
24964
|
+
}
|
|
24714
24965
|
async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
|
|
24715
24966
|
let filePath = src;
|
|
24716
24967
|
if (isHttpUrl(src)) {
|
|
@@ -24721,7 +24972,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
24721
24972
|
return { duration: 0, resolvedPath: src };
|
|
24722
24973
|
}
|
|
24723
24974
|
} else if (!filePath.startsWith("/")) {
|
|
24724
|
-
filePath =
|
|
24975
|
+
filePath = join29(baseDir, filePath);
|
|
24725
24976
|
}
|
|
24726
24977
|
if (!existsSync26(filePath)) {
|
|
24727
24978
|
return { duration: 0, resolvedPath: filePath };
|
|
@@ -24787,7 +25038,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
24787
25038
|
const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
|
|
24788
25039
|
const absoluteStart = parentOffset + elStart;
|
|
24789
25040
|
const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
|
|
24790
|
-
const filePath =
|
|
25041
|
+
const filePath = resolve14(projectDir, srcPath);
|
|
24791
25042
|
if (visited.has(filePath)) {
|
|
24792
25043
|
continue;
|
|
24793
25044
|
}
|
|
@@ -24987,7 +25238,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
24987
25238
|
if (!srcPath) continue;
|
|
24988
25239
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
24989
25240
|
if (!compHtml) {
|
|
24990
|
-
const filePath =
|
|
25241
|
+
const filePath = resolve14(projectDir, srcPath);
|
|
24991
25242
|
if (existsSync26(filePath)) {
|
|
24992
25243
|
compHtml = readFileSync19(filePath, "utf-8");
|
|
24993
25244
|
}
|
|
@@ -25200,7 +25451,7 @@ ${safeText}
|
|
|
25200
25451
|
return result;
|
|
25201
25452
|
}
|
|
25202
25453
|
function collectExternalAssets(html, projectDir) {
|
|
25203
|
-
const absProjectDir =
|
|
25454
|
+
const absProjectDir = resolve14(projectDir);
|
|
25204
25455
|
const externalAssets = /* @__PURE__ */ new Map();
|
|
25205
25456
|
const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
25206
25457
|
function processPath(rawPath) {
|
|
@@ -25208,12 +25459,12 @@ function collectExternalAssets(html, projectDir) {
|
|
|
25208
25459
|
if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
|
|
25209
25460
|
return null;
|
|
25210
25461
|
}
|
|
25211
|
-
const absPath =
|
|
25212
|
-
if (
|
|
25462
|
+
const absPath = resolve14(absProjectDir, trimmed);
|
|
25463
|
+
if (isPathInside(absPath, absProjectDir)) {
|
|
25213
25464
|
return null;
|
|
25214
25465
|
}
|
|
25215
25466
|
if (!existsSync26(absPath)) return null;
|
|
25216
|
-
const safeKey =
|
|
25467
|
+
const safeKey = toExternalAssetKey(absPath);
|
|
25217
25468
|
externalAssets.set(safeKey, absPath);
|
|
25218
25469
|
return safeKey;
|
|
25219
25470
|
}
|
|
@@ -25274,6 +25525,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
25274
25525
|
/(<(?:video|audio)\b[^>]*?)\s+preload\s*=\s*["']none["']/gi,
|
|
25275
25526
|
"$1"
|
|
25276
25527
|
);
|
|
25528
|
+
const renderModeHints = detectRenderModeHints(sanitizedHtml);
|
|
25277
25529
|
const coalescedHtml = await injectDeterministicFontFaces(
|
|
25278
25530
|
coalesceHeadStylesAndBodyScripts2(promoteCssImportsToLinkTags(sanitizedHtml))
|
|
25279
25531
|
);
|
|
@@ -25285,7 +25537,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
25285
25537
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
25286
25538
|
for (const video of videos) {
|
|
25287
25539
|
if (isHttpUrl(video.src)) continue;
|
|
25288
|
-
const videoPath =
|
|
25540
|
+
const videoPath = resolve14(projectDir, video.src);
|
|
25289
25541
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
25290
25542
|
Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
25291
25543
|
if (analysis.isProblematic) {
|
|
@@ -25317,7 +25569,8 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
25317
25569
|
externalAssets,
|
|
25318
25570
|
width,
|
|
25319
25571
|
height,
|
|
25320
|
-
staticDuration
|
|
25572
|
+
staticDuration,
|
|
25573
|
+
renderModeHints
|
|
25321
25574
|
};
|
|
25322
25575
|
}
|
|
25323
25576
|
async function discoverMediaFromBrowser(page) {
|
|
@@ -25411,18 +25664,22 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
25411
25664
|
subCompositions,
|
|
25412
25665
|
videos,
|
|
25413
25666
|
audios,
|
|
25414
|
-
unresolvedCompositions: remaining
|
|
25667
|
+
unresolvedCompositions: remaining,
|
|
25668
|
+
renderModeHints: compiled.renderModeHints
|
|
25415
25669
|
};
|
|
25416
25670
|
}
|
|
25671
|
+
var INLINE_SCRIPT_PATTERN;
|
|
25417
25672
|
var init_htmlCompiler2 = __esm({
|
|
25418
25673
|
"../producer/src/services/htmlCompiler.ts"() {
|
|
25419
25674
|
"use strict";
|
|
25420
25675
|
init_esm10();
|
|
25421
25676
|
init_src();
|
|
25422
25677
|
init_ffprobe2();
|
|
25678
|
+
init_paths();
|
|
25423
25679
|
init_src2();
|
|
25424
25680
|
init_urlDownloader2();
|
|
25425
25681
|
init_deterministicFonts();
|
|
25682
|
+
INLINE_SCRIPT_PATTERN = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
25426
25683
|
}
|
|
25427
25684
|
});
|
|
25428
25685
|
|
|
@@ -25478,7 +25735,7 @@ import {
|
|
|
25478
25735
|
copyFileSync as copyFileSync2,
|
|
25479
25736
|
appendFileSync
|
|
25480
25737
|
} from "fs";
|
|
25481
|
-
import { join as
|
|
25738
|
+
import { join as join30, dirname as dirname10, resolve as resolve15 } from "path";
|
|
25482
25739
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
25483
25740
|
import { freemem as freemem2 } from "os";
|
|
25484
25741
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -25534,17 +25791,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
|
|
|
25534
25791
|
};
|
|
25535
25792
|
}
|
|
25536
25793
|
function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
25537
|
-
const compileDir =
|
|
25794
|
+
const compileDir = join30(workDir, "compiled");
|
|
25538
25795
|
mkdirSync17(compileDir, { recursive: true });
|
|
25539
|
-
writeFileSync10(
|
|
25796
|
+
writeFileSync10(join30(compileDir, "index.html"), compiled.html, "utf-8");
|
|
25540
25797
|
for (const [srcPath, html] of compiled.subCompositions) {
|
|
25541
|
-
const outPath =
|
|
25798
|
+
const outPath = join30(compileDir, srcPath);
|
|
25542
25799
|
mkdirSync17(dirname10(outPath), { recursive: true });
|
|
25543
25800
|
writeFileSync10(outPath, html, "utf-8");
|
|
25544
25801
|
}
|
|
25545
25802
|
for (const [relativePath, absolutePath] of compiled.externalAssets) {
|
|
25546
|
-
const outPath =
|
|
25547
|
-
if (!outPath
|
|
25803
|
+
const outPath = resolve15(join30(compileDir, relativePath));
|
|
25804
|
+
if (!isPathInside(outPath, compileDir)) {
|
|
25548
25805
|
console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
|
|
25549
25806
|
continue;
|
|
25550
25807
|
}
|
|
@@ -25570,11 +25827,20 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
|
25570
25827
|
end: a.end,
|
|
25571
25828
|
mediaStart: a.mediaStart
|
|
25572
25829
|
})),
|
|
25573
|
-
subCompositions: Array.from(compiled.subCompositions.keys())
|
|
25830
|
+
subCompositions: Array.from(compiled.subCompositions.keys()),
|
|
25831
|
+
renderModeHints: compiled.renderModeHints
|
|
25574
25832
|
};
|
|
25575
|
-
writeFileSync10(
|
|
25833
|
+
writeFileSync10(join30(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
|
|
25576
25834
|
}
|
|
25577
25835
|
}
|
|
25836
|
+
function applyRenderModeHints(cfg, compiled, log = defaultLogger) {
|
|
25837
|
+
if (cfg.forceScreenshot || !compiled.renderModeHints.recommendScreenshot) return;
|
|
25838
|
+
cfg.forceScreenshot = true;
|
|
25839
|
+
log.warn("Auto-selected screenshot capture mode for render compatibility", {
|
|
25840
|
+
reasonCodes: compiled.renderModeHints.reasons.map((reason) => reason.code),
|
|
25841
|
+
reasons: compiled.renderModeHints.reasons.map((reason) => reason.message)
|
|
25842
|
+
});
|
|
25843
|
+
}
|
|
25578
25844
|
function createRenderJob(config) {
|
|
25579
25845
|
return {
|
|
25580
25846
|
id: randomUUID2(),
|
|
@@ -25616,9 +25882,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
|
|
|
25616
25882
|
}
|
|
25617
25883
|
async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
|
|
25618
25884
|
const moduleDir = dirname10(fileURLToPath3(import.meta.url));
|
|
25619
|
-
const producerRoot = process.env.PRODUCER_RENDERS_DIR ?
|
|
25620
|
-
const debugDir =
|
|
25621
|
-
const workDir = job.config.debug ?
|
|
25885
|
+
const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve15(process.env.PRODUCER_RENDERS_DIR, "..") : resolve15(moduleDir, "../..");
|
|
25886
|
+
const debugDir = join30(producerRoot, ".debug");
|
|
25887
|
+
const workDir = job.config.debug ? join30(debugDir, job.id) : join30(dirname10(outputPath), `work-${job.id}`);
|
|
25622
25888
|
const pipelineStart = Date.now();
|
|
25623
25889
|
const log = job.config.logger ?? defaultLogger;
|
|
25624
25890
|
let fileServer = null;
|
|
@@ -25626,7 +25892,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25626
25892
|
let lastBrowserConsole = [];
|
|
25627
25893
|
let restoreLogger = null;
|
|
25628
25894
|
const perfStages = {};
|
|
25629
|
-
const perfOutputPath =
|
|
25895
|
+
const perfOutputPath = join30(workDir, "perf-summary.json");
|
|
25630
25896
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
25631
25897
|
const outputFormat = job.config.format ?? "mp4";
|
|
25632
25898
|
const isWebm = outputFormat === "webm";
|
|
@@ -25648,19 +25914,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25648
25914
|
assertNotAborted();
|
|
25649
25915
|
if (!existsSync27(workDir)) mkdirSync17(workDir, { recursive: true });
|
|
25650
25916
|
if (job.config.debug) {
|
|
25651
|
-
const logPath =
|
|
25917
|
+
const logPath = join30(workDir, "render.log");
|
|
25652
25918
|
restoreLogger = installDebugLogger(logPath, log);
|
|
25653
25919
|
}
|
|
25654
25920
|
const entryFile = job.config.entryFile || "index.html";
|
|
25655
|
-
let htmlPath =
|
|
25921
|
+
let htmlPath = join30(projectDir, entryFile);
|
|
25656
25922
|
if (!existsSync27(htmlPath)) {
|
|
25657
25923
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
25658
25924
|
}
|
|
25659
25925
|
assertNotAborted();
|
|
25660
25926
|
const rawEntry = readFileSync20(htmlPath, "utf-8");
|
|
25661
25927
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
25662
|
-
const wrapperPath =
|
|
25663
|
-
const projectIndexPath =
|
|
25928
|
+
const wrapperPath = join30(workDir, "standalone-entry.html");
|
|
25929
|
+
const projectIndexPath = join30(projectDir, "index.html");
|
|
25664
25930
|
if (!existsSync27(projectIndexPath)) {
|
|
25665
25931
|
throw new Error(
|
|
25666
25932
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
@@ -25684,9 +25950,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25684
25950
|
const stage1Start = Date.now();
|
|
25685
25951
|
updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
|
|
25686
25952
|
const compileStart = Date.now();
|
|
25687
|
-
let compiled = await compileForRender(projectDir, htmlPath,
|
|
25953
|
+
let compiled = await compileForRender(projectDir, htmlPath, join30(workDir, "downloads"));
|
|
25688
25954
|
assertNotAborted();
|
|
25689
25955
|
perfStages.compileOnlyMs = Date.now() - compileStart;
|
|
25956
|
+
applyRenderModeHints(cfg, compiled, log);
|
|
25690
25957
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
25691
25958
|
log.info("Compiled composition metadata", {
|
|
25692
25959
|
entryFile,
|
|
@@ -25694,7 +25961,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25694
25961
|
width: compiled.width,
|
|
25695
25962
|
height: compiled.height,
|
|
25696
25963
|
videoCount: compiled.videos.length,
|
|
25697
|
-
audioCount: compiled.audios.length
|
|
25964
|
+
audioCount: compiled.audios.length,
|
|
25965
|
+
renderModeHints: compiled.renderModeHints
|
|
25698
25966
|
});
|
|
25699
25967
|
const composition = {
|
|
25700
25968
|
duration: compiled.staticDuration,
|
|
@@ -25713,8 +25981,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25713
25981
|
reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
|
|
25714
25982
|
fileServer = await createFileServer2({
|
|
25715
25983
|
projectDir,
|
|
25716
|
-
compiledDir:
|
|
25717
|
-
port: 0
|
|
25984
|
+
compiledDir: join30(workDir, "compiled"),
|
|
25985
|
+
port: 0,
|
|
25986
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
25718
25987
|
});
|
|
25719
25988
|
assertNotAborted();
|
|
25720
25989
|
const captureOpts = {
|
|
@@ -25726,7 +25995,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25726
25995
|
};
|
|
25727
25996
|
probeSession = await createCaptureSession(
|
|
25728
25997
|
fileServer.url,
|
|
25729
|
-
|
|
25998
|
+
join30(workDir, "probe"),
|
|
25730
25999
|
captureOpts,
|
|
25731
26000
|
null,
|
|
25732
26001
|
cfg
|
|
@@ -25758,7 +26027,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25758
26027
|
compiled,
|
|
25759
26028
|
resolutions,
|
|
25760
26029
|
projectDir,
|
|
25761
|
-
|
|
26030
|
+
join30(workDir, "downloads")
|
|
25762
26031
|
);
|
|
25763
26032
|
assertNotAborted();
|
|
25764
26033
|
composition.videos = compiled.videos;
|
|
@@ -25893,12 +26162,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25893
26162
|
const stage2Start = Date.now();
|
|
25894
26163
|
updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
|
|
25895
26164
|
let frameLookup = null;
|
|
25896
|
-
const compiledDir =
|
|
26165
|
+
const compiledDir = join30(workDir, "compiled");
|
|
25897
26166
|
if (composition.videos.length > 0) {
|
|
25898
26167
|
const extractionResult = await extractAllVideoFrames(
|
|
25899
26168
|
composition.videos,
|
|
25900
26169
|
projectDir,
|
|
25901
|
-
{ fps: job.config.fps, outputDir:
|
|
26170
|
+
{ fps: job.config.fps, outputDir: join30(workDir, "video-frames") },
|
|
25902
26171
|
abortSignal,
|
|
25903
26172
|
void 0,
|
|
25904
26173
|
compiledDir
|
|
@@ -25932,13 +26201,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25932
26201
|
}
|
|
25933
26202
|
const stage3Start = Date.now();
|
|
25934
26203
|
updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
|
|
25935
|
-
const audioOutputPath =
|
|
26204
|
+
const audioOutputPath = join30(workDir, "audio.aac");
|
|
25936
26205
|
let hasAudio = false;
|
|
25937
26206
|
if (composition.audios.length > 0) {
|
|
25938
26207
|
const audioResult = await processCompositionAudio(
|
|
25939
26208
|
composition.audios,
|
|
25940
26209
|
projectDir,
|
|
25941
|
-
|
|
26210
|
+
join30(workDir, "audio-work"),
|
|
25942
26211
|
audioOutputPath,
|
|
25943
26212
|
job.duration,
|
|
25944
26213
|
abortSignal,
|
|
@@ -25956,12 +26225,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25956
26225
|
if (!fileServer) {
|
|
25957
26226
|
fileServer = await createFileServer2({
|
|
25958
26227
|
projectDir,
|
|
25959
|
-
compiledDir:
|
|
25960
|
-
port: 0
|
|
26228
|
+
compiledDir: join30(workDir, "compiled"),
|
|
26229
|
+
port: 0,
|
|
26230
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
25961
26231
|
});
|
|
25962
26232
|
assertNotAborted();
|
|
25963
26233
|
}
|
|
25964
|
-
const framesDir =
|
|
26234
|
+
const framesDir = join30(workDir, "captured-frames");
|
|
25965
26235
|
if (!existsSync27(framesDir)) mkdirSync17(framesDir, { recursive: true });
|
|
25966
26236
|
const captureOptions = {
|
|
25967
26237
|
width,
|
|
@@ -25973,7 +26243,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
25973
26243
|
const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
|
|
25974
26244
|
const FORMAT_EXT2 = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
25975
26245
|
const videoExt = FORMAT_EXT2[outputFormat] ?? ".mp4";
|
|
25976
|
-
const videoOnlyPath =
|
|
26246
|
+
const videoOnlyPath = join30(workDir, `video-only${videoExt}`);
|
|
25977
26247
|
const preset = getEncoderPreset(job.config.quality, outputFormat);
|
|
25978
26248
|
const effectiveQuality = job.config.crf ?? preset.quality;
|
|
25979
26249
|
const effectiveBitrate = job.config.videoBitrate;
|
|
@@ -26249,7 +26519,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
26249
26519
|
}
|
|
26250
26520
|
if (job.config.debug) {
|
|
26251
26521
|
if (existsSync27(outputPath)) {
|
|
26252
|
-
const debugOutput =
|
|
26522
|
+
const debugOutput = join30(workDir, `output${videoExt}`);
|
|
26253
26523
|
copyFileSync2(outputPath, debugOutput);
|
|
26254
26524
|
}
|
|
26255
26525
|
} else {
|
|
@@ -26350,6 +26620,7 @@ var init_renderOrchestrator = __esm({
|
|
|
26350
26620
|
init_fileServer2();
|
|
26351
26621
|
init_htmlCompiler2();
|
|
26352
26622
|
init_logger();
|
|
26623
|
+
init_paths();
|
|
26353
26624
|
RenderCancelledError = class extends Error {
|
|
26354
26625
|
reason;
|
|
26355
26626
|
constructor(message = "render_cancelled", reason = "aborted") {
|
|
@@ -26387,7 +26658,7 @@ var init_config3 = __esm({
|
|
|
26387
26658
|
|
|
26388
26659
|
// ../producer/src/services/hyperframeLint.ts
|
|
26389
26660
|
import { existsSync as existsSync28, readFileSync as readFileSync21, statSync as statSync8 } from "fs";
|
|
26390
|
-
import { resolve as
|
|
26661
|
+
import { resolve as resolve16, join as join31 } from "path";
|
|
26391
26662
|
function isStringRecord(value) {
|
|
26392
26663
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
26393
26664
|
return false;
|
|
@@ -26414,7 +26685,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
26414
26685
|
return null;
|
|
26415
26686
|
}
|
|
26416
26687
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
26417
|
-
const absProjectDir =
|
|
26688
|
+
const absProjectDir = resolve16(projectDir);
|
|
26418
26689
|
if (!existsSync28(absProjectDir) || !statSync8(absProjectDir).isDirectory()) {
|
|
26419
26690
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
26420
26691
|
}
|
|
@@ -26422,7 +26693,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
26422
26693
|
(value) => typeof value === "string" && value.trim().length > 0
|
|
26423
26694
|
);
|
|
26424
26695
|
for (const entryFile of entryCandidates) {
|
|
26425
|
-
const absoluteEntryPath =
|
|
26696
|
+
const absoluteEntryPath = resolve16(absProjectDir, entryFile);
|
|
26426
26697
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
26427
26698
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
26428
26699
|
}
|
|
@@ -26435,7 +26706,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
26435
26706
|
}
|
|
26436
26707
|
}
|
|
26437
26708
|
return {
|
|
26438
|
-
error: `No HTML entry file found in project directory: ${
|
|
26709
|
+
error: `No HTML entry file found in project directory: ${join31(absProjectDir, preferredEntryFile || "index.html")}`
|
|
26439
26710
|
};
|
|
26440
26711
|
}
|
|
26441
26712
|
function prepareHyperframeLintBody(body) {
|
|
@@ -26481,23 +26752,6 @@ var init_hyperframeLint = __esm({
|
|
|
26481
26752
|
}
|
|
26482
26753
|
});
|
|
26483
26754
|
|
|
26484
|
-
// ../producer/src/utils/paths.ts
|
|
26485
|
-
import { resolve as resolve16, basename, join as join31 } from "path";
|
|
26486
|
-
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
26487
|
-
const absoluteProjectDir = resolve16(projectDir);
|
|
26488
|
-
const projectName = basename(absoluteProjectDir);
|
|
26489
|
-
const resolvedOutputPath = outputPath ?? join31(rendersDir, `${projectName}.mp4`);
|
|
26490
|
-
const absoluteOutputPath = resolve16(resolvedOutputPath);
|
|
26491
|
-
return { absoluteProjectDir, absoluteOutputPath };
|
|
26492
|
-
}
|
|
26493
|
-
var DEFAULT_RENDERS_DIR;
|
|
26494
|
-
var init_paths = __esm({
|
|
26495
|
-
"../producer/src/utils/paths.ts"() {
|
|
26496
|
-
"use strict";
|
|
26497
|
-
DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve16(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
26498
|
-
}
|
|
26499
|
-
});
|
|
26500
|
-
|
|
26501
26755
|
// ../producer/src/utils/semaphore.ts
|
|
26502
26756
|
var Semaphore;
|
|
26503
26757
|
var init_semaphore = __esm({
|
|
@@ -28300,7 +28554,7 @@ __export(add_exports, {
|
|
|
28300
28554
|
runAdd: () => runAdd
|
|
28301
28555
|
});
|
|
28302
28556
|
import { existsSync as existsSync33 } from "fs";
|
|
28303
|
-
import { resolve as resolve21, relative as
|
|
28557
|
+
import { resolve as resolve21, relative as relative3 } from "path";
|
|
28304
28558
|
function remapTarget(item, originalTarget, paths) {
|
|
28305
28559
|
if (item.type === "hyperframes:block") {
|
|
28306
28560
|
const blocksDir = paths.blocks.replace(/\/+$/, "");
|
|
@@ -28439,7 +28693,7 @@ var init_add = __esm({
|
|
|
28439
28693
|
console.log("");
|
|
28440
28694
|
console.log(`${c.success("\u2713")} Added ${c.accent(result.name)} (${result.type})`);
|
|
28441
28695
|
for (const file of result.written) {
|
|
28442
|
-
console.log(` ${c.dim(
|
|
28696
|
+
console.log(` ${c.dim(relative3(projectDir, file))}`);
|
|
28443
28697
|
}
|
|
28444
28698
|
if (result.snippet) {
|
|
28445
28699
|
console.log("");
|
|
@@ -30868,18 +31122,18 @@ function checkFFmpeg() {
|
|
|
30868
31122
|
return {
|
|
30869
31123
|
ok: false,
|
|
30870
31124
|
detail: "Not found",
|
|
30871
|
-
hint:
|
|
31125
|
+
hint: getFFmpegInstallHint()
|
|
30872
31126
|
};
|
|
30873
31127
|
}
|
|
30874
31128
|
function checkFFprobe() {
|
|
30875
31129
|
try {
|
|
30876
|
-
const
|
|
30877
|
-
return { ok: true, detail:
|
|
31130
|
+
const version = execSync3("ffprobe -version", { encoding: "utf-8", timeout: 5e3 }).split("\n")[0] ?? "";
|
|
31131
|
+
return { ok: true, detail: version.trim() };
|
|
30878
31132
|
} catch {
|
|
30879
31133
|
return {
|
|
30880
31134
|
ok: false,
|
|
30881
31135
|
detail: "Not found",
|
|
30882
|
-
hint:
|
|
31136
|
+
hint: `Installed with ffmpeg \u2014 ${getFFmpegInstallHint()}`
|
|
30883
31137
|
};
|
|
30884
31138
|
}
|
|
30885
31139
|
}
|
|
@@ -31531,7 +31785,7 @@ __export(snapshot_exports, {
|
|
|
31531
31785
|
examples: () => examples18
|
|
31532
31786
|
});
|
|
31533
31787
|
import { existsSync as existsSync44, readFileSync as readFileSync31, mkdirSync as mkdirSync24 } from "fs";
|
|
31534
|
-
import { resolve as resolve32, join as join44, dirname as dirname20, relative as
|
|
31788
|
+
import { resolve as resolve32, join as join44, dirname as dirname20, relative as relative4, isAbsolute as isAbsolute4 } from "path";
|
|
31535
31789
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
31536
31790
|
async function captureSnapshots(projectDir, opts) {
|
|
31537
31791
|
const { bundleToSingleHtml: bundleToSingleHtml2 } = await Promise.resolve().then(() => (init_compiler(), compiler_exports));
|
|
@@ -31564,8 +31818,8 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
31564
31818
|
return;
|
|
31565
31819
|
}
|
|
31566
31820
|
const filePath = resolve32(projectDir, decodeURIComponent(url).replace(/^\//, ""));
|
|
31567
|
-
const rel =
|
|
31568
|
-
if (rel.startsWith("..") ||
|
|
31821
|
+
const rel = relative4(projectDir, filePath);
|
|
31822
|
+
if (rel.startsWith("..") || isAbsolute4(rel)) {
|
|
31569
31823
|
res.writeHead(403);
|
|
31570
31824
|
res.end();
|
|
31571
31825
|
return;
|