@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/public-server.js
CHANGED
|
@@ -57866,7 +57866,7 @@ var require_util2 = __commonJS({
|
|
|
57866
57866
|
}
|
|
57867
57867
|
path12 = url.path;
|
|
57868
57868
|
}
|
|
57869
|
-
var
|
|
57869
|
+
var isAbsolute3 = exports.isAbsolute(path12);
|
|
57870
57870
|
var parts = path12.split(/\/+/);
|
|
57871
57871
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
57872
57872
|
part = parts[i];
|
|
@@ -57886,7 +57886,7 @@ var require_util2 = __commonJS({
|
|
|
57886
57886
|
}
|
|
57887
57887
|
path12 = parts.join("/");
|
|
57888
57888
|
if (path12 === "") {
|
|
57889
|
-
path12 =
|
|
57889
|
+
path12 = isAbsolute3 ? "/" : ".";
|
|
57890
57890
|
}
|
|
57891
57891
|
if (url) {
|
|
57892
57892
|
url.path = path12;
|
|
@@ -57931,7 +57931,7 @@ var require_util2 = __commonJS({
|
|
|
57931
57931
|
exports.isAbsolute = function(aPath) {
|
|
57932
57932
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
57933
57933
|
};
|
|
57934
|
-
function
|
|
57934
|
+
function relative3(aRoot, aPath) {
|
|
57935
57935
|
if (aRoot === "") {
|
|
57936
57936
|
aRoot = ".";
|
|
57937
57937
|
}
|
|
@@ -57950,7 +57950,7 @@ var require_util2 = __commonJS({
|
|
|
57950
57950
|
}
|
|
57951
57951
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
57952
57952
|
}
|
|
57953
|
-
exports.relative =
|
|
57953
|
+
exports.relative = relative3;
|
|
57954
57954
|
var supportsNullProto = (function() {
|
|
57955
57955
|
var obj = /* @__PURE__ */ Object.create(null);
|
|
57956
57956
|
return !("__proto__" in obj);
|
|
@@ -95503,10 +95503,10 @@ function compareDocumentPosition(nodeA, nodeB) {
|
|
|
95503
95503
|
function uniqueSort(nodes) {
|
|
95504
95504
|
nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
|
|
95505
95505
|
nodes.sort((a, b) => {
|
|
95506
|
-
const
|
|
95507
|
-
if (
|
|
95506
|
+
const relative3 = compareDocumentPosition(a, b);
|
|
95507
|
+
if (relative3 & DocumentPosition.PRECEDING) {
|
|
95508
95508
|
return -1;
|
|
95509
|
-
} else if (
|
|
95509
|
+
} else if (relative3 & DocumentPosition.FOLLOWING) {
|
|
95510
95510
|
return 1;
|
|
95511
95511
|
}
|
|
95512
95512
|
return 0;
|
|
@@ -103860,6 +103860,15 @@ function isFontResourceError(type, text, locationUrl) {
|
|
|
103860
103860
|
`${locationUrl} ${text}`
|
|
103861
103861
|
);
|
|
103862
103862
|
}
|
|
103863
|
+
async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100) {
|
|
103864
|
+
const deadline = Date.now() + timeoutMs;
|
|
103865
|
+
while (Date.now() < deadline) {
|
|
103866
|
+
const ready = Boolean(await page.evaluate(expression));
|
|
103867
|
+
if (ready) return true;
|
|
103868
|
+
await new Promise((resolve13) => setTimeout(resolve13, intervalMs));
|
|
103869
|
+
}
|
|
103870
|
+
return Boolean(await page.evaluate(expression));
|
|
103871
|
+
}
|
|
103863
103872
|
async function initializeSession(session) {
|
|
103864
103873
|
const { page, serverUrl } = session;
|
|
103865
103874
|
page.on("console", (msg) => {
|
|
@@ -103889,14 +103898,26 @@ async function initializeSession(session) {
|
|
|
103889
103898
|
if (session.captureMode === "screenshot") {
|
|
103890
103899
|
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 6e4 });
|
|
103891
103900
|
const pageReadyTimeout2 = session.config?.playerReadyTimeout ?? DEFAULT_CONFIG.playerReadyTimeout;
|
|
103892
|
-
await
|
|
103901
|
+
const pageReady2 = await pollPageExpression(
|
|
103902
|
+
page,
|
|
103893
103903
|
`!!(window.__hf && typeof window.__hf.seek === "function" && window.__hf.duration > 0)`,
|
|
103894
|
-
|
|
103904
|
+
pageReadyTimeout2
|
|
103895
103905
|
);
|
|
103896
|
-
|
|
103906
|
+
if (!pageReady2) {
|
|
103907
|
+
throw new Error(
|
|
103908
|
+
`[FrameCapture] window.__hf not ready after ${pageReadyTimeout2}ms. Page must expose window.__hf = { duration, seek }.`
|
|
103909
|
+
);
|
|
103910
|
+
}
|
|
103911
|
+
const videosReady = await pollPageExpression(
|
|
103912
|
+
page,
|
|
103897
103913
|
`document.querySelectorAll("video").length === 0 || Array.from(document.querySelectorAll("video")).every(v => v.readyState >= 1)`,
|
|
103898
|
-
|
|
103914
|
+
pageReadyTimeout2
|
|
103899
103915
|
);
|
|
103916
|
+
if (!videosReady) {
|
|
103917
|
+
throw new Error(
|
|
103918
|
+
`[FrameCapture] video metadata not ready after ${pageReadyTimeout2}ms. Video elements must load metadata before capture starts.`
|
|
103919
|
+
);
|
|
103920
|
+
}
|
|
103900
103921
|
await page.evaluate(`document.fonts?.ready`);
|
|
103901
103922
|
session.isInitialized = true;
|
|
103902
103923
|
return;
|
|
@@ -105931,7 +105952,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
|
|
|
105931
105952
|
}
|
|
105932
105953
|
|
|
105933
105954
|
// src/services/renderOrchestrator.ts
|
|
105934
|
-
import { join as
|
|
105955
|
+
import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
|
|
105935
105956
|
import { randomUUID } from "crypto";
|
|
105936
105957
|
import { freemem as freemem2 } from "os";
|
|
105937
105958
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -106036,6 +106057,102 @@ var MIME_TYPES = {
|
|
|
106036
106057
|
".ttf": "font/ttf",
|
|
106037
106058
|
".otf": "font/otf"
|
|
106038
106059
|
};
|
|
106060
|
+
var VIRTUAL_TIME_SHIM = String.raw`(function() {
|
|
106061
|
+
if (window.__HF_VIRTUAL_TIME__) return;
|
|
106062
|
+
|
|
106063
|
+
var virtualNowMs = 0;
|
|
106064
|
+
var rafId = 1;
|
|
106065
|
+
var rafQueue = [];
|
|
106066
|
+
var OriginalDate = Date;
|
|
106067
|
+
var originalSetTimeout = window.setTimeout.bind(window);
|
|
106068
|
+
var originalClearTimeout = window.clearTimeout.bind(window);
|
|
106069
|
+
var originalSetInterval = window.setInterval.bind(window);
|
|
106070
|
+
var originalClearInterval = window.clearInterval.bind(window);
|
|
106071
|
+
var originalRequestAnimationFrame = window.requestAnimationFrame
|
|
106072
|
+
? window.requestAnimationFrame.bind(window)
|
|
106073
|
+
: null;
|
|
106074
|
+
var originalCancelAnimationFrame = window.cancelAnimationFrame
|
|
106075
|
+
? window.cancelAnimationFrame.bind(window)
|
|
106076
|
+
: null;
|
|
106077
|
+
|
|
106078
|
+
function flushAnimationFrame() {
|
|
106079
|
+
if (!rafQueue.length) return;
|
|
106080
|
+
var current = rafQueue.slice();
|
|
106081
|
+
rafQueue.length = 0;
|
|
106082
|
+
for (var i = 0; i < current.length; i++) {
|
|
106083
|
+
var entry = current[i];
|
|
106084
|
+
if (entry.cancelled) continue;
|
|
106085
|
+
try {
|
|
106086
|
+
entry.callback(virtualNowMs);
|
|
106087
|
+
} catch {}
|
|
106088
|
+
}
|
|
106089
|
+
}
|
|
106090
|
+
|
|
106091
|
+
function VirtualDate() {
|
|
106092
|
+
var args = Array.prototype.slice.call(arguments);
|
|
106093
|
+
if (!(this instanceof VirtualDate)) {
|
|
106094
|
+
return OriginalDate.apply(null, args.length ? args : [virtualNowMs]);
|
|
106095
|
+
}
|
|
106096
|
+
var instance = args.length ? new (Function.prototype.bind.apply(OriginalDate, [null].concat(args)))() : new OriginalDate(virtualNowMs);
|
|
106097
|
+
Object.setPrototypeOf(instance, VirtualDate.prototype);
|
|
106098
|
+
return instance;
|
|
106099
|
+
}
|
|
106100
|
+
|
|
106101
|
+
VirtualDate.prototype = OriginalDate.prototype;
|
|
106102
|
+
Object.setPrototypeOf(VirtualDate, OriginalDate);
|
|
106103
|
+
VirtualDate.now = function() { return virtualNowMs; };
|
|
106104
|
+
VirtualDate.parse = OriginalDate.parse.bind(OriginalDate);
|
|
106105
|
+
VirtualDate.UTC = OriginalDate.UTC.bind(OriginalDate);
|
|
106106
|
+
|
|
106107
|
+
try {
|
|
106108
|
+
Object.defineProperty(window, "Date", {
|
|
106109
|
+
configurable: true,
|
|
106110
|
+
writable: true,
|
|
106111
|
+
value: VirtualDate,
|
|
106112
|
+
});
|
|
106113
|
+
} catch {}
|
|
106114
|
+
|
|
106115
|
+
if (window.performance && typeof window.performance.now === "function") {
|
|
106116
|
+
try {
|
|
106117
|
+
Object.defineProperty(window.performance, "now", {
|
|
106118
|
+
configurable: true,
|
|
106119
|
+
value: function() { return virtualNowMs; },
|
|
106120
|
+
});
|
|
106121
|
+
} catch {}
|
|
106122
|
+
}
|
|
106123
|
+
|
|
106124
|
+
window.requestAnimationFrame = function(callback) {
|
|
106125
|
+
if (typeof callback !== "function") return 0;
|
|
106126
|
+
var entry = { id: rafId++, callback: callback, cancelled: false };
|
|
106127
|
+
rafQueue.push(entry);
|
|
106128
|
+
return entry.id;
|
|
106129
|
+
};
|
|
106130
|
+
window.cancelAnimationFrame = function(id) {
|
|
106131
|
+
for (var i = 0; i < rafQueue.length; i++) {
|
|
106132
|
+
if (rafQueue[i].id === id) {
|
|
106133
|
+
rafQueue[i].cancelled = true;
|
|
106134
|
+
}
|
|
106135
|
+
}
|
|
106136
|
+
};
|
|
106137
|
+
|
|
106138
|
+
window.__HF_VIRTUAL_TIME__ = {
|
|
106139
|
+
originalSetTimeout: originalSetTimeout,
|
|
106140
|
+
originalClearTimeout: originalClearTimeout,
|
|
106141
|
+
originalSetInterval: originalSetInterval,
|
|
106142
|
+
originalClearInterval: originalClearInterval,
|
|
106143
|
+
originalRequestAnimationFrame: originalRequestAnimationFrame,
|
|
106144
|
+
originalCancelAnimationFrame: originalCancelAnimationFrame,
|
|
106145
|
+
seekToTime: function(nextTimeMs) {
|
|
106146
|
+
var safeTimeMs = Math.max(0, Number(nextTimeMs) || 0);
|
|
106147
|
+
virtualNowMs = safeTimeMs;
|
|
106148
|
+
flushAnimationFrame();
|
|
106149
|
+
return virtualNowMs;
|
|
106150
|
+
},
|
|
106151
|
+
getTime: function() {
|
|
106152
|
+
return virtualNowMs;
|
|
106153
|
+
},
|
|
106154
|
+
};
|
|
106155
|
+
})();`;
|
|
106039
106156
|
var RENDER_SEEK_MODE = process.env.PRODUCER_RUNTIME_RENDER_SEEK_MODE === "strict-boundary" ? "strict-boundary" : "preview-phase";
|
|
106040
106157
|
var RENDER_SEEK_DIAGNOSTICS = process.env.PRODUCER_DEBUG_SEEK_DIAGNOSTICS === "true";
|
|
106041
106158
|
var RENDER_SEEK_STEP = Math.max(
|
|
@@ -106047,6 +106164,10 @@ var RENDER_SEEK_OFFSET_FRACTION = Math.max(
|
|
|
106047
106164
|
Math.min(0.95, Number(process.env.PRODUCER_RUNTIME_RENDER_SEEK_OFFSET_FRACTION || 0.5))
|
|
106048
106165
|
);
|
|
106049
106166
|
var RENDER_MODE_SCRIPT = `(function() {
|
|
106167
|
+
var __realSetTimeout =
|
|
106168
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalSetTimeout === "function"
|
|
106169
|
+
? window.__HF_VIRTUAL_TIME__.originalSetTimeout
|
|
106170
|
+
: window.setTimeout.bind(window);
|
|
106050
106171
|
var __seekMode = ${JSON.stringify(RENDER_SEEK_MODE)};
|
|
106051
106172
|
var __seekDiagnostics = ${RENDER_SEEK_DIAGNOSTICS ? "true" : "false"};
|
|
106052
106173
|
var __seekStep = ${RENDER_SEEK_STEP};
|
|
@@ -106140,23 +106261,56 @@ var RENDER_MODE_SCRIPT = `(function() {
|
|
|
106140
106261
|
window.__renderReady = true;
|
|
106141
106262
|
return;
|
|
106142
106263
|
}
|
|
106143
|
-
|
|
106264
|
+
__realSetTimeout(waitForPlayer, 50);
|
|
106144
106265
|
return;
|
|
106145
106266
|
}
|
|
106146
106267
|
if (installMediaFallbackPlayer()) {
|
|
106147
106268
|
return;
|
|
106148
106269
|
}
|
|
106149
|
-
|
|
106270
|
+
__realSetTimeout(waitForPlayer, 50);
|
|
106150
106271
|
}
|
|
106151
106272
|
waitForPlayer();
|
|
106152
106273
|
})();`;
|
|
106153
106274
|
var HF_BRIDGE_SCRIPT = `(function() {
|
|
106275
|
+
var __realSetInterval =
|
|
106276
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalSetInterval === "function"
|
|
106277
|
+
? window.__HF_VIRTUAL_TIME__.originalSetInterval
|
|
106278
|
+
: window.setInterval.bind(window);
|
|
106279
|
+
var __realClearInterval =
|
|
106280
|
+
window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.originalClearInterval === "function"
|
|
106281
|
+
? window.__HF_VIRTUAL_TIME__.originalClearInterval
|
|
106282
|
+
: window.clearInterval.bind(window);
|
|
106154
106283
|
function getDeclaredDuration() {
|
|
106155
106284
|
var root = document.querySelector('[data-composition-id]');
|
|
106156
106285
|
if (!root) return 0;
|
|
106157
106286
|
var d = Number(root.getAttribute('data-duration'));
|
|
106158
106287
|
return Number.isFinite(d) && d > 0 ? d : 0;
|
|
106159
106288
|
}
|
|
106289
|
+
function seekSameOriginChildFrames(frameWindow, nextTimeMs) {
|
|
106290
|
+
var frames;
|
|
106291
|
+
try {
|
|
106292
|
+
frames = frameWindow.frames;
|
|
106293
|
+
} catch (_error) {
|
|
106294
|
+
return;
|
|
106295
|
+
}
|
|
106296
|
+
if (!frames || typeof frames.length !== "number") return;
|
|
106297
|
+
for (var i = 0; i < frames.length; i++) {
|
|
106298
|
+
var childWindow = null;
|
|
106299
|
+
try {
|
|
106300
|
+
childWindow = frames[i];
|
|
106301
|
+
if (!childWindow || childWindow === frameWindow) continue;
|
|
106302
|
+
if (
|
|
106303
|
+
childWindow.__HF_VIRTUAL_TIME__ &&
|
|
106304
|
+
typeof childWindow.__HF_VIRTUAL_TIME__.seekToTime === "function"
|
|
106305
|
+
) {
|
|
106306
|
+
childWindow.__HF_VIRTUAL_TIME__.seekToTime(nextTimeMs);
|
|
106307
|
+
}
|
|
106308
|
+
} catch (_error) {
|
|
106309
|
+
continue;
|
|
106310
|
+
}
|
|
106311
|
+
seekSameOriginChildFrames(childWindow, nextTimeMs);
|
|
106312
|
+
}
|
|
106313
|
+
}
|
|
106160
106314
|
function bridge() {
|
|
106161
106315
|
var p = window.__player;
|
|
106162
106316
|
if (!p || typeof p.renderSeek !== "function" || typeof p.getDuration !== "function") {
|
|
@@ -106167,13 +106321,20 @@ var HF_BRIDGE_SCRIPT = `(function() {
|
|
|
106167
106321
|
var d = p.getDuration();
|
|
106168
106322
|
return d > 0 ? d : getDeclaredDuration();
|
|
106169
106323
|
},
|
|
106170
|
-
seek: function(t) {
|
|
106324
|
+
seek: function(t) {
|
|
106325
|
+
p.renderSeek(t);
|
|
106326
|
+
var nextTimeMs = (Math.max(0, Number(t) || 0)) * 1000;
|
|
106327
|
+
if (window.__HF_VIRTUAL_TIME__ && typeof window.__HF_VIRTUAL_TIME__.seekToTime === "function") {
|
|
106328
|
+
window.__HF_VIRTUAL_TIME__.seekToTime(nextTimeMs);
|
|
106329
|
+
}
|
|
106330
|
+
seekSameOriginChildFrames(window, nextTimeMs);
|
|
106331
|
+
},
|
|
106171
106332
|
};
|
|
106172
106333
|
return true;
|
|
106173
106334
|
}
|
|
106174
106335
|
if (bridge()) return;
|
|
106175
|
-
var iv =
|
|
106176
|
-
if (bridge())
|
|
106336
|
+
var iv = __realSetInterval(function() {
|
|
106337
|
+
if (bridge()) __realClearInterval(iv);
|
|
106177
106338
|
}, 50);
|
|
106178
106339
|
})();`;
|
|
106179
106340
|
function stripEmbeddedRuntimeScripts(html) {
|
|
@@ -106235,8 +106396,22 @@ function injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbedded) {
|
|
|
106235
106396
|
}
|
|
106236
106397
|
return html;
|
|
106237
106398
|
}
|
|
106399
|
+
function injectScriptsAtHeadStart(html, scripts) {
|
|
106400
|
+
if (scripts.length === 0) return html;
|
|
106401
|
+
const headTags = scripts.map((src) => `<script>${src}</script>`).join("\n");
|
|
106402
|
+
if (html.includes("<head")) {
|
|
106403
|
+
return html.replace(/<head\b[^>]*>/i, (match2) => `${match2}
|
|
106404
|
+
${headTags}`);
|
|
106405
|
+
}
|
|
106406
|
+
if (html.includes("<body")) {
|
|
106407
|
+
return html.replace("<body", () => `${headTags}
|
|
106408
|
+
<body`);
|
|
106409
|
+
}
|
|
106410
|
+
return headTags + "\n" + html;
|
|
106411
|
+
}
|
|
106238
106412
|
function createFileServer2(options) {
|
|
106239
106413
|
const { projectDir, compiledDir, port = 0, stripEmbeddedRuntime = true } = options;
|
|
106414
|
+
const preHeadScripts = options.preHeadScripts ?? [];
|
|
106240
106415
|
const headScripts = options.headScripts ?? [getVerifiedHyperframeRuntimeSource()];
|
|
106241
106416
|
const bodyScripts = options.bodyScripts ?? [RENDER_MODE_SCRIPT, HF_BRIDGE_SCRIPT];
|
|
106242
106417
|
const app = new Hono2();
|
|
@@ -106260,7 +106435,11 @@ function createFileServer2(options) {
|
|
|
106260
106435
|
if (ext === ".html") {
|
|
106261
106436
|
const rawHtml = readFileSync6(filePath, "utf-8");
|
|
106262
106437
|
const isIndex = relativePath === "index.html";
|
|
106263
|
-
|
|
106438
|
+
let html = rawHtml;
|
|
106439
|
+
if (preHeadScripts.length > 0) {
|
|
106440
|
+
html = injectScriptsAtHeadStart(html, preHeadScripts);
|
|
106441
|
+
}
|
|
106442
|
+
html = isIndex ? injectScriptsIntoHtml(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
|
|
106264
106443
|
return c.text(html, 200, { "Content-Type": contentType });
|
|
106265
106444
|
}
|
|
106266
106445
|
const content = readFileSync6(filePath);
|
|
@@ -106291,13 +106470,41 @@ function createFileServer2(options) {
|
|
|
106291
106470
|
|
|
106292
106471
|
// src/services/htmlCompiler.ts
|
|
106293
106472
|
import { readFileSync as readFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
106294
|
-
import { join as
|
|
106473
|
+
import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
|
|
106295
106474
|
import postcss from "postcss";
|
|
106296
106475
|
|
|
106476
|
+
// src/utils/paths.ts
|
|
106477
|
+
import { resolve as resolve8, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
|
|
106478
|
+
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve8(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
106479
|
+
function isPathInside(childPath, parentPath) {
|
|
106480
|
+
const absChild = resolve8(childPath);
|
|
106481
|
+
const absParent = resolve8(parentPath);
|
|
106482
|
+
if (absChild === absParent) return true;
|
|
106483
|
+
const rel = relative2(absParent, absChild);
|
|
106484
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
106485
|
+
}
|
|
106486
|
+
function toExternalAssetKey(absPath) {
|
|
106487
|
+
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
106488
|
+
let normalised = absPath.replace(/\\/g, "/");
|
|
106489
|
+
normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
|
|
106490
|
+
normalised = normalised.replace(/^\/\/\?\//, "");
|
|
106491
|
+
normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
|
|
106492
|
+
normalised = normalised.replace(/^\/+/, "");
|
|
106493
|
+
normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
|
|
106494
|
+
return "hf-ext/" + normalised;
|
|
106495
|
+
}
|
|
106496
|
+
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
106497
|
+
const absoluteProjectDir = resolve8(projectDir);
|
|
106498
|
+
const projectName = basename2(absoluteProjectDir);
|
|
106499
|
+
const resolvedOutputPath = outputPath ?? join12(rendersDir, `${projectName}.mp4`);
|
|
106500
|
+
const absoluteOutputPath = resolve8(resolvedOutputPath);
|
|
106501
|
+
return { absoluteProjectDir, absoluteOutputPath };
|
|
106502
|
+
}
|
|
106503
|
+
|
|
106297
106504
|
// src/services/deterministicFonts.ts
|
|
106298
106505
|
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
|
|
106299
106506
|
import { homedir as homedir2 } from "node:os";
|
|
106300
|
-
import { join as
|
|
106507
|
+
import { join as join13 } from "node:path";
|
|
106301
106508
|
|
|
106302
106509
|
// src/services/fontData.generated.ts
|
|
106303
106510
|
var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
|
|
@@ -106575,20 +106782,20 @@ function warnUnresolvedFonts(unresolved) {
|
|
|
106575
106782
|
Docs: https://hyperframes.heygen.com/docs/fonts`
|
|
106576
106783
|
);
|
|
106577
106784
|
}
|
|
106578
|
-
var GOOGLE_FONTS_CACHE_DIR =
|
|
106785
|
+
var GOOGLE_FONTS_CACHE_DIR = join13(homedir2(), ".cache", "hyperframes", "fonts");
|
|
106579
106786
|
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";
|
|
106580
106787
|
function fontSlug(familyName) {
|
|
106581
106788
|
return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
106582
106789
|
}
|
|
106583
106790
|
function fontCacheDir(slug) {
|
|
106584
|
-
const dir =
|
|
106791
|
+
const dir = join13(GOOGLE_FONTS_CACHE_DIR, slug);
|
|
106585
106792
|
if (!existsSync13(dir)) {
|
|
106586
106793
|
mkdirSync8(dir, { recursive: true });
|
|
106587
106794
|
}
|
|
106588
106795
|
return dir;
|
|
106589
106796
|
}
|
|
106590
106797
|
function cachedWoff2Path(slug, weight, style) {
|
|
106591
|
-
return
|
|
106798
|
+
return join13(fontCacheDir(slug), `${weight}-${style}.woff2`);
|
|
106592
106799
|
}
|
|
106593
106800
|
async function fetchGoogleFont(familyName) {
|
|
106594
106801
|
const slug = fontSlug(familyName);
|
|
@@ -106680,6 +106887,37 @@ function dedupeElementsById(elements) {
|
|
|
106680
106887
|
}
|
|
106681
106888
|
return Array.from(deduped.values());
|
|
106682
106889
|
}
|
|
106890
|
+
var INLINE_SCRIPT_PATTERN = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
106891
|
+
function stripJsComments(source2) {
|
|
106892
|
+
return source2.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
106893
|
+
}
|
|
106894
|
+
function detectRenderModeHints(html) {
|
|
106895
|
+
const reasons = [];
|
|
106896
|
+
const { document: document2 } = parseHTML(html);
|
|
106897
|
+
if (document2.querySelector("iframe")) {
|
|
106898
|
+
reasons.push({
|
|
106899
|
+
code: "iframe",
|
|
106900
|
+
message: "Detected <iframe> in the composition DOM. Nested iframe animation is routed through screenshot capture mode for compatibility."
|
|
106901
|
+
});
|
|
106902
|
+
}
|
|
106903
|
+
let scriptMatch;
|
|
106904
|
+
const scriptPattern = new RegExp(INLINE_SCRIPT_PATTERN.source, INLINE_SCRIPT_PATTERN.flags);
|
|
106905
|
+
while ((scriptMatch = scriptPattern.exec(html)) !== null) {
|
|
106906
|
+
const attrs = scriptMatch[1] || "";
|
|
106907
|
+
if (/\bsrc\s*=/i.test(attrs)) continue;
|
|
106908
|
+
const content = stripJsComments(scriptMatch[2] || "");
|
|
106909
|
+
if (!/requestAnimationFrame\s*\(/.test(content)) continue;
|
|
106910
|
+
reasons.push({
|
|
106911
|
+
code: "requestAnimationFrame",
|
|
106912
|
+
message: "Detected raw requestAnimationFrame() in an inline script. This render is routed through screenshot capture mode with virtual time enabled."
|
|
106913
|
+
});
|
|
106914
|
+
break;
|
|
106915
|
+
}
|
|
106916
|
+
return {
|
|
106917
|
+
recommendScreenshot: reasons.length > 0,
|
|
106918
|
+
reasons
|
|
106919
|
+
};
|
|
106920
|
+
}
|
|
106683
106921
|
async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
|
|
106684
106922
|
let filePath = src;
|
|
106685
106923
|
if (isHttpUrl(src)) {
|
|
@@ -106690,7 +106928,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
106690
106928
|
return { duration: 0, resolvedPath: src };
|
|
106691
106929
|
}
|
|
106692
106930
|
} else if (!filePath.startsWith("/")) {
|
|
106693
|
-
filePath =
|
|
106931
|
+
filePath = join14(baseDir, filePath);
|
|
106694
106932
|
}
|
|
106695
106933
|
if (!existsSync14(filePath)) {
|
|
106696
106934
|
return { duration: 0, resolvedPath: filePath };
|
|
@@ -106756,7 +106994,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
106756
106994
|
const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
|
|
106757
106995
|
const absoluteStart = parentOffset + elStart;
|
|
106758
106996
|
const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
|
|
106759
|
-
const filePath =
|
|
106997
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106760
106998
|
if (visited.has(filePath)) {
|
|
106761
106999
|
continue;
|
|
106762
107000
|
}
|
|
@@ -106956,7 +107194,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
106956
107194
|
if (!srcPath) continue;
|
|
106957
107195
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
106958
107196
|
if (!compHtml) {
|
|
106959
|
-
const filePath =
|
|
107197
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106960
107198
|
if (existsSync14(filePath)) {
|
|
106961
107199
|
compHtml = readFileSync8(filePath, "utf-8");
|
|
106962
107200
|
}
|
|
@@ -107169,7 +107407,7 @@ ${safeText}
|
|
|
107169
107407
|
return result;
|
|
107170
107408
|
}
|
|
107171
107409
|
function collectExternalAssets(html, projectDir) {
|
|
107172
|
-
const absProjectDir =
|
|
107410
|
+
const absProjectDir = resolve9(projectDir);
|
|
107173
107411
|
const externalAssets = /* @__PURE__ */ new Map();
|
|
107174
107412
|
const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
107175
107413
|
function processPath(rawPath) {
|
|
@@ -107177,12 +107415,12 @@ function collectExternalAssets(html, projectDir) {
|
|
|
107177
107415
|
if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
|
|
107178
107416
|
return null;
|
|
107179
107417
|
}
|
|
107180
|
-
const absPath =
|
|
107181
|
-
if (
|
|
107418
|
+
const absPath = resolve9(absProjectDir, trimmed);
|
|
107419
|
+
if (isPathInside(absPath, absProjectDir)) {
|
|
107182
107420
|
return null;
|
|
107183
107421
|
}
|
|
107184
107422
|
if (!existsSync14(absPath)) return null;
|
|
107185
|
-
const safeKey =
|
|
107423
|
+
const safeKey = toExternalAssetKey(absPath);
|
|
107186
107424
|
externalAssets.set(safeKey, absPath);
|
|
107187
107425
|
return safeKey;
|
|
107188
107426
|
}
|
|
@@ -107243,6 +107481,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107243
107481
|
/(<(?:video|audio)\b[^>]*?)\s+preload\s*=\s*["']none["']/gi,
|
|
107244
107482
|
"$1"
|
|
107245
107483
|
);
|
|
107484
|
+
const renderModeHints = detectRenderModeHints(sanitizedHtml);
|
|
107246
107485
|
const coalescedHtml = await injectDeterministicFontFaces(
|
|
107247
107486
|
coalesceHeadStylesAndBodyScripts(promoteCssImportsToLinkTags(sanitizedHtml))
|
|
107248
107487
|
);
|
|
@@ -107254,7 +107493,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107254
107493
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
107255
107494
|
for (const video of videos) {
|
|
107256
107495
|
if (isHttpUrl(video.src)) continue;
|
|
107257
|
-
const videoPath =
|
|
107496
|
+
const videoPath = resolve9(projectDir, video.src);
|
|
107258
107497
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
107259
107498
|
Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
107260
107499
|
if (analysis.isProblematic) {
|
|
@@ -107286,7 +107525,8 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107286
107525
|
externalAssets,
|
|
107287
107526
|
width,
|
|
107288
107527
|
height,
|
|
107289
|
-
staticDuration
|
|
107528
|
+
staticDuration,
|
|
107529
|
+
renderModeHints
|
|
107290
107530
|
};
|
|
107291
107531
|
}
|
|
107292
107532
|
async function discoverMediaFromBrowser(page) {
|
|
@@ -107380,7 +107620,8 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
|
|
|
107380
107620
|
subCompositions,
|
|
107381
107621
|
videos,
|
|
107382
107622
|
audios,
|
|
107383
|
-
unresolvedCompositions: remaining
|
|
107623
|
+
unresolvedCompositions: remaining,
|
|
107624
|
+
renderModeHints: compiled.renderModeHints
|
|
107384
107625
|
};
|
|
107385
107626
|
}
|
|
107386
107627
|
|
|
@@ -107481,17 +107722,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
|
|
|
107481
107722
|
};
|
|
107482
107723
|
}
|
|
107483
107724
|
function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
107484
|
-
const compileDir =
|
|
107725
|
+
const compileDir = join15(workDir, "compiled");
|
|
107485
107726
|
mkdirSync10(compileDir, { recursive: true });
|
|
107486
|
-
writeFileSync4(
|
|
107727
|
+
writeFileSync4(join15(compileDir, "index.html"), compiled.html, "utf-8");
|
|
107487
107728
|
for (const [srcPath, html] of compiled.subCompositions) {
|
|
107488
|
-
const outPath =
|
|
107729
|
+
const outPath = join15(compileDir, srcPath);
|
|
107489
107730
|
mkdirSync10(dirname10(outPath), { recursive: true });
|
|
107490
107731
|
writeFileSync4(outPath, html, "utf-8");
|
|
107491
107732
|
}
|
|
107492
107733
|
for (const [relativePath, absolutePath] of compiled.externalAssets) {
|
|
107493
|
-
const outPath =
|
|
107494
|
-
if (!outPath
|
|
107734
|
+
const outPath = resolve10(join15(compileDir, relativePath));
|
|
107735
|
+
if (!isPathInside(outPath, compileDir)) {
|
|
107495
107736
|
console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
|
|
107496
107737
|
continue;
|
|
107497
107738
|
}
|
|
@@ -107517,11 +107758,20 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
|
107517
107758
|
end: a.end,
|
|
107518
107759
|
mediaStart: a.mediaStart
|
|
107519
107760
|
})),
|
|
107520
|
-
subCompositions: Array.from(compiled.subCompositions.keys())
|
|
107761
|
+
subCompositions: Array.from(compiled.subCompositions.keys()),
|
|
107762
|
+
renderModeHints: compiled.renderModeHints
|
|
107521
107763
|
};
|
|
107522
|
-
writeFileSync4(
|
|
107764
|
+
writeFileSync4(join15(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
|
|
107523
107765
|
}
|
|
107524
107766
|
}
|
|
107767
|
+
function applyRenderModeHints(cfg, compiled, log = defaultLogger) {
|
|
107768
|
+
if (cfg.forceScreenshot || !compiled.renderModeHints.recommendScreenshot) return;
|
|
107769
|
+
cfg.forceScreenshot = true;
|
|
107770
|
+
log.warn("Auto-selected screenshot capture mode for render compatibility", {
|
|
107771
|
+
reasonCodes: compiled.renderModeHints.reasons.map((reason) => reason.code),
|
|
107772
|
+
reasons: compiled.renderModeHints.reasons.map((reason) => reason.message)
|
|
107773
|
+
});
|
|
107774
|
+
}
|
|
107525
107775
|
function createRenderJob(config2) {
|
|
107526
107776
|
return {
|
|
107527
107777
|
id: randomUUID(),
|
|
@@ -107563,9 +107813,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
|
|
|
107563
107813
|
}
|
|
107564
107814
|
async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
|
|
107565
107815
|
const moduleDir = dirname10(fileURLToPath3(import.meta.url));
|
|
107566
|
-
const producerRoot = process.env.PRODUCER_RENDERS_DIR ?
|
|
107567
|
-
const debugDir =
|
|
107568
|
-
const workDir = job.config.debug ?
|
|
107816
|
+
const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve10(process.env.PRODUCER_RENDERS_DIR, "..") : resolve10(moduleDir, "../..");
|
|
107817
|
+
const debugDir = join15(producerRoot, ".debug");
|
|
107818
|
+
const workDir = job.config.debug ? join15(debugDir, job.id) : join15(dirname10(outputPath), `work-${job.id}`);
|
|
107569
107819
|
const pipelineStart = Date.now();
|
|
107570
107820
|
const log = job.config.logger ?? defaultLogger;
|
|
107571
107821
|
let fileServer = null;
|
|
@@ -107573,7 +107823,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107573
107823
|
let lastBrowserConsole = [];
|
|
107574
107824
|
let restoreLogger = null;
|
|
107575
107825
|
const perfStages = {};
|
|
107576
|
-
const perfOutputPath =
|
|
107826
|
+
const perfOutputPath = join15(workDir, "perf-summary.json");
|
|
107577
107827
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
107578
107828
|
const outputFormat = job.config.format ?? "mp4";
|
|
107579
107829
|
const isWebm = outputFormat === "webm";
|
|
@@ -107595,19 +107845,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107595
107845
|
assertNotAborted();
|
|
107596
107846
|
if (!existsSync15(workDir)) mkdirSync10(workDir, { recursive: true });
|
|
107597
107847
|
if (job.config.debug) {
|
|
107598
|
-
const logPath =
|
|
107848
|
+
const logPath = join15(workDir, "render.log");
|
|
107599
107849
|
restoreLogger = installDebugLogger(logPath, log);
|
|
107600
107850
|
}
|
|
107601
107851
|
const entryFile = job.config.entryFile || "index.html";
|
|
107602
|
-
let htmlPath =
|
|
107852
|
+
let htmlPath = join15(projectDir, entryFile);
|
|
107603
107853
|
if (!existsSync15(htmlPath)) {
|
|
107604
107854
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
107605
107855
|
}
|
|
107606
107856
|
assertNotAborted();
|
|
107607
107857
|
const rawEntry = readFileSync9(htmlPath, "utf-8");
|
|
107608
107858
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
107609
|
-
const wrapperPath =
|
|
107610
|
-
const projectIndexPath =
|
|
107859
|
+
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
107860
|
+
const projectIndexPath = join15(projectDir, "index.html");
|
|
107611
107861
|
if (!existsSync15(projectIndexPath)) {
|
|
107612
107862
|
throw new Error(
|
|
107613
107863
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
@@ -107631,9 +107881,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107631
107881
|
const stage1Start = Date.now();
|
|
107632
107882
|
updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
|
|
107633
107883
|
const compileStart = Date.now();
|
|
107634
|
-
let compiled = await compileForRender(projectDir, htmlPath,
|
|
107884
|
+
let compiled = await compileForRender(projectDir, htmlPath, join15(workDir, "downloads"));
|
|
107635
107885
|
assertNotAborted();
|
|
107636
107886
|
perfStages.compileOnlyMs = Date.now() - compileStart;
|
|
107887
|
+
applyRenderModeHints(cfg, compiled, log);
|
|
107637
107888
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
107638
107889
|
log.info("Compiled composition metadata", {
|
|
107639
107890
|
entryFile,
|
|
@@ -107641,7 +107892,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107641
107892
|
width: compiled.width,
|
|
107642
107893
|
height: compiled.height,
|
|
107643
107894
|
videoCount: compiled.videos.length,
|
|
107644
|
-
audioCount: compiled.audios.length
|
|
107895
|
+
audioCount: compiled.audios.length,
|
|
107896
|
+
renderModeHints: compiled.renderModeHints
|
|
107645
107897
|
});
|
|
107646
107898
|
const composition = {
|
|
107647
107899
|
duration: compiled.staticDuration,
|
|
@@ -107660,8 +107912,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107660
107912
|
reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
|
|
107661
107913
|
fileServer = await createFileServer2({
|
|
107662
107914
|
projectDir,
|
|
107663
|
-
compiledDir:
|
|
107664
|
-
port: 0
|
|
107915
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107916
|
+
port: 0,
|
|
107917
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
107665
107918
|
});
|
|
107666
107919
|
assertNotAborted();
|
|
107667
107920
|
const captureOpts = {
|
|
@@ -107673,7 +107926,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107673
107926
|
};
|
|
107674
107927
|
probeSession = await createCaptureSession(
|
|
107675
107928
|
fileServer.url,
|
|
107676
|
-
|
|
107929
|
+
join15(workDir, "probe"),
|
|
107677
107930
|
captureOpts,
|
|
107678
107931
|
null,
|
|
107679
107932
|
cfg
|
|
@@ -107705,7 +107958,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107705
107958
|
compiled,
|
|
107706
107959
|
resolutions,
|
|
107707
107960
|
projectDir,
|
|
107708
|
-
|
|
107961
|
+
join15(workDir, "downloads")
|
|
107709
107962
|
);
|
|
107710
107963
|
assertNotAborted();
|
|
107711
107964
|
composition.videos = compiled.videos;
|
|
@@ -107840,12 +108093,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107840
108093
|
const stage2Start = Date.now();
|
|
107841
108094
|
updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
|
|
107842
108095
|
let frameLookup = null;
|
|
107843
|
-
const compiledDir =
|
|
108096
|
+
const compiledDir = join15(workDir, "compiled");
|
|
107844
108097
|
if (composition.videos.length > 0) {
|
|
107845
108098
|
const extractionResult = await extractAllVideoFrames(
|
|
107846
108099
|
composition.videos,
|
|
107847
108100
|
projectDir,
|
|
107848
|
-
{ fps: job.config.fps, outputDir:
|
|
108101
|
+
{ fps: job.config.fps, outputDir: join15(workDir, "video-frames") },
|
|
107849
108102
|
abortSignal,
|
|
107850
108103
|
void 0,
|
|
107851
108104
|
compiledDir
|
|
@@ -107879,13 +108132,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107879
108132
|
}
|
|
107880
108133
|
const stage3Start = Date.now();
|
|
107881
108134
|
updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
|
|
107882
|
-
const audioOutputPath =
|
|
108135
|
+
const audioOutputPath = join15(workDir, "audio.aac");
|
|
107883
108136
|
let hasAudio = false;
|
|
107884
108137
|
if (composition.audios.length > 0) {
|
|
107885
108138
|
const audioResult = await processCompositionAudio(
|
|
107886
108139
|
composition.audios,
|
|
107887
108140
|
projectDir,
|
|
107888
|
-
|
|
108141
|
+
join15(workDir, "audio-work"),
|
|
107889
108142
|
audioOutputPath,
|
|
107890
108143
|
job.duration,
|
|
107891
108144
|
abortSignal,
|
|
@@ -107903,12 +108156,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107903
108156
|
if (!fileServer) {
|
|
107904
108157
|
fileServer = await createFileServer2({
|
|
107905
108158
|
projectDir,
|
|
107906
|
-
compiledDir:
|
|
107907
|
-
port: 0
|
|
108159
|
+
compiledDir: join15(workDir, "compiled"),
|
|
108160
|
+
port: 0,
|
|
108161
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
107908
108162
|
});
|
|
107909
108163
|
assertNotAborted();
|
|
107910
108164
|
}
|
|
107911
|
-
const framesDir =
|
|
108165
|
+
const framesDir = join15(workDir, "captured-frames");
|
|
107912
108166
|
if (!existsSync15(framesDir)) mkdirSync10(framesDir, { recursive: true });
|
|
107913
108167
|
const captureOptions = {
|
|
107914
108168
|
width,
|
|
@@ -107920,7 +108174,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107920
108174
|
const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
|
|
107921
108175
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
107922
108176
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
107923
|
-
const videoOnlyPath =
|
|
108177
|
+
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
107924
108178
|
const preset = getEncoderPreset(job.config.quality, outputFormat);
|
|
107925
108179
|
const effectiveQuality = job.config.crf ?? preset.quality;
|
|
107926
108180
|
const effectiveBitrate = job.config.videoBitrate;
|
|
@@ -108196,7 +108450,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108196
108450
|
}
|
|
108197
108451
|
if (job.config.debug) {
|
|
108198
108452
|
if (existsSync15(outputPath)) {
|
|
108199
|
-
const debugOutput =
|
|
108453
|
+
const debugOutput = join15(workDir, `output${videoExt}`);
|
|
108200
108454
|
copyFileSync2(outputPath, debugOutput);
|
|
108201
108455
|
}
|
|
108202
108456
|
} else {
|
|
@@ -108291,7 +108545,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108291
108545
|
|
|
108292
108546
|
// src/services/hyperframeLint.ts
|
|
108293
108547
|
import { existsSync as existsSync16, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
|
|
108294
|
-
import { resolve as
|
|
108548
|
+
import { resolve as resolve11, join as join16 } from "node:path";
|
|
108295
108549
|
function isStringRecord(value) {
|
|
108296
108550
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
108297
108551
|
return false;
|
|
@@ -108318,7 +108572,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
108318
108572
|
return null;
|
|
108319
108573
|
}
|
|
108320
108574
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
108321
|
-
const absProjectDir =
|
|
108575
|
+
const absProjectDir = resolve11(projectDir);
|
|
108322
108576
|
if (!existsSync16(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
|
|
108323
108577
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
108324
108578
|
}
|
|
@@ -108326,7 +108580,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108326
108580
|
(value) => typeof value === "string" && value.trim().length > 0
|
|
108327
108581
|
);
|
|
108328
108582
|
for (const entryFile of entryCandidates) {
|
|
108329
|
-
const absoluteEntryPath =
|
|
108583
|
+
const absoluteEntryPath = resolve11(absProjectDir, entryFile);
|
|
108330
108584
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
108331
108585
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
108332
108586
|
}
|
|
@@ -108339,7 +108593,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108339
108593
|
}
|
|
108340
108594
|
}
|
|
108341
108595
|
return {
|
|
108342
|
-
error: `No HTML entry file found in project directory: ${
|
|
108596
|
+
error: `No HTML entry file found in project directory: ${join16(absProjectDir, preferredEntryFile || "index.html")}`
|
|
108343
108597
|
};
|
|
108344
108598
|
}
|
|
108345
108599
|
function prepareHyperframeLintBody(body) {
|
|
@@ -108379,17 +108633,6 @@ function runHyperframeLint(prepared) {
|
|
|
108379
108633
|
return lintHyperframeHtml(prepared.html, { filePath: prepared.entryFile });
|
|
108380
108634
|
}
|
|
108381
108635
|
|
|
108382
|
-
// src/utils/paths.ts
|
|
108383
|
-
import { resolve as resolve11, basename as basename2, join as join16 } from "node:path";
|
|
108384
|
-
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
108385
|
-
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
108386
|
-
const absoluteProjectDir = resolve11(projectDir);
|
|
108387
|
-
const projectName = basename2(absoluteProjectDir);
|
|
108388
|
-
const resolvedOutputPath = outputPath ?? join16(rendersDir, `${projectName}.mp4`);
|
|
108389
|
-
const absoluteOutputPath = resolve11(resolvedOutputPath);
|
|
108390
|
-
return { absoluteProjectDir, absoluteOutputPath };
|
|
108391
|
-
}
|
|
108392
|
-
|
|
108393
108636
|
// src/utils/semaphore.ts
|
|
108394
108637
|
var Semaphore = class {
|
|
108395
108638
|
constructor(maxConcurrent) {
|