@hyperframes/producer 0.8.220 → 0.8.222

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.
@@ -1103,6 +1103,21 @@ function reportFrameProgress(job, stage, progress, onProgress, done, total) {
1103
1103
  total
1104
1104
  });
1105
1105
  }
1106
+ var lastExtractReportAt = /* @__PURE__ */ new WeakMap();
1107
+ function reportExtractProgress(job, done, total, onProgress) {
1108
+ if (total <= 0) return;
1109
+ const frames = Math.min(done, total);
1110
+ reportThrottled(
1111
+ lastExtractReportAt,
1112
+ job,
1113
+ "Extracting video frames",
1114
+ 10 + 10 * frames / total,
1115
+ onProgress,
1116
+ frames === total,
1117
+ { code: "extract_video", done: frames, total },
1118
+ "preprocessing"
1119
+ );
1120
+ }
1106
1121
  var lastEncodeReportAt = /* @__PURE__ */ new WeakMap();
1107
1122
  function reportEncodeProgress(job, done, total, onProgress, from) {
1108
1123
  if (total <= 0) return;
@@ -1134,6 +1149,14 @@ function reportAssembleProgress(job, done, total, onProgress) {
1134
1149
  );
1135
1150
  }
1136
1151
  var workerPhasesByJob = /* @__PURE__ */ new WeakMap();
1152
+ function forgetWorkerPhases(job) {
1153
+ workerPhasesByJob.delete(job);
1154
+ }
1155
+ function describeWorkerPhases(job) {
1156
+ const phases = workerPhasesByJob.get(job);
1157
+ if (!phases?.size) return void 0;
1158
+ return `Last phase per worker: ${[...phases].map(([id, phase]) => `worker ${id} ${phase}`).join(", ")}.`;
1159
+ }
1137
1160
  function reportWorkerStartup(job, progress, onProgress) {
1138
1161
  const phase = progress.latestWorkerPhase;
1139
1162
  if (!phase) return;
@@ -2215,6 +2238,11 @@ function aggregateChromeMemory(perfs) {
2215
2238
  samples: sampled.reduce((sum, p) => sum + (p.chromeMemorySamples ?? 0), 0)
2216
2239
  };
2217
2240
  }
2241
+ function frameWeightedAvgMs(perfs, avgOf) {
2242
+ const frames = perfs.reduce((sum, p) => sum + p.frames, 0);
2243
+ if (frames === 0) return void 0;
2244
+ return Math.round(perfs.reduce((sum, p) => sum + avgOf(p) * p.frames, 0) / frames);
2245
+ }
2218
2246
  function aggregateDedup(perfs) {
2219
2247
  if (perfs.length === 0) return void 0;
2220
2248
  const armed = perfs.some((p) => p.staticDedupArmed);
@@ -2313,6 +2341,10 @@ function buildRenderPerfSummary(input) {
2313
2341
  if (withSamples.length === 0) return void 0;
2314
2342
  return withSamples.reduce((a, b) => b.frames > a.frames ? b : a).p50TotalMs;
2315
2343
  })(),
2344
+ captureSeekAvgMs: frameWeightedAvgMs(input.dedupPerfs, (p) => p.avgSeekMs),
2345
+ captureBeforeCaptureAvgMs: frameWeightedAvgMs(input.dedupPerfs, (p) => p.avgBeforeCaptureMs),
2346
+ captureScreenshotAvgMs: frameWeightedAvgMs(input.dedupPerfs, (p) => p.avgScreenshotMs),
2347
+ encoderWaitAvgMs: input.perfStages.encoderDrainWaitMs !== void 0 && input.totalFrames > 0 ? Math.round(input.perfStages.encoderDrainWaitMs / input.totalFrames) : void 0,
2316
2348
  peakRssMb: Math.round(input.peakRssBytes / (1024 * 1024)),
2317
2349
  peakHeapUsedMb: Math.round(input.peakHeapUsedBytes / (1024 * 1024)),
2318
2350
  staticDedup: aggregateDedup(input.dedupPerfs),
@@ -4338,6 +4370,7 @@ async function runCaptureStreamingStage(input) {
4338
4370
  return {
4339
4371
  success: true,
4340
4372
  encodeMs: encodeResult.durationMs,
4373
+ encoderDrainWaitMs: encodeResult.drainWaitMs,
4341
4374
  probeSession,
4342
4375
  lastBrowserConsole,
4343
4376
  workerCount,
@@ -4437,7 +4470,7 @@ async function captureSegment(ctx, segment) {
4437
4470
  // finished; absent only in unit tests, whose fake encoder writes none.
4438
4471
  bytes: existsSync6(segmentPath) ? statSync3(segmentPath).size : 0
4439
4472
  });
4440
- return encodeResult.durationMs;
4473
+ return encodeResult;
4441
4474
  } finally {
4442
4475
  if (!encoderClosed) {
4443
4476
  await encoder.close().catch(() => {
@@ -4579,7 +4612,11 @@ async function retryAfterTargetLoss(run, worker, err, segment, segmentPath) {
4579
4612
  );
4580
4613
  run.deps.removeFile(segmentPath);
4581
4614
  await recycleWorkerSession(run, worker, "retry");
4582
- run.totals.encodeMs += await captureSegment(worker.ctx, segment);
4615
+ addSegmentEncode(run.totals, await captureSegment(worker.ctx, segment));
4616
+ }
4617
+ function addSegmentEncode(totals, result) {
4618
+ totals.encodeMs += result.durationMs;
4619
+ totals.encoderDrainWaitMs += result.drainWaitMs ?? 0;
4583
4620
  }
4584
4621
  async function runOneSegment(run, worker, segment) {
4585
4622
  const segmentPath = segmentOutputPath(run.segmentDir, segment.index);
@@ -4591,7 +4628,7 @@ async function runOneSegment(run, worker, segment) {
4591
4628
  segmentIndex: segment.index
4592
4629
  });
4593
4630
  try {
4594
- run.totals.encodeMs += await captureSegment(worker.ctx, segment);
4631
+ addSegmentEncode(run.totals, await captureSegment(worker.ctx, segment));
4595
4632
  } catch (err) {
4596
4633
  if (err instanceof SegmentEncoderSpawnError) return onSegmentSpawnFailure(run, err, segment);
4597
4634
  await retryAfterTargetLoss(run, worker, err, segment, segmentPath);
@@ -4634,7 +4671,7 @@ async function runCaptureSegmentedStage(input) {
4634
4671
  const run = {
4635
4672
  input,
4636
4673
  deps,
4637
- totals: { encodeMs: 0, segmentRetries: 0, browserRecycles: 0 },
4674
+ totals: { encodeMs: 0, encoderDrainWaitMs: 0, segmentRetries: 0, browserRecycles: 0 },
4638
4675
  segments,
4639
4676
  pending,
4640
4677
  segmentDir,
@@ -4687,6 +4724,7 @@ async function runCaptureSegmentedStage(input) {
4687
4724
  return {
4688
4725
  success: true,
4689
4726
  encodeMs: run.totals.encodeMs,
4727
+ encoderDrainWaitMs: run.totals.encoderDrainWaitMs,
4690
4728
  probeSession: null,
4691
4729
  lastBrowserConsole,
4692
4730
  workerCount: run.workerCount,
@@ -5498,16 +5536,17 @@ var RenderStageStalledError = class extends CaptureFailure2 {
5498
5536
  code = "RENDER_STAGE_STALLED";
5499
5537
  owner = "system";
5500
5538
  retryable = false;
5501
- constructor(phase, silentMs, progress) {
5539
+ constructor(phase, silentMs, progress, detail) {
5502
5540
  super({
5503
5541
  kind: "protocol_timeout",
5504
- message: `[Render] ${phase} stalled: no progress for ${silentMs}ms (stuck at ${progress}).`
5542
+ message: `[Render] ${phase} stalled: no progress for ${silentMs}ms (stuck at ${progress}).${detail ? ` ${detail}` : ""}`
5505
5543
  });
5506
5544
  this.name = "RenderStageStalledError";
5507
5545
  }
5508
5546
  };
5509
5547
  var STALL_POLL_MS = 5e3;
5510
5548
  function watchStall(phase, rule) {
5549
+ const detail = rule.detail ?? (() => void 0);
5511
5550
  let last = rule.progress();
5512
5551
  let budgetMs = rule.firstProgressMs;
5513
5552
  let lastChangeAt = Date.now();
@@ -5529,7 +5568,7 @@ function watchStall(phase, rule) {
5529
5568
  }
5530
5569
  if (current !== last) return restartWindow(rule.noProgressMs);
5531
5570
  if (Date.now() - lastChangeAt < budgetMs) return;
5532
- const error = new RenderStageStalledError(phase, budgetMs, current);
5571
+ const error = new RenderStageStalledError(phase, budgetMs, current, detail());
5533
5572
  if (attempt && !attempt.signal.aborted) {
5534
5573
  attempt.abort(error);
5535
5574
  return restartWindow(rule.noProgressMs);
@@ -5543,6 +5582,7 @@ function watchStall(phase, rule) {
5543
5582
  const openAttempt = (parent) => {
5544
5583
  attempt = new AbortController();
5545
5584
  inTail = false;
5585
+ rule.attemptOpened?.();
5546
5586
  restartWindow(rule.firstProgressMs);
5547
5587
  return parent ? AbortSignal.any([parent, attempt.signal]) : attempt.signal;
5548
5588
  };
@@ -7849,7 +7889,7 @@ function rebaseDirectEntryAssetPaths(html, projectDir, htmlPath) {
7849
7889
  const { document: document2 } = parseHTML5(html);
7850
7890
  const assetExists = (path) => existsSync10(resolve7(projectDir, path));
7851
7891
  rewriteAssetPaths(
7852
- document2.querySelectorAll("[src], [href]"),
7892
+ document2.querySelectorAll("[src], [href], [srcset]"),
7853
7893
  entryPath,
7854
7894
  (el, attr) => el.getAttribute(attr),
7855
7895
  (el, attr, value) => el.setAttribute(attr, value),
@@ -9531,6 +9571,8 @@ async function runExtractVideosStage(input) {
9531
9571
  safeVideoExtractionSourceLogMetadata(v.src)
9532
9572
  );
9533
9573
  }
9574
+ let framesPlanned = 0;
9575
+ let framesDone = 0;
9534
9576
  extractionResult = await extractAllVideoFrames(
9535
9577
  composition.videos,
9536
9578
  projectDir,
@@ -9547,7 +9589,12 @@ async function runExtractVideosStage(input) {
9547
9589
  collectProbeFailures: extractionPolicy.failureMode === "enforce",
9548
9590
  deferRangeExtraction,
9549
9591
  contentKeyedDirs: [join18(compiledDir, REMOTE_MEDIA_SUBDIR)],
9550
- urlByAbsentLocalPath
9592
+ urlByAbsentLocalPath,
9593
+ onProgress: ({ planned = 0, done = 0 }) => {
9594
+ framesPlanned += planned;
9595
+ framesDone += done;
9596
+ reportExtractProgress(job, framesDone, framesPlanned, input.onProgress);
9597
+ }
9551
9598
  },
9552
9599
  abortSignal,
9553
9600
  cfg,
@@ -12355,7 +12402,9 @@ function frameStallRule(job, totalFrames) {
12355
12402
  noProgressMs,
12356
12403
  firstProgressMs: Math.max(FIRST_FRAME_STALL_MS, noProgressMs),
12357
12404
  complete: () => (job.framesRendered ?? 0) >= totalFrames,
12358
- tailMs: Math.max(TAIL_STALL_MS, noProgressMs)
12405
+ tailMs: Math.max(TAIL_STALL_MS, noProgressMs),
12406
+ detail: () => describeWorkerPhases(job),
12407
+ attemptOpened: () => forgetWorkerPhases(job)
12359
12408
  };
12360
12409
  }
12361
12410
  function isRecoverableParallelCaptureError(error) {
@@ -12881,6 +12930,11 @@ function resolveDeSingleMinFrames(env) {
12881
12930
  function shouldPreferSingleWorkerDrawElement(args) {
12882
12931
  return args.workerCount > 1 && args.useDrawElement && !args.deCompileGate && !args.forceScreenshot && outputUsesH264Pipeline(args.outputFormat) && args.minFrames > 0 && args.totalFrames >= args.minFrames && args.singleWorkerStreamingOk && !args.layeredOrEffectRoute && !args.supersampling && !args.probeDeGated && !args.experimentalParallelDeOptIn;
12883
12932
  }
12933
+ function initialDeClampReason(args) {
12934
+ if (args.useDrawElement) return void 0;
12935
+ if (args.deCompileGate) return "compile_gate";
12936
+ return explainDrawElementDisabled(args.config);
12937
+ }
12884
12938
  function probeNeedsScreenshotFrames(session) {
12885
12939
  return (session?.deRiskFrames?.size ?? 0) > 0;
12886
12940
  }
@@ -13270,11 +13324,15 @@ async function executeRenderPipeline(input) {
13270
13324
  perfStages.compileOnlyMs = compileResult.compileOnlyMs;
13271
13325
  let captureForceScreenshot = compileResult.forceScreenshot;
13272
13326
  const deCompileGate = compileResult.deCompileGate;
13273
- let deClampReason = cfg.useDrawElement ? void 0 : explainDrawElementDisabled({
13274
- platform: process.platform,
13275
- browserGpuMode: cfg.browserGpuMode,
13276
- workerEncode: cfg.enableDrawElementWorkerEncode,
13277
- chromeCeiling: chromeMajorCeiling()
13327
+ let deClampReason = initialDeClampReason({
13328
+ useDrawElement: cfg.useDrawElement,
13329
+ deCompileGate,
13330
+ config: {
13331
+ platform: process.platform,
13332
+ browserGpuMode: cfg.browserGpuMode,
13333
+ workerEncode: cfg.enableDrawElementWorkerEncode,
13334
+ chromeCeiling: chromeMajorCeiling()
13335
+ }
13278
13336
  });
13279
13337
  let deWorkerInversion;
13280
13338
  let deParallelStreamForced = false;
@@ -13400,7 +13458,8 @@ async function executeRenderPipeline(input) {
13400
13458
  abortSignal: executionSignal,
13401
13459
  assertNotAborted,
13402
13460
  // Local staging can use links; distributed plan() alone requires real copies.
13403
- materializeSymlinks: false
13461
+ materializeSymlinks: false,
13462
+ onProgress
13404
13463
  })
13405
13464
  );
13406
13465
  const {
@@ -14443,6 +14502,7 @@ async function executeRenderPipeline(input) {
14443
14502
  perfStages.captureFrameMs = Date.now() - captureFrameStart;
14444
14503
  perfStages.captureSetupMs = Math.max(0, perfStages.captureMs - perfStages.captureFrameMs);
14445
14504
  perfStages.encodeMs = segmentedRes.encodeMs;
14505
+ perfStages.encoderDrainWaitMs = segmentedRes.encoderDrainWaitMs ?? 0;
14446
14506
  log.info(
14447
14507
  `[Render] Segmented capture complete: ${segmentedRes.segments} segment(s) concatenated.`,
14448
14508
  {
@@ -14620,6 +14680,7 @@ async function executeRenderPipeline(input) {
14620
14680
  perfStages.captureFrameMs = captureFrameMs;
14621
14681
  perfStages.captureSetupMs = Math.max(0, perfStages.captureMs - captureFrameMs);
14622
14682
  perfStages.encodeMs = streamingRes.encodeMs;
14683
+ perfStages.encoderDrainWaitMs = streamingRes.encoderDrainWaitMs ?? 0;
14623
14684
  } else {
14624
14685
  if (capturePlan.kind === "sdr_streaming") {
14625
14686
  capturePlan = replanAfterFailure(capturePlan, { kind: "streaming_unavailable" });
@@ -0,0 +1,19 @@
1
+ import { type DistributedRenderConfig } from "./plan.js";
2
+ export interface RenderSpanResult {
3
+ startFrame: number;
4
+ endFrame: number;
5
+ framesEncoded: number;
6
+ }
7
+ export declare class RenderSpanUnsupportedError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ /** The frames `[startFrame, endFrame)` of a `totalFrames` timeline that `[startSeconds, endSeconds)` covers. */
11
+ export declare function spanFrameRange(startSeconds: number, endSeconds: number | undefined, fps: number, totalFrames: number): {
12
+ startFrame: number;
13
+ endFrame: number;
14
+ };
15
+ /** Renders `[startSeconds, endSeconds)` as a standalone mp4 from 0, with that span's audio, by chunk sub-ranges. */
16
+ export declare function renderSpan(projectDir: string, config: DistributedRenderConfig, span: {
17
+ startSeconds: number;
18
+ endSeconds?: number;
19
+ }, outputPath: string): Promise<RenderSpanResult>;
@@ -337,6 +337,8 @@ export interface StageStallRule {
337
337
  complete?: () => boolean;
338
338
  /** Allowed silence once `complete()` holds; defaults to `noProgressMs`. */
339
339
  tailMs?: number;
340
+ detail?: () => string | undefined;
341
+ attemptOpened?: () => void;
340
342
  }
341
343
  /**
342
344
  * Classified like the per-call protocol timeout it replaces, so the capture retry ladder retries it.
@@ -346,7 +348,7 @@ export declare class RenderStageStalledError extends CaptureFailure {
346
348
  readonly code = "RENDER_STAGE_STALLED";
347
349
  readonly owner: "system";
348
350
  readonly retryable: false;
349
- constructor(phase: string, silentMs: number, progress: number);
351
+ constructor(phase: string, silentMs: number, progress: number, detail?: string);
350
352
  }
351
353
  /** Opens a capture attempt: a fresh no-progress window, and a signal the rule aborts when that window runs out. */
352
354
  export type OpenStallAttempt = (parent?: AbortSignal) => AbortSignal;
@@ -106,10 +106,14 @@ export declare function applyRenderModeHints(alreadyForced: boolean, compiled: C
106
106
  export declare function updateJobStatus(job: RenderJob, status: RenderStatus, stage: string, progress: number, onProgress?: ProgressCallback, stageProgress?: RenderStageProgress): void;
107
107
  /** Capture-loop progress: the first frame, the last frame, and at most four reports a second between. */
108
108
  export declare function reportFrameProgress(job: RenderJob, stage: string, progress: number, onProgress: ProgressCallback | undefined, done: number, total: number): void;
109
+ /** Frames ffmpeg has written for the source videos, 10% to 20%. */
110
+ export declare function reportExtractProgress(job: RenderJob, done: number, total: number, onProgress: ProgressCallback | undefined): void;
109
111
  /** Frames ffmpeg has encoded, from where capture left the bar up to 90%; same cadence as capture. */
110
112
  export declare function reportEncodeProgress(job: RenderJob, done: number, total: number, onProgress: ProgressCallback | undefined, from: number): void;
111
113
  /** Seconds of the final file written, 90% to 99%: only a complete file reaches 100. */
112
114
  export declare function reportAssembleProgress(job: RenderJob, done: number, total: number, onProgress: ProgressCallback | undefined): void;
115
+ export declare function forgetWorkerPhases(job: object): void;
116
+ export declare function describeWorkerPhases(job: object): string | undefined;
113
117
  /** Browser warm-up before the first frame, from the parallel workers' phase events. */
114
118
  export declare function reportWorkerStartup(job: RenderJob, progress: ParallelProgress, onProgress: ProgressCallback | undefined): void;
115
119
  /**
@@ -75,6 +75,7 @@ export interface CaptureSegmentedStageInput {
75
75
  export type CaptureSegmentedStageResult = {
76
76
  success: true;
77
77
  encodeMs: number;
78
+ encoderDrainWaitMs?: number;
78
79
  probeSession: null;
79
80
  lastBrowserConsole: string[];
80
81
  workerCount: number;
@@ -112,6 +112,7 @@ export type CaptureStreamingStageResult = {
112
112
  success: true;
113
113
  /** Wall-clock ms for the encode phase (overlapped with capture; from the encoder's own report). */
114
114
  encodeMs: number;
115
+ encoderDrainWaitMs?: number;
115
116
  probeSession: CaptureSession | null;
116
117
  lastBrowserConsole: string[];
117
118
  workerCount: number;
@@ -30,6 +30,7 @@
30
30
  import { type CaptureVideoMetadataHint, type EngineConfig, type ExtractionResult, type FrameLookupTable, type HdrTransfer, type VideoExtractionFailureKind, type VideoColorSpace, classifyVideoExtractionError, extractAllVideoFrames } from "@hyperframes/engine";
31
31
  import { type RenderJob } from "../../renderOrchestrator.js";
32
32
  import { type CompositionMetadata } from "../shared.js";
33
+ import type { ProgressCallback } from "../../renderOrchestrator.js";
33
34
  import type { ProducerLogger } from "../../../logger.js";
34
35
  import { type ExtractionFailureMetadataV1 } from "../extractionFailureMetadata.js";
35
36
  export interface ExtractVideosStageInput {
@@ -52,6 +53,7 @@ export interface ExtractVideosStageInput {
52
53
  materializeSymlinks?: boolean;
53
54
  deferRangeExtraction?: boolean;
54
55
  urlByAbsentLocalPath?: ReadonlyMap<string, string>;
56
+ onProgress?: ProgressCallback;
55
57
  }
56
58
  export interface ExtractVideosStageResult {
57
59
  /** Result of `extractAllVideoFrames`, or `null` if the composition has no videos. */
@@ -1,5 +1,5 @@
1
1
  import { type CanvasResolution, type Fps, type FpsInput, type HfVfxCapture } from "@hyperframes/core";
2
- import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ProresProfile, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, type CaptureFailureKind, type MotionBlurOptions } from "@hyperframes/engine";
2
+ import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ProresProfile, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, explainDrawElementDisabled, type CaptureFailureKind, type MotionBlurOptions } from "@hyperframes/engine";
3
3
  import { type ProducerLogger } from "../logger.js";
4
4
  import { type RenderOutputFormat } from "./render/renderFormat.js";
5
5
  import { type RenderCaptureObservability, type RenderObservabilitySummary, type OpenStallAttempt, type StageStallRule } from "./render/observability.js";
@@ -200,6 +200,11 @@ export interface RenderPerfSummary {
200
200
  * captured the most frames when parallel workers report separately.
201
201
  */
202
202
  captureP50Ms?: number;
203
+ /** Per-frame capture phases, frame-weighted across sessions; encoder wait is FFmpeg back-pressure. */
204
+ captureSeekAvgMs?: number;
205
+ captureBeforeCaptureAvgMs?: number;
206
+ captureScreenshotAvgMs?: number;
207
+ encoderWaitAvgMs?: number;
203
208
  /** Worst sub-composition timeline wait outcome across sessions. */
204
209
  subTimelineWait?: SubTimelineWaitOutcome;
205
210
  capturePeakMs?: number;
@@ -875,6 +880,12 @@ export declare function shouldPreferSingleWorkerDrawElement(args: {
875
880
  */
876
881
  experimentalParallelDeOptIn: boolean;
877
882
  }): boolean;
883
+ /** Why drawElement is off before capture; the compile stage's content gates are not config refusals. */
884
+ export declare function initialDeClampReason(args: {
885
+ useDrawElement: boolean;
886
+ deCompileGate: string | undefined;
887
+ config: Parameters<typeof explainDrawElementDisabled>[0];
888
+ }): string | undefined;
878
889
  /**
879
890
  * Plan the self-verify retry for an inverted render: the inversion bet on
880
891
  * drawElement and lost, so the re-render returns to the pre-inversion parallel
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.220",
3
+ "version": "0.8.222",
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.11.0",
37
37
  "puppeteer-core": "^25.11.0",
38
- "@hyperframes/core": "0.8.220",
39
- "@hyperframes/engine": "0.8.220",
40
- "@hyperframes/lint": "0.8.220",
41
- "@hyperframes/studio-server": "0.8.220",
42
- "@hyperframes/parsers": "0.8.220"
38
+ "@hyperframes/engine": "0.8.222",
39
+ "@hyperframes/studio-server": "0.8.222",
40
+ "@hyperframes/core": "0.8.222",
41
+ "@hyperframes/lint": "0.8.222",
42
+ "@hyperframes/parsers": "0.8.222"
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.220"
51
+ "@hyperframes/aws-lambda": "0.8.222"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"