@hyperframes/producer 0.8.189 → 0.8.190-hdr.1

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/index.js CHANGED
@@ -1188,6 +1188,14 @@ function materializeExtractedFramesForCompiledDir(extracted, compiledDir, option
1188
1188
  }
1189
1189
  }
1190
1190
 
1191
+ // src/services/render/frameCacheBudget.ts
1192
+ function frameCacheOptions(cfg, workers) {
1193
+ return {
1194
+ frameDataUriCacheLimit: cfg.frameDataUriCacheLimit,
1195
+ frameDataUriCacheBytesLimitMb: Math.floor(cfg.frameDataUriCacheBytesLimitMb / (workers || 1))
1196
+ };
1197
+ }
1198
+
1191
1199
  // src/services/render/cleanup.ts
1192
1200
  import { freemem } from "node:os";
1193
1201
 
@@ -12515,10 +12523,7 @@ async function executeRenderPipeline(input) {
12515
12523
  });
12516
12524
  }
12517
12525
  });
12518
- const createRenderVideoFrameInjector = () => createVideoFrameInjector(frameLookup, {
12519
- frameDataUriCacheLimit: cfg.frameDataUriCacheLimit,
12520
- frameDataUriCacheBytesLimitMb: cfg.frameDataUriCacheBytesLimitMb
12521
- });
12526
+ const createRenderVideoFrameInjector = () => createVideoFrameInjector(frameLookup, frameCacheOptions(cfg, workerCount));
12522
12527
  let captureCalibration;
12523
12528
  const htmlInCanvasDetected = compiled.renderModeHints.reasons.some(
12524
12529
  (r) => r.code === "htmlInCanvas"
@@ -14172,12 +14177,13 @@ var RenderChunkValidationError = class extends Error {
14172
14177
  this.code = code;
14173
14178
  }
14174
14179
  };
14175
- function createChunkVideoFrameInjectorFactory(frameLookup) {
14176
- if (!(frameLookup instanceof Promise)) return () => createVideoFrameInjector2(frameLookup);
14180
+ function createChunkVideoFrameInjectorFactory(frameLookup, options) {
14181
+ if (!(frameLookup instanceof Promise))
14182
+ return () => createVideoFrameInjector2(frameLookup, options);
14177
14183
  return () => {
14178
14184
  let hook;
14179
14185
  return async (page, time, heldVideoTime) => {
14180
- hook ??= createVideoFrameInjector2(await frameLookup);
14186
+ hook ??= createVideoFrameInjector2(await frameLookup, options);
14181
14187
  await hook?.(page, time, heldVideoTime);
14182
14188
  };
14183
14189
  };
@@ -18719,7 +18725,7 @@ function cfrEncodeArgs(inputArgs, encoder, fpsArg) {
18719
18725
  "-r",
18720
18726
  fpsArg
18721
18727
  ];
18722
- appendSoftwareEncoderThreadsArg(args);
18728
+ appendSoftwareEncoderThreadsArg(args, "libx264");
18723
18729
  return args;
18724
18730
  }
18725
18731
  async function reencodeCfr(ctx, chunkPaths, encoder) {
@@ -18975,6 +18981,22 @@ async function createVerifiedDistributedCaptureSession(serverUrl, framesDir, cap
18975
18981
  function isCaptureMode(value) {
18976
18982
  return value === "beginframe" || value === "screenshot" || value === "drawelement";
18977
18983
  }
18984
+ var MixedCaptureModesError = class extends Error {
18985
+ constructor(modes) {
18986
+ super(`[renderChunk] capture workers reported inconsistent modes: ${modes.join(",")}`);
18987
+ this.modes = modes;
18988
+ this.name = "MixedCaptureModesError";
18989
+ }
18990
+ };
18991
+ function observedChunkCaptureMode(perfs) {
18992
+ const modes = [...new Set(perfs.map((perf) => perf.captureMode))];
18993
+ if (modes.length > 1) throw new MixedCaptureModesError(modes);
18994
+ const [mode] = modes;
18995
+ if (!mode || !isCaptureMode(mode)) {
18996
+ throw new Error(`[renderChunk] capture workers reported an invalid mode: ${mode ?? "<none>"}`);
18997
+ }
18998
+ return mode;
18999
+ }
18978
19000
  function shouldRetryChunkCaptureWithScreenshot(error) {
18979
19001
  const failure = classifyCaptureFailure4(error);
18980
19002
  if (failure.kind === "cancelled" || failure.kind === "memory_exhaustion") return false;
@@ -19272,7 +19294,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19272
19294
  ) : null;
19273
19295
  videoFrameLookup?.catch(() => {
19274
19296
  });
19275
- const createChunkVideoFrameInjector = createChunkVideoFrameInjectorFactory(videoFrameLookup);
19297
+ const createChunkVideoFrameInjector = createChunkVideoFrameInjectorFactory(
19298
+ videoFrameLookup,
19299
+ frameCacheOptions(cfg, chunkWorkerCount)
19300
+ );
19276
19301
  const captureStarted = Date.now();
19277
19302
  captureMode = await runCaptureWithScreenshotFallback({
19278
19303
  forceScreenshot: forceScreenshotForChunk,
@@ -19326,17 +19351,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19326
19351
  },
19327
19352
  frameRange: range
19328
19353
  });
19329
- const observedModes = new Set(capturePerfs.map((perf) => perf.captureMode));
19330
- if (observedModes.size !== 1 || ![...observedModes].every(isCaptureMode)) {
19331
- throw new Error(
19332
- `[renderChunk] capture workers reported invalid or inconsistent modes: ${[...observedModes].join(",") || "<none>"}`
19333
- );
19334
- }
19335
- const [observedMode] = observedModes;
19336
- if (!observedMode || !isCaptureMode(observedMode)) {
19337
- throw new Error("[renderChunk] capture completed without an observed mode");
19338
- }
19339
- return observedMode;
19354
+ return observedChunkCaptureMode(capturePerfs);
19340
19355
  },
19341
19356
  resetForScreenshotRetry: () => {
19342
19357
  rmSync17(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
@@ -1208,6 +1208,14 @@ function materializeExtractedFramesForCompiledDir(extracted, compiledDir, option
1208
1208
  }
1209
1209
  }
1210
1210
 
1211
+ // src/services/render/frameCacheBudget.ts
1212
+ function frameCacheOptions(cfg, workers) {
1213
+ return {
1214
+ frameDataUriCacheLimit: cfg.frameDataUriCacheLimit,
1215
+ frameDataUriCacheBytesLimitMb: Math.floor(cfg.frameDataUriCacheBytesLimitMb / (workers || 1))
1216
+ };
1217
+ }
1218
+
1211
1219
  // src/services/render/cleanup.ts
1212
1220
  import { freemem } from "node:os";
1213
1221
 
@@ -12498,10 +12506,7 @@ async function executeRenderPipeline(input) {
12498
12506
  });
12499
12507
  }
12500
12508
  });
12501
- const createRenderVideoFrameInjector = () => createVideoFrameInjector(frameLookup, {
12502
- frameDataUriCacheLimit: cfg.frameDataUriCacheLimit,
12503
- frameDataUriCacheBytesLimitMb: cfg.frameDataUriCacheBytesLimitMb
12504
- });
12509
+ const createRenderVideoFrameInjector = () => createVideoFrameInjector(frameLookup, frameCacheOptions(cfg, workerCount));
12505
12510
  let captureCalibration;
12506
12511
  const htmlInCanvasDetected = compiled.renderModeHints.reasons.some(
12507
12512
  (r) => r.code === "htmlInCanvas"
@@ -1,4 +1,4 @@
1
- import { type BeforeCaptureHook, BROWSER_GPU_NOT_SOFTWARE, type CaptureOptions, type EngineConfig, type ExtractedFrames, type FrameLookupTable, type ShownBox } from "@hyperframes/engine";
1
+ import { type BeforeCaptureHook, BROWSER_GPU_NOT_SOFTWARE, type CaptureOptions, createVideoFrameInjector, type EngineConfig, type ExtractedFrames, type FrameLookupTable, type ShownBox } from "@hyperframes/engine";
2
2
  import type { LockedRenderConfig } from "../render/stages/freezePlan.js";
3
3
  import type { PlanV2RemoteSources } from "./planV2.js";
4
4
  import { type DistributedFormat, INVALID_VIDEO_METADATA, type PlanVideosJson } from "./shared.js";
@@ -17,7 +17,7 @@ export declare class RenderChunkValidationError extends Error {
17
17
  constructor(code: RenderChunkValidationCode, message: string);
18
18
  }
19
19
  /** One injector per browser session: a hook reused on a fresh page can skip its first injection. */
20
- export declare function createChunkVideoFrameInjectorFactory(frameLookup: FrameLookupTable | Promise<FrameLookupTable> | null): () => BeforeCaptureHook | null;
20
+ export declare function createChunkVideoFrameInjectorFactory(frameLookup: FrameLookupTable | Promise<FrameLookupTable> | null, options?: Parameters<typeof createVideoFrameInjector>[1]): () => BeforeCaptureHook | null;
21
21
  /**
22
22
  * Rebuilds `ExtractedFrames[]` from `<planDir>/video-frames/<videoId>/`. `framePaths` keys are 0-based
23
23
  * frame indexes (what `getFrameAtTime` reads); any other key drops every video's first-paint frame.
@@ -33,7 +33,7 @@
33
33
  * Every determinism toggle above is opt-in — only this primitive enables them.
34
34
  * In-process renders (`executeRenderJob`) leave them off.
35
35
  */
36
- import { assertSwiftShader, type CaptureOptions, type CaptureMode, type CaptureSession, closeCaptureSession, createCaptureSession, type EngineConfig, initializeSession, probeBeginFrameLiveness, readWebGlVendorInfoFromCanvas } from "@hyperframes/engine";
36
+ import { assertSwiftShader, type CaptureOptions, type CaptureMode, type CapturePerfSummary, type CaptureSession, closeCaptureSession, createCaptureSession, type EngineConfig, initializeSession, probeBeginFrameLiveness, readWebGlVendorInfoFromCanvas } from "@hyperframes/engine";
37
37
  import { type ChunkSliceJson, type LockedRenderConfig } from "../render/stages/freezePlan.js";
38
38
  import { type PlanVideosJson } from "./shared.js";
39
39
  export { CHUNK_FRAME_RANGE_INVALID, CHUNK_INDEX_OUT_OF_RANGE, createChunkVideoFrameInjectorFactory, extractDeferredVideoFramesForChunk, FFMPEG_VERSION_MISMATCH, INVALID_VIDEO_METADATA, MISSING_PLAN_ARTIFACT, MISSING_RUNTIME_ENV_SNAPSHOT, PLAN_HASH_MISMATCH, rebuildExtractedFramesFromPlanDir, RenderChunkValidationError, } from "./chunkFrames.js";
@@ -136,6 +136,12 @@ export declare const distributedCaptureSessionDependencies: DistributedCaptureSe
136
136
  * assertion, including fresh screenshot browsers created after a fallback.
137
137
  */
138
138
  export declare function createVerifiedDistributedCaptureSession(serverUrl: string, framesDir: string, captureOptions: CaptureOptions, cfg: EngineConfig, dependencies?: DistributedCaptureSessionDependencies): Promise<CaptureSession>;
139
+ /** Workers of one chunk launched in different modes: one worker's BeginFrame check failed and it fell back alone. */
140
+ export declare class MixedCaptureModesError extends Error {
141
+ readonly modes: readonly string[];
142
+ constructor(modes: readonly string[]);
143
+ }
144
+ export declare function observedChunkCaptureMode(perfs: readonly Pick<CapturePerfSummary, "captureMode">[]): CaptureMode;
139
145
  /**
140
146
  * Only BeginFrame-specific failures are safe to retry in screenshot mode.
141
147
  * Cancellation, memory exhaustion, and unrelated authoring/IO failures must
@@ -0,0 +1,3 @@
1
+ import type { EngineConfig } from "@hyperframes/engine";
2
+ /** Cache options for one of `workers` injectors that share the configured budget on the one Node heap. */
3
+ export declare function frameCacheOptions(cfg: Pick<EngineConfig, "frameDataUriCacheLimit" | "frameDataUriCacheBytesLimitMb">, workers: number | undefined): Pick<EngineConfig, "frameDataUriCacheLimit" | "frameDataUriCacheBytesLimitMb">;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.189",
3
+ "version": "0.8.190-hdr.1",
4
4
  "description": "HTML-to-video rendering engine using Chrome's BeginFrame API",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,11 +35,11 @@
35
35
  "postcss": "^8.4.0",
36
36
  "puppeteer": "^25.2.1",
37
37
  "puppeteer-core": "^25.2.1",
38
- "@hyperframes/engine": "0.8.189",
39
- "@hyperframes/parsers": "0.8.189",
40
- "@hyperframes/lint": "0.8.189",
41
- "@hyperframes/studio-server": "0.8.189",
42
- "@hyperframes/core": "0.8.189"
38
+ "@hyperframes/core": "0.8.190-hdr.1",
39
+ "@hyperframes/parsers": "0.8.190-hdr.1",
40
+ "@hyperframes/lint": "0.8.190-hdr.1",
41
+ "@hyperframes/studio-server": "0.8.190-hdr.1",
42
+ "@hyperframes/engine": "0.8.190-hdr.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^25.0.10",
@@ -48,7 +48,7 @@
48
48
  "tsx": "^4.21.0",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^4.1.11",
51
- "@hyperframes/aws-lambda": "0.8.189"
51
+ "@hyperframes/aws-lambda": "0.8.190-hdr.1"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"