@hyperframes/producer 0.8.203 → 0.8.204

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.
@@ -1259,6 +1259,7 @@ function buildRenderErrorDetails(input) {
1259
1259
 
1260
1260
  // src/services/render/renderEventPublisher.ts
1261
1261
  import { cloneCaptureWarnings } from "@hyperframes/engine";
1262
+ var FLUSH_TIMEOUT_MS = 1e4;
1262
1263
  function snapshotJob(job) {
1263
1264
  return {
1264
1265
  ...job,
@@ -1288,7 +1289,15 @@ var OrderedRenderEventPublisher = class {
1288
1289
  });
1289
1290
  }
1290
1291
  async flush() {
1291
- await this.tail;
1292
+ let timer;
1293
+ const drained = await Promise.race([
1294
+ this.tail.then(() => true),
1295
+ new Promise((resolve10) => {
1296
+ timer = setTimeout(() => resolve10(false), FLUSH_TIMEOUT_MS);
1297
+ })
1298
+ ]);
1299
+ clearTimeout(timer);
1300
+ if (!drained) this.log.warn("Render event sink did not drain; continuing without it");
1292
1301
  }
1293
1302
  };
1294
1303
  function publishRenderFailure(job, failure, onProgress) {
@@ -5120,6 +5129,7 @@ function shouldFallbackToScreenshotAfterCalibrationError(error) {
5120
5129
  // src/services/render/observability.ts
5121
5130
  import { createHash as createHash3 } from "node:crypto";
5122
5131
  import { redactTelemetryString } from "@hyperframes/core";
5132
+ import { CaptureFailure as CaptureFailure2 } from "@hyperframes/engine";
5123
5133
  var MAX_EVENTS = 160;
5124
5134
  var ALLOWED_STRING_DATA_KEYS = /* @__PURE__ */ new Set([
5125
5135
  "browserGpuMode",
@@ -5352,6 +5362,56 @@ function heartbeatTargetMs(index) {
5352
5362
  const overflow = index - HEARTBEAT_RAMP_MS.length + 1;
5353
5363
  return HEARTBEAT_RAMP_END_MS + overflow * HEARTBEAT_REPEAT_MS;
5354
5364
  }
5365
+ var RenderStageStalledError = class extends CaptureFailure2 {
5366
+ code = "RENDER_STAGE_STALLED";
5367
+ owner = "system";
5368
+ retryable = false;
5369
+ constructor(phase, silentMs, progress) {
5370
+ super({
5371
+ kind: "protocol_timeout",
5372
+ message: `[Render] ${phase} stalled: no progress for ${silentMs}ms (stuck at ${progress}).`
5373
+ });
5374
+ this.name = "RenderStageStalledError";
5375
+ }
5376
+ };
5377
+ var STALL_POLL_MS = 5e3;
5378
+ function watchStall(phase, rule) {
5379
+ let last = rule.progress();
5380
+ let budgetMs = rule.firstProgressMs;
5381
+ let lastChangeAt = Date.now();
5382
+ let attempt;
5383
+ let timer;
5384
+ const restartWindow = (ms) => {
5385
+ last = rule.progress();
5386
+ budgetMs = ms;
5387
+ lastChangeAt = Date.now();
5388
+ };
5389
+ const tripped = new Promise((_, reject) => {
5390
+ timer = setInterval(
5391
+ () => {
5392
+ const current = rule.progress();
5393
+ if (current !== last) return restartWindow(rule.noProgressMs);
5394
+ if (Date.now() - lastChangeAt < budgetMs) return;
5395
+ const error = new RenderStageStalledError(phase, budgetMs, current);
5396
+ if (attempt && !attempt.signal.aborted) {
5397
+ attempt.abort(error);
5398
+ return restartWindow(rule.noProgressMs);
5399
+ }
5400
+ clearInterval(timer);
5401
+ reject(error);
5402
+ },
5403
+ Math.min(STALL_POLL_MS, rule.noProgressMs, rule.firstProgressMs)
5404
+ );
5405
+ });
5406
+ const openAttempt = (parent) => {
5407
+ attempt = new AbortController();
5408
+ restartWindow(rule.firstProgressMs);
5409
+ return parent ? AbortSignal.any([parent, attempt.signal]) : attempt.signal;
5410
+ };
5411
+ const stalledBy = () => attempt?.signal.aborted ? attempt.signal.reason : void 0;
5412
+ return { tripped, openAttempt, stalledBy, stop: () => clearInterval(timer) };
5413
+ }
5414
+ var openUnwatchedAttempt = (parent) => parent ?? new AbortController().signal;
5355
5415
  async function observeRenderStage(recorder, phase, data, fn, options = {}) {
5356
5416
  const heartbeatMessage = options.heartbeatMessage ?? "stage still running";
5357
5417
  const startedAt = recorder.stageStart(phase, data);
@@ -5373,15 +5433,19 @@ async function observeRenderStage(recorder, phase, data, fn, options = {}) {
5373
5433
  heartbeatTimer.unref?.();
5374
5434
  };
5375
5435
  scheduleNextHeartbeat();
5436
+ const stall = options.stall ? watchStall(phase, options.stall) : void 0;
5376
5437
  const clearHeartbeats = () => {
5377
5438
  clearTimeout(heartbeatTimer);
5439
+ stall?.stop();
5378
5440
  };
5379
5441
  try {
5380
- const result = await fn();
5442
+ const run = fn(stall?.openAttempt ?? openUnwatchedAttempt);
5443
+ const result = await (stall ? Promise.race([run, stall.tripped]) : run);
5381
5444
  clearHeartbeats();
5382
5445
  recorder.stageEnd(phase, startedAt, data);
5383
5446
  return result;
5384
- } catch (error) {
5447
+ } catch (caught) {
5448
+ const error = stall?.stalledBy() ?? caught;
5385
5449
  clearHeartbeats();
5386
5450
  recorder.stageError(phase, startedAt, error, data);
5387
5451
  throw error;
@@ -7536,9 +7600,10 @@ async function discoverMediaFromBrowser(page) {
7536
7600
  const tagName = isImage ? "image" : htmlEl.tagName.toLowerCase() === "video" ? "video" : "audio";
7537
7601
  const id = htmlEl.getAttribute("data-hf-render-id") || htmlEl.id || (isImage ? autoImageIds.get(htmlEl) : void 0);
7538
7602
  if (!id) return;
7539
- const ownSrc = htmlEl.getAttribute("src");
7540
- const blankSrc = ownSrc !== null && ownSrc.trim() === "" && !htmlEl.querySelector("source[src]");
7541
- const src = blankSrc ? "" : htmlEl.currentSrc || htmlEl.src || ownSrc || "";
7603
+ const resolvedSrc = htmlEl.currentSrc || htmlEl.src || htmlEl.getAttribute("src") || "";
7604
+ const withoutQueryAndHash = (url) => url.replace(/[?#][\s\S]*$/, "");
7605
+ const isPageItself = withoutQueryAndHash(resolvedSrc) === withoutQueryAndHash(location.href);
7606
+ const src = isPageItself ? "" : resolvedSrc;
7542
7607
  const start = parseFloat(htmlEl.getAttribute("data-start") || "0");
7543
7608
  const endRaw = htmlEl.getAttribute("data-end");
7544
7609
  const durationRaw = htmlEl.getAttribute("data-duration");
@@ -9808,6 +9873,7 @@ async function runCaptureStage(input) {
9808
9873
  interleaveFrames: input.interleaveFrames,
9809
9874
  dedupPerfs,
9810
9875
  pageErrorLines: workerPageErrors,
9876
+ openAttempt: input.openAttempt,
9811
9877
  onProgress: (progress) => {
9812
9878
  if (progress.latestWorkerPhase) {
9813
9879
  if (progress.capturedFrames === 0) reportWorkerStartup(job, progress, onProgress);
@@ -9879,6 +9945,11 @@ async function runSequentialDiskCapture(input, captureOptions, captureCfg, check
9879
9945
  let transientRetriesUsed = 0;
9880
9946
  let resumeFrom = 0;
9881
9947
  while (true) {
9948
+ const attempt = input.openAttempt?.();
9949
+ const assertAttemptActive = () => {
9950
+ assertNotAborted();
9951
+ attempt?.throwIfAborted();
9952
+ };
9882
9953
  const videoInjector = createRenderVideoFrameInjector();
9883
9954
  const session = probeSession ?? await createCaptureSession5(
9884
9955
  fileServer.url,
@@ -9894,10 +9965,10 @@ async function runSequentialDiskCapture(input, captureOptions, captureCfg, check
9894
9965
  probeSession = null;
9895
9966
  }
9896
9967
  await ensureSessionReady(session);
9897
- assertNotAborted();
9968
+ assertAttemptActive();
9898
9969
  lastBrowserConsole = session.browserConsoleBuffer;
9899
9970
  await captureSessionFrames(session, {
9900
- input,
9971
+ input: { ...input, assertNotAborted: assertAttemptActive },
9901
9972
  rangeStart,
9902
9973
  rangeEnd,
9903
9974
  resumeFrom,
@@ -11757,7 +11828,17 @@ function captureAttemptMadeProgress(attemptTargetFrameCount, remainingFrameCount
11757
11828
  function resetCaptureAttemptProgress(job) {
11758
11829
  job.framesRendered = 0;
11759
11830
  }
11831
+ var FIRST_FRAME_STALL_MS = 3e5;
11832
+ function frameStallRule(job) {
11833
+ const noProgressMs = resolveCaptureStallTimeoutMs();
11834
+ return {
11835
+ progress: () => job.framesRendered ?? 0,
11836
+ noProgressMs,
11837
+ firstProgressMs: Math.max(FIRST_FRAME_STALL_MS, noProgressMs)
11838
+ };
11839
+ }
11760
11840
  function isRecoverableParallelCaptureError(error) {
11841
+ if (error instanceof RenderStageStalledError) return true;
11761
11842
  const message = normalizeErrorMessage(error);
11762
11843
  if (!message.includes("[Parallel] Capture failed")) return false;
11763
11844
  const kind = classifyCaptureFailure3(error).kind;
@@ -11820,8 +11901,10 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
11820
11901
  )
11821
11902
  ];
11822
11903
  options.dedupPerfs.length = 0;
11904
+ let attemptSignal = options.abortSignal;
11823
11905
  try {
11824
11906
  for (const tasks of batches) {
11907
+ attemptSignal = options.openAttempt?.(options.abortSignal) ?? options.abortSignal;
11825
11908
  const capturedBeforeBatch = countCapturedFrames(
11826
11909
  options.totalFrames,
11827
11910
  options.framesDir,
@@ -11834,7 +11917,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
11834
11917
  tasks,
11835
11918
  options.captureOptions,
11836
11919
  options.createBeforeCaptureHook,
11837
- options.abortSignal,
11920
+ attemptSignal,
11838
11921
  options.onProgress ? (progress) => {
11839
11922
  options.onProgress?.({
11840
11923
  ...progress,
@@ -11882,7 +11965,8 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
11882
11965
  currentWorkers = nextWorkers;
11883
11966
  missingRanges = remaining;
11884
11967
  attempt++;
11885
- } catch (error) {
11968
+ } catch (caught) {
11969
+ const error = attemptSignal?.aborted && !options.abortSignal?.aborted ? attemptSignal.reason : caught;
11886
11970
  const failure = classifyCaptureFailure3(error, { signal: options.abortSignal });
11887
11971
  if (failure.kind === "cancelled") {
11888
11972
  throw error;
@@ -13551,37 +13635,44 @@ async function executeRenderPipeline(input) {
13551
13635
  observability,
13552
13636
  "capture_hdr_layered",
13553
13637
  captureStageObservationData({ hasHdrContent }),
13554
- () => runCaptureHdrStage({
13555
- job,
13556
- cfg,
13557
- plan: layeredPlan,
13558
- log,
13559
- projectDir,
13560
- compiledDir,
13561
- framesDir,
13562
- videoOnlyPath,
13563
- width,
13564
- height,
13565
- totalFrames,
13566
- composition,
13567
- hasHdrContent,
13568
- effectiveHdr,
13569
- nativeHdrVideoIds,
13570
- nativeHdrImageIds,
13571
- videoTransfers,
13572
- imageTransfers,
13573
- hdrImageSrcPaths,
13574
- preset,
13575
- effectiveQuality,
13576
- effectiveBitrate,
13577
- fileServer: activeFileServer,
13578
- buildCaptureOptions,
13579
- createRenderVideoFrameInjector,
13580
- hdrDiagnostics,
13581
- abortSignal: executionSignal,
13582
- assertNotAborted,
13583
- onProgress
13584
- })
13638
+ (openAttempt) => {
13639
+ const attempt = openAttempt(executionSignal);
13640
+ return runCaptureHdrStage({
13641
+ job,
13642
+ cfg,
13643
+ plan: layeredPlan,
13644
+ log,
13645
+ projectDir,
13646
+ compiledDir,
13647
+ framesDir,
13648
+ videoOnlyPath,
13649
+ width,
13650
+ height,
13651
+ totalFrames,
13652
+ composition,
13653
+ hasHdrContent,
13654
+ effectiveHdr,
13655
+ nativeHdrVideoIds,
13656
+ nativeHdrImageIds,
13657
+ videoTransfers,
13658
+ imageTransfers,
13659
+ hdrImageSrcPaths,
13660
+ preset,
13661
+ effectiveQuality,
13662
+ effectiveBitrate,
13663
+ fileServer: activeFileServer,
13664
+ buildCaptureOptions,
13665
+ createRenderVideoFrameInjector,
13666
+ hdrDiagnostics,
13667
+ abortSignal: attempt,
13668
+ assertNotAborted: () => {
13669
+ assertNotAborted();
13670
+ attempt.throwIfAborted();
13671
+ },
13672
+ onProgress
13673
+ });
13674
+ },
13675
+ { stall: frameStallRule(job) }
13585
13676
  );
13586
13677
  lastBrowserConsole = hdrRes.lastBrowserConsole;
13587
13678
  layeredCaptureWarnings.push(...hdrRes.warnings);
@@ -13946,7 +14037,7 @@ async function executeRenderPipeline(input) {
13946
14037
  observability,
13947
14038
  "capture_disk",
13948
14039
  captureStageObservationData({ needsAlpha: diskPlan.needsAlpha }),
13949
- () => runCaptureStage({
14040
+ (openAttempt) => runCaptureStage({
13950
14041
  fileServer: activeFileServer,
13951
14042
  workDir,
13952
14043
  framesDir,
@@ -13964,8 +14055,10 @@ async function executeRenderPipeline(input) {
13964
14055
  assertNotAborted,
13965
14056
  onProgress,
13966
14057
  onFrameLanded: (frame) => overlap?.onFrameLanded(frame),
13967
- interleaveFrames: overlap !== null
13968
- })
14058
+ interleaveFrames: overlap !== null,
14059
+ openAttempt
14060
+ }),
14061
+ { stall: frameStallRule(job) }
13969
14062
  );
13970
14063
  let captureRes;
13971
14064
  try {
@@ -14849,6 +14942,7 @@ function renderConfigFromRequest(request, runtime = {}) {
14849
14942
 
14850
14943
  // src/server.ts
14851
14944
  var DEFAULT_SERVER_FPS = { num: 30, den: 1 };
14945
+ var SSE_KEEPALIVE_MS = 3e4;
14852
14946
  var SAFE_RENDER_ERROR_CODES = /* @__PURE__ */ new Set([
14853
14947
  "ASSET_MEDIA_TYPE_MISMATCH",
14854
14948
  "NOT_MEDIA_PAYLOAD",
@@ -14856,7 +14950,8 @@ var SAFE_RENDER_ERROR_CODES = /* @__PURE__ */ new Set([
14856
14950
  "VIDEO_SOURCE_UNRENDERABLE",
14857
14951
  "VIDEO_EXTRACTION_FAILED",
14858
14952
  "ENCODER_INTERRUPTED",
14859
- "RENDER_TOO_SLOW"
14953
+ "RENDER_TOO_SLOW",
14954
+ "RENDER_STAGE_STALLED"
14860
14955
  ]);
14861
14956
  function extractSafeRenderErrorCode(error) {
14862
14957
  if (typeof error !== "object" || error === null || !("code" in error)) return void 0;
@@ -15370,15 +15465,21 @@ function createRenderHandlers(options = {}) {
15370
15465
  })
15371
15466
  });
15372
15467
  }
15468
+ const reportProgress = createSseProgressReporter(stream, requestId);
15469
+ const keepalive = setInterval(() => {
15470
+ Promise.resolve(reportProgress(job, job.currentStage)).catch(() => {
15471
+ });
15472
+ }, SSE_KEEPALIVE_MS);
15373
15473
  const release = await renderSemaphore.acquire();
15374
15474
  try {
15375
15475
  await executeRenderJob(
15376
15476
  job,
15377
15477
  input.projectDir,
15378
15478
  absoluteOutputPath,
15379
- createSseProgressReporter(stream, requestId),
15479
+ reportProgress,
15380
15480
  abortController.signal
15381
- );
15481
+ ).finally(release);
15482
+ clearInterval(keepalive);
15382
15483
  const fileSize = outputFileSize(absoluteOutputPath);
15383
15484
  const outputToken = store.register(absoluteOutputPath);
15384
15485
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
@@ -15398,6 +15499,7 @@ function createRenderHandlers(options = {}) {
15398
15499
  })
15399
15500
  });
15400
15501
  } catch (error) {
15502
+ clearInterval(keepalive);
15401
15503
  await writeRenderStreamFailure({
15402
15504
  error,
15403
15505
  job,
@@ -15407,7 +15509,6 @@ function createRenderHandlers(options = {}) {
15407
15509
  log
15408
15510
  });
15409
15511
  } finally {
15410
- release();
15411
15512
  c.req.raw.signal.removeEventListener("abort", onRequestAbort);
15412
15513
  cleanupTempDir(cleanupProjectDir, log);
15413
15514
  }
@@ -1,3 +1,4 @@
1
+ import { CaptureFailure } from "@hyperframes/engine";
1
2
  import type { ProducerLogger } from "../../logger.js";
2
3
  export type RenderObservationStatus = "start" | "end" | "error" | "checkpoint";
3
4
  export type RenderObservationValue = string | number | boolean | null;
@@ -323,5 +324,26 @@ export interface ObserveRenderStageOptions {
323
324
  * Defaults to "stage still running".
324
325
  */
325
326
  heartbeatMessage?: string;
327
+ stall?: StageStallRule;
326
328
  }
327
- export declare function observeRenderStage<T>(recorder: RenderObservabilityRecorder, phase: string, data: RenderObservationData | undefined, fn: () => Promise<T>, options?: ObserveRenderStageOptions): Promise<T>;
329
+ /** Watches a stage's `progress()`; any change, in either direction, is progress. */
330
+ export interface StageStallRule {
331
+ progress: () => number;
332
+ /** Allowed silence once `progress()` has changed in the current attempt. */
333
+ noProgressMs: number;
334
+ /** Allowed silence before the current attempt's first change. */
335
+ firstProgressMs: number;
336
+ }
337
+ /**
338
+ * Classified like the per-call protocol timeout it replaces, so the capture retry ladder retries it.
339
+ * Not retryable on the wire: the producer already spent its retries on it.
340
+ */
341
+ export declare class RenderStageStalledError extends CaptureFailure {
342
+ readonly code = "RENDER_STAGE_STALLED";
343
+ readonly owner: "system";
344
+ readonly retryable: false;
345
+ constructor(phase: string, silentMs: number, progress: number);
346
+ }
347
+ /** Opens a capture attempt: a fresh no-progress window, and a signal the rule aborts when that window runs out. */
348
+ export type OpenStallAttempt = (parent?: AbortSignal) => AbortSignal;
349
+ export declare function observeRenderStage<T>(recorder: RenderObservabilityRecorder, phase: string, data: RenderObservationData | undefined, fn: (openAttempt: OpenStallAttempt) => Promise<T>, options?: ObserveRenderStageOptions): Promise<T>;
@@ -35,6 +35,7 @@ import type { FileServerHandle } from "../../fileServer.js";
35
35
  import type { ProducerLogger } from "../../../logger.js";
36
36
  import { type CaptureAttemptSummary, type ProgressCallback, type RenderConfig, type RenderJob } from "../../renderOrchestrator.js";
37
37
  import type { SdrDiskCapturePlan } from "../capturePlan.js";
38
+ import type { OpenStallAttempt } from "../observability.js";
38
39
  export interface CaptureStageInput {
39
40
  fileServer: FileServerHandle;
40
41
  workDir: string;
@@ -85,6 +86,8 @@ export interface CaptureStageInput {
85
86
  };
86
87
  onFrameLanded?: (frame: LandedFrame) => void;
87
88
  interleaveFrames?: boolean;
89
+ /** Each capture attempt opens one, so a stalled attempt is retried by the ladders below. */
90
+ openAttempt?: OpenStallAttempt;
88
91
  }
89
92
  export interface CaptureStageResult {
90
93
  /** Final worker count after any adaptive retry. */
@@ -2,7 +2,7 @@ import { type CanvasResolution, type Fps, type FpsInput, type HfVfxCapture } fro
2
2
  import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, 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
- import { type RenderCaptureObservability, type RenderObservabilitySummary } from "./render/observability.js";
5
+ import { type RenderCaptureObservability, type RenderObservabilitySummary, type OpenStallAttempt, type StageStallRule } from "./render/observability.js";
6
6
  import { type HdrPerfSummary } from "./render/hdrPerf.js";
7
7
  export declare function sampleDirectoryBytes(dir: string): number;
8
8
  export type RenderStatus = "queued" | "preprocessing" | "rendering" | "encoding" | "assembling" | "complete" | "failed" | "cancelled";
@@ -559,6 +559,10 @@ export declare function captureAttemptMadeProgress(attemptTargetFrameCount: numb
559
559
  export declare function resetCaptureAttemptProgress(job: {
560
560
  framesRendered?: number;
561
561
  }): void;
562
+ /** The no-progress rule for capture stages that have no watchdog of their own: disk, HDR, chunk. */
563
+ export declare function frameStallRule(job: {
564
+ framesRendered?: number;
565
+ }): StageStallRule;
562
566
  export declare function isRecoverableParallelCaptureError(error: unknown): boolean;
563
567
  /**
564
568
  * Turn a cryptic memory-exhaustion failure (V8 `Set maximum size exceeded`,
@@ -599,6 +603,7 @@ export declare function executeDiskCaptureWithAdaptiveRetry(options: {
599
603
  dedupPerfs: CapturePerfSummary[];
600
604
  /** Mutated in place: the workers' page-error console lines, for the render's error count. */
601
605
  pageErrorLines?: string[];
606
+ openAttempt?: OpenStallAttempt;
602
607
  }): Promise<CaptureAttemptSummary[]>;
603
608
  export type RenderConfigInput = Omit<RenderConfig, "fps"> & {
604
609
  fps: FpsInput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.203",
3
+ "version": "0.8.204",
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/core": "0.8.203",
39
- "@hyperframes/engine": "0.8.203",
40
- "@hyperframes/lint": "0.8.203",
41
- "@hyperframes/parsers": "0.8.203",
42
- "@hyperframes/studio-server": "0.8.203"
38
+ "@hyperframes/engine": "0.8.204",
39
+ "@hyperframes/lint": "0.8.204",
40
+ "@hyperframes/core": "0.8.204",
41
+ "@hyperframes/parsers": "0.8.204",
42
+ "@hyperframes/studio-server": "0.8.204"
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.203"
51
+ "@hyperframes/aws-lambda": "0.8.204"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"