@hyperframes/producer 0.8.198 → 0.8.199
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/distributed.js +134 -145
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +59 -59
- package/dist/index.js +647 -421
- package/dist/public-server.js +489 -263
- package/dist/renderRequest.d.ts +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/services/hdrCompositor.d.ts +5 -5
- package/dist/services/hdrFrameWindows.d.ts +23 -0
- package/dist/services/render/renderEtaGuard.d.ts +35 -0
- package/dist/services/render/stages/captureHdrResources.d.ts +5 -17
- package/dist/services/renderOrchestrator.d.ts +5 -5
- package/package.json +7 -7
package/dist/distributed.js
CHANGED
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
cpSync as cpSync2,
|
|
6
6
|
existsSync as existsSync15,
|
|
7
7
|
linkSync,
|
|
8
|
-
mkdirSync as
|
|
9
|
-
rmSync as
|
|
8
|
+
mkdirSync as mkdirSync9,
|
|
9
|
+
rmSync as rmSync8,
|
|
10
10
|
writeFileSync as writeFileSync6
|
|
11
11
|
} from "node:fs";
|
|
12
12
|
import { extname as extname4, isAbsolute as isAbsolute3, join as join21, relative as relative5, sep as sep2 } from "node:path";
|
|
@@ -66,10 +66,10 @@ var defaultLogger = createConsoleLogger("info");
|
|
|
66
66
|
import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
|
|
67
67
|
import {
|
|
68
68
|
existsSync as existsSync10,
|
|
69
|
-
mkdirSync as
|
|
70
|
-
readFileSync as
|
|
69
|
+
mkdirSync as mkdirSync5,
|
|
70
|
+
readFileSync as readFileSync5,
|
|
71
71
|
readdirSync as readdirSync3,
|
|
72
|
-
rmSync as
|
|
72
|
+
rmSync as rmSync6,
|
|
73
73
|
statSync as statSync4,
|
|
74
74
|
writeFileSync as writeFileSync3,
|
|
75
75
|
copyFileSync as copyFileSync4,
|
|
@@ -1297,17 +1297,6 @@ import {
|
|
|
1297
1297
|
} from "@hyperframes/engine";
|
|
1298
1298
|
|
|
1299
1299
|
// src/services/render/stages/captureHdrResources.ts
|
|
1300
|
-
import {
|
|
1301
|
-
closeSync as closeSync2,
|
|
1302
|
-
constants as constants2,
|
|
1303
|
-
fstatSync as fstatSync2,
|
|
1304
|
-
mkdirSync as mkdirSync2,
|
|
1305
|
-
mkdtempSync,
|
|
1306
|
-
openSync as openSync2,
|
|
1307
|
-
readFileSync as readFileSync2,
|
|
1308
|
-
rmSync as rmSync2,
|
|
1309
|
-
statfsSync
|
|
1310
|
-
} from "node:fs";
|
|
1311
1300
|
import {
|
|
1312
1301
|
decodePngToRgb48le,
|
|
1313
1302
|
extractMediaMetadata as extractMediaMetadata2,
|
|
@@ -1321,8 +1310,8 @@ import {
|
|
|
1321
1310
|
runFfmpeg
|
|
1322
1311
|
} from "@hyperframes/engine";
|
|
1323
1312
|
import { fpsToFfmpegArg, fpsToNumber as fpsToNumber4 } from "@hyperframes/core";
|
|
1324
|
-
var NO_FOLLOW_FLAG = constants2.O_NOFOLLOW ?? 0;
|
|
1325
1313
|
var BYTES_PER_MIB = 1024 * 1024;
|
|
1314
|
+
var DEFAULT_HDR_WINDOW_BYTES = 512 * BYTES_PER_MIB;
|
|
1326
1315
|
|
|
1327
1316
|
// src/services/render/stages/captureStreamingStage.ts
|
|
1328
1317
|
import {
|
|
@@ -1476,7 +1465,7 @@ import { suggestMatchingPreset } from "@hyperframes/core";
|
|
|
1476
1465
|
// src/services/htmlCompiler.ts
|
|
1477
1466
|
import { decodedUrlPath } from "@hyperframes/parsers/asset-paths";
|
|
1478
1467
|
import { createHash as createHash3 } from "node:crypto";
|
|
1479
|
-
import { createReadStream as createReadStream2, existsSync as existsSync6, mkdirSync as
|
|
1468
|
+
import { createReadStream as createReadStream2, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "fs";
|
|
1480
1469
|
import { join as join5, dirname as dirname4, resolve as resolve5, basename as basename3, relative as relative2 } from "path";
|
|
1481
1470
|
import { parseHTML as parseHTML4 } from "linkedom";
|
|
1482
1471
|
import {
|
|
@@ -1704,7 +1693,7 @@ import {
|
|
|
1704
1693
|
|
|
1705
1694
|
// src/services/animatedGifPrep.ts
|
|
1706
1695
|
import { createHash as createHash2 } from "node:crypto";
|
|
1707
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as
|
|
1696
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, statSync as statSync2 } from "node:fs";
|
|
1708
1697
|
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve4 } from "node:path";
|
|
1709
1698
|
import { parseHTML as parseHTML3 } from "linkedom";
|
|
1710
1699
|
import { parseAnimatedGifMetadata } from "@hyperframes/core";
|
|
@@ -1862,10 +1851,10 @@ async function runAnimatedGifTranscode(request) {
|
|
|
1862
1851
|
}
|
|
1863
1852
|
async function ensurePreparedWebm(input) {
|
|
1864
1853
|
if (!existsSync4(dirname3(input.cachePath))) {
|
|
1865
|
-
|
|
1854
|
+
mkdirSync2(dirname3(input.cachePath), { recursive: true });
|
|
1866
1855
|
}
|
|
1867
1856
|
if (!existsSync4(dirname3(input.outputPath))) {
|
|
1868
|
-
|
|
1857
|
+
mkdirSync2(dirname3(input.outputPath), { recursive: true });
|
|
1869
1858
|
}
|
|
1870
1859
|
if (!isUsableFile(input.cachePath)) {
|
|
1871
1860
|
const tmpPath = `${input.cachePath}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -1889,10 +1878,10 @@ async function ensurePreparedWebm(input) {
|
|
|
1889
1878
|
if (!isUsableFile(input.cachePath)) {
|
|
1890
1879
|
renameWithRetry3(tmpPath, input.cachePath);
|
|
1891
1880
|
} else {
|
|
1892
|
-
|
|
1881
|
+
rmSync2(tmpPath, { force: true });
|
|
1893
1882
|
}
|
|
1894
1883
|
} catch (error) {
|
|
1895
|
-
|
|
1884
|
+
rmSync2(tmpPath, { force: true });
|
|
1896
1885
|
throw error;
|
|
1897
1886
|
}
|
|
1898
1887
|
}
|
|
@@ -1962,7 +1951,7 @@ async function prepareAnimatedGifInputs(html, options) {
|
|
|
1962
1951
|
if (!hasGifExtension(src)) continue;
|
|
1963
1952
|
const sourcePath = resolveGifSourcePath(src, options);
|
|
1964
1953
|
if (!sourcePath) continue;
|
|
1965
|
-
const bytes =
|
|
1954
|
+
const bytes = readFileSync2(sourcePath);
|
|
1966
1955
|
const metadata = parseAnimatedGifMetadata(bytes);
|
|
1967
1956
|
if (!metadata?.animated) continue;
|
|
1968
1957
|
const loop = resolveLoop(metadata, readLoopOverride(img));
|
|
@@ -2375,7 +2364,7 @@ function detectShaderTransitionUsage(html) {
|
|
|
2375
2364
|
async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, downloadDir, tagName, elementIdentity, log, urlByAbsentLocalPath) {
|
|
2376
2365
|
let filePath = src;
|
|
2377
2366
|
if (isHttpUrl(src)) {
|
|
2378
|
-
if (!existsSync6(downloadDir))
|
|
2367
|
+
if (!existsSync6(downloadDir)) mkdirSync3(downloadDir, { recursive: true });
|
|
2379
2368
|
try {
|
|
2380
2369
|
filePath = await downloadToTemp(src, downloadDir, void 0, void 0, void 0, {
|
|
2381
2370
|
onTelemetry: logRemoteDownloadTelemetry
|
|
@@ -2958,7 +2947,7 @@ var REMOTE_SOURCE_TAG_RE = /<source\b[^>]*?\bsrc\s*=\s*["'](https?:\/\/[^"']+)["
|
|
|
2958
2947
|
var REMOTE_IMG_TAG_RE = /<img\b[^>]*?(?<![\w-])src\s*=\s*["'](https?:\/\/[^"']+)["'][^>]*>/gi;
|
|
2959
2948
|
async function downloadAndRewriteUrls(urlSet, html, remoteDir, warnLabel, logLabel, extraRewrite) {
|
|
2960
2949
|
if (urlSet.size === 0) return { html, remoteMediaAssets: /* @__PURE__ */ new Map() };
|
|
2961
|
-
if (!existsSync6(remoteDir))
|
|
2950
|
+
if (!existsSync6(remoteDir)) mkdirSync3(remoteDir, { recursive: true });
|
|
2962
2951
|
const urlToLocal = /* @__PURE__ */ new Map();
|
|
2963
2952
|
await Promise.all(
|
|
2964
2953
|
[...urlSet].map(async (url) => {
|
|
@@ -3304,7 +3293,7 @@ function rebaseDirectEntryAssetPaths(html, projectDir, htmlPath) {
|
|
|
3304
3293
|
}
|
|
3305
3294
|
async function compileForRender(projectDir, htmlPath, downloadDir, options = {}) {
|
|
3306
3295
|
const entryHtml = rebaseDirectEntryAssetPaths(
|
|
3307
|
-
|
|
3296
|
+
readFileSync3(htmlPath, "utf-8"),
|
|
3308
3297
|
projectDir,
|
|
3309
3298
|
htmlPath
|
|
3310
3299
|
);
|
|
@@ -5073,7 +5062,7 @@ async function appendVideoAudioFromProbe(input) {
|
|
|
5073
5062
|
|
|
5074
5063
|
// src/services/render/stages/audioStage.ts
|
|
5075
5064
|
import { join as join10 } from "node:path";
|
|
5076
|
-
import { rmSync as
|
|
5065
|
+
import { rmSync as rmSync4 } from "node:fs";
|
|
5077
5066
|
import {
|
|
5078
5067
|
MIXED_AUDIO_FILENAME,
|
|
5079
5068
|
audioFailureDiagnostics,
|
|
@@ -5082,7 +5071,7 @@ import {
|
|
|
5082
5071
|
|
|
5083
5072
|
// src/services/render/audioPadTrim.ts
|
|
5084
5073
|
import { spawn } from "node:child_process";
|
|
5085
|
-
import { mkdtempSync
|
|
5074
|
+
import { mkdtempSync, rmSync as rmSync3 } from "node:fs";
|
|
5086
5075
|
import { dirname as dirname5, join as join9 } from "node:path";
|
|
5087
5076
|
import {
|
|
5088
5077
|
DEFAULT_CONFIG,
|
|
@@ -5286,7 +5275,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
5286
5275
|
error: `audioPadTrim: failed to materialize ${plan2.operation}: ${err instanceof Error ? err.message : String(err)}`
|
|
5287
5276
|
};
|
|
5288
5277
|
} finally {
|
|
5289
|
-
for (const path of plan2.cleanupPaths)
|
|
5278
|
+
for (const path of plan2.cleanupPaths) rmSync3(path, { force: true });
|
|
5290
5279
|
}
|
|
5291
5280
|
let loweredDb = 0;
|
|
5292
5281
|
if (probeTruePeak) {
|
|
@@ -5332,7 +5321,7 @@ async function constrainAacTruePeak(input) {
|
|
|
5332
5321
|
async function enforceAacTruePeak(input) {
|
|
5333
5322
|
let scratchDir;
|
|
5334
5323
|
try {
|
|
5335
|
-
scratchDir =
|
|
5324
|
+
scratchDir = mkdtempSync(join9(dirname5(input.audioPath), ".true-peak-"));
|
|
5336
5325
|
const correctedPath = join9(scratchDir, "audio.m4a");
|
|
5337
5326
|
const measurements = [];
|
|
5338
5327
|
let attenuationDb = 0;
|
|
@@ -5384,7 +5373,7 @@ async function enforceAacTruePeak(input) {
|
|
|
5384
5373
|
)}`
|
|
5385
5374
|
};
|
|
5386
5375
|
} finally {
|
|
5387
|
-
if (scratchDir)
|
|
5376
|
+
if (scratchDir) rmSync3(scratchDir, { recursive: true, force: true });
|
|
5388
5377
|
}
|
|
5389
5378
|
}
|
|
5390
5379
|
function failResult(outputPath, target, source, error) {
|
|
@@ -5551,7 +5540,7 @@ async function runAudioStage(input) {
|
|
|
5551
5540
|
}
|
|
5552
5541
|
return { ...result, audioLoweredDb, audioProcessMs: Date.now() - stageStart };
|
|
5553
5542
|
} finally {
|
|
5554
|
-
|
|
5543
|
+
rmSync4(pcmSourcePath, { force: true });
|
|
5555
5544
|
}
|
|
5556
5545
|
}
|
|
5557
5546
|
async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
@@ -5648,7 +5637,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
5648
5637
|
}
|
|
5649
5638
|
|
|
5650
5639
|
// src/services/render/stages/captureStage.ts
|
|
5651
|
-
import { existsSync as existsSync8, readdirSync, statfsSync
|
|
5640
|
+
import { existsSync as existsSync8, readdirSync, statfsSync } from "node:fs";
|
|
5652
5641
|
import { join as join11 } from "node:path";
|
|
5653
5642
|
import {
|
|
5654
5643
|
classifyCaptureFailure as classifyCaptureFailure2,
|
|
@@ -5670,7 +5659,7 @@ function shouldAllowAdaptiveCaptureRetry(workerCount, _explicitlyConfigured) {
|
|
|
5670
5659
|
var DISK_PROJECTION_SAMPLE_FRAMES = 10;
|
|
5671
5660
|
function freeDiskBytesAt(path) {
|
|
5672
5661
|
try {
|
|
5673
|
-
const stat =
|
|
5662
|
+
const stat = statfsSync(path);
|
|
5674
5663
|
return stat.bavail * stat.bsize;
|
|
5675
5664
|
} catch {
|
|
5676
5665
|
return null;
|
|
@@ -6030,10 +6019,10 @@ import {
|
|
|
6030
6019
|
import {
|
|
6031
6020
|
copyFileSync as copyFileSync3,
|
|
6032
6021
|
existsSync as existsSync9,
|
|
6033
|
-
mkdirSync as
|
|
6022
|
+
mkdirSync as mkdirSync4,
|
|
6034
6023
|
readdirSync as readdirSync2,
|
|
6035
|
-
readFileSync as
|
|
6036
|
-
rmSync as
|
|
6024
|
+
readFileSync as readFileSync4,
|
|
6025
|
+
rmSync as rmSync5,
|
|
6037
6026
|
statSync as statSync3,
|
|
6038
6027
|
writeFileSync as writeFileSync2
|
|
6039
6028
|
} from "node:fs";
|
|
@@ -6126,7 +6115,7 @@ async function reencodeWithClearedWholeFrames(argsInput, run, startTime) {
|
|
|
6126
6115
|
const error = formatFfmpegError(result.exitCode, result.stderr);
|
|
6127
6116
|
return gifEncodeFailure(startTime, outputPath, error, result.failureReason);
|
|
6128
6117
|
}
|
|
6129
|
-
const gif =
|
|
6118
|
+
const gif = readFileSync4(outputPath);
|
|
6130
6119
|
if (!clearGifFramesBeforeNext(gif)) {
|
|
6131
6120
|
const error = "[FFmpeg] GIF output could not be parsed to clear its frames";
|
|
6132
6121
|
return gifEncodeFailure(startTime, outputPath, error);
|
|
@@ -6159,7 +6148,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
|
|
|
6159
6148
|
return gifEncodeFailure(startTime, outputPath, error, result.failureReason);
|
|
6160
6149
|
}
|
|
6161
6150
|
}
|
|
6162
|
-
if (input.preserveAlpha && gifClearsAfterLeavingFrameInPlace(
|
|
6151
|
+
if (input.preserveAlpha && gifClearsAfterLeavingFrameInPlace(readFileSync4(outputPath)) !== false) {
|
|
6163
6152
|
const failure = await reencodeWithClearedWholeFrames(argsInput, run, startTime);
|
|
6164
6153
|
if (failure) return failure;
|
|
6165
6154
|
}
|
|
@@ -6172,7 +6161,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
|
|
|
6172
6161
|
fileSize
|
|
6173
6162
|
};
|
|
6174
6163
|
} finally {
|
|
6175
|
-
|
|
6164
|
+
rmSync5(input.palettePath, { force: true });
|
|
6176
6165
|
}
|
|
6177
6166
|
}
|
|
6178
6167
|
function startEncodeProgress(job, stage, onProgress) {
|
|
@@ -6322,7 +6311,7 @@ async function runEncodeStage(input) {
|
|
|
6322
6311
|
const stage5Start = Date.now();
|
|
6323
6312
|
if (isPngSequence) {
|
|
6324
6313
|
const encoded = startEncodeProgress(job, "Writing PNG sequence", onProgress);
|
|
6325
|
-
if (!existsSync9(outputPath))
|
|
6314
|
+
if (!existsSync9(outputPath)) mkdirSync4(outputPath, { recursive: true });
|
|
6326
6315
|
const captured = readdirSync2(framesDir).filter((name) => name.endsWith(".png")).sort();
|
|
6327
6316
|
if (captured.length === 0) {
|
|
6328
6317
|
throw new Error(
|
|
@@ -6778,7 +6767,7 @@ import {
|
|
|
6778
6767
|
// src/services/distributed/shared.ts
|
|
6779
6768
|
import { execFile as execFileCallback } from "node:child_process";
|
|
6780
6769
|
import { dirname as dirname8, join as join14 } from "node:path";
|
|
6781
|
-
import { existsSync as existsSync11, readFileSync as
|
|
6770
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6 } from "node:fs";
|
|
6782
6771
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6783
6772
|
import { promisify as promisify2 } from "node:util";
|
|
6784
6773
|
import {
|
|
@@ -7056,7 +7045,7 @@ function readProducerVersion() {
|
|
|
7056
7045
|
const candidate = join14(current, "package.json");
|
|
7057
7046
|
if (existsSync11(candidate)) {
|
|
7058
7047
|
try {
|
|
7059
|
-
const pkg = JSON.parse(
|
|
7048
|
+
const pkg = JSON.parse(readFileSync6(candidate, "utf-8"));
|
|
7060
7049
|
if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
|
|
7061
7050
|
cachedProducerVersion = pkg.version;
|
|
7062
7051
|
return pkg.version;
|
|
@@ -7374,7 +7363,7 @@ function buildWeightedChunkSlices(weights, chunkCount, minFrames, maxFrames) {
|
|
|
7374
7363
|
}
|
|
7375
7364
|
|
|
7376
7365
|
// src/services/render/stages/freezePlan.ts
|
|
7377
|
-
import { existsSync as existsSync13, mkdirSync as
|
|
7366
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync7, readdirSync as readdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
7378
7367
|
import { join as join17, relative as relative3, resolve as resolve7 } from "node:path";
|
|
7379
7368
|
|
|
7380
7369
|
// src/services/distributed/planProtocol.ts
|
|
@@ -7474,7 +7463,7 @@ function readPlanProtocolV1(planJson, capabilities = DISTRIBUTED_RENDER_CAPABILI
|
|
|
7474
7463
|
|
|
7475
7464
|
// src/services/render/stages/planHash.ts
|
|
7476
7465
|
import { createHash as createHash4 } from "node:crypto";
|
|
7477
|
-
import { closeSync as
|
|
7466
|
+
import { closeSync as closeSync2, createReadStream as createReadStream3, openSync as openSync2, readSync } from "node:fs";
|
|
7478
7467
|
var PLAN_HASH_SCHEMA_PREFIX = "hyperframes-plan-hash-v1\0";
|
|
7479
7468
|
var FIELD_DELIMITER = Buffer.from([0]);
|
|
7480
7469
|
function computePlanHash(input) {
|
|
@@ -7532,7 +7521,7 @@ function sha256Hex(bytes) {
|
|
|
7532
7521
|
function sha256File(path) {
|
|
7533
7522
|
const hash = createHash4("sha256");
|
|
7534
7523
|
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
7535
|
-
const fd =
|
|
7524
|
+
const fd = openSync2(path, "r");
|
|
7536
7525
|
try {
|
|
7537
7526
|
let bytesRead = 0;
|
|
7538
7527
|
do {
|
|
@@ -7540,7 +7529,7 @@ function sha256File(path) {
|
|
|
7540
7529
|
if (bytesRead > 0) hash.update(buffer.subarray(0, bytesRead));
|
|
7541
7530
|
} while (bytesRead > 0);
|
|
7542
7531
|
} finally {
|
|
7543
|
-
|
|
7532
|
+
closeSync2(fd);
|
|
7544
7533
|
}
|
|
7545
7534
|
return hash.digest("hex");
|
|
7546
7535
|
}
|
|
@@ -7614,7 +7603,7 @@ function collectPlanAssetShas(planDir, digests) {
|
|
|
7614
7603
|
const assets = [];
|
|
7615
7604
|
for (const file of files) {
|
|
7616
7605
|
if (file.planRelativePath === COMPILED_INDEX_RELATIVE_PATH) {
|
|
7617
|
-
compositionHtml =
|
|
7606
|
+
compositionHtml = readFileSync7(file.absolutePath);
|
|
7618
7607
|
continue;
|
|
7619
7608
|
}
|
|
7620
7609
|
if (HASH_EXCLUDED_PLAN_FILES.has(file.planRelativePath)) continue;
|
|
@@ -7638,7 +7627,7 @@ function writePlanRemoteFiles(planDir, files) {
|
|
|
7638
7627
|
}
|
|
7639
7628
|
function readPlanRemoteFiles(planDir) {
|
|
7640
7629
|
const path = join17(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
|
|
7641
|
-
return existsSync13(path) ? JSON.parse(
|
|
7630
|
+
return existsSync13(path) ? JSON.parse(readFileSync7(path, "utf-8")) : [];
|
|
7642
7631
|
}
|
|
7643
7632
|
function recomputePlanHashFromPlanDir(planDir, digests) {
|
|
7644
7633
|
const planJsonPath = join17(planDir, "plan.json");
|
|
@@ -7649,8 +7638,8 @@ function recomputePlanHashFromPlanDir(planDir, digests) {
|
|
|
7649
7638
|
if (!existsSync13(encoderJsonPath)) {
|
|
7650
7639
|
throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
|
|
7651
7640
|
}
|
|
7652
|
-
const planJson = JSON.parse(
|
|
7653
|
-
const encoderConfigCanonicalJson =
|
|
7641
|
+
const planJson = JSON.parse(readFileSync7(planJsonPath, "utf-8"));
|
|
7642
|
+
const encoderConfigCanonicalJson = readFileSync7(encoderJsonPath, "utf-8");
|
|
7654
7643
|
const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
|
|
7655
7644
|
return computePlanHash({
|
|
7656
7645
|
compositionHtml,
|
|
@@ -7680,7 +7669,7 @@ async function freezePlan(input) {
|
|
|
7680
7669
|
throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
|
|
7681
7670
|
}
|
|
7682
7671
|
const metaDir = join17(planDir, "meta");
|
|
7683
|
-
if (!existsSync13(metaDir))
|
|
7672
|
+
if (!existsSync13(metaDir)) mkdirSync6(metaDir, { recursive: true });
|
|
7684
7673
|
writeFileSync4(
|
|
7685
7674
|
join17(metaDir, "composition.json"),
|
|
7686
7675
|
`${JSON.stringify(composition, null, 2)}
|
|
@@ -7756,13 +7745,13 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
|
|
|
7756
7745
|
}
|
|
7757
7746
|
|
|
7758
7747
|
// src/services/distributed/chunkAudio.ts
|
|
7759
|
-
import { closeSync as
|
|
7748
|
+
import { closeSync as closeSync3, existsSync as existsSync14, ftruncateSync, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync8 } from "node:fs";
|
|
7760
7749
|
import { writeFileSync as writeFileSync5, writeSync } from "node:fs";
|
|
7761
7750
|
import { join as join19 } from "node:path";
|
|
7762
7751
|
import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure3, runFfmpeg as runFfmpeg6 } from "@hyperframes/engine";
|
|
7763
7752
|
|
|
7764
7753
|
// src/services/distributed/mp4Stitch.ts
|
|
7765
|
-
import { createReadStream as createReadStream4, createWriteStream, mkdirSync as
|
|
7754
|
+
import { createReadStream as createReadStream4, createWriteStream, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync7 } from "node:fs";
|
|
7766
7755
|
import { open } from "node:fs/promises";
|
|
7767
7756
|
import { renameWithRetry as renameWithRetry5 } from "@hyperframes/engine";
|
|
7768
7757
|
import { dirname as dirname9, join as join18 } from "node:path";
|
|
@@ -8129,8 +8118,8 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
|
|
|
8129
8118
|
const sourcePaths = audioPath ? [audioPath, ...chunkPaths] : chunkPaths;
|
|
8130
8119
|
const layouts = await Promise.all(sourcePaths.map((path) => readMp4Layout(fileRange(path))));
|
|
8131
8120
|
const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
|
|
8132
|
-
|
|
8133
|
-
const workDir =
|
|
8121
|
+
mkdirSync7(dirname9(outputPath), { recursive: true });
|
|
8122
|
+
const workDir = mkdtempSync2(`${outputPath}.stitch-`);
|
|
8134
8123
|
const out = createWriteStream(join18(workDir, "out.mp4"));
|
|
8135
8124
|
try {
|
|
8136
8125
|
out.write(header);
|
|
@@ -8140,7 +8129,7 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
|
|
|
8140
8129
|
renameWithRetry5(join18(workDir, "out.mp4"), outputPath);
|
|
8141
8130
|
} finally {
|
|
8142
8131
|
out.destroy();
|
|
8143
|
-
|
|
8132
|
+
rmSync7(workDir, { recursive: true, force: true });
|
|
8144
8133
|
}
|
|
8145
8134
|
}
|
|
8146
8135
|
|
|
@@ -8229,9 +8218,9 @@ async function writeChunkAudioSlices(input) {
|
|
|
8229
8218
|
offset += track.sizes[offsets.length - 1];
|
|
8230
8219
|
}
|
|
8231
8220
|
});
|
|
8232
|
-
const bytes =
|
|
8221
|
+
const bytes = readFileSync8(input.audioPath);
|
|
8233
8222
|
const layout = { sizeBytes: bytes.length, payloadStart, payloadEnd, partStarts: {} };
|
|
8234
|
-
|
|
8223
|
+
mkdirSync8(join19(input.planDir, SLICE_DIR), { recursive: true });
|
|
8235
8224
|
input.chunks.forEach((_, index) => {
|
|
8236
8225
|
const cut = audioCutForChunk(grid, input.chunks, index, input.fps);
|
|
8237
8226
|
if (!cut) return;
|
|
@@ -8248,9 +8237,9 @@ async function writeChunkAudioSlices(input) {
|
|
|
8248
8237
|
function chunkAudioSource(planDir, chunkIndex, scratchPath) {
|
|
8249
8238
|
const layoutPath = join19(planDir, SLICE_LAYOUT);
|
|
8250
8239
|
if (!existsSync14(layoutPath)) return resolvePlanAudioPath(planDir);
|
|
8251
|
-
const layout = JSON.parse(
|
|
8252
|
-
const frame =
|
|
8253
|
-
const fd =
|
|
8240
|
+
const layout = JSON.parse(readFileSync8(layoutPath, "utf-8"));
|
|
8241
|
+
const frame = readFileSync8(join19(planDir, SLICE_FRAME));
|
|
8242
|
+
const fd = openSync3(scratchPath, "w");
|
|
8254
8243
|
try {
|
|
8255
8244
|
writeSync(fd, frame, 0, layout.payloadStart, 0);
|
|
8256
8245
|
writeSync(
|
|
@@ -8262,12 +8251,12 @@ function chunkAudioSource(planDir, chunkIndex, scratchPath) {
|
|
|
8262
8251
|
);
|
|
8263
8252
|
const start = layout.partStarts[chunkIndex];
|
|
8264
8253
|
if (start !== void 0) {
|
|
8265
|
-
const part =
|
|
8254
|
+
const part = readFileSync8(join19(planDir, chunkAudioSlicePath(chunkIndex)));
|
|
8266
8255
|
writeSync(fd, part, 0, part.length, start);
|
|
8267
8256
|
}
|
|
8268
8257
|
ftruncateSync(fd, layout.sizeBytes);
|
|
8269
8258
|
} finally {
|
|
8270
|
-
|
|
8259
|
+
closeSync3(fd);
|
|
8271
8260
|
}
|
|
8272
8261
|
return scratchPath;
|
|
8273
8262
|
}
|
|
@@ -8652,7 +8641,7 @@ var FREEZE_OWNED_PLAN_FILES = [
|
|
|
8652
8641
|
];
|
|
8653
8642
|
function removeFreezeOwnedPlanFiles(planDir) {
|
|
8654
8643
|
for (const relativePath of FREEZE_OWNED_PLAN_FILES) {
|
|
8655
|
-
|
|
8644
|
+
rmSync8(join21(planDir, relativePath), { force: true });
|
|
8656
8645
|
}
|
|
8657
8646
|
}
|
|
8658
8647
|
function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
|
|
@@ -8806,7 +8795,7 @@ function createVideoSourceShipper(input) {
|
|
|
8806
8795
|
if (result === null) {
|
|
8807
8796
|
result = `video-sources/${shipped.size}${extname4(current)}`;
|
|
8808
8797
|
const destination = join21(input.planDir, ...result.split("/"));
|
|
8809
|
-
|
|
8798
|
+
mkdirSync9(join21(input.planDir, "video-sources"), { recursive: true });
|
|
8810
8799
|
try {
|
|
8811
8800
|
linkSync(current, destination);
|
|
8812
8801
|
} catch {
|
|
@@ -8826,7 +8815,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
8826
8815
|
useGpu: false,
|
|
8827
8816
|
browserGpuMode: "software"
|
|
8828
8817
|
});
|
|
8829
|
-
if (!existsSync15(planDir))
|
|
8818
|
+
if (!existsSync15(planDir)) mkdirSync9(planDir, { recursive: true });
|
|
8830
8819
|
const log = config.logger ?? defaultLogger;
|
|
8831
8820
|
const sizeLimitBytes = options.executionPlanSizeLimitBytes ?? config.planDirSizeLimitBytes ?? PLAN_DIR_SIZE_LIMIT_BYTES;
|
|
8832
8821
|
const abortSignal = config.abortSignal;
|
|
@@ -8860,10 +8849,10 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
8860
8849
|
throw new Error(`[plan] entry file not found: ${htmlPath}`);
|
|
8861
8850
|
}
|
|
8862
8851
|
const workDir = join21(planDir, ".plan-work");
|
|
8863
|
-
|
|
8864
|
-
|
|
8852
|
+
rmSync8(workDir, { recursive: true, force: true });
|
|
8853
|
+
mkdirSync9(workDir, { recursive: true });
|
|
8865
8854
|
const compiledDir = join21(workDir, "compiled");
|
|
8866
|
-
|
|
8855
|
+
mkdirSync9(compiledDir, { recursive: true });
|
|
8867
8856
|
let stageStarted = Date.now();
|
|
8868
8857
|
cpSync2(projectDir, compiledDir, {
|
|
8869
8858
|
recursive: true,
|
|
@@ -9067,15 +9056,15 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
9067
9056
|
logPlanStage(log, "extract", stageStarted);
|
|
9068
9057
|
const stagedVideoFrames = join21(compiledDir, "__hyperframes_video_frames");
|
|
9069
9058
|
const videoFramesDst = join21(planDir, "video-frames");
|
|
9070
|
-
if (existsSync15(videoFramesDst))
|
|
9059
|
+
if (existsSync15(videoFramesDst)) rmSync8(videoFramesDst, { recursive: true, force: true });
|
|
9071
9060
|
const videoSourcesDir = join21(planDir, "video-sources");
|
|
9072
|
-
|
|
9061
|
+
rmSync8(videoSourcesDir, { recursive: true, force: true });
|
|
9073
9062
|
if (existsSync15(stagedVideoFrames)) {
|
|
9074
9063
|
renameWithRetry6(stagedVideoFrames, videoFramesDst);
|
|
9075
9064
|
} else {
|
|
9076
|
-
|
|
9065
|
+
mkdirSync9(videoFramesDst, { recursive: true });
|
|
9077
9066
|
}
|
|
9078
|
-
if (existsSync15(finalCompiledDir))
|
|
9067
|
+
if (existsSync15(finalCompiledDir)) rmSync8(finalCompiledDir, { recursive: true, force: true });
|
|
9079
9068
|
renameWithRetry6(compiledDir, finalCompiledDir);
|
|
9080
9069
|
const shipVideoSource = createVideoSourceShipper({
|
|
9081
9070
|
planDir,
|
|
@@ -9105,7 +9094,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
9105
9094
|
};
|
|
9106
9095
|
})
|
|
9107
9096
|
});
|
|
9108
|
-
|
|
9097
|
+
mkdirSync9(join21(planDir, "meta"), { recursive: true });
|
|
9109
9098
|
writePlanRemoteFiles(
|
|
9110
9099
|
planDir,
|
|
9111
9100
|
remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
|
|
@@ -9243,7 +9232,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
9243
9232
|
format: config.format
|
|
9244
9233
|
};
|
|
9245
9234
|
try {
|
|
9246
|
-
|
|
9235
|
+
rmSync8(workDir, { recursive: true, force: true });
|
|
9247
9236
|
} catch (err) {
|
|
9248
9237
|
log.warn("[plan] failed to remove temp work dir", {
|
|
9249
9238
|
workDir,
|
|
@@ -9313,7 +9302,7 @@ async function buildPlanAudio(projectDir, config, workRoot, outputPath, options
|
|
|
9313
9302
|
renameWithRetry6(mixed.audioOutputPath, outputPath);
|
|
9314
9303
|
return { hasAudio: true };
|
|
9315
9304
|
} finally {
|
|
9316
|
-
|
|
9305
|
+
rmSync8(c.workDir, { recursive: true, force: true });
|
|
9317
9306
|
}
|
|
9318
9307
|
}
|
|
9319
9308
|
async function plan(projectDir, config, planDir, options = {}) {
|
|
@@ -9338,11 +9327,11 @@ import {
|
|
|
9338
9327
|
copyFileSync as copyFileSync7,
|
|
9339
9328
|
existsSync as existsSync17,
|
|
9340
9329
|
lstatSync as lstatSync2,
|
|
9341
|
-
mkdirSync as
|
|
9342
|
-
mkdtempSync as
|
|
9343
|
-
readFileSync as
|
|
9330
|
+
mkdirSync as mkdirSync11,
|
|
9331
|
+
mkdtempSync as mkdtempSync4,
|
|
9332
|
+
readFileSync as readFileSync9,
|
|
9344
9333
|
readdirSync as readdirSync7,
|
|
9345
|
-
rmSync as
|
|
9334
|
+
rmSync as rmSync10,
|
|
9346
9335
|
statSync as statSync6,
|
|
9347
9336
|
writeFileSync as writeFileSync8
|
|
9348
9337
|
} from "node:fs";
|
|
@@ -9356,9 +9345,9 @@ import {
|
|
|
9356
9345
|
copyFileSync as copyFileSync6,
|
|
9357
9346
|
existsSync as existsSync16,
|
|
9358
9347
|
linkSync as linkSync2,
|
|
9359
|
-
mkdirSync as
|
|
9360
|
-
mkdtempSync as
|
|
9361
|
-
rmSync as
|
|
9348
|
+
mkdirSync as mkdirSync10,
|
|
9349
|
+
mkdtempSync as mkdtempSync3,
|
|
9350
|
+
rmSync as rmSync9,
|
|
9362
9351
|
statSync as statSync5,
|
|
9363
9352
|
writeFileSync as writeFileSync7
|
|
9364
9353
|
} from "node:fs";
|
|
@@ -9428,8 +9417,8 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
9428
9417
|
}
|
|
9429
9418
|
this.destinationDir = destinationDir;
|
|
9430
9419
|
this.#linkFile = options.linkFile ?? linkSync2;
|
|
9431
|
-
|
|
9432
|
-
this.temporaryDir =
|
|
9420
|
+
mkdirSync10(dirname10(destinationDir), { recursive: true });
|
|
9421
|
+
this.temporaryDir = mkdtempSync3(join23(dirname10(destinationDir), ".plan-v2-publish-"));
|
|
9433
9422
|
}
|
|
9434
9423
|
async putBlob(blob) {
|
|
9435
9424
|
const digest = assertPlanV2Sha256(blob.sha256, "published blob sha256");
|
|
@@ -9441,8 +9430,8 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
9441
9430
|
}
|
|
9442
9431
|
const destinationPath = planV2BlobPath(this.temporaryDir, digest);
|
|
9443
9432
|
if (existsSync16(destinationPath)) return;
|
|
9444
|
-
|
|
9445
|
-
const stagingDir =
|
|
9433
|
+
mkdirSync10(dirname10(destinationPath), { recursive: true });
|
|
9434
|
+
const stagingDir = mkdtempSync3(join23(dirname10(destinationPath), ".plan-v2-blob-"));
|
|
9446
9435
|
const temporaryPath = join23(stagingDir, "blob");
|
|
9447
9436
|
try {
|
|
9448
9437
|
try {
|
|
@@ -9453,7 +9442,7 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
9453
9442
|
}
|
|
9454
9443
|
renameWithRetry7(temporaryPath, destinationPath);
|
|
9455
9444
|
} finally {
|
|
9456
|
-
|
|
9445
|
+
rmSync9(stagingDir, { recursive: true, force: true });
|
|
9457
9446
|
}
|
|
9458
9447
|
}
|
|
9459
9448
|
async commitManifest(manifestBytes) {
|
|
@@ -9470,7 +9459,7 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
9470
9459
|
}
|
|
9471
9460
|
async abort() {
|
|
9472
9461
|
if (!this.#committed) {
|
|
9473
|
-
|
|
9462
|
+
rmSync9(this.temporaryDir, { recursive: true, force: true });
|
|
9474
9463
|
}
|
|
9475
9464
|
}
|
|
9476
9465
|
};
|
|
@@ -9489,7 +9478,7 @@ function isNonNegativeIntegerArray(value) {
|
|
|
9489
9478
|
return Array.isArray(value) && value.every((item) => typeof item === "number" && Number.isInteger(item) && item >= 0);
|
|
9490
9479
|
}
|
|
9491
9480
|
function readJsonFile(path, label) {
|
|
9492
|
-
const contents =
|
|
9481
|
+
const contents = readFileSync9(path, "utf-8");
|
|
9493
9482
|
try {
|
|
9494
9483
|
const parsed = JSON.parse(contents);
|
|
9495
9484
|
return parsed;
|
|
@@ -9641,7 +9630,7 @@ function materializeExtractedVideoDirectories(planDir) {
|
|
|
9641
9630
|
if (!existsSync17(videosPath)) return;
|
|
9642
9631
|
const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
|
|
9643
9632
|
for (const video of videos.extracted) {
|
|
9644
|
-
|
|
9633
|
+
mkdirSync11(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
|
|
9645
9634
|
}
|
|
9646
9635
|
}
|
|
9647
9636
|
function parseChunkSlices(value) {
|
|
@@ -9727,14 +9716,14 @@ function computeManifestHash(manifest) {
|
|
|
9727
9716
|
}
|
|
9728
9717
|
function writeBlob(sourcePath, destinationPath) {
|
|
9729
9718
|
if (existsSync17(destinationPath)) return;
|
|
9730
|
-
|
|
9731
|
-
const temporaryDir =
|
|
9719
|
+
mkdirSync11(dirname11(destinationPath), { recursive: true });
|
|
9720
|
+
const temporaryDir = mkdtempSync4(join24(dirname11(destinationPath), ".plan-v2-blob-"));
|
|
9732
9721
|
const temporaryPath = join24(temporaryDir, "blob");
|
|
9733
9722
|
try {
|
|
9734
9723
|
copyFileSync7(sourcePath, temporaryPath);
|
|
9735
9724
|
renameWithRetry8(temporaryPath, destinationPath);
|
|
9736
9725
|
} finally {
|
|
9737
|
-
|
|
9726
|
+
rmSync10(temporaryDir, { recursive: true, force: true });
|
|
9738
9727
|
}
|
|
9739
9728
|
}
|
|
9740
9729
|
function publishBlobFor(absolutePath, digests) {
|
|
@@ -9853,8 +9842,8 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
|
|
|
9853
9842
|
if (publication.storedBlobs.length > 0) {
|
|
9854
9843
|
throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
|
|
9855
9844
|
}
|
|
9856
|
-
|
|
9857
|
-
const tempDir =
|
|
9845
|
+
mkdirSync11(dirname11(planV2Dir), { recursive: true });
|
|
9846
|
+
const tempDir = mkdtempSync4(join24(dirname11(planV2Dir), ".plan-v2-build-"));
|
|
9858
9847
|
try {
|
|
9859
9848
|
for (const blob of publication.blobs) {
|
|
9860
9849
|
writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
|
|
@@ -9867,7 +9856,7 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
|
|
|
9867
9856
|
renameWithRetry8(tempDir, planV2Dir);
|
|
9868
9857
|
return resultFromManifest(planV2Dir, publication.manifest);
|
|
9869
9858
|
} catch (error) {
|
|
9870
|
-
|
|
9859
|
+
rmSync10(tempDir, { recursive: true, force: true });
|
|
9871
9860
|
throw error;
|
|
9872
9861
|
}
|
|
9873
9862
|
}
|
|
@@ -9907,7 +9896,7 @@ async function publishPlanV2FromV1(executionPlanDir, publisher) {
|
|
|
9907
9896
|
return publishPlanV2FromExecutionPlan(executionPlanDir, publisher);
|
|
9908
9897
|
}
|
|
9909
9898
|
async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
|
|
9910
|
-
const stagingRoot =
|
|
9899
|
+
const stagingRoot = mkdtempSync4(join24(options.stagingParentDir ?? tmpdir(), ".execution-plan-"));
|
|
9911
9900
|
const digests = /* @__PURE__ */ new Map();
|
|
9912
9901
|
try {
|
|
9913
9902
|
await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
|
|
@@ -9934,7 +9923,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
9934
9923
|
}
|
|
9935
9924
|
throw error;
|
|
9936
9925
|
} finally {
|
|
9937
|
-
|
|
9926
|
+
rmSync10(stagingRoot, { recursive: true, force: true });
|
|
9938
9927
|
}
|
|
9939
9928
|
}
|
|
9940
9929
|
async function planV2(projectDir, config, planV2Dir) {
|
|
@@ -10131,12 +10120,12 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
|
|
|
10131
10120
|
artifact,
|
|
10132
10121
|
sourcePath: verifyBlob(planV2Dir, artifact)
|
|
10133
10122
|
}));
|
|
10134
|
-
|
|
10135
|
-
const tempDir =
|
|
10123
|
+
mkdirSync11(dirname11(destinationDir), { recursive: true });
|
|
10124
|
+
const tempDir = mkdtempSync4(join24(dirname11(destinationDir), ".plan-v2-materialize-"));
|
|
10136
10125
|
try {
|
|
10137
10126
|
for (const { artifact, sourcePath } of verified) {
|
|
10138
10127
|
const destinationPath = join24(tempDir, ...artifact.path.split("/"));
|
|
10139
|
-
|
|
10128
|
+
mkdirSync11(dirname11(destinationPath), { recursive: true });
|
|
10140
10129
|
copyFileSync7(sourcePath, destinationPath);
|
|
10141
10130
|
}
|
|
10142
10131
|
if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
|
|
@@ -10151,7 +10140,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
|
|
|
10151
10140
|
);
|
|
10152
10141
|
renameWithRetry8(tempDir, destinationDir);
|
|
10153
10142
|
} catch (error) {
|
|
10154
|
-
|
|
10143
|
+
rmSync10(tempDir, { recursive: true, force: true });
|
|
10155
10144
|
throw error;
|
|
10156
10145
|
}
|
|
10157
10146
|
return {
|
|
@@ -10215,7 +10204,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
|
|
|
10215
10204
|
}
|
|
10216
10205
|
|
|
10217
10206
|
// src/services/distributed/planV2Execution.ts
|
|
10218
|
-
import { mkdtempSync as
|
|
10207
|
+
import { mkdtempSync as mkdtempSync6, rmSync as rmSync13 } from "node:fs";
|
|
10219
10208
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
10220
10209
|
import { join as join27 } from "node:path";
|
|
10221
10210
|
|
|
@@ -10223,11 +10212,11 @@ import { join as join27 } from "node:path";
|
|
|
10223
10212
|
import {
|
|
10224
10213
|
cpSync as cpSync3,
|
|
10225
10214
|
existsSync as existsSync18,
|
|
10226
|
-
mkdirSync as
|
|
10227
|
-
mkdtempSync as
|
|
10228
|
-
readFileSync as
|
|
10215
|
+
mkdirSync as mkdirSync12,
|
|
10216
|
+
mkdtempSync as mkdtempSync5,
|
|
10217
|
+
readFileSync as readFileSync10,
|
|
10229
10218
|
readdirSync as readdirSync8,
|
|
10230
|
-
rmSync as
|
|
10219
|
+
rmSync as rmSync11,
|
|
10231
10220
|
statSync as statSync7,
|
|
10232
10221
|
writeFileSync as writeFileSync9
|
|
10233
10222
|
} from "node:fs";
|
|
@@ -10273,9 +10262,9 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
10273
10262
|
const format = plan2.dimensions.format;
|
|
10274
10263
|
const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
|
|
10275
10264
|
if (!existsSync18(dirname12(outputPath))) {
|
|
10276
|
-
|
|
10265
|
+
mkdirSync12(dirname12(outputPath), { recursive: true });
|
|
10277
10266
|
}
|
|
10278
|
-
const workDir =
|
|
10267
|
+
const workDir = mkdtempSync5(`${outputPath}.assemble-work-`);
|
|
10279
10268
|
const fps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
|
|
10280
10269
|
const stageMs = {};
|
|
10281
10270
|
const ctx = {
|
|
@@ -10306,7 +10295,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
10306
10295
|
});
|
|
10307
10296
|
} finally {
|
|
10308
10297
|
try {
|
|
10309
|
-
|
|
10298
|
+
rmSync11(workDir, { recursive: true, force: true });
|
|
10310
10299
|
} catch (err) {
|
|
10311
10300
|
log.warn("[assemble] failed to remove work dir", {
|
|
10312
10301
|
workDir,
|
|
@@ -10328,13 +10317,13 @@ function readAssemblePlan(planDir, chunkPaths) {
|
|
|
10328
10317
|
if (!existsSync18(planJsonPath)) {
|
|
10329
10318
|
throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
|
|
10330
10319
|
}
|
|
10331
|
-
const plan2 = JSON.parse(
|
|
10320
|
+
const plan2 = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
|
|
10332
10321
|
readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
|
|
10333
10322
|
validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
|
|
10334
10323
|
if (!existsSync18(chunksJsonPath)) {
|
|
10335
10324
|
throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
|
|
10336
10325
|
}
|
|
10337
|
-
const chunks = JSON.parse(
|
|
10326
|
+
const chunks = JSON.parse(readFileSync10(chunksJsonPath, "utf-8"));
|
|
10338
10327
|
if (chunkPaths.length !== chunks.length) {
|
|
10339
10328
|
throw new Error(
|
|
10340
10329
|
`[assemble] chunkPaths length (${chunkPaths.length}) does not match chunks.json length (${chunks.length}). Adapters must pass one path per chunk, ordered by index.`
|
|
@@ -10477,13 +10466,13 @@ function stitchesSeparateAudio(planDir) {
|
|
|
10477
10466
|
return lockedAudio(planDir).separateAudio === true;
|
|
10478
10467
|
}
|
|
10479
10468
|
function planFormat(planDir) {
|
|
10480
|
-
const plan2 = JSON.parse(
|
|
10469
|
+
const plan2 = JSON.parse(readFileSync10(join25(planDir, "plan.json"), "utf-8"));
|
|
10481
10470
|
return plan2.dimensions.format;
|
|
10482
10471
|
}
|
|
10483
10472
|
function lockedAudio(planDir) {
|
|
10484
10473
|
const encoderJsonPath = join25(planDir, "meta", "encoder.json");
|
|
10485
10474
|
if (!existsSync18(encoderJsonPath)) return {};
|
|
10486
|
-
return JSON.parse(
|
|
10475
|
+
return JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
|
|
10487
10476
|
}
|
|
10488
10477
|
function readCfrEncoder(planDir, format) {
|
|
10489
10478
|
if (format !== "mp4") {
|
|
@@ -10495,7 +10484,7 @@ function readCfrEncoder(planDir, format) {
|
|
|
10495
10484
|
if (!existsSync18(encoderJsonPath)) {
|
|
10496
10485
|
throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
|
|
10497
10486
|
}
|
|
10498
|
-
const encoderJson = JSON.parse(
|
|
10487
|
+
const encoderJson = JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
|
|
10499
10488
|
if (encoderJson.encoder === "libx265-software") {
|
|
10500
10489
|
throw new Error(
|
|
10501
10490
|
`[assemble] cfr=true is not yet supported with codec: "h265". The cfr re-encode pass uses libx264 and would silently transcode the h265 chunks. Either disable cfr or render with codec: "h264".`
|
|
@@ -10504,8 +10493,8 @@ function readCfrEncoder(planDir, format) {
|
|
|
10504
10493
|
return encoderJson;
|
|
10505
10494
|
}
|
|
10506
10495
|
function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
|
|
10507
|
-
if (existsSync18(outputPath))
|
|
10508
|
-
|
|
10496
|
+
if (existsSync18(outputPath)) rmSync11(outputPath, { recursive: true, force: true });
|
|
10497
|
+
mkdirSync12(outputPath, { recursive: true });
|
|
10509
10498
|
let globalIdx = 0;
|
|
10510
10499
|
for (const chunkDir of chunkPaths) {
|
|
10511
10500
|
if (!statSync7(chunkDir).isDirectory()) {
|
|
@@ -10549,7 +10538,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
10549
10538
|
|
|
10550
10539
|
// src/services/distributed/renderChunk.ts
|
|
10551
10540
|
import { randomBytes } from "node:crypto";
|
|
10552
|
-
import { existsSync as existsSync19, mkdirSync as
|
|
10541
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync13, readFileSync as readFileSync11, readdirSync as readdirSync9, rmSync as rmSync12, writeFileSync as writeFileSync10 } from "node:fs";
|
|
10553
10542
|
import { cpus } from "node:os";
|
|
10554
10543
|
import { join as join26 } from "node:path";
|
|
10555
10544
|
import {
|
|
@@ -10667,10 +10656,10 @@ async function beginFrameSessionNeedsScreenshotFallback(session, probe = probeBe
|
|
|
10667
10656
|
return !await probe(session.page, timeoutMs, probeTick, session.beginFrameIntervalMs);
|
|
10668
10657
|
}
|
|
10669
10658
|
function hashChunkOutput(outputPath, kind) {
|
|
10670
|
-
if (kind === "file") return sha256Hex(
|
|
10659
|
+
if (kind === "file") return sha256Hex(readFileSync11(outputPath));
|
|
10671
10660
|
const entries = readdirSync9(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
|
|
10672
10661
|
const lines = entries.map(
|
|
10673
|
-
(name) => `${name}\0${sha256Hex(
|
|
10662
|
+
(name) => `${name}\0${sha256Hex(readFileSync11(join26(outputPath, name)))}`
|
|
10674
10663
|
);
|
|
10675
10664
|
return sha256Hex(lines.join("\0"));
|
|
10676
10665
|
}
|
|
@@ -10696,7 +10685,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
10696
10685
|
`[renderChunk] planDir is missing required artifact: ${planJsonPath}`
|
|
10697
10686
|
);
|
|
10698
10687
|
}
|
|
10699
|
-
const plan2 = JSON.parse(
|
|
10688
|
+
const plan2 = JSON.parse(readFileSync11(planJsonPath, "utf-8"));
|
|
10700
10689
|
readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.chunk);
|
|
10701
10690
|
const planHashStarted = Date.now();
|
|
10702
10691
|
const v2Materialization = readValidatedPlanV2Materialization(planDir, {
|
|
@@ -10713,13 +10702,13 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
10713
10702
|
);
|
|
10714
10703
|
}
|
|
10715
10704
|
}
|
|
10716
|
-
const encoder = JSON.parse(
|
|
10717
|
-
const chunks = JSON.parse(
|
|
10705
|
+
const encoder = JSON.parse(readFileSync11(encoderJsonPath, "utf-8"));
|
|
10706
|
+
const chunks = JSON.parse(readFileSync11(chunksJsonPath, "utf-8"));
|
|
10718
10707
|
const videosJsonPath = join26(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
10719
10708
|
let planVideos = null;
|
|
10720
10709
|
if (existsSync19(videosJsonPath)) {
|
|
10721
10710
|
try {
|
|
10722
|
-
planVideos = validatePlanVideosForChunk(JSON.parse(
|
|
10711
|
+
planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync11(videosJsonPath, "utf-8")));
|
|
10723
10712
|
} catch (err) {
|
|
10724
10713
|
if (err instanceof RenderChunkValidationError) throw err;
|
|
10725
10714
|
throw new RenderChunkValidationError(
|
|
@@ -10804,9 +10793,9 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
10804
10793
|
forceScreenshotExplicitlyOptedOut: !encoder.forceScreenshot
|
|
10805
10794
|
};
|
|
10806
10795
|
const workDir = `${outputChunkPath}.work.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
10807
|
-
|
|
10796
|
+
mkdirSync13(workDir, { recursive: true });
|
|
10808
10797
|
const framesDir = join26(workDir, "captured-frames");
|
|
10809
|
-
|
|
10798
|
+
mkdirSync13(framesDir, { recursive: true });
|
|
10810
10799
|
const videoFramesDir = `${workDir}.video-frames`;
|
|
10811
10800
|
const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
|
|
10812
10801
|
const chunkFps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
|
|
@@ -10830,7 +10819,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
10830
10819
|
dimensions: plan2.dimensions,
|
|
10831
10820
|
encoder,
|
|
10832
10821
|
videoCount: planVideos?.videos.length ?? 0,
|
|
10833
|
-
html:
|
|
10822
|
+
html: readFileSync11(join26(compiledDir, "index.html"), "utf-8"),
|
|
10834
10823
|
// The plan ships a deferred source only to chunks that show it; don't wait on the rest.
|
|
10835
10824
|
skipReadinessVideoIds: deferredVideos.filter(
|
|
10836
10825
|
(video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
|
|
@@ -10953,10 +10942,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
10953
10942
|
const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
|
|
10954
10943
|
const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
|
|
10955
10944
|
if (isPngSequence) {
|
|
10956
|
-
if (!existsSync19(outputChunkPath))
|
|
10945
|
+
if (!existsSync19(outputChunkPath)) mkdirSync13(outputChunkPath, { recursive: true });
|
|
10957
10946
|
} else {
|
|
10958
10947
|
const outDir = join26(outputChunkPath, "..");
|
|
10959
|
-
if (!existsSync19(outDir))
|
|
10948
|
+
if (!existsSync19(outDir)) mkdirSync13(outDir, { recursive: true });
|
|
10960
10949
|
}
|
|
10961
10950
|
const encodeInput = {
|
|
10962
10951
|
job,
|
|
@@ -11059,8 +11048,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11059
11048
|
return observedChunkCaptureMode(capturePerfs);
|
|
11060
11049
|
},
|
|
11061
11050
|
resetForScreenshotRetry: () => {
|
|
11062
|
-
|
|
11063
|
-
|
|
11051
|
+
rmSync12(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
11052
|
+
mkdirSync13(framesDir, { recursive: true });
|
|
11064
11053
|
capturePerfs.length = 0;
|
|
11065
11054
|
captureAttempts.length = 0;
|
|
11066
11055
|
job.framesRendered = 0;
|
|
@@ -11102,8 +11091,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11102
11091
|
fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
|
|
11103
11092
|
timeoutMs: cfg.ffmpegProcessTimeout
|
|
11104
11093
|
});
|
|
11105
|
-
|
|
11106
|
-
|
|
11094
|
+
rmSync12(videoOnlyPath, { force: true });
|
|
11095
|
+
rmSync12(audioScratchPath, { force: true });
|
|
11107
11096
|
}
|
|
11108
11097
|
encodeStageMs = Date.now() - encodeStarted;
|
|
11109
11098
|
} finally {
|
|
@@ -11151,8 +11140,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11151
11140
|
writeFileSync10(perfPath, `${JSON.stringify(perfPayload, null, 2)}
|
|
11152
11141
|
`, "utf-8");
|
|
11153
11142
|
try {
|
|
11154
|
-
|
|
11155
|
-
|
|
11143
|
+
rmSync12(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
11144
|
+
rmSync12(videoFramesDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
11156
11145
|
} catch (err) {
|
|
11157
11146
|
log.warn("[renderChunk] failed to remove work dir", {
|
|
11158
11147
|
workDir,
|
|
@@ -11181,17 +11170,17 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11181
11170
|
|
|
11182
11171
|
// src/services/distributed/planV2Execution.ts
|
|
11183
11172
|
async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
|
|
11184
|
-
const workRoot =
|
|
11173
|
+
const workRoot = mkdtempSync6(join27(tmpdir2(), "hf-plan-v2-chunk-"));
|
|
11185
11174
|
const materializedPlanDir = join27(workRoot, "plan");
|
|
11186
11175
|
try {
|
|
11187
11176
|
materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
|
|
11188
11177
|
return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
|
|
11189
11178
|
} finally {
|
|
11190
|
-
|
|
11179
|
+
rmSync13(workRoot, { recursive: true, force: true });
|
|
11191
11180
|
}
|
|
11192
11181
|
}
|
|
11193
11182
|
async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
11194
|
-
const workRoot =
|
|
11183
|
+
const workRoot = mkdtempSync6(join27(tmpdir2(), "hf-plan-v2-assembler-"));
|
|
11195
11184
|
const materializedPlanDir = join27(workRoot, "plan");
|
|
11196
11185
|
try {
|
|
11197
11186
|
const materialized = materializePlanV2Target(
|
|
@@ -11207,7 +11196,7 @@ async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
|
11207
11196
|
options
|
|
11208
11197
|
);
|
|
11209
11198
|
} finally {
|
|
11210
|
-
|
|
11199
|
+
rmSync13(workRoot, { recursive: true, force: true });
|
|
11211
11200
|
}
|
|
11212
11201
|
}
|
|
11213
11202
|
|
|
@@ -11456,7 +11445,7 @@ function validateIntDimension(field, value) {
|
|
|
11456
11445
|
}
|
|
11457
11446
|
|
|
11458
11447
|
// src/services/distributed/projectHash.ts
|
|
11459
|
-
import { closeSync as
|
|
11448
|
+
import { closeSync as closeSync4, openSync as openSync4, readdirSync as readdirSync10, readSync as readSync3, realpathSync as realpathSync2, statSync as statSync8 } from "node:fs";
|
|
11460
11449
|
import { createHash as createHash6 } from "node:crypto";
|
|
11461
11450
|
import { join as join28 } from "node:path";
|
|
11462
11451
|
var SITE_ID_SCHEME = "site-v2\0";
|
|
@@ -11497,14 +11486,14 @@ function hashProjectDir(projectDir, files = listSiteFiles(projectDir)) {
|
|
|
11497
11486
|
for (const rel of files) {
|
|
11498
11487
|
hash.update(rel);
|
|
11499
11488
|
hash.update("\0");
|
|
11500
|
-
const fd =
|
|
11489
|
+
const fd = openSync4(join28(projectDir, rel), "r");
|
|
11501
11490
|
try {
|
|
11502
11491
|
let read;
|
|
11503
11492
|
while ((read = readSync3(fd, chunk, 0, chunk.length, null)) > 0) {
|
|
11504
11493
|
hash.update(chunk.subarray(0, read));
|
|
11505
11494
|
}
|
|
11506
11495
|
} finally {
|
|
11507
|
-
|
|
11496
|
+
closeSync4(fd);
|
|
11508
11497
|
}
|
|
11509
11498
|
}
|
|
11510
11499
|
return hash.digest("hex").slice(0, 16);
|