@hyperframes/producer 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/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +5 -5
- package/dist/index.js +321 -78
- package/dist/index.js.map +4 -4
- package/dist/public-server.js +321 -78
- package/dist/public-server.js.map +4 -4
- package/dist/services/fileServer.d.ts +11 -0
- package/dist/services/fileServer.d.ts.map +1 -1
- package/dist/services/htmlCompiler.d.ts +11 -0
- package/dist/services/htmlCompiler.d.ts.map +1 -1
- package/dist/services/renderOrchestrator.d.ts +6 -0
- package/dist/services/renderOrchestrator.d.ts.map +1 -1
- package/dist/utils/paths.d.ts +35 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -57865,7 +57865,7 @@ var require_util2 = __commonJS({
|
|
|
57865
57865
|
}
|
|
57866
57866
|
path12 = url.path;
|
|
57867
57867
|
}
|
|
57868
|
-
var
|
|
57868
|
+
var isAbsolute3 = exports.isAbsolute(path12);
|
|
57869
57869
|
var parts = path12.split(/\/+/);
|
|
57870
57870
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
57871
57871
|
part = parts[i];
|
|
@@ -57885,7 +57885,7 @@ var require_util2 = __commonJS({
|
|
|
57885
57885
|
}
|
|
57886
57886
|
path12 = parts.join("/");
|
|
57887
57887
|
if (path12 === "") {
|
|
57888
|
-
path12 =
|
|
57888
|
+
path12 = isAbsolute3 ? "/" : ".";
|
|
57889
57889
|
}
|
|
57890
57890
|
if (url) {
|
|
57891
57891
|
url.path = path12;
|
|
@@ -57930,7 +57930,7 @@ var require_util2 = __commonJS({
|
|
|
57930
57930
|
exports.isAbsolute = function(aPath) {
|
|
57931
57931
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
57932
57932
|
};
|
|
57933
|
-
function
|
|
57933
|
+
function relative3(aRoot, aPath) {
|
|
57934
57934
|
if (aRoot === "") {
|
|
57935
57935
|
aRoot = ".";
|
|
57936
57936
|
}
|
|
@@ -57949,7 +57949,7 @@ var require_util2 = __commonJS({
|
|
|
57949
57949
|
}
|
|
57950
57950
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
57951
57951
|
}
|
|
57952
|
-
exports.relative =
|
|
57952
|
+
exports.relative = relative3;
|
|
57953
57953
|
var supportsNullProto = (function() {
|
|
57954
57954
|
var obj = /* @__PURE__ */ Object.create(null);
|
|
57955
57955
|
return !("__proto__" in obj);
|
|
@@ -92714,10 +92714,10 @@ function compareDocumentPosition(nodeA, nodeB) {
|
|
|
92714
92714
|
function uniqueSort(nodes) {
|
|
92715
92715
|
nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
|
|
92716
92716
|
nodes.sort((a, b) => {
|
|
92717
|
-
const
|
|
92718
|
-
if (
|
|
92717
|
+
const relative3 = compareDocumentPosition(a, b);
|
|
92718
|
+
if (relative3 & DocumentPosition.PRECEDING) {
|
|
92719
92719
|
return -1;
|
|
92720
|
-
} else if (
|
|
92720
|
+
} else if (relative3 & DocumentPosition.FOLLOWING) {
|
|
92721
92721
|
return 1;
|
|
92722
92722
|
}
|
|
92723
92723
|
return 0;
|
|
@@ -101071,6 +101071,15 @@ function isFontResourceError(type, text, locationUrl) {
|
|
|
101071
101071
|
`${locationUrl} ${text}`
|
|
101072
101072
|
);
|
|
101073
101073
|
}
|
|
101074
|
+
async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100) {
|
|
101075
|
+
const deadline = Date.now() + timeoutMs;
|
|
101076
|
+
while (Date.now() < deadline) {
|
|
101077
|
+
const ready = Boolean(await page.evaluate(expression));
|
|
101078
|
+
if (ready) return true;
|
|
101079
|
+
await new Promise((resolve13) => setTimeout(resolve13, intervalMs));
|
|
101080
|
+
}
|
|
101081
|
+
return Boolean(await page.evaluate(expression));
|
|
101082
|
+
}
|
|
101074
101083
|
async function initializeSession(session) {
|
|
101075
101084
|
const { page, serverUrl } = session;
|
|
101076
101085
|
page.on("console", (msg) => {
|
|
@@ -101100,14 +101109,26 @@ async function initializeSession(session) {
|
|
|
101100
101109
|
if (session.captureMode === "screenshot") {
|
|
101101
101110
|
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 6e4 });
|
|
101102
101111
|
const pageReadyTimeout2 = session.config?.playerReadyTimeout ?? DEFAULT_CONFIG.playerReadyTimeout;
|
|
101103
|
-
await
|
|
101112
|
+
const pageReady2 = await pollPageExpression(
|
|
101113
|
+
page,
|
|
101104
101114
|
`!!(window.__hf && typeof window.__hf.seek === "function" && window.__hf.duration > 0)`,
|
|
101105
|
-
|
|
101115
|
+
pageReadyTimeout2
|
|
101106
101116
|
);
|
|
101107
|
-
|
|
101117
|
+
if (!pageReady2) {
|
|
101118
|
+
throw new Error(
|
|
101119
|
+
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout2}ms. Page must expose window.__hf = { duration, seek }.`
|
|
101120
|
+
);
|
|
101121
|
+
}
|
|
101122
|
+
const videosReady = await pollPageExpression(
|
|
101123
|
+
page,
|
|
101108
101124
|
`document.querySelectorAll("video").length === 0 || Array.from(document.querySelectorAll("video")).every(v => v.readyState >= 1)`,
|
|
101109
|
-
|
|
101125
|
+
pageReadyTimeout2
|
|
101110
101126
|
);
|
|
101127
|
+
if (!videosReady) {
|
|
101128
|
+
throw new Error(
|
|
101129
|
+
`[FrameCapture] video metadata not ready after ${pageReadyTimeout2}ms. Video elements must load metadata before capture starts.`
|
|
101130
|
+
);
|
|
101131
|
+
}
|
|
101111
101132
|
await page.evaluate(`document.fonts?.ready`);
|
|
101112
101133
|
session.isInitialized = true;
|
|
101113
101134
|
return;
|
|
@@ -105766,7 +105787,7 @@ var serve = (options, listeningListener) => {
|
|
|
105766
105787
|
};
|
|
105767
105788
|
|
|
105768
105789
|
// src/services/renderOrchestrator.ts
|
|
105769
|
-
import { join as
|
|
105790
|
+
import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
|
|
105770
105791
|
import { randomUUID } from "crypto";
|
|
105771
105792
|
import { freemem as freemem2 } from "os";
|
|
105772
105793
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -105871,6 +105892,102 @@ var MIME_TYPES = {
|
|
|
105871
105892
|
".ttf": "font/ttf",
|
|
105872
105893
|
".otf": "font/otf"
|
|
105873
105894
|
};
|
|
105895
|
+
var VIRTUAL_TIME_SHIM = String.raw`(function() {
|
|
105896
|
+
if (window.__HF_VIRTUAL_TIME__) return;
|
|
105897
|
+
|
|
105898
|
+
var virtualNowMs = 0;
|
|
105899
|
+
var rafId = 1;
|
|
105900
|
+
var rafQueue = [];
|
|
105901
|
+
var OriginalDate = Date;
|
|
105902
|
+
var originalSetTimeout = window.setTimeout.bind(window);
|
|
105903
|
+
var originalClearTimeout = window.clearTimeout.bind(window);
|
|
105904
|
+
var originalSetInterval = window.setInterval.bind(window);
|
|
105905
|
+
var originalClearInterval = window.clearInterval.bind(window);
|
|
105906
|
+
var originalRequestAnimationFrame = window.requestAnimationFrame
|
|
105907
|
+
? window.requestAnimationFrame.bind(window)
|
|
105908
|
+
: null;
|
|
105909
|
+
var originalCancelAnimationFrame = window.cancelAnimationFrame
|
|
105910
|
+
? window.cancelAnimationFrame.bind(window)
|
|
105911
|
+
: null;
|
|
105912
|
+
|
|
105913
|
+
function flushAnimationFrame() {
|
|
105914
|
+
if (!rafQueue.length) return;
|
|
105915
|
+
var current = rafQueue.slice();
|
|
105916
|
+
rafQueue.length = 0;
|
|
105917
|
+
for (var i = 0; i < current.length; i++) {
|
|
105918
|
+
var entry = current[i];
|
|
105919
|
+
if (entry.cancelled) continue;
|
|
105920
|
+
try {
|
|
105921
|
+
entry.callback(virtualNowMs);
|
|
105922
|
+
} catch {}
|
|
105923
|
+
}
|
|
105924
|
+
}
|
|
105925
|
+
|
|
105926
|
+
function VirtualDate() {
|
|
105927
|
+
var args = Array.prototype.slice.call(arguments);
|
|
105928
|
+
if (!(this instanceof VirtualDate)) {
|
|
105929
|
+
return OriginalDate.apply(null, args.length ? args : [virtualNowMs]);
|
|
105930
|
+
}
|
|
105931
|
+
var instance = args.length ? new (Function.prototype.bind.apply(OriginalDate, [null].concat(args)))() : new OriginalDate(virtualNowMs);
|
|
105932
|
+
Object.setPrototypeOf(instance, VirtualDate.prototype);
|
|
105933
|
+
return instance;
|
|
105934
|
+
}
|
|
105935
|
+
|
|
105936
|
+
VirtualDate.prototype = OriginalDate.prototype;
|
|
105937
|
+
Object.setPrototypeOf(VirtualDate, OriginalDate);
|
|
105938
|
+
VirtualDate.now = function() { return virtualNowMs; };
|
|
105939
|
+
VirtualDate.parse = OriginalDate.parse.bind(OriginalDate);
|
|
105940
|
+
VirtualDate.UTC = OriginalDate.UTC.bind(OriginalDate);
|
|
105941
|
+
|
|
105942
|
+
try {
|
|
105943
|
+
Object.defineProperty(window, "Date", {
|
|
105944
|
+
configurable: true,
|
|
105945
|
+
writable: true,
|
|
105946
|
+
value: VirtualDate,
|
|
105947
|
+
});
|
|
105948
|
+
} catch {}
|
|
105949
|
+
|
|
105950
|
+
if (window.performance && typeof window.performance.now === "function") {
|
|
105951
|
+
try {
|
|
105952
|
+
Object.defineProperty(window.performance, "now", {
|
|
105953
|
+
configurable: true,
|
|
105954
|
+
value: function() { return virtualNowMs; },
|
|
105955
|
+
});
|
|
105956
|
+
} catch {}
|
|
105957
|
+
}
|
|
105958
|
+
|
|
105959
|
+
window.requestAnimationFrame = function(callback) {
|
|
105960
|
+
if (typeof callback !== "function") return 0;
|
|
105961
|
+
var entry = { id: rafId++, callback: callback, cancelled: false };
|
|
105962
|
+
rafQueue.push(entry);
|
|
105963
|
+
return entry.id;
|
|
105964
|
+
};
|
|
105965
|
+
window.cancelAnimationFrame = function(id) {
|
|
105966
|
+
for (var i = 0; i < rafQueue.length; i++) {
|
|
105967
|
+
if (rafQueue[i].id === id) {
|
|
105968
|
+
rafQueue[i].cancelled = true;
|
|
105969
|
+
}
|
|
105970
|
+
}
|
|
105971
|
+
};
|
|
105972
|
+
|
|
105973
|
+
window.__HF_VIRTUAL_TIME__ = {
|
|
105974
|
+
originalSetTimeout: originalSetTimeout,
|
|
105975
|
+
originalClearTimeout: originalClearTimeout,
|
|
105976
|
+
originalSetInterval: originalSetInterval,
|
|
105977
|
+
originalClearInterval: originalClearInterval,
|
|
105978
|
+
originalRequestAnimationFrame: originalRequestAnimationFrame,
|
|
105979
|
+
originalCancelAnimationFrame: originalCancelAnimationFrame,
|
|
105980
|
+
seekToTime: function(nextTimeMs) {
|
|
105981
|
+
var safeTimeMs = Math.max(0, Number(nextTimeMs) || 0);
|
|
105982
|
+
virtualNowMs = safeTimeMs;
|
|
105983
|
+
flushAnimationFrame();
|
|
105984
|
+
return virtualNowMs;
|
|
105985
|
+
},
|
|
105986
|
+
getTime: function() {
|
|
105987
|
+
return virtualNowMs;
|
|
105988
|
+
},
|
|
105989
|
+
};
|
|
105990
|
+
})();`;
|
|
105874
105991
|
var RENDER_SEEK_MODE = process.env.PRODUCER_RUNTIME_RENDER_SEEK_MODE === "strict-boundary" ? "strict-boundary" : "preview-phase";
|
|
105875
105992
|
var RENDER_SEEK_DIAGNOSTICS = process.env.PRODUCER_DEBUG_SEEK_DIAGNOSTICS === "true";
|
|
105876
105993
|
var RENDER_SEEK_STEP = Math.max(
|
|
@@ -105882,6 +105999,10 @@ var RENDER_SEEK_OFFSET_FRACTION = Math.max(
|
|
|
105882
105999
|
Math.min(0.95, Number(process.env.PRODUCER_RUNTIME_RENDER_SEEK_OFFSET_FRACTION || 0.5))
|
|
105883
106000
|
);
|
|
105884
106001
|
var RENDER_MODE_SCRIPT = `(function() {
|
|
106002
|
+
var __realSetTimeout =
|
|
106003
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalSetTimeout === "function"
|
|
106004
|
+
? window.__HF_VIRTUAL_TIME__.originalSetTimeout
|
|
106005
|
+
: window.setTimeout.bind(window);
|
|
105885
106006
|
var __seekMode = ${JSON.stringify(RENDER_SEEK_MODE)};
|
|
105886
106007
|
var __seekDiagnostics = ${RENDER_SEEK_DIAGNOSTICS ? "true" : "false"};
|
|
105887
106008
|
var __seekStep = ${RENDER_SEEK_STEP};
|
|
@@ -105975,23 +106096,56 @@ var RENDER_MODE_SCRIPT = `(function() {
|
|
|
105975
106096
|
window.__renderReady = true;
|
|
105976
106097
|
return;
|
|
105977
106098
|
}
|
|
105978
|
-
|
|
106099
|
+
__realSetTimeout(waitForPlayer, 50);
|
|
105979
106100
|
return;
|
|
105980
106101
|
}
|
|
105981
106102
|
if (installMediaFallbackPlayer()) {
|
|
105982
106103
|
return;
|
|
105983
106104
|
}
|
|
105984
|
-
|
|
106105
|
+
__realSetTimeout(waitForPlayer, 50);
|
|
105985
106106
|
}
|
|
105986
106107
|
waitForPlayer();
|
|
105987
106108
|
})();`;
|
|
105988
106109
|
var HF_BRIDGE_SCRIPT = `(function() {
|
|
106110
|
+
var __realSetInterval =
|
|
106111
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalSetInterval === "function"
|
|
106112
|
+
? window.__HF_VIRTUAL_TIME__.originalSetInterval
|
|
106113
|
+
: window.setInterval.bind(window);
|
|
106114
|
+
var __realClearInterval =
|
|
106115
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalClearInterval === "function"
|
|
106116
|
+
? window.__HF_VIRTUAL_TIME__.originalClearInterval
|
|
106117
|
+
: window.clearInterval.bind(window);
|
|
105989
106118
|
function getDeclaredDuration() {
|
|
105990
106119
|
var root = document.querySelector('[data-composition-id]');
|
|
105991
106120
|
if (!root) return 0;
|
|
105992
106121
|
var d = Number(root.getAttribute('data-duration'));
|
|
105993
106122
|
return Number.isFinite(d) && d > 0 ? d : 0;
|
|
105994
106123
|
}
|
|
106124
|
+
function seekSameOriginChildFrames(frameWindow, nextTimeMs) {
|
|
106125
|
+
var frames;
|
|
106126
|
+
try {
|
|
106127
|
+
frames = frameWindow.frames;
|
|
106128
|
+
} catch (_error) {
|
|
106129
|
+
return;
|
|
106130
|
+
}
|
|
106131
|
+
if (!frames || typeof frames.length !== "number") return;
|
|
106132
|
+
for (var i = 0; i < frames.length; i++) {
|
|
106133
|
+
var childWindow = null;
|
|
106134
|
+
try {
|
|
106135
|
+
childWindow = frames[i];
|
|
106136
|
+
if (!childWindow || childWindow === frameWindow) continue;
|
|
106137
|
+
if (
|
|
106138
|
+
childWindow.__HF_VIRTUAL_TIME__ &&
|
|
106139
|
+
typeof childWindow.__HF_VIRTUAL_TIME__.seekToTime === "function"
|
|
106140
|
+
) {
|
|
106141
|
+
childWindow.__HF_VIRTUAL_TIME__.seekToTime(nextTimeMs);
|
|
106142
|
+
}
|
|
106143
|
+
} catch (_error) {
|
|
106144
|
+
continue;
|
|
106145
|
+
}
|
|
106146
|
+
seekSameOriginChildFrames(childWindow, nextTimeMs);
|
|
106147
|
+
}
|
|
106148
|
+
}
|
|
105995
106149
|
function bridge() {
|
|
105996
106150
|
var p = window.__player;
|
|
105997
106151
|
if (!p || typeof p.renderSeek !== "function" || typeof p.getDuration !== "function") {
|
|
@@ -106002,13 +106156,20 @@ var HF_BRIDGE_SCRIPT = `(function() {
|
|
|
106002
106156
|
var d = p.getDuration();
|
|
106003
106157
|
return d > 0 ? d : getDeclaredDuration();
|
|
106004
106158
|
},
|
|
106005
|
-
seek: function(t) {
|
|
106159
|
+
seek: function(t) {
|
|
106160
|
+
p.renderSeek(t);
|
|
106161
|
+
var nextTimeMs = (Math.max(0, Number(t) || 0)) * 1000;
|
|
106162
|
+
if (window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.seekToTime === "function") {
|
|
106163
|
+
window.__HF_VIRTUAL_TIME__.seekToTime(nextTimeMs);
|
|
106164
|
+
}
|
|
106165
|
+
seekSameOriginChildFrames(window, nextTimeMs);
|
|
106166
|
+
},
|
|
106006
106167
|
};
|
|
106007
106168
|
return true;
|
|
106008
106169
|
}
|
|
106009
106170
|
if (bridge()) return;
|
|
106010
|
-
var iv =
|
|
106011
|
-
if (bridge())
|
|
106171
|
+
var iv = __realSetInterval(function() {
|
|
106172
|
+
if (bridge()) __realClearInterval(iv);
|
|
106012
106173
|
}, 50);
|
|
106013
106174
|
})();`;
|
|
106014
106175
|
function stripEmbeddedRuntimeScripts(html) {
|
|
@@ -106070,8 +106231,22 @@ function injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbedded) {
|
|
|
106070
106231
|
}
|
|
106071
106232
|
return html;
|
|
106072
106233
|
}
|
|
106234
|
+
function injectScriptsAtHeadStart(html, scripts) {
|
|
106235
|
+
if (scripts.length === 0) return html;
|
|
106236
|
+
const headTags = scripts.map((src) => `<script>${src}</script>`).join("\n");
|
|
106237
|
+
if (html.includes("<head")) {
|
|
106238
|
+
return html.replace(/<head\b[^>]*>/i, (match2) => `${match2}
|
|
106239
|
+
${headTags}`);
|
|
106240
|
+
}
|
|
106241
|
+
if (html.includes("<body")) {
|
|
106242
|
+
return html.replace("<body", () => `${headTags}
|
|
106243
|
+
<body`);
|
|
106244
|
+
}
|
|
106245
|
+
return headTags + "\n" + html;
|
|
106246
|
+
}
|
|
106073
106247
|
function createFileServer2(options) {
|
|
106074
106248
|
const { projectDir, compiledDir, port = 0, stripEmbeddedRuntime = true } = options;
|
|
106249
|
+
const preHeadScripts = options.preHeadScripts ?? [];
|
|
106075
106250
|
const headScripts = options.headScripts ?? [getVerifiedHyperframeRuntimeSource()];
|
|
106076
106251
|
const bodyScripts = options.bodyScripts ?? [RENDER_MODE_SCRIPT, HF_BRIDGE_SCRIPT];
|
|
106077
106252
|
const app = new Hono2();
|
|
@@ -106095,7 +106270,11 @@ function createFileServer2(options) {
|
|
|
106095
106270
|
if (ext === ".html") {
|
|
106096
106271
|
const rawHtml = readFileSync6(filePath, "utf-8");
|
|
106097
106272
|
const isIndex = relativePath === "index.html";
|
|
106098
|
-
|
|
106273
|
+
let html = rawHtml;
|
|
106274
|
+
if (preHeadScripts.length > 0) {
|
|
106275
|
+
html = injectScriptsAtHeadStart(html, preHeadScripts);
|
|
106276
|
+
}
|
|
106277
|
+
html = isIndex ? injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
|
|
106099
106278
|
return c.text(html, 200, { "Content-Type": contentType });
|
|
106100
106279
|
}
|
|
106101
106280
|
const content = readFileSync6(filePath);
|
|
@@ -106126,13 +106305,41 @@ function createFileServer2(options) {
|
|
|
106126
106305
|
|
|
106127
106306
|
// src/services/htmlCompiler.ts
|
|
106128
106307
|
import { readFileSync as readFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
106129
|
-
import { join as
|
|
106308
|
+
import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
|
|
106130
106309
|
import postcss from "postcss";
|
|
106131
106310
|
|
|
106311
|
+
// src/utils/paths.ts
|
|
106312
|
+
import { resolve as resolve8, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
|
|
106313
|
+
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve8(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
106314
|
+
function isPathInside(childPath, parentPath) {
|
|
106315
|
+
const absChild = resolve8(childPath);
|
|
106316
|
+
const absParent = resolve8(parentPath);
|
|
106317
|
+
if (absChild === absParent) return true;
|
|
106318
|
+
const rel = relative2(absParent, absChild);
|
|
106319
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
106320
|
+
}
|
|
106321
|
+
function toExternalAssetKey(absPath) {
|
|
106322
|
+
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
106323
|
+
let normalised = absPath.replace(/\\/g, "/");
|
|
106324
|
+
normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
|
|
106325
|
+
normalised = normalised.replace(/^\/\/\?\//, "");
|
|
106326
|
+
normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
|
|
106327
|
+
normalised = normalised.replace(/^\/+/, "");
|
|
106328
|
+
normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
|
|
106329
|
+
return "hf-ext/" + normalised;
|
|
106330
|
+
}
|
|
106331
|
+
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
106332
|
+
const absoluteProjectDir = resolve8(projectDir);
|
|
106333
|
+
const projectName = basename2(absoluteProjectDir);
|
|
106334
|
+
const resolvedOutputPath = outputPath ?? join12(rendersDir, `${projectName}.mp4`);
|
|
106335
|
+
const absoluteOutputPath = resolve8(resolvedOutputPath);
|
|
106336
|
+
return { absoluteProjectDir, absoluteOutputPath };
|
|
106337
|
+
}
|
|
106338
|
+
|
|
106132
106339
|
// src/services/deterministicFonts.ts
|
|
106133
106340
|
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
|
|
106134
106341
|
import { homedir as homedir2 } from "node:os";
|
|
106135
|
-
import { join as
|
|
106342
|
+
import { join as join13 } from "node:path";
|
|
106136
106343
|
|
|
106137
106344
|
// src/services/fontData.generated.ts
|
|
106138
106345
|
var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
|
|
@@ -106410,20 +106617,20 @@ function warnUnresolvedFonts(unresolved) {
|
|
|
106410
106617
|
Docs: https://hyperframes.heygen.com/docs/fonts`
|
|
106411
106618
|
);
|
|
106412
106619
|
}
|
|
106413
|
-
var GOOGLE_FONTS_CACHE_DIR =
|
|
106620
|
+
var GOOGLE_FONTS_CACHE_DIR = join13(homedir2(), ".cache", "hyperframes", "fonts");
|
|
106414
106621
|
var 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";
|
|
106415
106622
|
function fontSlug(familyName) {
|
|
106416
106623
|
return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
106417
106624
|
}
|
|
106418
106625
|
function fontCacheDir(slug) {
|
|
106419
|
-
const dir =
|
|
106626
|
+
const dir = join13(GOOGLE_FONTS_CACHE_DIR, slug);
|
|
106420
106627
|
if (!existsSync13(dir)) {
|
|
106421
106628
|
mkdirSync8(dir, { recursive: true });
|
|
106422
106629
|
}
|
|
106423
106630
|
return dir;
|
|
106424
106631
|
}
|
|
106425
106632
|
function cachedWoff2Path(slug, weight, style) {
|
|
106426
|
-
return
|
|
106633
|
+
return join13(fontCacheDir(slug), `${weight}-${style}.woff2`);
|
|
106427
106634
|
}
|
|
106428
106635
|
async function fetchGoogleFont(familyName) {
|
|
106429
106636
|
const slug = fontSlug(familyName);
|
|
@@ -106515,6 +106722,37 @@ function dedupeElementsById(elements) {
|
|
|
106515
106722
|
}
|
|
106516
106723
|
return Array.from(deduped.values());
|
|
106517
106724
|
}
|
|
106725
|
+
var INLINE_SCRIPT_PATTERN = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
106726
|
+
function stripJsComments(source2) {
|
|
106727
|
+
return source2.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
106728
|
+
}
|
|
106729
|
+
function detectRenderModeHints(html) {
|
|
106730
|
+
const reasons = [];
|
|
106731
|
+
const { document: document2 } = parseHTML(html);
|
|
106732
|
+
if (document2.querySelector("iframe")) {
|
|
106733
|
+
reasons.push({
|
|
106734
|
+
code: "iframe",
|
|
106735
|
+
message: "Detected <iframe> in the composition DOM. Nested iframe animation is routed through screenshot capture mode for compatibility."
|
|
106736
|
+
});
|
|
106737
|
+
}
|
|
106738
|
+
let scriptMatch;
|
|
106739
|
+
const scriptPattern = new RegExp(INLINE_SCRIPT_PATTERN.source, INLINE_SCRIPT_PATTERN.flags);
|
|
106740
|
+
while ((scriptMatch = scriptPattern.exec(html)) !== null) {
|
|
106741
|
+
const attrs = scriptMatch[1] || "";
|
|
106742
|
+
if (/\bsrc\s*=/i.test(attrs)) continue;
|
|
106743
|
+
const content = stripJsComments(scriptMatch[2] || "");
|
|
106744
|
+
if (!/requestAnimationFrame\s*\(/.test(content)) continue;
|
|
106745
|
+
reasons.push({
|
|
106746
|
+
code: "requestAnimationFrame",
|
|
106747
|
+
message: "Detected raw requestAnimationFrame() in an inline script. This render is routed through screenshot capture mode with virtual time enabled."
|
|
106748
|
+
});
|
|
106749
|
+
break;
|
|
106750
|
+
}
|
|
106751
|
+
return {
|
|
106752
|
+
recommendScreenshot: reasons.length > 0,
|
|
106753
|
+
reasons
|
|
106754
|
+
};
|
|
106755
|
+
}
|
|
106518
106756
|
async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
|
|
106519
106757
|
let filePath = src;
|
|
106520
106758
|
if (isHttpUrl(src)) {
|
|
@@ -106525,7 +106763,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
106525
106763
|
return { duration: 0, resolvedPath: src };
|
|
106526
106764
|
}
|
|
106527
106765
|
} else if (!filePath.startsWith("/")) {
|
|
106528
|
-
filePath =
|
|
106766
|
+
filePath = join14(baseDir, filePath);
|
|
106529
106767
|
}
|
|
106530
106768
|
if (!existsSync14(filePath)) {
|
|
106531
106769
|
return { duration: 0, resolvedPath: filePath };
|
|
@@ -106591,7 +106829,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
106591
106829
|
const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
|
|
106592
106830
|
const absoluteStart = parentOffset + elStart;
|
|
106593
106831
|
const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
|
|
106594
|
-
const filePath =
|
|
106832
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106595
106833
|
if (visited.has(filePath)) {
|
|
106596
106834
|
continue;
|
|
106597
106835
|
}
|
|
@@ -106791,7 +107029,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
106791
107029
|
if (!srcPath) continue;
|
|
106792
107030
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
106793
107031
|
if (!compHtml) {
|
|
106794
|
-
const filePath =
|
|
107032
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106795
107033
|
if (existsSync14(filePath)) {
|
|
106796
107034
|
compHtml = readFileSync8(filePath, "utf-8");
|
|
106797
107035
|
}
|
|
@@ -107004,7 +107242,7 @@ ${safeText}
|
|
|
107004
107242
|
return result;
|
|
107005
107243
|
}
|
|
107006
107244
|
function collectExternalAssets(html, projectDir) {
|
|
107007
|
-
const absProjectDir =
|
|
107245
|
+
const absProjectDir = resolve9(projectDir);
|
|
107008
107246
|
const externalAssets = /* @__PURE__ */ new Map();
|
|
107009
107247
|
const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
107010
107248
|
function processPath(rawPath) {
|
|
@@ -107012,12 +107250,12 @@ function collectExternalAssets(html, projectDir) {
|
|
|
107012
107250
|
if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
|
|
107013
107251
|
return null;
|
|
107014
107252
|
}
|
|
107015
|
-
const absPath =
|
|
107016
|
-
if (
|
|
107253
|
+
const absPath = resolve9(absProjectDir, trimmed);
|
|
107254
|
+
if (isPathInside(absPath, absProjectDir)) {
|
|
107017
107255
|
return null;
|
|
107018
107256
|
}
|
|
107019
107257
|
if (!existsSync14(absPath)) return null;
|
|
107020
|
-
const safeKey =
|
|
107258
|
+
const safeKey = toExternalAssetKey(absPath);
|
|
107021
107259
|
externalAssets.set(safeKey, absPath);
|
|
107022
107260
|
return safeKey;
|
|
107023
107261
|
}
|
|
@@ -107078,6 +107316,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107078
107316
|
/(<(?:video|audio)\b[^>]*?)\s+preload\s*=\s*["']none["']/gi,
|
|
107079
107317
|
"$1"
|
|
107080
107318
|
);
|
|
107319
|
+
const renderModeHints = detectRenderModeHints(sanitizedHtml);
|
|
107081
107320
|
const coalescedHtml = await injectDeterministicFontFaces(
|
|
107082
107321
|
coalesceHeadStylesAndBodyScripts(promoteCssImportsToLinkTags(sanitizedHtml))
|
|
107083
107322
|
);
|
|
@@ -107089,7 +107328,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107089
107328
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
107090
107329
|
for (const video of videos) {
|
|
107091
107330
|
if (isHttpUrl(video.src)) continue;
|
|
107092
|
-
const videoPath =
|
|
107331
|
+
const videoPath = resolve9(projectDir, video.src);
|
|
107093
107332
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
107094
107333
|
Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
107095
107334
|
if (analysis.isProblematic) {
|
|
@@ -107121,7 +107360,8 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107121
107360
|
externalAssets,
|
|
107122
107361
|
width,
|
|
107123
107362
|
height,
|
|
107124
|
-
staticDuration
|
|
107363
|
+
staticDuration,
|
|
107364
|
+
renderModeHints
|
|
107125
107365
|
};
|
|
107126
107366
|
}
|
|
107127
107367
|
async function discoverMediaFromBrowser(page) {
|
|
@@ -107215,7 +107455,8 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
107215
107455
|
subCompositions,
|
|
107216
107456
|
videos,
|
|
107217
107457
|
audios,
|
|
107218
|
-
unresolvedCompositions: remaining
|
|
107458
|
+
unresolvedCompositions: remaining,
|
|
107459
|
+
renderModeHints: compiled.renderModeHints
|
|
107219
107460
|
};
|
|
107220
107461
|
}
|
|
107221
107462
|
|
|
@@ -107316,17 +107557,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
|
|
|
107316
107557
|
};
|
|
107317
107558
|
}
|
|
107318
107559
|
function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
107319
|
-
const compileDir =
|
|
107560
|
+
const compileDir = join15(workDir, "compiled");
|
|
107320
107561
|
mkdirSync10(compileDir, { recursive: true });
|
|
107321
|
-
writeFileSync4(
|
|
107562
|
+
writeFileSync4(join15(compileDir, "index.html"), compiled.html, "utf-8");
|
|
107322
107563
|
for (const [srcPath, html] of compiled.subCompositions) {
|
|
107323
|
-
const outPath =
|
|
107564
|
+
const outPath = join15(compileDir, srcPath);
|
|
107324
107565
|
mkdirSync10(dirname10(outPath), { recursive: true });
|
|
107325
107566
|
writeFileSync4(outPath, html, "utf-8");
|
|
107326
107567
|
}
|
|
107327
107568
|
for (const [relativePath, absolutePath] of compiled.externalAssets) {
|
|
107328
|
-
const outPath =
|
|
107329
|
-
if (!outPath
|
|
107569
|
+
const outPath = resolve10(join15(compileDir, relativePath));
|
|
107570
|
+
if (!isPathInside(outPath, compileDir)) {
|
|
107330
107571
|
console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
|
|
107331
107572
|
continue;
|
|
107332
107573
|
}
|
|
@@ -107352,11 +107593,20 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
|
107352
107593
|
end: a.end,
|
|
107353
107594
|
mediaStart: a.mediaStart
|
|
107354
107595
|
})),
|
|
107355
|
-
subCompositions: Array.from(compiled.subCompositions.keys())
|
|
107596
|
+
subCompositions: Array.from(compiled.subCompositions.keys()),
|
|
107597
|
+
renderModeHints: compiled.renderModeHints
|
|
107356
107598
|
};
|
|
107357
|
-
writeFileSync4(
|
|
107599
|
+
writeFileSync4(join15(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
|
|
107358
107600
|
}
|
|
107359
107601
|
}
|
|
107602
|
+
function applyRenderModeHints(cfg, compiled, log = defaultLogger) {
|
|
107603
|
+
if (cfg.forceScreenshot || !compiled.renderModeHints.recommendScreenshot) return;
|
|
107604
|
+
cfg.forceScreenshot = true;
|
|
107605
|
+
log.warn("Auto-selected screenshot capture mode for render compatibility", {
|
|
107606
|
+
reasonCodes: compiled.renderModeHints.reasons.map((reason) => reason.code),
|
|
107607
|
+
reasons: compiled.renderModeHints.reasons.map((reason) => reason.message)
|
|
107608
|
+
});
|
|
107609
|
+
}
|
|
107360
107610
|
function createRenderJob(config2) {
|
|
107361
107611
|
return {
|
|
107362
107612
|
id: randomUUID(),
|
|
@@ -107398,9 +107648,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
|
|
|
107398
107648
|
}
|
|
107399
107649
|
async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
|
|
107400
107650
|
const moduleDir = dirname10(fileURLToPath3(import.meta.url));
|
|
107401
|
-
const producerRoot = process.env.PRODUCER_RENDERS_DIR ?
|
|
107402
|
-
const debugDir =
|
|
107403
|
-
const workDir = job.config.debug ?
|
|
107651
|
+
const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve10(process.env.PRODUCER_RENDERS_DIR, "..") : resolve10(moduleDir, "../..");
|
|
107652
|
+
const debugDir = join15(producerRoot, ".debug");
|
|
107653
|
+
const workDir = job.config.debug ? join15(debugDir, job.id) : join15(dirname10(outputPath), `work-${job.id}`);
|
|
107404
107654
|
const pipelineStart = Date.now();
|
|
107405
107655
|
const log = job.config.logger ?? defaultLogger;
|
|
107406
107656
|
let fileServer = null;
|
|
@@ -107408,7 +107658,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107408
107658
|
let lastBrowserConsole = [];
|
|
107409
107659
|
let restoreLogger = null;
|
|
107410
107660
|
const perfStages = {};
|
|
107411
|
-
const perfOutputPath =
|
|
107661
|
+
const perfOutputPath = join15(workDir, "perf-summary.json");
|
|
107412
107662
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
107413
107663
|
const outputFormat = job.config.format ?? "mp4";
|
|
107414
107664
|
const isWebm = outputFormat === "webm";
|
|
@@ -107430,19 +107680,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107430
107680
|
assertNotAborted();
|
|
107431
107681
|
if (!existsSync15(workDir)) mkdirSync10(workDir, { recursive: true });
|
|
107432
107682
|
if (job.config.debug) {
|
|
107433
|
-
const logPath =
|
|
107683
|
+
const logPath = join15(workDir, "render.log");
|
|
107434
107684
|
restoreLogger = installDebugLogger(logPath, log);
|
|
107435
107685
|
}
|
|
107436
107686
|
const entryFile = job.config.entryFile || "index.html";
|
|
107437
|
-
let htmlPath =
|
|
107687
|
+
let htmlPath = join15(projectDir, entryFile);
|
|
107438
107688
|
if (!existsSync15(htmlPath)) {
|
|
107439
107689
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
107440
107690
|
}
|
|
107441
107691
|
assertNotAborted();
|
|
107442
107692
|
const rawEntry = readFileSync9(htmlPath, "utf-8");
|
|
107443
107693
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
107444
|
-
const wrapperPath =
|
|
107445
|
-
const projectIndexPath =
|
|
107694
|
+
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
107695
|
+
const projectIndexPath = join15(projectDir, "index.html");
|
|
107446
107696
|
if (!existsSync15(projectIndexPath)) {
|
|
107447
107697
|
throw new Error(
|
|
107448
107698
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
@@ -107466,9 +107716,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107466
107716
|
const stage1Start = Date.now();
|
|
107467
107717
|
updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
|
|
107468
107718
|
const compileStart = Date.now();
|
|
107469
|
-
let compiled = await compileForRender(projectDir, htmlPath,
|
|
107719
|
+
let compiled = await compileForRender(projectDir, htmlPath, join15(workDir, "downloads"));
|
|
107470
107720
|
assertNotAborted();
|
|
107471
107721
|
perfStages.compileOnlyMs = Date.now() - compileStart;
|
|
107722
|
+
applyRenderModeHints(cfg, compiled, log);
|
|
107472
107723
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
107473
107724
|
log.info("Compiled composition metadata", {
|
|
107474
107725
|
entryFile,
|
|
@@ -107476,7 +107727,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107476
107727
|
width: compiled.width,
|
|
107477
107728
|
height: compiled.height,
|
|
107478
107729
|
videoCount: compiled.videos.length,
|
|
107479
|
-
audioCount: compiled.audios.length
|
|
107730
|
+
audioCount: compiled.audios.length,
|
|
107731
|
+
renderModeHints: compiled.renderModeHints
|
|
107480
107732
|
});
|
|
107481
107733
|
const composition = {
|
|
107482
107734
|
duration: compiled.staticDuration,
|
|
@@ -107495,8 +107747,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107495
107747
|
reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
|
|
107496
107748
|
fileServer = await createFileServer2({
|
|
107497
107749
|
projectDir,
|
|
107498
|
-
compiledDir:
|
|
107499
|
-
port: 0
|
|
107750
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107751
|
+
port: 0,
|
|
107752
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
107500
107753
|
});
|
|
107501
107754
|
assertNotAborted();
|
|
107502
107755
|
const captureOpts = {
|
|
@@ -107508,7 +107761,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107508
107761
|
};
|
|
107509
107762
|
probeSession = await createCaptureSession(
|
|
107510
107763
|
fileServer.url,
|
|
107511
|
-
|
|
107764
|
+
join15(workDir, "probe"),
|
|
107512
107765
|
captureOpts,
|
|
107513
107766
|
null,
|
|
107514
107767
|
cfg
|
|
@@ -107540,7 +107793,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107540
107793
|
compiled,
|
|
107541
107794
|
resolutions,
|
|
107542
107795
|
projectDir,
|
|
107543
|
-
|
|
107796
|
+
join15(workDir, "downloads")
|
|
107544
107797
|
);
|
|
107545
107798
|
assertNotAborted();
|
|
107546
107799
|
composition.videos = compiled.videos;
|
|
@@ -107675,12 +107928,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107675
107928
|
const stage2Start = Date.now();
|
|
107676
107929
|
updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
|
|
107677
107930
|
let frameLookup = null;
|
|
107678
|
-
const compiledDir =
|
|
107931
|
+
const compiledDir = join15(workDir, "compiled");
|
|
107679
107932
|
if (composition.videos.length > 0) {
|
|
107680
107933
|
const extractionResult = await extractAllVideoFrames(
|
|
107681
107934
|
composition.videos,
|
|
107682
107935
|
projectDir,
|
|
107683
|
-
{ fps: job.config.fps, outputDir:
|
|
107936
|
+
{ fps: job.config.fps, outputDir: join15(workDir, "video-frames") },
|
|
107684
107937
|
abortSignal,
|
|
107685
107938
|
void 0,
|
|
107686
107939
|
compiledDir
|
|
@@ -107714,13 +107967,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107714
107967
|
}
|
|
107715
107968
|
const stage3Start = Date.now();
|
|
107716
107969
|
updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
|
|
107717
|
-
const audioOutputPath =
|
|
107970
|
+
const audioOutputPath = join15(workDir, "audio.aac");
|
|
107718
107971
|
let hasAudio = false;
|
|
107719
107972
|
if (composition.audios.length > 0) {
|
|
107720
107973
|
const audioResult = await processCompositionAudio(
|
|
107721
107974
|
composition.audios,
|
|
107722
107975
|
projectDir,
|
|
107723
|
-
|
|
107976
|
+
join15(workDir, "audio-work"),
|
|
107724
107977
|
audioOutputPath,
|
|
107725
107978
|
job.duration,
|
|
107726
107979
|
abortSignal,
|
|
@@ -107738,12 +107991,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107738
107991
|
if (!fileServer) {
|
|
107739
107992
|
fileServer = await createFileServer2({
|
|
107740
107993
|
projectDir,
|
|
107741
|
-
compiledDir:
|
|
107742
|
-
port: 0
|
|
107994
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107995
|
+
port: 0,
|
|
107996
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
107743
107997
|
});
|
|
107744
107998
|
assertNotAborted();
|
|
107745
107999
|
}
|
|
107746
|
-
const framesDir =
|
|
108000
|
+
const framesDir = join15(workDir, "captured-frames");
|
|
107747
108001
|
if (!existsSync15(framesDir)) mkdirSync10(framesDir, { recursive: true });
|
|
107748
108002
|
const captureOptions = {
|
|
107749
108003
|
width,
|
|
@@ -107755,7 +108009,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107755
108009
|
const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
|
|
107756
108010
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
107757
108011
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
107758
|
-
const videoOnlyPath =
|
|
108012
|
+
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
107759
108013
|
const preset = getEncoderPreset(job.config.quality, outputFormat);
|
|
107760
108014
|
const effectiveQuality = job.config.crf ?? preset.quality;
|
|
107761
108015
|
const effectiveBitrate = job.config.videoBitrate;
|
|
@@ -108031,7 +108285,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108031
108285
|
}
|
|
108032
108286
|
if (job.config.debug) {
|
|
108033
108287
|
if (existsSync15(outputPath)) {
|
|
108034
|
-
const debugOutput =
|
|
108288
|
+
const debugOutput = join15(workDir, `output${videoExt}`);
|
|
108035
108289
|
copyFileSync2(outputPath, debugOutput);
|
|
108036
108290
|
}
|
|
108037
108291
|
} else {
|
|
@@ -108290,7 +108544,7 @@ var streamSSE = (c, cb, onError) => {
|
|
|
108290
108544
|
|
|
108291
108545
|
// src/services/hyperframeLint.ts
|
|
108292
108546
|
import { existsSync as existsSync16, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
|
|
108293
|
-
import { resolve as
|
|
108547
|
+
import { resolve as resolve11, join as join16 } from "node:path";
|
|
108294
108548
|
function isStringRecord(value) {
|
|
108295
108549
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
108296
108550
|
return false;
|
|
@@ -108317,7 +108571,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
108317
108571
|
return null;
|
|
108318
108572
|
}
|
|
108319
108573
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
108320
|
-
const absProjectDir =
|
|
108574
|
+
const absProjectDir = resolve11(projectDir);
|
|
108321
108575
|
if (!existsSync16(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
|
|
108322
108576
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
108323
108577
|
}
|
|
@@ -108325,7 +108579,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108325
108579
|
(value) => typeof value === "string" && value.trim().length > 0
|
|
108326
108580
|
);
|
|
108327
108581
|
for (const entryFile of entryCandidates) {
|
|
108328
|
-
const absoluteEntryPath =
|
|
108582
|
+
const absoluteEntryPath = resolve11(absProjectDir, entryFile);
|
|
108329
108583
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
108330
108584
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
108331
108585
|
}
|
|
@@ -108338,7 +108592,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108338
108592
|
}
|
|
108339
108593
|
}
|
|
108340
108594
|
return {
|
|
108341
|
-
error: `No HTML entry file found in project directory: ${
|
|
108595
|
+
error: `No HTML entry file found in project directory: ${join16(absProjectDir, preferredEntryFile || "index.html")}`
|
|
108342
108596
|
};
|
|
108343
108597
|
}
|
|
108344
108598
|
function prepareHyperframeLintBody(body) {
|
|
@@ -108378,17 +108632,6 @@ function runHyperframeLint(prepared) {
|
|
|
108378
108632
|
return lintHyperframeHtml(prepared.html, { filePath: prepared.entryFile });
|
|
108379
108633
|
}
|
|
108380
108634
|
|
|
108381
|
-
// src/utils/paths.ts
|
|
108382
|
-
import { resolve as resolve11, basename as basename2, join as join16 } from "node:path";
|
|
108383
|
-
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
108384
|
-
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
108385
|
-
const absoluteProjectDir = resolve11(projectDir);
|
|
108386
|
-
const projectName = basename2(absoluteProjectDir);
|
|
108387
|
-
const resolvedOutputPath = outputPath ?? join16(rendersDir, `${projectName}.mp4`);
|
|
108388
|
-
const absoluteOutputPath = resolve11(resolvedOutputPath);
|
|
108389
|
-
return { absoluteProjectDir, absoluteOutputPath };
|
|
108390
|
-
}
|
|
108391
|
-
|
|
108392
108635
|
// src/utils/semaphore.ts
|
|
108393
108636
|
var Semaphore = class {
|
|
108394
108637
|
constructor(maxConcurrent) {
|