@hyperframes/producer 0.8.168 → 0.8.170
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 +182 -17
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +63 -62
- package/dist/index.js +189 -17
- package/dist/services/distributed/chunkAudio.d.ts +30 -0
- package/dist/services/distributed/plan.d.ts +5 -0
- package/dist/services/distributed/planV2.d.ts +1 -0
- package/dist/services/render/audioPadTrim.d.ts +1 -0
- package/dist/services/render/stages/freezePlan.d.ts +1 -0
- package/package.json +7 -7
package/dist/distributed.js
CHANGED
|
@@ -7400,9 +7400,28 @@ function buildLockedRenderConfig(input) {
|
|
|
7400
7400
|
chunkSize: input.effectiveChunkSize,
|
|
7401
7401
|
chunkCount: input.chunkCount,
|
|
7402
7402
|
runtimeEnv: input.runtimeEnv,
|
|
7403
|
-
variables: config.variables
|
|
7403
|
+
variables: config.variables,
|
|
7404
|
+
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {}
|
|
7404
7405
|
};
|
|
7405
7406
|
}
|
|
7407
|
+
function carriesChunkAudio(config, options) {
|
|
7408
|
+
return options.chunksCarryAudio === true && config.format === "mp4" && config.cfr !== true;
|
|
7409
|
+
}
|
|
7410
|
+
async function fitPlanAudioToFrames(audioPath, workDir, totalFrames, fps, run) {
|
|
7411
|
+
const fittedPath = join18(workDir, "audio-fitted.m4a");
|
|
7412
|
+
const result = await padOrTrimAudioToVideoFrameCount({
|
|
7413
|
+
videoPath: audioPath,
|
|
7414
|
+
probeVideoFrameInfo: async () => ({ frameCount: totalFrames, fpsNum: fps, fpsDen: 1 }),
|
|
7415
|
+
audioPath,
|
|
7416
|
+
outputPath: fittedPath,
|
|
7417
|
+
signal: run.signal,
|
|
7418
|
+
timeoutMs: run.timeoutMs
|
|
7419
|
+
});
|
|
7420
|
+
if (!result.success) {
|
|
7421
|
+
throw encoderFailureError("[plan] audio pad/trim failed", result);
|
|
7422
|
+
}
|
|
7423
|
+
renameSync3(fittedPath, audioPath);
|
|
7424
|
+
}
|
|
7406
7425
|
function resolveEncoderTriple(config) {
|
|
7407
7426
|
if (config.format === "mp4") {
|
|
7408
7427
|
return resolveMp4EncoderTriple(config.codec);
|
|
@@ -7456,6 +7475,13 @@ function pathInside(root, path) {
|
|
|
7456
7475
|
const rel = relative5(root, path);
|
|
7457
7476
|
return rel === "" || rel.startsWith("..") || isAbsolute3(rel) ? null : rel;
|
|
7458
7477
|
}
|
|
7478
|
+
function stableSourcePath(roots, srcPath) {
|
|
7479
|
+
for (const [root, prefix] of roots) {
|
|
7480
|
+
const rel = pathInside(root, srcPath);
|
|
7481
|
+
if (rel !== null) return [prefix, ...rel.split(sep2)].filter(Boolean).join("/");
|
|
7482
|
+
}
|
|
7483
|
+
return srcPath;
|
|
7484
|
+
}
|
|
7459
7485
|
function createVideoSourceShipper(input) {
|
|
7460
7486
|
const shipped = /* @__PURE__ */ new Map();
|
|
7461
7487
|
return (srcPath) => {
|
|
@@ -7668,12 +7694,17 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
7668
7694
|
workCompiledDir: compiledDir,
|
|
7669
7695
|
workVideoFramesDir: stagedVideoFrames
|
|
7670
7696
|
});
|
|
7697
|
+
const sourceRoots = [
|
|
7698
|
+
[stagedVideoFrames, "video-frames"],
|
|
7699
|
+
[compiledDir, "compiled"],
|
|
7700
|
+
[projectDir, ""]
|
|
7701
|
+
];
|
|
7671
7702
|
const planVideosJson = buildPlanVideosJson({
|
|
7672
7703
|
videos: composition.videos,
|
|
7673
7704
|
compositionEnd: job.duration ?? Number.NaN,
|
|
7674
7705
|
extracted: (extractResult.extractionResult?.extracted ?? []).map((ext) => ({
|
|
7675
7706
|
videoId: ext.videoId,
|
|
7676
|
-
srcPath: ext.srcPath,
|
|
7707
|
+
srcPath: stableSourcePath(sourceRoots, ext.srcPath),
|
|
7677
7708
|
framePattern: ext.framePattern,
|
|
7678
7709
|
fps: ext.fps,
|
|
7679
7710
|
totalFrames: ext.totalFrames,
|
|
@@ -7724,6 +7755,13 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
7724
7755
|
if (audioResult.hasAudio && existsSync13(audioResult.audioOutputPath)) {
|
|
7725
7756
|
renameSync3(audioResult.audioOutputPath, planAudioPath);
|
|
7726
7757
|
}
|
|
7758
|
+
const chunksCarryAudio2 = carriesChunkAudio(config, options);
|
|
7759
|
+
if (chunksCarryAudio2 && existsSync13(planAudioPath)) {
|
|
7760
|
+
await fitPlanAudioToFrames(planAudioPath, workDir, totalFrames, config.fps, {
|
|
7761
|
+
signal: abortSignal,
|
|
7762
|
+
timeoutMs: cfg.ffmpegProcessTimeout
|
|
7763
|
+
});
|
|
7764
|
+
}
|
|
7727
7765
|
const ffmpegVersion = await readFfmpegVersion();
|
|
7728
7766
|
const producerVersion = readProducerVersion();
|
|
7729
7767
|
const fontSnapshotSha = await readFontSnapshotSha();
|
|
@@ -7736,7 +7774,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
7736
7774
|
engineConfig: cfg,
|
|
7737
7775
|
effectiveChunkSize,
|
|
7738
7776
|
chunkCount,
|
|
7739
|
-
runtimeEnv
|
|
7777
|
+
runtimeEnv,
|
|
7778
|
+
chunksCarryAudio: chunksCarryAudio2
|
|
7740
7779
|
});
|
|
7741
7780
|
const compositionJson = {
|
|
7742
7781
|
durationSeconds: job.duration ?? 0,
|
|
@@ -8050,8 +8089,10 @@ function resolveExtractedVideoOutputDir(planDir, videoId) {
|
|
|
8050
8089
|
}
|
|
8051
8090
|
return outputDir;
|
|
8052
8091
|
}
|
|
8053
|
-
function artifactTargets(path, videoDependencies) {
|
|
8054
|
-
if (isPlanAudioArtifactPath(path))
|
|
8092
|
+
function artifactTargets(path, videoDependencies, chunksCarryAudio2) {
|
|
8093
|
+
if (isPlanAudioArtifactPath(path)) {
|
|
8094
|
+
return { chunks: chunksCarryAudio2 ? "all" : [], assembler: true };
|
|
8095
|
+
}
|
|
8055
8096
|
if (path === "plan.json" || path === "meta/chunks.json" || path === "meta/encoder.json") {
|
|
8056
8097
|
return { chunks: "all", assembler: true };
|
|
8057
8098
|
}
|
|
@@ -8273,9 +8314,11 @@ function buildPlanV2Publication(executionPlanDir, digests) {
|
|
|
8273
8314
|
}
|
|
8274
8315
|
validateExtractionCacheCompleteSentinels(executionPlanDir);
|
|
8275
8316
|
const videoDependencyPlan = buildVideoChunkDependencies(executionPlanDir, dimensions);
|
|
8317
|
+
const encoder = readJsonFile(join21(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
|
|
8318
|
+
const chunksCarryAudio2 = isRecord3(encoder) && encoder.chunksCarryAudio === true;
|
|
8276
8319
|
for (const file of listFiles(executionPlanDir)) {
|
|
8277
8320
|
if (isExtractionCacheCompleteSentinelPath(file.path)) continue;
|
|
8278
|
-
const targets = artifactTargets(file.path, videoDependencyPlan.dependencies);
|
|
8321
|
+
const targets = artifactTargets(file.path, videoDependencyPlan.dependencies, chunksCarryAudio2);
|
|
8279
8322
|
if ((file.path.startsWith("video-frames/") || file.path.startsWith("video-sources/")) && targets.chunks !== "all" && targets.chunks.length === 0 && !targets.assembler) {
|
|
8280
8323
|
continue;
|
|
8281
8324
|
}
|
|
@@ -8378,7 +8421,8 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
8378
8421
|
listFiles(join21(stagingRoot, "compiled")).map(
|
|
8379
8422
|
(file) => publishBlobFor(file.absolutePath, digests)
|
|
8380
8423
|
)
|
|
8381
|
-
)
|
|
8424
|
+
),
|
|
8425
|
+
chunksCarryAudio: options.chunksCarryAudio
|
|
8382
8426
|
});
|
|
8383
8427
|
return await publishExecutionPlan(stagingRoot, publisher, { digests, log: config.logger });
|
|
8384
8428
|
} catch (error) {
|
|
@@ -8701,6 +8745,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
8701
8745
|
format,
|
|
8702
8746
|
fps,
|
|
8703
8747
|
fpsArg: fpsToFfmpegArg3(fps),
|
|
8748
|
+
chunkSeconds: chunksCarryAudio(planDir) ? plan2.chunks.map((chunk) => (chunk.endFrame - chunk.startFrame) * fps.den / fps.num) : null,
|
|
8704
8749
|
signal: options?.abortSignal,
|
|
8705
8750
|
timeout: resolveConfig4().ffmpegProcessTimeout,
|
|
8706
8751
|
log,
|
|
@@ -8763,10 +8808,10 @@ function readAssemblePlan(planDir, chunkPaths) {
|
|
|
8763
8808
|
throw new Error(`[assemble] chunk path does not exist: ${path}`);
|
|
8764
8809
|
}
|
|
8765
8810
|
}
|
|
8766
|
-
return plan2;
|
|
8811
|
+
return { ...plan2, chunks };
|
|
8767
8812
|
}
|
|
8768
8813
|
function videoInputArgs(ctx, videoSources) {
|
|
8769
|
-
return videoSources.length === 1 ? ["-i", videoSources[0]] : concatDemuxerInput(videoSources, ctx.workDir, ctx.fpsArg);
|
|
8814
|
+
return videoSources.length === 1 ? ["-i", videoSources[0]] : concatDemuxerInput(videoSources, ctx.workDir, ctx.fpsArg, ctx.chunkSeconds);
|
|
8770
8815
|
}
|
|
8771
8816
|
async function reencodeCfr(ctx, chunkPaths, encoder) {
|
|
8772
8817
|
const cfrOutputPath = join22(ctx.workDir, `cfr.${ctx.format}`);
|
|
@@ -8846,10 +8891,15 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
|
|
|
8846
8891
|
throw encoderFailureError("[assemble] audio mux failed", muxResult);
|
|
8847
8892
|
}
|
|
8848
8893
|
}
|
|
8849
|
-
function concatDemuxerInput(chunkPaths, workDir, fpsArg) {
|
|
8894
|
+
function concatDemuxerInput(chunkPaths, workDir, fpsArg, chunkSeconds) {
|
|
8850
8895
|
const listPath = join22(workDir, "concat-list.txt");
|
|
8851
|
-
const
|
|
8852
|
-
|
|
8896
|
+
const head = chunkSeconds ? ["stream", "exact_stream_id 1"] : [];
|
|
8897
|
+
const body = chunkPaths.map((path, i) => {
|
|
8898
|
+
const line = `file '${path.replace(/'/g, "'\\''")}'`;
|
|
8899
|
+
return chunkSeconds ? `${line}
|
|
8900
|
+
duration ${chunkSeconds[i].toFixed(6)}` : line;
|
|
8901
|
+
});
|
|
8902
|
+
writeFileSync8(listPath, `${[...head, ...body].join("\n")}
|
|
8853
8903
|
`, "utf-8");
|
|
8854
8904
|
return ["-r", fpsArg, "-f", "concat", "-safe", "0", "-i", listPath];
|
|
8855
8905
|
}
|
|
@@ -8872,6 +8922,11 @@ async function runAssembleFfmpeg(args, step, signal, timeout) {
|
|
|
8872
8922
|
});
|
|
8873
8923
|
}
|
|
8874
8924
|
}
|
|
8925
|
+
function chunksCarryAudio(planDir) {
|
|
8926
|
+
const encoderJsonPath = join22(planDir, "meta", "encoder.json");
|
|
8927
|
+
if (!existsSync16(encoderJsonPath)) return false;
|
|
8928
|
+
return JSON.parse(readFileSync10(encoderJsonPath, "utf-8")).chunksCarryAudio === true;
|
|
8929
|
+
}
|
|
8875
8930
|
function readCfrEncoder(planDir, format) {
|
|
8876
8931
|
if (format !== "mp4") {
|
|
8877
8932
|
throw new Error(
|
|
@@ -8956,6 +9011,104 @@ import {
|
|
|
8956
9011
|
readWebGlVendorInfoFromCanvas,
|
|
8957
9012
|
resolveConfig as resolveConfig5
|
|
8958
9013
|
} from "@hyperframes/engine";
|
|
9014
|
+
|
|
9015
|
+
// src/services/distributed/chunkAudio.ts
|
|
9016
|
+
import { appendRenderProvenanceArgs as appendRenderProvenanceArgs2, describeFfmpegFailure as describeFfmpegFailure3, runFfmpeg as runFfmpeg6 } from "@hyperframes/engine";
|
|
9017
|
+
function audioCutForChunk(grid, chunks, index, fps) {
|
|
9018
|
+
const firstPacketAt = (frame) => Math.min(
|
|
9019
|
+
grid.packetCount,
|
|
9020
|
+
Math.max(
|
|
9021
|
+
0,
|
|
9022
|
+
Math.ceil(
|
|
9023
|
+
(frame * fps.den * grid.sampleRate - grid.firstStart * fps.num) / (grid.packetSamples * fps.num)
|
|
9024
|
+
)
|
|
9025
|
+
)
|
|
9026
|
+
);
|
|
9027
|
+
const first = index === 0 ? 0 : firstPacketAt(chunks[index].startFrame);
|
|
9028
|
+
const end = index === chunks.length - 1 ? grid.packetCount : firstPacketAt(chunks[index + 1].startFrame);
|
|
9029
|
+
if (end <= first) return null;
|
|
9030
|
+
const cutSeconds = (packet) => (grid.firstStart + packet * grid.packetSamples - grid.packetSamples / 2) / grid.sampleRate;
|
|
9031
|
+
const seekSeconds = index === 0 ? null : cutSeconds(first);
|
|
9032
|
+
const durationSeconds = end === grid.packetCount ? null : cutSeconds(end) - (seekSeconds ?? 0);
|
|
9033
|
+
return { seekSeconds, durationSeconds, firstPacket: first, packetCount: end - first };
|
|
9034
|
+
}
|
|
9035
|
+
async function probeAacPacketGrid(audioPath) {
|
|
9036
|
+
const probe = await runFfprobeJson([
|
|
9037
|
+
"-v",
|
|
9038
|
+
"error",
|
|
9039
|
+
"-select_streams",
|
|
9040
|
+
"a:0",
|
|
9041
|
+
"-show_entries",
|
|
9042
|
+
"stream=sample_rate,time_base,nb_frames:packet=pts,duration",
|
|
9043
|
+
"-read_intervals",
|
|
9044
|
+
"%+#1",
|
|
9045
|
+
"-of",
|
|
9046
|
+
"json",
|
|
9047
|
+
"--",
|
|
9048
|
+
audioPath
|
|
9049
|
+
]);
|
|
9050
|
+
const stream = probe.streams?.[0] ?? {};
|
|
9051
|
+
const packet = probe.packets?.[0] ?? {};
|
|
9052
|
+
const sampleRate = Number(stream.sample_rate);
|
|
9053
|
+
const [tbNum = NaN, tbDen = NaN] = String(stream.time_base).split("/").map(Number);
|
|
9054
|
+
const toSamples = (ticks) => Number(ticks) * sampleRate * tbNum / tbDen;
|
|
9055
|
+
const grid = {
|
|
9056
|
+
sampleRate,
|
|
9057
|
+
firstStart: toSamples(packet.pts),
|
|
9058
|
+
packetSamples: toSamples(packet.duration),
|
|
9059
|
+
packetCount: Number(stream.nb_frames)
|
|
9060
|
+
};
|
|
9061
|
+
const counts = [grid.sampleRate, grid.packetSamples, grid.packetCount];
|
|
9062
|
+
if (!Number.isFinite(grid.firstStart) || !counts.every((n) => Number.isFinite(n) && n > 0)) {
|
|
9063
|
+
throw new Error(`[chunkAudio] could not read the AAC packet grid: ${JSON.stringify(probe)}`);
|
|
9064
|
+
}
|
|
9065
|
+
return grid;
|
|
9066
|
+
}
|
|
9067
|
+
function chunkMuxArgs(input, cut) {
|
|
9068
|
+
if (!cut) return ["-i", input.videoPath, "-map", "0:v:0"];
|
|
9069
|
+
const seek = cut.seekSeconds === null ? [] : ["-ss", cut.seekSeconds.toFixed(6)];
|
|
9070
|
+
const length = cut.durationSeconds === null ? [] : ["-t", cut.durationSeconds.toFixed(6)];
|
|
9071
|
+
const exact = seek.length ? ["-copypriorss", "0"] : [];
|
|
9072
|
+
return [
|
|
9073
|
+
...["-i", input.videoPath, ...seek, ...length, "-i", input.audioPath],
|
|
9074
|
+
...["-map", "0:v:0", "-map", "1:a:0", ...exact]
|
|
9075
|
+
];
|
|
9076
|
+
}
|
|
9077
|
+
async function muxChunkWithAudio(input) {
|
|
9078
|
+
const grid = input.audioPath ? await probeAacPacketGrid(input.audioPath) : null;
|
|
9079
|
+
const cut = grid ? audioCutForChunk(grid, input.chunks, input.chunkIndex, input.fps) : null;
|
|
9080
|
+
const args = [...chunkMuxArgs(input, cut), "-c", "copy"];
|
|
9081
|
+
appendRenderProvenanceArgs2(args, input.outputPath);
|
|
9082
|
+
args.push("-y", input.outputPath);
|
|
9083
|
+
const result = await runFfmpeg6(args, { signal: input.signal, timeout: input.timeoutMs });
|
|
9084
|
+
if (!result.success) {
|
|
9085
|
+
throw new Error(
|
|
9086
|
+
`[chunkAudio] chunk mux failed: ${describeFfmpegFailure3(result, input.timeoutMs)}`
|
|
9087
|
+
);
|
|
9088
|
+
}
|
|
9089
|
+
const slice = input.chunks[input.chunkIndex];
|
|
9090
|
+
const expected = { video: slice.endFrame - slice.startFrame };
|
|
9091
|
+
if (cut) expected.audio = cut.packetCount;
|
|
9092
|
+
const probe = await runFfprobeJson([
|
|
9093
|
+
"-v",
|
|
9094
|
+
"error",
|
|
9095
|
+
"-count_packets",
|
|
9096
|
+
"-show_entries",
|
|
9097
|
+
"stream=codec_type,nb_read_packets",
|
|
9098
|
+
"-of",
|
|
9099
|
+
"json",
|
|
9100
|
+
"--",
|
|
9101
|
+
input.outputPath
|
|
9102
|
+
]);
|
|
9103
|
+
for (const [type, count] of Object.entries(expected)) {
|
|
9104
|
+
const packets = Number(probe.streams?.find((s) => s.codec_type === type)?.nb_read_packets ?? 0);
|
|
9105
|
+
if (packets !== count) {
|
|
9106
|
+
throw new Error(`[chunkAudio] ${type} packets in chunk ${packets}, expected ${count}`);
|
|
9107
|
+
}
|
|
9108
|
+
}
|
|
9109
|
+
}
|
|
9110
|
+
|
|
9111
|
+
// src/services/distributed/renderChunk.ts
|
|
8959
9112
|
import { readWebGlVendorInfoFromCanvas as readWebGlVendorInfoFromCanvas2 } from "@hyperframes/engine";
|
|
8960
9113
|
var FFMPEG_VERSION_MISMATCH = "FFMPEG_VERSION_MISMATCH";
|
|
8961
9114
|
var PLAN_HASH_MISMATCH = "PLAN_HASH_MISMATCH";
|
|
@@ -9505,7 +9658,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
9505
9658
|
const preset = resolvePresetForLockedEncoder(basePreset, encoder.encoder);
|
|
9506
9659
|
const effectiveQuality = encoder.crf ?? preset.quality;
|
|
9507
9660
|
const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
|
|
9508
|
-
const videoOnlyPath = outputChunkPath;
|
|
9661
|
+
const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
|
|
9509
9662
|
if (isPngSequence) {
|
|
9510
9663
|
if (!existsSync17(outputChunkPath)) mkdirSync12(outputChunkPath, { recursive: true });
|
|
9511
9664
|
} else {
|
|
@@ -9516,16 +9669,16 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
9516
9669
|
await runEncodeStage({
|
|
9517
9670
|
job,
|
|
9518
9671
|
log,
|
|
9519
|
-
outputPath:
|
|
9672
|
+
outputPath: videoOnlyPath,
|
|
9520
9673
|
framesDir,
|
|
9521
9674
|
videoOnlyPath,
|
|
9522
9675
|
width: Math.round(plan2.dimensions.width * encoder.deviceScaleFactor),
|
|
9523
9676
|
height: Math.round(plan2.dimensions.height * encoder.deviceScaleFactor),
|
|
9524
9677
|
needsAlpha: plan2.dimensions.format !== "mp4",
|
|
9525
9678
|
captureImageFormat: captureOptions.format ?? "jpeg",
|
|
9526
|
-
//
|
|
9527
|
-
//
|
|
9528
|
-
// AND the mp4 audio mux.
|
|
9679
|
+
// The encoder writes video only; audio joins at assemble time or in the
|
|
9680
|
+
// chunk that carries audio. Suppressing `hasAudio` skips the png-sequence audio
|
|
9681
|
+
// sidecar AND the mp4 audio mux.
|
|
9529
9682
|
hasAudio: false,
|
|
9530
9683
|
isPngSequence,
|
|
9531
9684
|
// `DistributedFormat` has no "gif" member — distributed chunks are
|
|
@@ -9552,6 +9705,18 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
9552
9705
|
lockGopForChunkConcat: !isPngSequence,
|
|
9553
9706
|
gopSize: framesInChunk
|
|
9554
9707
|
});
|
|
9708
|
+
if (encoder.chunksCarryAudio) {
|
|
9709
|
+
await muxChunkWithAudio({
|
|
9710
|
+
videoPath: videoOnlyPath,
|
|
9711
|
+
audioPath: resolvePlanAudioPath(planDir),
|
|
9712
|
+
outputPath: outputChunkPath,
|
|
9713
|
+
chunks,
|
|
9714
|
+
chunkIndex,
|
|
9715
|
+
fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
|
|
9716
|
+
timeoutMs: cfg.ffmpegProcessTimeout
|
|
9717
|
+
});
|
|
9718
|
+
rmSync11(videoOnlyPath, { force: true });
|
|
9719
|
+
}
|
|
9555
9720
|
encodeStageMs = Date.now() - encodeStarted;
|
|
9556
9721
|
} finally {
|
|
9557
9722
|
if (session) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "0.1.0",
|
|
3
3
|
"buildId": "dev",
|
|
4
|
-
"sha256": "
|
|
4
|
+
"sha256": "4a56ffcd5e2b0d5c22cce6c2201205b85cb77ad9d7e32796c2e789fa46231935",
|
|
5
5
|
"artifacts": {
|
|
6
6
|
"iife": "hyperframe.runtime.iife.js",
|
|
7
7
|
"esm": "hyperframe.runtime.mjs"
|