hyperframes 0.6.74 → 0.6.76
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 +188 -37
- package/dist/studio/assets/hyperframes-player-WXAuftNy.js +418 -0
- package/dist/studio/assets/index-DcyZuBcU.css +1 -0
- package/dist/studio/assets/index-IDqTMz4S.js +140 -0
- package/dist/studio/index.html +2 -2
- package/package.json +1 -1
- package/dist/studio/assets/hyperframes-player-DOZ3POPj.js +0 -418
- package/dist/studio/assets/index-BcJO6Ej5.js +0 -140
- package/dist/studio/assets/index-C2gBZ2km.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ var VERSION;
|
|
|
50
50
|
var init_version = __esm({
|
|
51
51
|
"src/version.ts"() {
|
|
52
52
|
"use strict";
|
|
53
|
-
VERSION = true ? "0.6.
|
|
53
|
+
VERSION = true ? "0.6.76" : "0.0.0-dev";
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -62042,21 +62042,33 @@ var init_manager2 = __esm({
|
|
|
62042
62042
|
}
|
|
62043
62043
|
});
|
|
62044
62044
|
|
|
62045
|
-
// ../engine/src/
|
|
62045
|
+
// ../engine/src/services/systemMemory.ts
|
|
62046
62046
|
import { totalmem as totalmem2 } from "os";
|
|
62047
62047
|
function getSystemTotalMb() {
|
|
62048
62048
|
return Math.floor(totalmem2() / (1024 * 1024));
|
|
62049
62049
|
}
|
|
62050
|
+
function isLowMemorySystem(totalMb = getSystemTotalMb()) {
|
|
62051
|
+
return totalMb <= LOW_MEMORY_TOTAL_MB_THRESHOLD;
|
|
62052
|
+
}
|
|
62053
|
+
var LOW_MEMORY_TOTAL_MB_THRESHOLD;
|
|
62054
|
+
var init_systemMemory = __esm({
|
|
62055
|
+
"../engine/src/services/systemMemory.ts"() {
|
|
62056
|
+
"use strict";
|
|
62057
|
+
LOW_MEMORY_TOTAL_MB_THRESHOLD = 8192;
|
|
62058
|
+
}
|
|
62059
|
+
});
|
|
62060
|
+
|
|
62061
|
+
// ../engine/src/config.ts
|
|
62050
62062
|
function memoryAdaptiveCacheLimit() {
|
|
62051
62063
|
const total = getSystemTotalMb();
|
|
62052
62064
|
if (total < 4096) return 32;
|
|
62053
|
-
if (total <=
|
|
62065
|
+
if (total <= LOW_MEMORY_TOTAL_MB_THRESHOLD) return 64;
|
|
62054
62066
|
return DEFAULT_CONFIG2.frameDataUriCacheLimit;
|
|
62055
62067
|
}
|
|
62056
62068
|
function memoryAdaptiveCacheBytesMb() {
|
|
62057
62069
|
const total = getSystemTotalMb();
|
|
62058
62070
|
if (total < 4096) return 128;
|
|
62059
|
-
if (total <=
|
|
62071
|
+
if (total <= LOW_MEMORY_TOTAL_MB_THRESHOLD) return 256;
|
|
62060
62072
|
return DEFAULT_CONFIG2.frameDataUriCacheBytesLimitMb;
|
|
62061
62073
|
}
|
|
62062
62074
|
function resolveConfig(overrides) {
|
|
@@ -62077,6 +62089,12 @@ function resolveConfig(overrides) {
|
|
|
62077
62089
|
if (raw === "hardware" || raw === "software" || raw === "auto") return raw;
|
|
62078
62090
|
return DEFAULT_CONFIG2.browserGpuMode;
|
|
62079
62091
|
};
|
|
62092
|
+
const resolveLowMemoryMode = () => {
|
|
62093
|
+
const raw = env("PRODUCER_LOW_MEMORY_MODE")?.toLowerCase();
|
|
62094
|
+
if (raw === "true" || raw === "on" || raw === "1") return true;
|
|
62095
|
+
if (raw === "false" || raw === "off" || raw === "0") return false;
|
|
62096
|
+
return isLowMemorySystem();
|
|
62097
|
+
};
|
|
62080
62098
|
const fromEnv = {
|
|
62081
62099
|
concurrency: env("PRODUCER_MAX_WORKERS") ? Number(env("PRODUCER_MAX_WORKERS")) : void 0,
|
|
62082
62100
|
coresPerWorker: envNum("PRODUCER_CORES_PER_WORKER", DEFAULT_CONFIG2.coresPerWorker),
|
|
@@ -62096,6 +62114,7 @@ function resolveConfig(overrides) {
|
|
|
62096
62114
|
),
|
|
62097
62115
|
expectedChromiumMajor: env("PRODUCER_EXPECTED_CHROMIUM_MAJOR") ? Number(env("PRODUCER_EXPECTED_CHROMIUM_MAJOR")) : void 0,
|
|
62098
62116
|
forceScreenshot: envBool("PRODUCER_FORCE_SCREENSHOT", DEFAULT_CONFIG2.forceScreenshot),
|
|
62117
|
+
lowMemoryMode: resolveLowMemoryMode(),
|
|
62099
62118
|
enablePageSideCompositing: envBool(
|
|
62100
62119
|
"HF_PAGE_SIDE_COMPOSITING",
|
|
62101
62120
|
DEFAULT_CONFIG2.enablePageSideCompositing
|
|
@@ -62167,6 +62186,7 @@ var DEFAULT_CONFIG2;
|
|
|
62167
62186
|
var init_config2 = __esm({
|
|
62168
62187
|
"../engine/src/config.ts"() {
|
|
62169
62188
|
"use strict";
|
|
62189
|
+
init_systemMemory();
|
|
62170
62190
|
DEFAULT_CONFIG2 = {
|
|
62171
62191
|
fps: 30,
|
|
62172
62192
|
quality: "standard",
|
|
@@ -62182,6 +62202,9 @@ var init_config2 = __esm({
|
|
|
62182
62202
|
browserTimeout: 12e4,
|
|
62183
62203
|
protocolTimeout: 3e5,
|
|
62184
62204
|
forceScreenshot: false,
|
|
62205
|
+
// Auto-detected per host in `resolveConfig`; defaults off for the raw
|
|
62206
|
+
// DEFAULT_CONFIG (used directly by tests and worker-sizing fallbacks).
|
|
62207
|
+
lowMemoryMode: false,
|
|
62185
62208
|
enablePageSideCompositing: true,
|
|
62186
62209
|
enableChunkedEncode: false,
|
|
62187
62210
|
chunkSizeFrames: 360,
|
|
@@ -62208,7 +62231,7 @@ var init_config2 = __esm({
|
|
|
62208
62231
|
import { execSync as execSync4 } from "child_process";
|
|
62209
62232
|
import { existsSync as existsSync19, readdirSync as readdirSync9 } from "fs";
|
|
62210
62233
|
import { join as join23 } from "path";
|
|
62211
|
-
import { homedir as homedir6
|
|
62234
|
+
import { homedir as homedir6 } from "os";
|
|
62212
62235
|
async function getPuppeteer() {
|
|
62213
62236
|
if (_puppeteer) return _puppeteer;
|
|
62214
62237
|
try {
|
|
@@ -62402,6 +62425,10 @@ async function launchBrowser(chromeArgs, config) {
|
|
|
62402
62425
|
timeout: browserTimeout,
|
|
62403
62426
|
protocolTimeout
|
|
62404
62427
|
});
|
|
62428
|
+
const browserVersion = await browser.version().catch(() => "unknown");
|
|
62429
|
+
console.log(
|
|
62430
|
+
`[BrowserManager] Browser launched (${browserVersion}, ${captureMode}, headlessShell=${!!headlessShell}, platform=${process.platform})`
|
|
62431
|
+
);
|
|
62405
62432
|
if (captureMode === "beginframe") {
|
|
62406
62433
|
const supported = await probeBeginFrameSupport(browser).catch(() => true);
|
|
62407
62434
|
if (!supported) {
|
|
@@ -62480,9 +62507,6 @@ async function drainBrowserPool() {
|
|
|
62480
62507
|
});
|
|
62481
62508
|
}
|
|
62482
62509
|
}
|
|
62483
|
-
function getTotalMemMb() {
|
|
62484
|
-
return Math.floor(totalmem3() / (1024 * 1024));
|
|
62485
|
-
}
|
|
62486
62510
|
function probeNvidiaVramMb() {
|
|
62487
62511
|
if (_cachedVramMb !== null) return _cachedVramMb;
|
|
62488
62512
|
try {
|
|
@@ -62503,14 +62527,14 @@ function probeNvidiaVramMb() {
|
|
|
62503
62527
|
function getGpuMemBudgetMb() {
|
|
62504
62528
|
const vram = probeNvidiaVramMb();
|
|
62505
62529
|
if (vram) return Math.min(vram, 16384);
|
|
62506
|
-
const total =
|
|
62530
|
+
const total = getSystemTotalMb();
|
|
62507
62531
|
if (total < 4096) return 512;
|
|
62508
|
-
if (total <=
|
|
62532
|
+
if (total <= LOW_MEMORY_TOTAL_MB_THRESHOLD) return 1024;
|
|
62509
62533
|
return Math.min(Math.floor(total / 2), 16384);
|
|
62510
62534
|
}
|
|
62511
62535
|
function getLowMemoryFlags() {
|
|
62512
|
-
const total =
|
|
62513
|
-
if (total >
|
|
62536
|
+
const total = getSystemTotalMb();
|
|
62537
|
+
if (total > LOW_MEMORY_TOTAL_MB_THRESHOLD) return [];
|
|
62514
62538
|
const heapMb = total < 4096 ? 256 : 512;
|
|
62515
62539
|
return [`--js-flags=--max-old-space-size=${heapMb}`];
|
|
62516
62540
|
}
|
|
@@ -62606,6 +62630,7 @@ var init_browserManager = __esm({
|
|
|
62606
62630
|
"../engine/src/services/browserManager.ts"() {
|
|
62607
62631
|
"use strict";
|
|
62608
62632
|
init_config2();
|
|
62633
|
+
init_systemMemory();
|
|
62609
62634
|
pooledBrowser = null;
|
|
62610
62635
|
pooledBrowserRefCount = 0;
|
|
62611
62636
|
pooledCaptureMode = "screenshot";
|
|
@@ -63305,17 +63330,26 @@ async function initializeSession(session) {
|
|
|
63305
63330
|
});
|
|
63306
63331
|
const url = `${serverUrl}/index.html`;
|
|
63307
63332
|
const pageNavigationTimeout = session.config?.pageNavigationTimeout ?? DEFAULT_CONFIG2.pageNavigationTimeout;
|
|
63333
|
+
const initStart = Date.now();
|
|
63334
|
+
const logInitPhase = (phase) => {
|
|
63335
|
+
console.log(`[initSession:${session.captureMode}] ${phase} (${Date.now() - initStart}ms)`);
|
|
63336
|
+
};
|
|
63308
63337
|
if (session.captureMode === "screenshot") {
|
|
63309
63338
|
await page.goto(url, { waitUntil: "domcontentloaded", timeout: pageNavigationTimeout });
|
|
63339
|
+
logInitPhase("page.goto complete");
|
|
63310
63340
|
const pageReadyTimeout2 = session.config?.playerReadyTimeout ?? DEFAULT_CONFIG2.playerReadyTimeout;
|
|
63311
63341
|
await pollHfReady(page, pageReadyTimeout2);
|
|
63342
|
+
logInitPhase("pollHfReady complete");
|
|
63312
63343
|
await pollSubCompositionTimelines(page, pageReadyTimeout2);
|
|
63344
|
+
logInitPhase("pollSubCompositionTimelines complete");
|
|
63313
63345
|
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
63346
|
+
logInitPhase("applyVideoMetadataHints complete");
|
|
63314
63347
|
const videosReady = await pollVideosReady(
|
|
63315
63348
|
page,
|
|
63316
63349
|
session.options.skipReadinessVideoIds ?? [],
|
|
63317
63350
|
pageReadyTimeout2
|
|
63318
63351
|
);
|
|
63352
|
+
logInitPhase("pollVideosReady complete");
|
|
63319
63353
|
if (!videosReady) {
|
|
63320
63354
|
const failedVideos = await page.evaluate((skipIdList) => {
|
|
63321
63355
|
const skip = new Set(skipIdList);
|
|
@@ -63340,8 +63374,11 @@ async function initializeSession(session) {
|
|
|
63340
63374
|
);
|
|
63341
63375
|
}
|
|
63342
63376
|
await decodeAllImages(page);
|
|
63377
|
+
logInitPhase("images ready + decoded");
|
|
63343
63378
|
await page.evaluate(`document.fonts?.ready`);
|
|
63379
|
+
logInitPhase("fonts ready");
|
|
63344
63380
|
await waitForOptionalTailwindReady(page, pageReadyTimeout2);
|
|
63381
|
+
logInitPhase("tailwind ready");
|
|
63345
63382
|
if (session.options.format === "png") {
|
|
63346
63383
|
await initTransparentBackground(session.page);
|
|
63347
63384
|
}
|
|
@@ -63384,16 +63421,21 @@ async function initializeSession(session) {
|
|
|
63384
63421
|
})();
|
|
63385
63422
|
warmupLoopPromise.catch(() => {
|
|
63386
63423
|
});
|
|
63424
|
+
logInitPhase("warmup loop started");
|
|
63387
63425
|
await page.goto(url, { waitUntil: "domcontentloaded", timeout: pageNavigationTimeout });
|
|
63426
|
+
logInitPhase("page.goto complete");
|
|
63388
63427
|
const pageReadyTimeout = session.config?.playerReadyTimeout ?? DEFAULT_CONFIG2.playerReadyTimeout;
|
|
63389
63428
|
try {
|
|
63390
63429
|
await pollHfReady(page, pageReadyTimeout);
|
|
63430
|
+
logInitPhase("pollHfReady complete");
|
|
63391
63431
|
} catch (err) {
|
|
63392
63432
|
warmupState.running = false;
|
|
63393
63433
|
throw err;
|
|
63394
63434
|
}
|
|
63395
63435
|
await pollSubCompositionTimelines(page, pageReadyTimeout);
|
|
63436
|
+
logInitPhase("pollSubCompositionTimelines complete");
|
|
63396
63437
|
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
63438
|
+
logInitPhase("applyVideoMetadataHints complete");
|
|
63397
63439
|
const bfVideosReady = await pollVideosReady(
|
|
63398
63440
|
page,
|
|
63399
63441
|
session.options.skipReadinessVideoIds ?? [],
|
|
@@ -63408,6 +63450,7 @@ async function initializeSession(session) {
|
|
|
63408
63450
|
`[FrameCapture] Some video elements did not decode within ${pageReadyTimeout}ms: ${failedVideos}. Continuing render \u2014 affected videos will appear as blank/black frames.`
|
|
63409
63451
|
);
|
|
63410
63452
|
}
|
|
63453
|
+
logInitPhase("pollVideosReady complete");
|
|
63411
63454
|
const bfImagesReady = await pollImagesReady(page, pageReadyTimeout);
|
|
63412
63455
|
if (!bfImagesReady) {
|
|
63413
63456
|
const failedImages = await page.evaluate(() => {
|
|
@@ -63423,8 +63466,11 @@ async function initializeSession(session) {
|
|
|
63423
63466
|
);
|
|
63424
63467
|
}
|
|
63425
63468
|
await decodeAllImages(page);
|
|
63469
|
+
logInitPhase("images ready + decoded");
|
|
63426
63470
|
await page.evaluate(`document.fonts?.ready`);
|
|
63471
|
+
logInitPhase("fonts ready");
|
|
63427
63472
|
await waitForOptionalTailwindReady(page, pageReadyTimeout);
|
|
63473
|
+
logInitPhase("tailwind ready");
|
|
63428
63474
|
warmupState.running = false;
|
|
63429
63475
|
if (lockWarmupTicks) {
|
|
63430
63476
|
await warmupLoopPromise.catch(() => {
|
|
@@ -68579,7 +68625,7 @@ var init_readWebGlVendorInfoFromCanvas = __esm({
|
|
|
68579
68625
|
});
|
|
68580
68626
|
|
|
68581
68627
|
// ../engine/src/services/parallelCoordinator.ts
|
|
68582
|
-
import { cpus as cpus2, freemem as freemem3, totalmem as
|
|
68628
|
+
import { cpus as cpus2, freemem as freemem3, totalmem as totalmem3 } from "os";
|
|
68583
68629
|
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readdirSync as readdirSync13 } from "fs";
|
|
68584
68630
|
import { copyFile, rename } from "fs/promises";
|
|
68585
68631
|
import { join as join31 } from "path";
|
|
@@ -68604,7 +68650,7 @@ function calculateOptimalWorkers(totalFrames, requested, config) {
|
|
|
68604
68650
|
if (totalFrames < MIN_FRAMES_PER_WORKER * 2) return 1;
|
|
68605
68651
|
const cpuCount = cpus2().length;
|
|
68606
68652
|
const cpuBasedWorkers = Math.max(1, cpuCount - 2);
|
|
68607
|
-
const totalMemoryMB = Math.round(
|
|
68653
|
+
const totalMemoryMB = Math.round(totalmem3() / (1024 * 1024));
|
|
68608
68654
|
const memoryBasedWorkers = Math.max(1, Math.floor(totalMemoryMB * 0.5 / MEMORY_PER_WORKER_MB));
|
|
68609
68655
|
const frameBasedWorkers = Math.floor(totalFrames / MIN_FRAMES_PER_WORKER);
|
|
68610
68656
|
const optimal = Math.min(cpuBasedWorkers, memoryBasedWorkers, frameBasedWorkers);
|
|
@@ -68782,7 +68828,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
|
|
|
68782
68828
|
function getSystemResources() {
|
|
68783
68829
|
return {
|
|
68784
68830
|
cpuCores: cpus2().length,
|
|
68785
|
-
totalMemoryMB: Math.round(
|
|
68831
|
+
totalMemoryMB: Math.round(totalmem3() / (1024 * 1024)),
|
|
68786
68832
|
freeMemoryMB: Math.round(freemem3() / (1024 * 1024)),
|
|
68787
68833
|
recommendedWorkers: calculateOptimalWorkers(1e3)
|
|
68788
68834
|
};
|
|
@@ -70357,6 +70403,7 @@ __export(src_exports2, {
|
|
|
70357
70403
|
ENABLE_BROWSER_POOL: () => ENABLE_BROWSER_POOL,
|
|
70358
70404
|
ENCODER_PRESETS: () => ENCODER_PRESETS,
|
|
70359
70405
|
FrameLookupTable: () => FrameLookupTable,
|
|
70406
|
+
LOW_MEMORY_TOTAL_MB_THRESHOLD: () => LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
70360
70407
|
MEDIA_VISUAL_STYLE_PROPERTIES: () => MEDIA_VISUAL_STYLE_PROPERTIES,
|
|
70361
70408
|
SwiftShaderAssertionError: () => SwiftShaderAssertionError,
|
|
70362
70409
|
TRANSITIONS: () => TRANSITIONS,
|
|
@@ -70412,6 +70459,7 @@ __export(src_exports2, {
|
|
|
70412
70459
|
getFrameAtTime: () => getFrameAtTime,
|
|
70413
70460
|
getHdrEncoderColorParams: () => getHdrEncoderColorParams,
|
|
70414
70461
|
getSystemResources: () => getSystemResources,
|
|
70462
|
+
getSystemTotalMb: () => getSystemTotalMb,
|
|
70415
70463
|
groupIntoLayers: () => groupIntoLayers,
|
|
70416
70464
|
hdrToLinear: () => hdrToLinear,
|
|
70417
70465
|
hideVideoElements: () => hideVideoElements,
|
|
@@ -70421,6 +70469,7 @@ __export(src_exports2, {
|
|
|
70421
70469
|
injectVideoFramesBatch: () => injectVideoFramesBatch,
|
|
70422
70470
|
isHdrColorSpace: () => isHdrColorSpace,
|
|
70423
70471
|
isHttpUrl: () => isHttpUrl,
|
|
70472
|
+
isLowMemorySystem: () => isLowMemorySystem,
|
|
70424
70473
|
killTrackedProcesses: () => killTrackedProcesses,
|
|
70425
70474
|
launchHdrBrowser: () => launchHdrBrowser,
|
|
70426
70475
|
linearToHdr: () => linearToHdr,
|
|
@@ -70459,6 +70508,7 @@ var init_src2 = __esm({
|
|
|
70459
70508
|
"../engine/src/index.ts"() {
|
|
70460
70509
|
"use strict";
|
|
70461
70510
|
init_config2();
|
|
70511
|
+
init_systemMemory();
|
|
70462
70512
|
init_browserManager();
|
|
70463
70513
|
init_frameCapture();
|
|
70464
70514
|
init_screenshotService();
|
|
@@ -72130,6 +72180,12 @@ function resolveRenderWorkerCount(totalFrames, requestedWorkers, cfg, compiled,
|
|
|
72130
72180
|
);
|
|
72131
72181
|
return 1;
|
|
72132
72182
|
}
|
|
72183
|
+
if (cfg.lowMemoryMode && requestedWorkers === void 0) {
|
|
72184
|
+
log2.info(
|
|
72185
|
+
"[Render] Low-memory profile \u2014 pinning to 1 capture worker (auto-worker calibration skipped)."
|
|
72186
|
+
);
|
|
72187
|
+
return 1;
|
|
72188
|
+
}
|
|
72133
72189
|
const captureCost = combineCaptureCostEstimates(
|
|
72134
72190
|
estimateCaptureCostMultiplier(compiled),
|
|
72135
72191
|
measuredCaptureCost
|
|
@@ -72158,7 +72214,7 @@ function resolveRenderWorkerCount(totalFrames, requestedWorkers, cfg, compiled,
|
|
|
72158
72214
|
function createCaptureCalibrationConfig(cfg) {
|
|
72159
72215
|
return {
|
|
72160
72216
|
...cfg,
|
|
72161
|
-
protocolTimeout: Math.
|
|
72217
|
+
protocolTimeout: Math.min(cfg.protocolTimeout, CAPTURE_CALIBRATION_PROTOCOL_TIMEOUT_MS)
|
|
72162
72218
|
};
|
|
72163
72219
|
}
|
|
72164
72220
|
function estimateMeasuredCaptureCostMultiplier(samples) {
|
|
@@ -72290,6 +72346,12 @@ async function runCaptureCalibration(input2) {
|
|
|
72290
72346
|
return result;
|
|
72291
72347
|
};
|
|
72292
72348
|
const calibrationCfg = createCaptureCalibrationConfig({ ...cfg, forceScreenshot });
|
|
72349
|
+
log2.info("[Render] Calibration config", {
|
|
72350
|
+
protocolTimeout: calibrationCfg.protocolTimeout,
|
|
72351
|
+
parentProtocolTimeout: cfg.protocolTimeout,
|
|
72352
|
+
forceScreenshot,
|
|
72353
|
+
totalFrames
|
|
72354
|
+
});
|
|
72293
72355
|
let calibration;
|
|
72294
72356
|
try {
|
|
72295
72357
|
calibration = await runOneCalibration(join38(workDir, "capture-calibration"), calibrationCfg);
|
|
@@ -76531,6 +76593,20 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
76531
76593
|
};
|
|
76532
76594
|
job.startedAt = /* @__PURE__ */ new Date();
|
|
76533
76595
|
assertNotAborted();
|
|
76596
|
+
log2.info("[Render] Pipeline started", {
|
|
76597
|
+
platform: process.platform,
|
|
76598
|
+
arch: process.arch,
|
|
76599
|
+
nodeVersion: process.version,
|
|
76600
|
+
fps: job.config.fps,
|
|
76601
|
+
format: outputFormat,
|
|
76602
|
+
quality: job.config.quality,
|
|
76603
|
+
browserGpuMode: cfg.browserGpuMode,
|
|
76604
|
+
forceScreenshot: cfg.forceScreenshot,
|
|
76605
|
+
protocolTimeout: cfg.protocolTimeout,
|
|
76606
|
+
browserTimeout: cfg.browserTimeout,
|
|
76607
|
+
pageNavigationTimeout: cfg.pageNavigationTimeout,
|
|
76608
|
+
playerReadyTimeout: cfg.playerReadyTimeout
|
|
76609
|
+
});
|
|
76534
76610
|
if (!existsSync40(workDir)) mkdirSync24(workDir, { recursive: true });
|
|
76535
76611
|
if (job.config.debug) {
|
|
76536
76612
|
const logPath = join50(workDir, "render.log");
|
|
@@ -76585,6 +76661,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
76585
76661
|
const { width, height } = composition;
|
|
76586
76662
|
perfStages.compileOnlyMs = compileResult.compileOnlyMs;
|
|
76587
76663
|
let captureForceScreenshot = compileResult.forceScreenshot;
|
|
76664
|
+
if (cfg.lowMemoryMode) {
|
|
76665
|
+
captureForceScreenshot = true;
|
|
76666
|
+
log2.info(
|
|
76667
|
+
"[Render] Low-memory render profile active \u2014 screenshot capture, auto-worker calibration skipped" + (job.config.workers === void 0 ? ", pinned to 1 worker" : "") + ". Override with --no-low-memory-mode or PRODUCER_LOW_MEMORY_MODE=false.",
|
|
76668
|
+
{ totalMemMb: getSystemTotalMb(), thresholdMb: LOW_MEMORY_TOTAL_MB_THRESHOLD }
|
|
76669
|
+
);
|
|
76670
|
+
}
|
|
76588
76671
|
const probeResult = await runProbeStage({
|
|
76589
76672
|
projectDir,
|
|
76590
76673
|
workDir,
|
|
@@ -76689,7 +76772,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
76689
76772
|
const htmlInCanvasDetected = compiled.renderModeHints.reasons.some(
|
|
76690
76773
|
(r2) => r2.code === "htmlInCanvas"
|
|
76691
76774
|
);
|
|
76692
|
-
if (job.config.workers === void 0 && totalFrames >= 60 && !htmlInCanvasDetected) {
|
|
76775
|
+
if (job.config.workers === void 0 && totalFrames >= 60 && !htmlInCanvasDetected && !cfg.lowMemoryMode) {
|
|
76693
76776
|
const outcome = await runCaptureCalibration({
|
|
76694
76777
|
cfg,
|
|
76695
76778
|
fileServer,
|
|
@@ -77006,6 +77089,16 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
77006
77089
|
perfStages,
|
|
77007
77090
|
hdrDiagnostics
|
|
77008
77091
|
});
|
|
77092
|
+
log2.info("[Render] Failure summary", {
|
|
77093
|
+
failedStage: job.currentStage,
|
|
77094
|
+
error: errorMessage,
|
|
77095
|
+
elapsedMs: Date.now() - pipelineStart,
|
|
77096
|
+
stageTimings: perfStages,
|
|
77097
|
+
isTimeout: isTimeoutError,
|
|
77098
|
+
workers: job.config.workers ?? "auto",
|
|
77099
|
+
protocolTimeout: cfg.protocolTimeout,
|
|
77100
|
+
browserConsoleErrors: lastBrowserConsole.filter((l) => l.includes("ERROR") || l.includes("PAGEERROR")).slice(-5)
|
|
77101
|
+
});
|
|
77009
77102
|
await cleanupRenderResources({
|
|
77010
77103
|
fileServer,
|
|
77011
77104
|
probeSession,
|
|
@@ -83467,6 +83560,10 @@ var init_render2 = __esm({
|
|
|
83467
83560
|
"player-ready-timeout": {
|
|
83468
83561
|
type: "string",
|
|
83469
83562
|
description: "Timeout in ms for the composition player to become ready. Increase for complex compositions on slow hardware. Default: 45000 (45 s). Env: PRODUCER_PLAYER_READY_TIMEOUT_MS."
|
|
83563
|
+
},
|
|
83564
|
+
"low-memory-mode": {
|
|
83565
|
+
type: "boolean",
|
|
83566
|
+
description: "Force the low-memory safe render profile on (--low-memory-mode) or off (--no-low-memory-mode). Safe mode pins to 1 worker, uses screenshot capture, and skips auto-worker calibration to avoid memory thrash on constrained machines. Default: auto-detected from total RAM (<= 8 GB). Env: PRODUCER_LOW_MEMORY_MODE."
|
|
83470
83567
|
}
|
|
83471
83568
|
},
|
|
83472
83569
|
// `run` is the citty handler for `hyperframes render` — sequential flag
|
|
@@ -83550,6 +83647,9 @@ var init_render2 = __esm({
|
|
|
83550
83647
|
if (args["page-side-compositing"] === false) {
|
|
83551
83648
|
process.env.HF_PAGE_SIDE_COMPOSITING = "false";
|
|
83552
83649
|
}
|
|
83650
|
+
if (args["low-memory-mode"] != null) {
|
|
83651
|
+
process.env.PRODUCER_LOW_MEMORY_MODE = args["low-memory-mode"] ? "true" : "false";
|
|
83652
|
+
}
|
|
83553
83653
|
if (args["max-concurrent-renders"] != null) {
|
|
83554
83654
|
const parsed = parseInt(args["max-concurrent-renders"], 10);
|
|
83555
83655
|
if (isNaN(parsed) || parsed < 1 || parsed > 10) {
|
|
@@ -127970,35 +128070,71 @@ async function downloadAndRewriteFonts(css, outputDir) {
|
|
|
127970
128070
|
}
|
|
127971
128071
|
return rewritten;
|
|
127972
128072
|
}
|
|
128073
|
+
function isPrivateIpv4(host) {
|
|
128074
|
+
const octets = host.split(".").map(Number);
|
|
128075
|
+
if (octets.length !== 4) return false;
|
|
128076
|
+
const [a, b2] = octets;
|
|
128077
|
+
return PRIVATE_V4_BLOCKS.some(([first, lo, hi]) => a === first && b2 >= lo && b2 <= hi);
|
|
128078
|
+
}
|
|
128079
|
+
function isPrivateIpv6(bracketed) {
|
|
128080
|
+
const addr = bracketed.replace(/^\[|\]$/g, "").toLowerCase();
|
|
128081
|
+
if (addr === "::1" || addr === "::") return true;
|
|
128082
|
+
const mapped = /^::ffff:(.+)$/.exec(addr);
|
|
128083
|
+
if (mapped) {
|
|
128084
|
+
const tail = mapped[1];
|
|
128085
|
+
if (tail.includes(".")) return isPrivateIpv4(tail);
|
|
128086
|
+
const hex = tail.split(":");
|
|
128087
|
+
if (hex.length === 2) {
|
|
128088
|
+
const n = (parseInt(hex[0], 16) << 16 | parseInt(hex[1], 16)) >>> 0;
|
|
128089
|
+
return isPrivateIpv4(
|
|
128090
|
+
[n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255].join(".")
|
|
128091
|
+
);
|
|
128092
|
+
}
|
|
128093
|
+
}
|
|
128094
|
+
if (/^f[cd]/.test(addr)) return true;
|
|
128095
|
+
if (/^fe[89ab]/.test(addr)) return true;
|
|
128096
|
+
return false;
|
|
128097
|
+
}
|
|
127973
128098
|
function isPrivateUrl(url) {
|
|
127974
128099
|
try {
|
|
127975
|
-
const
|
|
127976
|
-
if (
|
|
127977
|
-
|
|
128100
|
+
const u = new URL(url);
|
|
128101
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") return true;
|
|
128102
|
+
const hostname = u.hostname;
|
|
128103
|
+
if (hostname === "localhost") return true;
|
|
127978
128104
|
if (hostname.endsWith(".internal") || hostname.endsWith(".local")) return true;
|
|
127979
|
-
|
|
127980
|
-
if (
|
|
127981
|
-
if (parts[0] === 10) return true;
|
|
127982
|
-
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
|
|
127983
|
-
if (parts[0] === 192 && parts[1] === 168) return true;
|
|
127984
|
-
if (parts[0] === 169 && parts[1] === 254) return true;
|
|
127985
|
-
}
|
|
127986
|
-
const scheme = new URL(url).protocol;
|
|
127987
|
-
if (scheme !== "http:" && scheme !== "https:") return true;
|
|
128105
|
+
if (hostname.startsWith("[")) return isPrivateIpv6(hostname);
|
|
128106
|
+
if (/^\d+(\.\d+){3}$/.test(hostname)) return isPrivateIpv4(hostname);
|
|
127988
128107
|
return false;
|
|
127989
128108
|
} catch {
|
|
127990
128109
|
return true;
|
|
127991
128110
|
}
|
|
127992
128111
|
}
|
|
128112
|
+
async function safeFetch(url, init) {
|
|
128113
|
+
let current = url;
|
|
128114
|
+
for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {
|
|
128115
|
+
if (isPrivateUrl(current)) return null;
|
|
128116
|
+
const res = await fetch(current, { ...init, redirect: "manual" });
|
|
128117
|
+
if (res.status >= 300 && res.status < 400) {
|
|
128118
|
+
const loc = res.headers.get("location");
|
|
128119
|
+
if (!loc) return res;
|
|
128120
|
+
try {
|
|
128121
|
+
current = new URL(loc, current).toString();
|
|
128122
|
+
} catch {
|
|
128123
|
+
return null;
|
|
128124
|
+
}
|
|
128125
|
+
continue;
|
|
128126
|
+
}
|
|
128127
|
+
return res;
|
|
128128
|
+
}
|
|
128129
|
+
return null;
|
|
128130
|
+
}
|
|
127993
128131
|
async function fetchBuffer(url) {
|
|
127994
128132
|
try {
|
|
127995
|
-
|
|
127996
|
-
const res = await fetch(url, {
|
|
128133
|
+
const res = await safeFetch(url, {
|
|
127997
128134
|
signal: AbortSignal.timeout(1e4),
|
|
127998
|
-
headers: { "User-Agent": "HyperFrames/1.0" }
|
|
127999
|
-
redirect: "follow"
|
|
128135
|
+
headers: { "User-Agent": "HyperFrames/1.0" }
|
|
128000
128136
|
});
|
|
128001
|
-
if (!res.ok) return null;
|
|
128137
|
+
if (!res || !res.ok) return null;
|
|
128002
128138
|
const ct2 = res.headers.get("content-type") || "";
|
|
128003
128139
|
if (ct2.includes("text/xml") || ct2.includes("text/html") || ct2.includes("application/xml")) {
|
|
128004
128140
|
return null;
|
|
@@ -128046,9 +128182,25 @@ function deriveAssetName(parsedUrl, catalog, isPoster, idx, usedNames) {
|
|
|
128046
128182
|
}
|
|
128047
128183
|
return final;
|
|
128048
128184
|
}
|
|
128185
|
+
var PRIVATE_V4_BLOCKS, MAX_FETCH_REDIRECTS;
|
|
128049
128186
|
var init_assetDownloader = __esm({
|
|
128050
128187
|
"src/capture/assetDownloader.ts"() {
|
|
128051
128188
|
"use strict";
|
|
128189
|
+
PRIVATE_V4_BLOCKS = [
|
|
128190
|
+
[0, 0, 255],
|
|
128191
|
+
// 0.0.0.0/8 (incl. 0.0.0.0, which routes to localhost)
|
|
128192
|
+
[10, 0, 255],
|
|
128193
|
+
// 10.0.0.0/8
|
|
128194
|
+
[127, 0, 255],
|
|
128195
|
+
// 127.0.0.0/8 loopback
|
|
128196
|
+
[172, 16, 31],
|
|
128197
|
+
// 172.16.0.0/12
|
|
128198
|
+
[192, 168, 168],
|
|
128199
|
+
// 192.168.0.0/16
|
|
128200
|
+
[169, 254, 254]
|
|
128201
|
+
// 169.254.0.0/16 link-local (cloud metadata)
|
|
128202
|
+
];
|
|
128203
|
+
MAX_FETCH_REDIRECTS = 5;
|
|
128052
128204
|
}
|
|
128053
128205
|
});
|
|
128054
128206
|
|
|
@@ -129245,12 +129397,11 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
|
|
|
129245
129397
|
if (lottieItem.data) {
|
|
129246
129398
|
jsonData = JSON.stringify(lottieItem.data);
|
|
129247
129399
|
} else if (lottieItem.url) {
|
|
129248
|
-
|
|
129249
|
-
const res = await fetch(lottieItem.url, {
|
|
129400
|
+
const res = await safeFetch(lottieItem.url, {
|
|
129250
129401
|
signal: AbortSignal.timeout(1e4),
|
|
129251
129402
|
headers: { "User-Agent": "HyperFrames/1.0" }
|
|
129252
129403
|
});
|
|
129253
|
-
if (!res.ok) continue;
|
|
129404
|
+
if (!res || !res.ok) continue;
|
|
129254
129405
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
129255
129406
|
if (lottieItem.url.endsWith(".lottie")) {
|
|
129256
129407
|
try {
|