@hyperframes/producer 0.9.4 → 0.9.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/distributed.js +230 -120
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +64 -64
- package/dist/index.d.ts +1 -0
- package/dist/index.js +297 -141
- package/dist/public-server.js +58 -9
- package/dist/services/distributed/assemble.d.ts +2 -21
- package/dist/services/distributed/plan.d.ts +3 -2
- package/dist/services/distributed/planV2.d.ts +2 -13
- package/dist/services/distributed/renderSpan.d.ts +2 -1
- package/dist/services/render/planReferenceBackground.d.ts +12 -0
- package/dist/services/render/stages/freezePlan.d.ts +2 -2
- package/dist/services/render/stages/probeStage.d.ts +3 -3
- package/dist/services/renderOrchestrator.d.ts +5 -1
- package/package.json +7 -7
package/dist/distributed.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// src/services/distributed/plan.ts
|
|
2
|
+
import {
|
|
3
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD2,
|
|
4
|
+
referenceBackgroundResult as referenceBackgroundResult4,
|
|
5
|
+
createReferenceBackgroundRecorder as createReferenceBackgroundRecorder2
|
|
6
|
+
} from "@hyperframes/engine";
|
|
2
7
|
import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframes/engine";
|
|
3
8
|
import {
|
|
4
9
|
copyFileSync as copyFileSync6,
|
|
@@ -9,7 +14,7 @@ import {
|
|
|
9
14
|
rmSync as rmSync7,
|
|
10
15
|
writeFileSync as writeFileSync7
|
|
11
16
|
} from "node:fs";
|
|
12
|
-
import { extname as extname4, isAbsolute as isAbsolute3, join as
|
|
17
|
+
import { extname as extname4, isAbsolute as isAbsolute3, join as join24, relative as relative5, sep as sep2 } from "node:path";
|
|
13
18
|
import {
|
|
14
19
|
fpsToNumber as fpsToNumber9,
|
|
15
20
|
HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR2
|
|
@@ -120,6 +125,10 @@ import {
|
|
|
120
125
|
augmentProtocolTimeoutError,
|
|
121
126
|
augmentPageNavigationTimeoutError
|
|
122
127
|
} from "@hyperframes/engine";
|
|
128
|
+
import {
|
|
129
|
+
referenceBackgroundResult,
|
|
130
|
+
createReferenceBackgroundRecorder
|
|
131
|
+
} from "@hyperframes/engine";
|
|
123
132
|
import { join as join15, dirname as dirname9, resolve as resolve7 } from "path";
|
|
124
133
|
import { randomUUID } from "crypto";
|
|
125
134
|
|
|
@@ -4920,6 +4929,7 @@ async function runProbeStage(input) {
|
|
|
4920
4929
|
const motionBlur = job.config.motionBlur;
|
|
4921
4930
|
const captureFormat = resolveCaptureImageFormat({ needsAlpha, motionBlur });
|
|
4922
4931
|
const captureOpts = {
|
|
4932
|
+
recordReferenceBackground: input.recordReferenceBackground,
|
|
4923
4933
|
width,
|
|
4924
4934
|
height,
|
|
4925
4935
|
fps: job.config.fps,
|
|
@@ -7679,6 +7689,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
|
|
|
7679
7689
|
}
|
|
7680
7690
|
function createRenderJob(config) {
|
|
7681
7691
|
return {
|
|
7692
|
+
...referenceBackgroundResult(void 0),
|
|
7682
7693
|
id: randomUUID(),
|
|
7683
7694
|
config: {
|
|
7684
7695
|
...config,
|
|
@@ -8342,9 +8353,69 @@ function buildWeightedChunkSlices(weights, chunkCount, minFrames, maxFrames) {
|
|
|
8342
8353
|
return slices;
|
|
8343
8354
|
}
|
|
8344
8355
|
|
|
8356
|
+
// src/services/render/planReferenceBackground.ts
|
|
8357
|
+
import { join as join19 } from "node:path";
|
|
8358
|
+
import {
|
|
8359
|
+
closeCaptureSession as closeCaptureSession10,
|
|
8360
|
+
createCaptureSession as createCaptureSession10,
|
|
8361
|
+
readReferenceBackground,
|
|
8362
|
+
referenceBackgroundResult as referenceBackgroundResult2
|
|
8363
|
+
} from "@hyperframes/engine";
|
|
8364
|
+
async function readPlanReferenceBackground(input) {
|
|
8365
|
+
let server;
|
|
8366
|
+
let session;
|
|
8367
|
+
try {
|
|
8368
|
+
server = await createFileServer({
|
|
8369
|
+
projectDir: input.projectDir,
|
|
8370
|
+
compiledDir: join19(input.workDir, "compiled"),
|
|
8371
|
+
port: 0,
|
|
8372
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM],
|
|
8373
|
+
fps: input.options.fps
|
|
8374
|
+
});
|
|
8375
|
+
session = await createCaptureSession10(
|
|
8376
|
+
server.url,
|
|
8377
|
+
join19(input.workDir, "reference"),
|
|
8378
|
+
{
|
|
8379
|
+
...input.options,
|
|
8380
|
+
requiresWebGpu: false
|
|
8381
|
+
},
|
|
8382
|
+
null,
|
|
8383
|
+
{
|
|
8384
|
+
...input.cfg,
|
|
8385
|
+
forceScreenshot: true,
|
|
8386
|
+
useDrawElement: false,
|
|
8387
|
+
enablePageSideCompositing: false
|
|
8388
|
+
}
|
|
8389
|
+
);
|
|
8390
|
+
const page = session.page;
|
|
8391
|
+
await page.goto(`${server.url}/index.html`, {
|
|
8392
|
+
waitUntil: "domcontentloaded",
|
|
8393
|
+
timeout: input.cfg.pageNavigationTimeout
|
|
8394
|
+
});
|
|
8395
|
+
await page.evaluate("window.__hfFlushSync?.()");
|
|
8396
|
+
await page.waitForFunction(
|
|
8397
|
+
'!!(window.__hf && typeof window.__hf.seek === "function" && window.__hf.duration > 0)',
|
|
8398
|
+
{ timeout: input.cfg.playerReadyTimeout, polling: 100 }
|
|
8399
|
+
);
|
|
8400
|
+
return referenceBackgroundResult2(await readReferenceBackground(page));
|
|
8401
|
+
} catch (error) {
|
|
8402
|
+
input.log.debug("Reference background unavailable", {
|
|
8403
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8404
|
+
});
|
|
8405
|
+
return referenceBackgroundResult2(void 0);
|
|
8406
|
+
} finally {
|
|
8407
|
+
if (session) await closeCaptureSession10(session).catch(() => void 0);
|
|
8408
|
+
if (server) closeFileServerSafely(server, "reference background", input.log);
|
|
8409
|
+
}
|
|
8410
|
+
}
|
|
8411
|
+
|
|
8345
8412
|
// src/services/render/stages/freezePlan.ts
|
|
8346
8413
|
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8347
|
-
import { join as
|
|
8414
|
+
import { join as join20, relative as relative3, resolve as resolve8 } from "node:path";
|
|
8415
|
+
import {
|
|
8416
|
+
REFERENCE_BACKGROUND_FIELD,
|
|
8417
|
+
referenceBackgroundResult as referenceBackgroundResult3
|
|
8418
|
+
} from "@hyperframes/engine";
|
|
8348
8419
|
|
|
8349
8420
|
// src/services/distributed/planProtocol.ts
|
|
8350
8421
|
var PLAN_SCHEMA_VERSION = 1;
|
|
@@ -8558,7 +8629,7 @@ function listPlanFiles(planDir) {
|
|
|
8558
8629
|
function walk(dir) {
|
|
8559
8630
|
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
8560
8631
|
for (const entry of entries) {
|
|
8561
|
-
const full =
|
|
8632
|
+
const full = join20(dir, entry.name);
|
|
8562
8633
|
if (entry.isDirectory()) {
|
|
8563
8634
|
walk(full);
|
|
8564
8635
|
} else if (entry.isFile()) {
|
|
@@ -8599,15 +8670,15 @@ var PLAN_REMOTE_FILES_RELATIVE_PATH = "meta/remote-files.json";
|
|
|
8599
8670
|
function writePlanRemoteFiles(planDir, files) {
|
|
8600
8671
|
if (files.length === 0) return;
|
|
8601
8672
|
const sorted = [...files].sort((a, b) => a.path < b.path ? -1 : 1);
|
|
8602
|
-
writeFileSync5(
|
|
8673
|
+
writeFileSync5(join20(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
|
|
8603
8674
|
}
|
|
8604
8675
|
function readPlanRemoteFiles(planDir) {
|
|
8605
|
-
const path =
|
|
8676
|
+
const path = join20(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
|
|
8606
8677
|
return existsSync14(path) ? JSON.parse(readFileSync6(path, "utf-8")) : [];
|
|
8607
8678
|
}
|
|
8608
8679
|
function recomputePlanHashFromPlanDir(planDir, digests) {
|
|
8609
|
-
const planJsonPath =
|
|
8610
|
-
const encoderJsonPath =
|
|
8680
|
+
const planJsonPath = join20(planDir, "plan.json");
|
|
8681
|
+
const encoderJsonPath = join20(planDir, "meta", "encoder.json");
|
|
8611
8682
|
if (!existsSync14(planJsonPath)) {
|
|
8612
8683
|
throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
|
|
8613
8684
|
}
|
|
@@ -8644,18 +8715,18 @@ async function freezePlan(input) {
|
|
|
8644
8715
|
if (!existsSync14(planDir)) {
|
|
8645
8716
|
throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
|
|
8646
8717
|
}
|
|
8647
|
-
const metaDir =
|
|
8718
|
+
const metaDir = join20(planDir, "meta");
|
|
8648
8719
|
if (!existsSync14(metaDir)) mkdirSync7(metaDir, { recursive: true });
|
|
8649
8720
|
writeFileSync5(
|
|
8650
|
-
|
|
8721
|
+
join20(metaDir, "composition.json"),
|
|
8651
8722
|
`${JSON.stringify(composition, null, 2)}
|
|
8652
8723
|
`,
|
|
8653
8724
|
"utf-8"
|
|
8654
8725
|
);
|
|
8655
8726
|
const encoderForCanonical = stripUndefined(encoder);
|
|
8656
8727
|
const encoderConfigCanonicalJson = canonicalJsonStringify(encoderForCanonical);
|
|
8657
|
-
writeFileSync5(
|
|
8658
|
-
writeFileSync5(
|
|
8728
|
+
writeFileSync5(join20(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
|
|
8729
|
+
writeFileSync5(join20(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
|
|
8659
8730
|
`, "utf-8");
|
|
8660
8731
|
const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
|
|
8661
8732
|
const planHash = computePlanHash({
|
|
@@ -8668,6 +8739,7 @@ async function freezePlan(input) {
|
|
|
8668
8739
|
dimensions
|
|
8669
8740
|
});
|
|
8670
8741
|
const planJson = {
|
|
8742
|
+
...referenceBackgroundResult3(composition[REFERENCE_BACKGROUND_FIELD]),
|
|
8671
8743
|
protocol: PLAN_PROTOCOL_V1,
|
|
8672
8744
|
planHash,
|
|
8673
8745
|
producerVersion,
|
|
@@ -8679,7 +8751,7 @@ async function freezePlan(input) {
|
|
|
8679
8751
|
duration: durationSeconds,
|
|
8680
8752
|
hasAudio
|
|
8681
8753
|
};
|
|
8682
|
-
const planJsonPath =
|
|
8754
|
+
const planJsonPath = join20(planDir, "plan.json");
|
|
8683
8755
|
writeFileSync5(planJsonPath, `${JSON.stringify(planJson, null, 2)}
|
|
8684
8756
|
`, "utf-8");
|
|
8685
8757
|
return { planJsonPath, planHash };
|
|
@@ -8723,14 +8795,14 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
|
|
|
8723
8795
|
// src/services/distributed/chunkAudio.ts
|
|
8724
8796
|
import { closeSync as closeSync4, existsSync as existsSync15, ftruncateSync, mkdirSync as mkdirSync9, openSync as openSync4, readFileSync as readFileSync7 } from "node:fs";
|
|
8725
8797
|
import { writeFileSync as writeFileSync6, writeSync } from "node:fs";
|
|
8726
|
-
import { join as
|
|
8798
|
+
import { join as join22 } from "node:path";
|
|
8727
8799
|
import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
|
|
8728
8800
|
|
|
8729
8801
|
// src/services/distributed/mp4Stitch.ts
|
|
8730
8802
|
import { createReadStream as createReadStream4, createWriteStream, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, rmSync as rmSync6 } from "node:fs";
|
|
8731
8803
|
import { open } from "node:fs/promises";
|
|
8732
8804
|
import { renameWithRetry as renameWithRetry7 } from "@hyperframes/engine";
|
|
8733
|
-
import { dirname as dirname11, join as
|
|
8805
|
+
import { dirname as dirname11, join as join21 } from "node:path";
|
|
8734
8806
|
import { finished, pipeline } from "node:stream/promises";
|
|
8735
8807
|
function boxAt(src, off, at, limit) {
|
|
8736
8808
|
let size = src.readUInt32BE(off);
|
|
@@ -9096,13 +9168,13 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
|
|
|
9096
9168
|
const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
|
|
9097
9169
|
mkdirSync8(dirname11(outputPath), { recursive: true });
|
|
9098
9170
|
const workDir = mkdtempSync2(`${outputPath}.stitch-`);
|
|
9099
|
-
const out = createWriteStream(
|
|
9171
|
+
const out = createWriteStream(join21(workDir, "out.mp4"));
|
|
9100
9172
|
try {
|
|
9101
9173
|
out.write(header);
|
|
9102
9174
|
for (const [i, path] of sourcePaths.entries()) await copyPayload(path, layouts[i], i, out);
|
|
9103
9175
|
out.end();
|
|
9104
9176
|
await finished(out);
|
|
9105
|
-
renameWithRetry7(
|
|
9177
|
+
renameWithRetry7(join21(workDir, "out.mp4"), outputPath);
|
|
9106
9178
|
} finally {
|
|
9107
9179
|
out.destroy();
|
|
9108
9180
|
rmSync6(workDir, { recursive: true, force: true });
|
|
@@ -9196,7 +9268,7 @@ async function writeChunkAudioSlices(input) {
|
|
|
9196
9268
|
});
|
|
9197
9269
|
const bytes = readFileSync7(input.audioPath);
|
|
9198
9270
|
const layout = { sizeBytes: bytes.length, payloadStart, payloadEnd, partStarts: {} };
|
|
9199
|
-
mkdirSync9(
|
|
9271
|
+
mkdirSync9(join22(input.planDir, SLICE_DIR), { recursive: true });
|
|
9200
9272
|
input.chunks.forEach((_, index) => {
|
|
9201
9273
|
const cut = audioCutForChunk(grid, input.chunks, index, input.fps);
|
|
9202
9274
|
if (!cut) return;
|
|
@@ -9204,17 +9276,17 @@ async function writeChunkAudioSlices(input) {
|
|
|
9204
9276
|
const start = offsets[cut.firstPacket];
|
|
9205
9277
|
layout.partStarts[index] = start;
|
|
9206
9278
|
const end = offsets[last] + track.sizes[last];
|
|
9207
|
-
writeFileSync6(
|
|
9279
|
+
writeFileSync6(join22(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
|
|
9208
9280
|
});
|
|
9209
9281
|
const frame = [bytes.subarray(0, payloadStart), bytes.subarray(payloadEnd)];
|
|
9210
|
-
writeFileSync6(
|
|
9211
|
-
writeFileSync6(
|
|
9282
|
+
writeFileSync6(join22(input.planDir, SLICE_FRAME), Buffer.concat(frame));
|
|
9283
|
+
writeFileSync6(join22(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
|
|
9212
9284
|
}
|
|
9213
9285
|
function chunkAudioSource(planDir, chunkIndex, scratchPath) {
|
|
9214
|
-
const layoutPath =
|
|
9286
|
+
const layoutPath = join22(planDir, SLICE_LAYOUT);
|
|
9215
9287
|
if (!existsSync15(layoutPath)) return resolvePlanAudioPath(planDir);
|
|
9216
9288
|
const layout = JSON.parse(readFileSync7(layoutPath, "utf-8"));
|
|
9217
|
-
const frame = readFileSync7(
|
|
9289
|
+
const frame = readFileSync7(join22(planDir, SLICE_FRAME));
|
|
9218
9290
|
const fd = openSync4(scratchPath, "w");
|
|
9219
9291
|
try {
|
|
9220
9292
|
writeSync(fd, frame, 0, layout.payloadStart, 0);
|
|
@@ -9227,7 +9299,7 @@ function chunkAudioSource(planDir, chunkIndex, scratchPath) {
|
|
|
9227
9299
|
);
|
|
9228
9300
|
const start = layout.partStarts[chunkIndex];
|
|
9229
9301
|
if (start !== void 0) {
|
|
9230
|
-
const part = readFileSync7(
|
|
9302
|
+
const part = readFileSync7(join22(planDir, chunkAudioSlicePath(chunkIndex)));
|
|
9231
9303
|
writeSync(fd, part, 0, part.length, start);
|
|
9232
9304
|
}
|
|
9233
9305
|
ftruncateSync(fd, layout.sizeBytes);
|
|
@@ -9283,7 +9355,7 @@ async function muxChunkWithAudio(input) {
|
|
|
9283
9355
|
// src/services/distributed/planSize.ts
|
|
9284
9356
|
import { createHash as createHash7 } from "node:crypto";
|
|
9285
9357
|
import { lstatSync, readdirSync as readdirSync6 } from "node:fs";
|
|
9286
|
-
import { extname as extname3, join as
|
|
9358
|
+
import { extname as extname3, join as join23, relative as relative4 } from "node:path";
|
|
9287
9359
|
var MAX_TOP_COMPONENTS = 10;
|
|
9288
9360
|
var SOURCE_MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9289
9361
|
".aac",
|
|
@@ -9395,7 +9467,7 @@ function walkRegularFiles(dir, visit) {
|
|
|
9395
9467
|
return;
|
|
9396
9468
|
}
|
|
9397
9469
|
for (const entry of entries) {
|
|
9398
|
-
const full =
|
|
9470
|
+
const full = join23(dir, entry.name);
|
|
9399
9471
|
if (entry.isDirectory()) {
|
|
9400
9472
|
walkRegularFiles(full, visit);
|
|
9401
9473
|
} else if (entry.isFile()) {
|
|
@@ -9611,13 +9683,13 @@ function assertPositiveInteger(name, value) {
|
|
|
9611
9683
|
}
|
|
9612
9684
|
var FREEZE_OWNED_PLAN_FILES = [
|
|
9613
9685
|
"plan.json",
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9686
|
+
join24("meta", "composition.json"),
|
|
9687
|
+
join24("meta", "encoder.json"),
|
|
9688
|
+
join24("meta", "chunks.json")
|
|
9617
9689
|
];
|
|
9618
9690
|
function removeFreezeOwnedPlanFiles(planDir) {
|
|
9619
9691
|
for (const relativePath of FREEZE_OWNED_PLAN_FILES) {
|
|
9620
|
-
rmSync7(
|
|
9692
|
+
rmSync7(join24(planDir, relativePath), { force: true });
|
|
9621
9693
|
}
|
|
9622
9694
|
}
|
|
9623
9695
|
function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
|
|
@@ -9772,19 +9844,19 @@ function createVideoSourceShipper(input) {
|
|
|
9772
9844
|
const known = shipped.get(srcPath);
|
|
9773
9845
|
if (known) return known;
|
|
9774
9846
|
const stagedRel = pathInside(input.workVideoFramesDir, srcPath);
|
|
9775
|
-
const current = stagedRel === null ? srcPath :
|
|
9847
|
+
const current = stagedRel === null ? srcPath : join24(input.planDir, "video-frames", stagedRel);
|
|
9776
9848
|
let result = null;
|
|
9777
9849
|
for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
|
|
9778
9850
|
const rel = pathInside(root, srcPath);
|
|
9779
|
-
if (rel !== null && (existsSync16(
|
|
9851
|
+
if (rel !== null && (existsSync16(join24(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
|
|
9780
9852
|
result = ["compiled", ...rel.split(sep2)].join("/");
|
|
9781
9853
|
break;
|
|
9782
9854
|
}
|
|
9783
9855
|
}
|
|
9784
9856
|
if (result === null) {
|
|
9785
9857
|
result = `video-sources/${shipped.size}${extname4(current)}`;
|
|
9786
|
-
const destination =
|
|
9787
|
-
mkdirSync10(
|
|
9858
|
+
const destination = join24(input.planDir, ...result.split("/"));
|
|
9859
|
+
mkdirSync10(join24(input.planDir, "video-sources"), { recursive: true });
|
|
9788
9860
|
try {
|
|
9789
9861
|
linkSync(current, destination);
|
|
9790
9862
|
} catch {
|
|
@@ -9833,14 +9905,14 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
9833
9905
|
variables: config.variables
|
|
9834
9906
|
});
|
|
9835
9907
|
const entryFile = config.entryFile ?? "index.html";
|
|
9836
|
-
const htmlPath =
|
|
9908
|
+
const htmlPath = join24(projectDir, entryFile);
|
|
9837
9909
|
if (!existsSync16(htmlPath)) {
|
|
9838
9910
|
throw new Error(`[plan] entry file not found: ${htmlPath}`);
|
|
9839
9911
|
}
|
|
9840
|
-
const workDir =
|
|
9912
|
+
const workDir = join24(planDir, ".plan-work");
|
|
9841
9913
|
rmSync7(workDir, { recursive: true, force: true });
|
|
9842
9914
|
mkdirSync10(workDir, { recursive: true });
|
|
9843
|
-
const compiledDir =
|
|
9915
|
+
const compiledDir = join24(workDir, "compiled");
|
|
9844
9916
|
mkdirSync10(compiledDir, { recursive: true });
|
|
9845
9917
|
let stageStarted = Date.now();
|
|
9846
9918
|
cpSync2(projectDir, compiledDir, {
|
|
@@ -9854,10 +9926,10 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
9854
9926
|
}
|
|
9855
9927
|
});
|
|
9856
9928
|
logPlanStage(log, "copy", stageStarted);
|
|
9857
|
-
const finalCompiledDir =
|
|
9929
|
+
const finalCompiledDir = join24(planDir, "compiled");
|
|
9858
9930
|
const needsAlpha = outputNeedsAlpha(config.format);
|
|
9859
9931
|
const remoteFiles = Object.entries(options.remoteFiles ?? {});
|
|
9860
|
-
const remoteLocalPath = (rel) =>
|
|
9932
|
+
const remoteLocalPath = (rel) => join24(projectDir, ...rel.split("/"));
|
|
9861
9933
|
for (const [, file] of remoteFiles) {
|
|
9862
9934
|
declareContentAddressedUrl(file.url, file.sha256);
|
|
9863
9935
|
if (file.probeFactsUrl) declareProbeFactsUrl(file.url, file.probeFactsUrl);
|
|
@@ -9907,6 +9979,9 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
9907
9979
|
}
|
|
9908
9980
|
stageStarted = Date.now();
|
|
9909
9981
|
const probeResult = await runProbeStage({
|
|
9982
|
+
recordReferenceBackground: createReferenceBackgroundRecorder2(
|
|
9983
|
+
(result) => Object.assign(job, result)
|
|
9984
|
+
),
|
|
9910
9985
|
projectDir,
|
|
9911
9986
|
workDir,
|
|
9912
9987
|
job,
|
|
@@ -9924,6 +9999,21 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
9924
9999
|
subTimelineWaitMemo: {}
|
|
9925
10000
|
});
|
|
9926
10001
|
logPlanStage(log, "probe", stageStarted);
|
|
10002
|
+
if (!probeResult.probeSession) {
|
|
10003
|
+
stageStarted = Date.now();
|
|
10004
|
+
Object.assign(
|
|
10005
|
+
job,
|
|
10006
|
+
await readPlanReferenceBackground({
|
|
10007
|
+
projectDir,
|
|
10008
|
+
workDir,
|
|
10009
|
+
cfg,
|
|
10010
|
+
log,
|
|
10011
|
+
options: { width, height, fps: job.config.fps, variables: job.config.variables }
|
|
10012
|
+
})
|
|
10013
|
+
);
|
|
10014
|
+
assertNotAborted();
|
|
10015
|
+
logPlanStage(log, "reference_background", stageStarted);
|
|
10016
|
+
}
|
|
9927
10017
|
compiled = probeResult.compiled;
|
|
9928
10018
|
job.duration = probeResult.duration;
|
|
9929
10019
|
job.totalFrames = probeResult.totalFrames;
|
|
@@ -9936,8 +10026,8 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
9936
10026
|
if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
|
|
9937
10027
|
if (probeResult.probeSession) {
|
|
9938
10028
|
try {
|
|
9939
|
-
const { closeCaptureSession:
|
|
9940
|
-
await
|
|
10029
|
+
const { closeCaptureSession: closeCaptureSession12 } = await import("@hyperframes/engine");
|
|
10030
|
+
await closeCaptureSession12(probeResult.probeSession);
|
|
9941
10031
|
} catch (err) {
|
|
9942
10032
|
log.warn("[plan] probe session close failed", {
|
|
9943
10033
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -10043,10 +10133,10 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
10043
10133
|
let stageStarted = Date.now();
|
|
10044
10134
|
const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
|
|
10045
10135
|
logPlanStage(log, "extract", stageStarted);
|
|
10046
|
-
const stagedVideoFrames =
|
|
10047
|
-
const videoFramesDst =
|
|
10136
|
+
const stagedVideoFrames = join24(compiledDir, "__hyperframes_video_frames");
|
|
10137
|
+
const videoFramesDst = join24(planDir, "video-frames");
|
|
10048
10138
|
if (existsSync16(videoFramesDst)) rmSync7(videoFramesDst, { recursive: true, force: true });
|
|
10049
|
-
const videoSourcesDir =
|
|
10139
|
+
const videoSourcesDir = join24(planDir, "video-sources");
|
|
10050
10140
|
rmSync7(videoSourcesDir, { recursive: true, force: true });
|
|
10051
10141
|
if (existsSync16(stagedVideoFrames)) {
|
|
10052
10142
|
renameWithRetry8(stagedVideoFrames, videoFramesDst);
|
|
@@ -10083,7 +10173,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
10083
10173
|
};
|
|
10084
10174
|
})
|
|
10085
10175
|
});
|
|
10086
|
-
mkdirSync10(
|
|
10176
|
+
mkdirSync10(join24(planDir, "meta"), { recursive: true });
|
|
10087
10177
|
writePlanRemoteFiles(
|
|
10088
10178
|
planDir,
|
|
10089
10179
|
remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
|
|
@@ -10093,7 +10183,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
10093
10183
|
}))
|
|
10094
10184
|
);
|
|
10095
10185
|
writeFileSync7(
|
|
10096
|
-
|
|
10186
|
+
join24(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
|
|
10097
10187
|
JSON.stringify(planVideosJson, null, 2),
|
|
10098
10188
|
"utf-8"
|
|
10099
10189
|
);
|
|
@@ -10172,7 +10262,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
10172
10262
|
if (audioResult?.audioError) {
|
|
10173
10263
|
applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
|
|
10174
10264
|
}
|
|
10175
|
-
const planAudioPath =
|
|
10265
|
+
const planAudioPath = join24(planDir, PLAN_AUDIO_RELATIVE_PATH);
|
|
10176
10266
|
if (audioResult?.hasAudio && existsSync16(audioResult.audioOutputPath)) {
|
|
10177
10267
|
renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
|
|
10178
10268
|
}
|
|
@@ -10205,6 +10295,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
10205
10295
|
separateAudio
|
|
10206
10296
|
});
|
|
10207
10297
|
const compositionJson = {
|
|
10298
|
+
...referenceBackgroundResult4(job[REFERENCE_BACKGROUND_FIELD2]),
|
|
10208
10299
|
durationSeconds: job.duration ?? 0,
|
|
10209
10300
|
width,
|
|
10210
10301
|
height,
|
|
@@ -10260,6 +10351,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
10260
10351
|
log
|
|
10261
10352
|
});
|
|
10262
10353
|
return {
|
|
10354
|
+
...referenceBackgroundResult4(job[REFERENCE_BACKGROUND_FIELD2]),
|
|
10263
10355
|
executionPlanDir: planDir,
|
|
10264
10356
|
executionPlanHash: planHash,
|
|
10265
10357
|
chunkCount,
|
|
@@ -10296,6 +10388,10 @@ async function buildPlanAudio(projectDir, config, workRoot, outputPath, options
|
|
|
10296
10388
|
}
|
|
10297
10389
|
|
|
10298
10390
|
// src/services/distributed/planV2.ts
|
|
10391
|
+
import {
|
|
10392
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD3,
|
|
10393
|
+
referenceBackgroundResult as referenceBackgroundResult5
|
|
10394
|
+
} from "@hyperframes/engine";
|
|
10299
10395
|
import {
|
|
10300
10396
|
copyFileSync as copyFileSync8,
|
|
10301
10397
|
existsSync as existsSync18,
|
|
@@ -10309,7 +10405,7 @@ import {
|
|
|
10309
10405
|
writeFileSync as writeFileSync9
|
|
10310
10406
|
} from "node:fs";
|
|
10311
10407
|
import { tmpdir } from "node:os";
|
|
10312
|
-
import { dirname as dirname13, isAbsolute as isAbsolute4, join as
|
|
10408
|
+
import { dirname as dirname13, isAbsolute as isAbsolute4, join as join27, relative as relative6, resolve as resolve9, sep as sep3 } from "node:path";
|
|
10313
10409
|
import { DISTRIBUTED_FPS, isDistributedFps } from "@hyperframes/core";
|
|
10314
10410
|
import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as renameWithRetry10 } from "@hyperframes/engine";
|
|
10315
10411
|
|
|
@@ -10325,7 +10421,7 @@ import {
|
|
|
10325
10421
|
writeFileSync as writeFileSync8
|
|
10326
10422
|
} from "node:fs";
|
|
10327
10423
|
import { renameWithRetry as renameWithRetry9 } from "@hyperframes/engine";
|
|
10328
|
-
import { dirname as dirname12, join as
|
|
10424
|
+
import { dirname as dirname12, join as join26 } from "node:path";
|
|
10329
10425
|
|
|
10330
10426
|
// src/services/distributed/planV2Errors.ts
|
|
10331
10427
|
var PLAN_V2_INTEGRITY_UNRECOVERABLE = "PLAN_V2_INTEGRITY_UNRECOVERABLE";
|
|
@@ -10340,7 +10436,7 @@ var PlanV2IntegrityError = class extends Error {
|
|
|
10340
10436
|
};
|
|
10341
10437
|
|
|
10342
10438
|
// src/services/distributed/planV2Layout.ts
|
|
10343
|
-
import { join as
|
|
10439
|
+
import { join as join25 } from "node:path";
|
|
10344
10440
|
var SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
10345
10441
|
function assertPlanV2Sha256(value, field) {
|
|
10346
10442
|
if (typeof value !== "string" || !SHA256_PATTERN.test(value)) {
|
|
@@ -10350,7 +10446,7 @@ function assertPlanV2Sha256(value, field) {
|
|
|
10350
10446
|
}
|
|
10351
10447
|
function planV2BlobPath(root, sha256) {
|
|
10352
10448
|
const digest = assertPlanV2Sha256(sha256, "artifact sha256");
|
|
10353
|
-
return
|
|
10449
|
+
return join25(root, "artifacts", "sha256", digest.slice(0, 2), digest);
|
|
10354
10450
|
}
|
|
10355
10451
|
|
|
10356
10452
|
// src/services/distributed/planV2Publisher.ts
|
|
@@ -10391,7 +10487,7 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
10391
10487
|
this.destinationDir = destinationDir;
|
|
10392
10488
|
this.#linkFile = options.linkFile ?? linkSync2;
|
|
10393
10489
|
mkdirSync11(dirname12(destinationDir), { recursive: true });
|
|
10394
|
-
this.temporaryDir = mkdtempSync3(
|
|
10490
|
+
this.temporaryDir = mkdtempSync3(join26(dirname12(destinationDir), ".plan-v2-publish-"));
|
|
10395
10491
|
}
|
|
10396
10492
|
async putBlob(blob) {
|
|
10397
10493
|
const digest = assertPlanV2Sha256(blob.sha256, "published blob sha256");
|
|
@@ -10404,8 +10500,8 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
10404
10500
|
const destinationPath = planV2BlobPath(this.temporaryDir, digest);
|
|
10405
10501
|
if (existsSync17(destinationPath)) return;
|
|
10406
10502
|
mkdirSync11(dirname12(destinationPath), { recursive: true });
|
|
10407
|
-
const stagingDir = mkdtempSync3(
|
|
10408
|
-
const temporaryPath =
|
|
10503
|
+
const stagingDir = mkdtempSync3(join26(dirname12(destinationPath), ".plan-v2-blob-"));
|
|
10504
|
+
const temporaryPath = join26(stagingDir, "blob");
|
|
10409
10505
|
try {
|
|
10410
10506
|
try {
|
|
10411
10507
|
this.#linkFile(blob.sourcePath, temporaryPath);
|
|
@@ -10426,7 +10522,7 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
10426
10522
|
);
|
|
10427
10523
|
}
|
|
10428
10524
|
}
|
|
10429
|
-
writeFileSync8(
|
|
10525
|
+
writeFileSync8(join26(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
|
|
10430
10526
|
renameWithRetry9(this.temporaryDir, this.destinationDir);
|
|
10431
10527
|
this.#committed = true;
|
|
10432
10528
|
}
|
|
@@ -10471,7 +10567,7 @@ function listFiles(root) {
|
|
|
10471
10567
|
const rootResolved = resolve9(root);
|
|
10472
10568
|
function walk(dir) {
|
|
10473
10569
|
for (const entry of readdirSync7(dir, { withFileTypes: true })) {
|
|
10474
|
-
const absolutePath =
|
|
10570
|
+
const absolutePath = join27(dir, entry.name);
|
|
10475
10571
|
if (entry.isDirectory()) {
|
|
10476
10572
|
walk(absolutePath);
|
|
10477
10573
|
} else if (entry.isFile()) {
|
|
@@ -10498,13 +10594,13 @@ function assertValidExtractionCacheCompleteSentinel(path) {
|
|
|
10498
10594
|
}
|
|
10499
10595
|
}
|
|
10500
10596
|
function validateExtractionCacheCompleteSentinels(executionPlanDir) {
|
|
10501
|
-
const videoRoot =
|
|
10597
|
+
const videoRoot = join27(executionPlanDir, "video-frames");
|
|
10502
10598
|
if (!existsSync18(videoRoot)) return;
|
|
10503
10599
|
for (const videoEntry of readdirSync7(videoRoot, { withFileTypes: true })) {
|
|
10504
10600
|
if (!videoEntry.isDirectory()) continue;
|
|
10505
|
-
const videoDir =
|
|
10601
|
+
const videoDir = join27(videoRoot, videoEntry.name);
|
|
10506
10602
|
if (readdirSync7(videoDir).includes(EXTRACTION_CACHE_COMPLETE_SENTINEL)) {
|
|
10507
|
-
const sentinelPath =
|
|
10603
|
+
const sentinelPath = join27(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
|
|
10508
10604
|
assertValidExtractionCacheCompleteSentinel(sentinelPath);
|
|
10509
10605
|
}
|
|
10510
10606
|
}
|
|
@@ -10551,7 +10647,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
|
|
|
10551
10647
|
if (video.deferredRange) {
|
|
10552
10648
|
const framePaths2 = /* @__PURE__ */ new Map();
|
|
10553
10649
|
for (let index = 0; index < video.totalFrames; index++) {
|
|
10554
|
-
framePaths2.set(index,
|
|
10650
|
+
framePaths2.set(index, join27(outputDir, String(index)));
|
|
10555
10651
|
}
|
|
10556
10652
|
return { ...video, outputDir, framePaths: framePaths2, ownedByLookup: false };
|
|
10557
10653
|
}
|
|
@@ -10559,7 +10655,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
|
|
|
10559
10655
|
const framePaths = /* @__PURE__ */ new Map();
|
|
10560
10656
|
for (const frameName of frameNames) {
|
|
10561
10657
|
if (frameName === EXTRACTION_CACHE_COMPLETE_SENTINEL) {
|
|
10562
|
-
assertValidExtractionCacheCompleteSentinel(
|
|
10658
|
+
assertValidExtractionCacheCompleteSentinel(join27(outputDir, frameName));
|
|
10563
10659
|
continue;
|
|
10564
10660
|
}
|
|
10565
10661
|
const match = /(\d+)(?=\.[^.]+$)/.exec(frameName);
|
|
@@ -10578,7 +10674,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
|
|
|
10578
10674
|
`duplicate extracted frame index ${frameIndex} in ${outputDir}`
|
|
10579
10675
|
);
|
|
10580
10676
|
}
|
|
10581
|
-
framePaths.set(frameIndex,
|
|
10677
|
+
framePaths.set(frameIndex, join27(outputDir, frameName));
|
|
10582
10678
|
}
|
|
10583
10679
|
return {
|
|
10584
10680
|
...video,
|
|
@@ -10599,7 +10695,7 @@ function parsePlanVideosJson2(value) {
|
|
|
10599
10695
|
}
|
|
10600
10696
|
}
|
|
10601
10697
|
function materializeExtractedVideoDirectories(planDir) {
|
|
10602
|
-
const videosPath =
|
|
10698
|
+
const videosPath = join27(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
10603
10699
|
if (!existsSync18(videosPath)) return;
|
|
10604
10700
|
const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
|
|
10605
10701
|
for (const video of videos.extracted) {
|
|
@@ -10633,13 +10729,13 @@ function parseChunkSlices(value) {
|
|
|
10633
10729
|
});
|
|
10634
10730
|
}
|
|
10635
10731
|
function buildVideoChunkDependencies(executionPlanDir, dimensions) {
|
|
10636
|
-
const videoRoot =
|
|
10732
|
+
const videoRoot = join27(executionPlanDir, "video-frames");
|
|
10637
10733
|
const hasExtractedFrames = existsSync18(videoRoot) && listFiles(videoRoot).length > 0;
|
|
10638
|
-
const videosPath =
|
|
10734
|
+
const videosPath = join27(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
10639
10735
|
if (!existsSync18(videosPath)) {
|
|
10640
10736
|
return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
|
|
10641
10737
|
}
|
|
10642
|
-
const chunksPath =
|
|
10738
|
+
const chunksPath = join27(executionPlanDir, "meta", "chunks.json");
|
|
10643
10739
|
const videos = readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
10644
10740
|
const chunks = readJsonFile(chunksPath, "meta/chunks.json");
|
|
10645
10741
|
const parsedVideos = parsePlanVideosJson2(videos);
|
|
@@ -10695,8 +10791,8 @@ function computeManifestHash(manifest) {
|
|
|
10695
10791
|
function writeBlob(sourcePath, destinationPath) {
|
|
10696
10792
|
if (existsSync18(destinationPath)) return;
|
|
10697
10793
|
mkdirSync12(dirname13(destinationPath), { recursive: true });
|
|
10698
|
-
const temporaryDir = mkdtempSync4(
|
|
10699
|
-
const temporaryPath =
|
|
10794
|
+
const temporaryDir = mkdtempSync4(join27(dirname13(destinationPath), ".plan-v2-blob-"));
|
|
10795
|
+
const temporaryPath = join27(temporaryDir, "blob");
|
|
10700
10796
|
try {
|
|
10701
10797
|
copyFileSync8(sourcePath, temporaryPath);
|
|
10702
10798
|
renameWithRetry10(temporaryPath, destinationPath);
|
|
@@ -10732,7 +10828,7 @@ async function putTasks(tasks) {
|
|
|
10732
10828
|
if (failure) throw failure.reason;
|
|
10733
10829
|
}
|
|
10734
10830
|
function buildPlanV2Publication(executionPlanDir, digests) {
|
|
10735
|
-
const executionPlanPath =
|
|
10831
|
+
const executionPlanPath = join27(executionPlanDir, "plan.json");
|
|
10736
10832
|
if (!existsSync18(executionPlanPath)) {
|
|
10737
10833
|
throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
|
|
10738
10834
|
}
|
|
@@ -10760,7 +10856,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
|
|
|
10760
10856
|
}
|
|
10761
10857
|
validateExtractionCacheCompleteSentinels(executionPlanDir);
|
|
10762
10858
|
const videoDependencyPlan = buildVideoChunkDependencies(executionPlanDir, dimensions);
|
|
10763
|
-
const encoder = readJsonFile(
|
|
10859
|
+
const encoder = readJsonFile(join27(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
|
|
10764
10860
|
const files = listFiles(executionPlanDir);
|
|
10765
10861
|
const chunkAudio = !isRecord3(encoder) || encoder.chunksCarryAudio !== true ? "none" : files.some((file) => chunkAudioSliceTarget(file.path) !== null) ? "sliced" : "whole";
|
|
10766
10862
|
for (const file of files) {
|
|
@@ -10821,13 +10917,13 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
|
|
|
10821
10917
|
throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
|
|
10822
10918
|
}
|
|
10823
10919
|
mkdirSync12(dirname13(planV2Dir), { recursive: true });
|
|
10824
|
-
const tempDir = mkdtempSync4(
|
|
10920
|
+
const tempDir = mkdtempSync4(join27(dirname13(planV2Dir), ".plan-v2-build-"));
|
|
10825
10921
|
try {
|
|
10826
10922
|
for (const blob of publication.blobs) {
|
|
10827
10923
|
writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
|
|
10828
10924
|
}
|
|
10829
10925
|
writeFileSync9(
|
|
10830
|
-
|
|
10926
|
+
join27(tempDir, "plan.json"),
|
|
10831
10927
|
canonicalJsonStringify(publication.manifest),
|
|
10832
10928
|
"utf-8"
|
|
10833
10929
|
);
|
|
@@ -10868,7 +10964,7 @@ async function publishExecutionPlan(executionPlanDir, publisher, { digests, log
|
|
|
10868
10964
|
}
|
|
10869
10965
|
}
|
|
10870
10966
|
async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
|
|
10871
|
-
const stagingRoot = mkdtempSync4(
|
|
10967
|
+
const stagingRoot = mkdtempSync4(join27(options.stagingParentDir ?? tmpdir(), ".execution-plan-"));
|
|
10872
10968
|
const digests = /* @__PURE__ */ new Map();
|
|
10873
10969
|
try {
|
|
10874
10970
|
await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
|
|
@@ -10879,7 +10975,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
10879
10975
|
// artifactTargets ships every compiled/ file to all chunks, so each is in the manifest.
|
|
10880
10976
|
whileAudioMixes: () => putBlobs(
|
|
10881
10977
|
publisher,
|
|
10882
|
-
listFiles(
|
|
10978
|
+
listFiles(join27(stagingRoot, "compiled")).map(
|
|
10883
10979
|
(file) => publishBlobFor(file.absolutePath, digests)
|
|
10884
10980
|
)
|
|
10885
10981
|
),
|
|
@@ -10909,9 +11005,14 @@ async function planV2(projectDir, config, planV2Dir) {
|
|
|
10909
11005
|
return resultFromManifest(planV2Dir, manifest);
|
|
10910
11006
|
}
|
|
10911
11007
|
function resultFromManifest(planV2Dir, manifest) {
|
|
11008
|
+
const artifact = manifest.artifacts.find((entry) => entry.path === "plan.json");
|
|
11009
|
+
const executionPlan = artifact ? readJsonFile(verifyBlob(planV2Dir, artifact), "execution plan.json") : null;
|
|
10912
11010
|
return {
|
|
11011
|
+
...referenceBackgroundResult5(
|
|
11012
|
+
isRecord3(executionPlan) ? executionPlan[REFERENCE_BACKGROUND_FIELD3] : void 0
|
|
11013
|
+
),
|
|
10913
11014
|
planDir: planV2Dir,
|
|
10914
|
-
manifestPath:
|
|
11015
|
+
manifestPath: join27(planV2Dir, "plan.json"),
|
|
10915
11016
|
planProtocol: PLAN_PROTOCOL_V2,
|
|
10916
11017
|
planHash: manifest.planHash,
|
|
10917
11018
|
sourcePlanV1Hash: getPlanV2ExecutionPlanHash(manifest),
|
|
@@ -11047,7 +11148,7 @@ function parsePlanV2Manifest(value) {
|
|
|
11047
11148
|
return parsed;
|
|
11048
11149
|
}
|
|
11049
11150
|
function readPlanV2Manifest(planV2Dir) {
|
|
11050
|
-
const manifestPath =
|
|
11151
|
+
const manifestPath = join27(planV2Dir, "plan.json");
|
|
11051
11152
|
if (!existsSync18(manifestPath)) {
|
|
11052
11153
|
throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
|
|
11053
11154
|
}
|
|
@@ -11093,16 +11194,16 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
|
|
|
11093
11194
|
sourcePath: verifyBlob(planV2Dir, artifact)
|
|
11094
11195
|
}));
|
|
11095
11196
|
mkdirSync12(dirname13(destinationDir), { recursive: true });
|
|
11096
|
-
const tempDir = mkdtempSync4(
|
|
11197
|
+
const tempDir = mkdtempSync4(join27(dirname13(destinationDir), ".plan-v2-materialize-"));
|
|
11097
11198
|
try {
|
|
11098
11199
|
for (const { artifact, sourcePath } of verified) {
|
|
11099
|
-
const destinationPath =
|
|
11200
|
+
const destinationPath = join27(tempDir, ...artifact.path.split("/"));
|
|
11100
11201
|
mkdirSync12(dirname13(destinationPath), { recursive: true });
|
|
11101
11202
|
copyFileSync8(sourcePath, destinationPath);
|
|
11102
11203
|
}
|
|
11103
11204
|
if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
|
|
11104
11205
|
writeFileSync9(
|
|
11105
|
-
|
|
11206
|
+
join27(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
|
|
11106
11207
|
canonicalJsonStringify({
|
|
11107
11208
|
manifest,
|
|
11108
11209
|
target,
|
|
@@ -11125,7 +11226,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
|
|
|
11125
11226
|
// Join the artifact's OWN name, not the current constant: a plan written
|
|
11126
11227
|
// before the container change carries the legacy name, and materializing it
|
|
11127
11228
|
// under the new one would point at a file that was never written.
|
|
11128
|
-
audioPath: target.role === "assembler" ? audioArtifact ?
|
|
11229
|
+
audioPath: target.role === "assembler" ? audioArtifact ? join27(destinationDir, audioArtifact.path) : null : null
|
|
11129
11230
|
};
|
|
11130
11231
|
}
|
|
11131
11232
|
function assertRemoteSources(remoteSources, artifacts) {
|
|
@@ -11144,7 +11245,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
|
|
|
11144
11245
|
return readValidatedPlanV2Materialization(planDir, expectedTarget)?.manifest ?? null;
|
|
11145
11246
|
}
|
|
11146
11247
|
function readValidatedPlanV2Materialization(planDir, expectedTarget) {
|
|
11147
|
-
const markerPath =
|
|
11248
|
+
const markerPath = join27(planDir, PLAN_V2_MATERIALIZATION_MARKER);
|
|
11148
11249
|
if (!existsSync18(markerPath)) return null;
|
|
11149
11250
|
const marker = readJsonFile(markerPath, "materialization marker");
|
|
11150
11251
|
if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
|
|
@@ -11162,7 +11263,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
|
|
|
11162
11263
|
assertRemoteSources(remoteSources, required);
|
|
11163
11264
|
for (const artifact of required) {
|
|
11164
11265
|
if (Object.hasOwn(remoteSources, artifact.path)) continue;
|
|
11165
|
-
const path =
|
|
11266
|
+
const path = join27(planDir, ...artifact.path.split("/"));
|
|
11166
11267
|
if (!existsSync18(path) || statSync7(path).size !== artifact.sizeBytes) {
|
|
11167
11268
|
throw new PlanV2IntegrityError(
|
|
11168
11269
|
`materialized artifact missing or truncated: ${artifact.path}`
|
|
@@ -11178,9 +11279,13 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
|
|
|
11178
11279
|
// src/services/distributed/planV2Execution.ts
|
|
11179
11280
|
import { mkdtempSync as mkdtempSync6, rmSync as rmSync12 } from "node:fs";
|
|
11180
11281
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
11181
|
-
import { join as
|
|
11282
|
+
import { join as join30 } from "node:path";
|
|
11182
11283
|
|
|
11183
11284
|
// src/services/distributed/assemble.ts
|
|
11285
|
+
import {
|
|
11286
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD4,
|
|
11287
|
+
referenceBackgroundResult as referenceBackgroundResult6
|
|
11288
|
+
} from "@hyperframes/engine";
|
|
11184
11289
|
import {
|
|
11185
11290
|
cpSync as cpSync3,
|
|
11186
11291
|
existsSync as existsSync19,
|
|
@@ -11192,7 +11297,7 @@ import {
|
|
|
11192
11297
|
statSync as statSync8,
|
|
11193
11298
|
writeFileSync as writeFileSync10
|
|
11194
11299
|
} from "node:fs";
|
|
11195
|
-
import { dirname as dirname14, join as
|
|
11300
|
+
import { dirname as dirname14, join as join28 } from "node:path";
|
|
11196
11301
|
import {
|
|
11197
11302
|
appendRateCapArgs as appendRateCapArgs2,
|
|
11198
11303
|
appendRenderProvenanceArgs as appendRenderProvenanceArgs2,
|
|
@@ -11220,12 +11325,16 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
11220
11325
|
const plan = readAssemblePlan(planDir, chunkOutputs);
|
|
11221
11326
|
const chunkPaths = chunkOutputs.flat();
|
|
11222
11327
|
if (plan.dimensions.format === "png-sequence") {
|
|
11223
|
-
return
|
|
11328
|
+
return {
|
|
11329
|
+
...mergePngFrameDirs(chunkPaths, outputPath, plan.totalFrames, audioPath, start),
|
|
11330
|
+
...referenceBackgroundResult6(plan[REFERENCE_BACKGROUND_FIELD4])
|
|
11331
|
+
};
|
|
11224
11332
|
}
|
|
11225
11333
|
if (chunksAreStitchedMp4(planDir, cfr)) {
|
|
11226
11334
|
const separateAudio = stitchesSeparateAudio(planDir) && audioPath !== null;
|
|
11227
11335
|
await writeStitchedMp4(chunkPaths, outputPath, separateAudio ? audioPath : void 0);
|
|
11228
11336
|
return {
|
|
11337
|
+
...referenceBackgroundResult6(plan[REFERENCE_BACKGROUND_FIELD4]),
|
|
11229
11338
|
outputPath,
|
|
11230
11339
|
durationMs: Date.now() - start,
|
|
11231
11340
|
framesEncoded: plan.totalFrames,
|
|
@@ -11257,7 +11366,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
11257
11366
|
};
|
|
11258
11367
|
try {
|
|
11259
11368
|
const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
|
|
11260
|
-
const finalPath =
|
|
11369
|
+
const finalPath = join28(workDir, `output.${format}`);
|
|
11261
11370
|
const audio = audioPath !== null && existsSync19(audioPath) ? audioPath : null;
|
|
11262
11371
|
await writeJoined(ctx, videoSources, audio, finalPath);
|
|
11263
11372
|
renameWithRetry11(finalPath, outputPath);
|
|
@@ -11278,6 +11387,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
11278
11387
|
}
|
|
11279
11388
|
const fileSize = existsSync19(outputPath) ? statSync8(outputPath).size : 0;
|
|
11280
11389
|
return {
|
|
11390
|
+
...referenceBackgroundResult6(plan[REFERENCE_BACKGROUND_FIELD4]),
|
|
11281
11391
|
outputPath,
|
|
11282
11392
|
durationMs: Date.now() - start,
|
|
11283
11393
|
framesEncoded: plan.totalFrames,
|
|
@@ -11285,8 +11395,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
11285
11395
|
};
|
|
11286
11396
|
}
|
|
11287
11397
|
function readAssemblePlan(planDir, chunkPaths) {
|
|
11288
|
-
const planJsonPath =
|
|
11289
|
-
const chunksJsonPath =
|
|
11398
|
+
const planJsonPath = join28(planDir, "plan.json");
|
|
11399
|
+
const chunksJsonPath = join28(planDir, "meta", "chunks.json");
|
|
11290
11400
|
if (!existsSync19(planJsonPath)) {
|
|
11291
11401
|
throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
|
|
11292
11402
|
}
|
|
@@ -11337,7 +11447,7 @@ function cfrEncodeArgs(inputArgs, encoder, fpsArg) {
|
|
|
11337
11447
|
return args;
|
|
11338
11448
|
}
|
|
11339
11449
|
async function reencodeCfr(ctx, chunkPaths, encoder) {
|
|
11340
|
-
const cfrOutputPath =
|
|
11450
|
+
const cfrOutputPath = join28(ctx.workDir, `cfr.${ctx.format}`);
|
|
11341
11451
|
const cfrArgs = cfrEncodeArgs(videoInputArgs(ctx, chunkPaths), encoder, ctx.fpsArg);
|
|
11342
11452
|
appendRenderProvenanceArgs2(cfrArgs, cfrOutputPath);
|
|
11343
11453
|
cfrArgs.push("-y", cfrOutputPath);
|
|
@@ -11364,7 +11474,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
|
|
|
11364
11474
|
);
|
|
11365
11475
|
return;
|
|
11366
11476
|
}
|
|
11367
|
-
const paddedAudioPath =
|
|
11477
|
+
const paddedAudioPath = join28(ctx.workDir, "audio-padded.m4a");
|
|
11368
11478
|
const padTrimResult = await ctx.timed(
|
|
11369
11479
|
"audioMs",
|
|
11370
11480
|
() => padOrTrimAudioToVideoFrameCount({
|
|
@@ -11404,7 +11514,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
|
|
|
11404
11514
|
}
|
|
11405
11515
|
}
|
|
11406
11516
|
function concatDemuxerInput(chunkPaths, workDir, fpsArg) {
|
|
11407
|
-
const listPath =
|
|
11517
|
+
const listPath = join28(workDir, "concat-list.txt");
|
|
11408
11518
|
const body = chunkPaths.map((path) => `file '${path.replace(/'/g, "'\\''")}'`).join("\n");
|
|
11409
11519
|
writeFileSync10(listPath, `${body}
|
|
11410
11520
|
`, "utf-8");
|
|
@@ -11442,11 +11552,11 @@ function stitchesSeparateAudio(planDir) {
|
|
|
11442
11552
|
return lockedAudio(planDir).separateAudio === true;
|
|
11443
11553
|
}
|
|
11444
11554
|
function planFormat(planDir) {
|
|
11445
|
-
const plan = JSON.parse(readFileSync9(
|
|
11555
|
+
const plan = JSON.parse(readFileSync9(join28(planDir, "plan.json"), "utf-8"));
|
|
11446
11556
|
return plan.dimensions.format;
|
|
11447
11557
|
}
|
|
11448
11558
|
function lockedAudio(planDir) {
|
|
11449
|
-
const encoderJsonPath =
|
|
11559
|
+
const encoderJsonPath = join28(planDir, "meta", "encoder.json");
|
|
11450
11560
|
if (!existsSync19(encoderJsonPath)) return {};
|
|
11451
11561
|
return JSON.parse(readFileSync9(encoderJsonPath, "utf-8"));
|
|
11452
11562
|
}
|
|
@@ -11456,7 +11566,7 @@ function readCfrEncoder(planDir, format) {
|
|
|
11456
11566
|
`[assemble] cfr=true is only supported for format="mp4" (got "${format}"). Stream-copy paths for webm and mov already produce exact avg_frame_rate; cfr re-encode is not needed.`
|
|
11457
11567
|
);
|
|
11458
11568
|
}
|
|
11459
|
-
const encoderJsonPath =
|
|
11569
|
+
const encoderJsonPath = join28(planDir, "meta", "encoder.json");
|
|
11460
11570
|
if (!existsSync19(encoderJsonPath)) {
|
|
11461
11571
|
throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
|
|
11462
11572
|
}
|
|
@@ -11483,8 +11593,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
11483
11593
|
throw new Error(`[assemble] png-sequence chunk has no frames: ${chunkDir}`);
|
|
11484
11594
|
}
|
|
11485
11595
|
for (const frame of frames) {
|
|
11486
|
-
const dst =
|
|
11487
|
-
cpSync3(
|
|
11596
|
+
const dst = join28(outputPath, formatExportFrameName(globalIdx, "png"));
|
|
11597
|
+
cpSync3(join28(chunkDir, frame), dst);
|
|
11488
11598
|
globalIdx += 1;
|
|
11489
11599
|
}
|
|
11490
11600
|
}
|
|
@@ -11494,13 +11604,13 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
11494
11604
|
);
|
|
11495
11605
|
}
|
|
11496
11606
|
if (audioPath !== null && existsSync19(audioPath)) {
|
|
11497
|
-
const sidecar =
|
|
11607
|
+
const sidecar = join28(outputPath, MIXED_AUDIO_FILENAME4);
|
|
11498
11608
|
cpSync3(audioPath, sidecar);
|
|
11499
11609
|
}
|
|
11500
11610
|
let fileSize = 0;
|
|
11501
11611
|
for (const name of readdirSync8(outputPath)) {
|
|
11502
11612
|
try {
|
|
11503
|
-
fileSize += statSync8(
|
|
11613
|
+
fileSize += statSync8(join28(outputPath, name)).size;
|
|
11504
11614
|
} catch {
|
|
11505
11615
|
}
|
|
11506
11616
|
}
|
|
@@ -11516,14 +11626,14 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
11516
11626
|
import { randomBytes } from "node:crypto";
|
|
11517
11627
|
import { existsSync as existsSync20, mkdirSync as mkdirSync14, readFileSync as readFileSync10, readdirSync as readdirSync9, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
|
|
11518
11628
|
import { cpus } from "node:os";
|
|
11519
|
-
import { join as
|
|
11629
|
+
import { join as join29 } from "node:path";
|
|
11520
11630
|
import {
|
|
11521
11631
|
assertSwiftShader,
|
|
11522
11632
|
BROWSER_GPU_NOT_SOFTWARE as BROWSER_GPU_NOT_SOFTWARE4,
|
|
11523
11633
|
calculateOptimalWorkers as calculateOptimalWorkers2,
|
|
11524
11634
|
classifyCaptureFailure as classifyCaptureFailure4,
|
|
11525
|
-
closeCaptureSession as
|
|
11526
|
-
createCaptureSession as
|
|
11635
|
+
closeCaptureSession as closeCaptureSession11,
|
|
11636
|
+
createCaptureSession as createCaptureSession11,
|
|
11527
11637
|
createFrameLookupTable as createFrameLookupTable5,
|
|
11528
11638
|
deriveBeginFrameProbeTimeTicks as deriveBeginFrameProbeTimeTicks2,
|
|
11529
11639
|
getEncoderPreset as getEncoderPreset6,
|
|
@@ -11566,10 +11676,10 @@ function resolveChunkFrameRange(slice, chunkIndex, frameRange) {
|
|
|
11566
11676
|
return { startFrame, endFrame };
|
|
11567
11677
|
}
|
|
11568
11678
|
var distributedCaptureSessionDependencies = {
|
|
11569
|
-
createCaptureSession:
|
|
11679
|
+
createCaptureSession: createCaptureSession11,
|
|
11570
11680
|
assertSwiftShader,
|
|
11571
11681
|
initializeSession: initializeSession10,
|
|
11572
|
-
closeCaptureSession:
|
|
11682
|
+
closeCaptureSession: closeCaptureSession11,
|
|
11573
11683
|
readWebGlVendorInfo: readWebGlVendorInfoFromCanvas
|
|
11574
11684
|
};
|
|
11575
11685
|
async function createVerifiedDistributedCaptureSession(serverUrl, framesDir, captureOptions, cfg, dependencies = distributedCaptureSessionDependencies) {
|
|
@@ -11640,7 +11750,7 @@ function hashChunkOutput(outputPath, kind) {
|
|
|
11640
11750
|
if (kind === "file") return sha256Hex(readFileSync10(outputPath));
|
|
11641
11751
|
const entries = readdirSync9(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
|
|
11642
11752
|
const lines = entries.map(
|
|
11643
|
-
(name) => `${name}\0${sha256Hex(readFileSync10(
|
|
11753
|
+
(name) => `${name}\0${sha256Hex(readFileSync10(join29(outputPath, name)))}`
|
|
11644
11754
|
);
|
|
11645
11755
|
return sha256Hex(lines.join("\0"));
|
|
11646
11756
|
}
|
|
@@ -11657,9 +11767,9 @@ function resolveLockedVp9CpuUsed(lockedEncoder) {
|
|
|
11657
11767
|
async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
11658
11768
|
const start = Date.now();
|
|
11659
11769
|
const log = defaultLogger;
|
|
11660
|
-
const planJsonPath =
|
|
11661
|
-
const encoderJsonPath =
|
|
11662
|
-
const chunksJsonPath =
|
|
11770
|
+
const planJsonPath = join29(planDir, "plan.json");
|
|
11771
|
+
const encoderJsonPath = join29(planDir, "meta", "encoder.json");
|
|
11772
|
+
const chunksJsonPath = join29(planDir, "meta", "chunks.json");
|
|
11663
11773
|
if (!existsSync20(planJsonPath)) {
|
|
11664
11774
|
throw new RenderChunkValidationError(
|
|
11665
11775
|
MISSING_PLAN_ARTIFACT,
|
|
@@ -11685,7 +11795,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11685
11795
|
}
|
|
11686
11796
|
const encoder = JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
|
|
11687
11797
|
const chunks = JSON.parse(readFileSync10(chunksJsonPath, "utf-8"));
|
|
11688
|
-
const videosJsonPath =
|
|
11798
|
+
const videosJsonPath = join29(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
11689
11799
|
let planVideos = null;
|
|
11690
11800
|
if (existsSync20(videosJsonPath)) {
|
|
11691
11801
|
try {
|
|
@@ -11717,7 +11827,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11717
11827
|
}
|
|
11718
11828
|
const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
|
|
11719
11829
|
const framesInChunk = range.endFrame - range.startFrame;
|
|
11720
|
-
const compiledDir =
|
|
11830
|
+
const compiledDir = join29(planDir, "compiled");
|
|
11721
11831
|
if (!existsSync20(compiledDir)) {
|
|
11722
11832
|
throw new RenderChunkValidationError(
|
|
11723
11833
|
MISSING_PLAN_ARTIFACT,
|
|
@@ -11775,7 +11885,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11775
11885
|
};
|
|
11776
11886
|
const workDir = `${outputChunkPath}.work.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
11777
11887
|
mkdirSync14(workDir, { recursive: true });
|
|
11778
|
-
const framesDir =
|
|
11888
|
+
const framesDir = join29(workDir, "captured-frames");
|
|
11779
11889
|
mkdirSync14(framesDir, { recursive: true });
|
|
11780
11890
|
const videoFramesDir = `${workDir}.video-frames`;
|
|
11781
11891
|
const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
|
|
@@ -11800,7 +11910,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11800
11910
|
dimensions: plan.dimensions,
|
|
11801
11911
|
encoder,
|
|
11802
11912
|
videoCount: planVideos?.videos.length ?? 0,
|
|
11803
|
-
html: readFileSync10(
|
|
11913
|
+
html: readFileSync10(join29(compiledDir, "index.html"), "utf-8"),
|
|
11804
11914
|
// The plan ships a deferred source only to chunks that show it; don't wait on the rest.
|
|
11805
11915
|
skipReadinessVideoIds: deferredVideos.filter(
|
|
11806
11916
|
(video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
|
|
@@ -11871,7 +11981,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11871
11981
|
"[renderChunk] BeginFrame liveness probe failed; using screenshot capture for the entire chunk",
|
|
11872
11982
|
{ chunkIndex }
|
|
11873
11983
|
);
|
|
11874
|
-
await
|
|
11984
|
+
await closeCaptureSession11(session).catch(() => {
|
|
11875
11985
|
});
|
|
11876
11986
|
session = null;
|
|
11877
11987
|
const screenshotBootStarted = Date.now();
|
|
@@ -11970,7 +12080,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
11970
12080
|
if (isPngSequence) {
|
|
11971
12081
|
if (!existsSync20(outputChunkPath)) mkdirSync14(outputChunkPath, { recursive: true });
|
|
11972
12082
|
} else {
|
|
11973
|
-
const outDir =
|
|
12083
|
+
const outDir = join29(outputChunkPath, "..");
|
|
11974
12084
|
if (!existsSync20(outDir)) mkdirSync14(outDir, { recursive: true });
|
|
11975
12085
|
}
|
|
11976
12086
|
const encodeInput = {
|
|
@@ -12144,7 +12254,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
12144
12254
|
});
|
|
12145
12255
|
if (session) {
|
|
12146
12256
|
try {
|
|
12147
|
-
await
|
|
12257
|
+
await closeCaptureSession11(session);
|
|
12148
12258
|
} catch (err) {
|
|
12149
12259
|
log.warn("[renderChunk] error closing capture session in finally", {
|
|
12150
12260
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -12214,8 +12324,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
12214
12324
|
|
|
12215
12325
|
// src/services/distributed/planV2Execution.ts
|
|
12216
12326
|
async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
|
|
12217
|
-
const workRoot = mkdtempSync6(
|
|
12218
|
-
const materializedPlanDir =
|
|
12327
|
+
const workRoot = mkdtempSync6(join30(tmpdir2(), "hf-plan-v2-chunk-"));
|
|
12328
|
+
const materializedPlanDir = join30(workRoot, "plan");
|
|
12219
12329
|
try {
|
|
12220
12330
|
materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
|
|
12221
12331
|
return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
|
|
@@ -12224,8 +12334,8 @@ async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
|
|
|
12224
12334
|
}
|
|
12225
12335
|
}
|
|
12226
12336
|
async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
12227
|
-
const workRoot = mkdtempSync6(
|
|
12228
|
-
const materializedPlanDir =
|
|
12337
|
+
const workRoot = mkdtempSync6(join30(tmpdir2(), "hf-plan-v2-assembler-"));
|
|
12338
|
+
const materializedPlanDir = join30(workRoot, "plan");
|
|
12229
12339
|
try {
|
|
12230
12340
|
const materialized = materializePlanV2Target(
|
|
12231
12341
|
planV2Dir,
|
|
@@ -12517,7 +12627,7 @@ function validateIntDimension(field, value) {
|
|
|
12517
12627
|
// src/services/distributed/projectHash.ts
|
|
12518
12628
|
import { closeSync as closeSync5, openSync as openSync5, readdirSync as readdirSync10, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
|
|
12519
12629
|
import { createHash as createHash8 } from "node:crypto";
|
|
12520
|
-
import { join as
|
|
12630
|
+
import { join as join31 } from "node:path";
|
|
12521
12631
|
var SITE_ID_SCHEME = "site-v2\0";
|
|
12522
12632
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
12523
12633
|
function listSiteFiles(projectDir) {
|
|
@@ -12526,7 +12636,7 @@ function listSiteFiles(projectDir) {
|
|
|
12526
12636
|
function walk(dir, rel) {
|
|
12527
12637
|
for (const name of readdirSync10(dir).sort()) {
|
|
12528
12638
|
if (rel === "" && PLAN_PROJECT_DIR_SKIP_SEGMENTS.has(name)) continue;
|
|
12529
|
-
const full =
|
|
12639
|
+
const full = join31(dir, name);
|
|
12530
12640
|
const relPath = rel === "" ? name : `${rel}/${name}`;
|
|
12531
12641
|
let stat;
|
|
12532
12642
|
try {
|
|
@@ -12556,7 +12666,7 @@ function hashProjectDir(projectDir, files = listSiteFiles(projectDir)) {
|
|
|
12556
12666
|
for (const rel of files) {
|
|
12557
12667
|
hash.update(rel);
|
|
12558
12668
|
hash.update("\0");
|
|
12559
|
-
const fd = openSync5(
|
|
12669
|
+
const fd = openSync5(join31(projectDir, rel), "r");
|
|
12560
12670
|
try {
|
|
12561
12671
|
let read;
|
|
12562
12672
|
while ((read = readSync4(fd, chunk, 0, chunk.length, null)) > 0) {
|