hyperframes 0.8.192 → 0.8.194

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.
Files changed (189) hide show
  1. package/dist/{add-TZU2UW7A.js → add-47UAIWY4.js} +12 -12
  2. package/dist/{animatedGifPrep-NLAXC3VV.js → animatedGifPrep-TFSQZWK6.js} +8 -7
  3. package/dist/api.js +18 -17
  4. package/dist/{asset-JAJXA6LB.js → asset-AU7PZHXA.js} +2 -2
  5. package/dist/{assetCataloger-4WTX3J4I.js → assetCataloger-HC5N6WPT.js} +8 -7
  6. package/dist/{audio-XLWC7JKS.js → audio-7AWMZWBM.js} +14 -13
  7. package/dist/{auth-5K6X3NPJ.js → auth-GXH3QNDJ.js} +1 -1
  8. package/dist/{autoUpdate-RNV7SKGB.js → autoUpdate-GVGP5O2I.js} +3 -3
  9. package/dist/{backgroundChecks-QXLVZVGX.js → backgroundChecks-IUJM2Q35.js} +3 -3
  10. package/dist/backgroundChecksWorker.js +3 -3
  11. package/dist/{batchRender-THKSPDZR.js → batchRender-3XS2Y2Y4.js} +4 -4
  12. package/dist/{beats-K7CGCFVL.js → beats-U64B4S7Z.js} +9 -9
  13. package/dist/{benchmark-PHRDIXNL.js → benchmark-2YUPAI76.js} +9 -9
  14. package/dist/{browser-GN6R5ZSK.js → browser-DBFH7KXM.js} +5 -5
  15. package/dist/{bundleWithLocalizedFonts-C325UNR4.js → bundleWithLocalizedFonts-XWL7KSQJ.js} +2 -2
  16. package/dist/{capture-BZ7APOGQ.js → capture-E4VW75NM.js} +2 -2
  17. package/dist/{capture-6UBQFHZQ.js → capture-YWH7BPBI.js} +13 -12
  18. package/dist/{captureCompositionFrame-VORSCTWC.js → captureCompositionFrame-IG6S2OHG.js} +13 -12
  19. package/dist/{catalog-PHU2RUZ3.js → catalog-LZIZLZ34.js} +12 -12
  20. package/dist/{catch-up-HCNRM46J.js → catch-up-ZVNPIACY.js} +4 -4
  21. package/dist/{check-TJ5ZLB4I.js → check-EKEOD4UM.js} +38 -37
  22. package/dist/{checkBrowser-DWP7ZXJ7.js → checkBrowser-MYH6HPHH.js} +33 -32
  23. package/dist/{chunk-XF77MK3J.js → chunk-2AJU7PZ6.js} +1 -1
  24. package/dist/chunk-2D5WP2NI.js +3901 -0
  25. package/dist/{chunk-FBVUAH7N.js → chunk-2OYYNKJ4.js} +1 -1
  26. package/dist/{chunk-R2U2G4OS.js → chunk-37IHQVNQ.js} +1 -1
  27. package/dist/{chunk-IMSI7IFW.js → chunk-3OSBSUN3.js} +18 -18
  28. package/dist/{chunk-RHYOWDI6.js → chunk-3S3CXF4W.js} +2 -2
  29. package/dist/{chunk-YMQQXPD5.js → chunk-452UK7E7.js} +5 -12
  30. package/dist/{chunk-L2YGSAOL.js → chunk-4FVNEXSV.js} +3 -3
  31. package/dist/{chunk-7UZC4N62.js → chunk-4GMDL4N5.js} +1 -1
  32. package/dist/{chunk-YWRQHRDY.js → chunk-4PIPQPCW.js} +7 -7
  33. package/dist/{chunk-J2ASTCU6.js → chunk-4VSV56F2.js} +2 -2
  34. package/dist/{chunk-NXMYHJAL.js → chunk-4VYPICIA.js} +29 -1
  35. package/dist/{chunk-QX4TB4NH.js → chunk-52YJKWV3.js} +379 -127
  36. package/dist/{chunk-GANST5K3.js → chunk-54PZ2EQZ.js} +1 -1
  37. package/dist/{chunk-5IPKQHOL.js → chunk-B3GG3HJB.js} +1 -1
  38. package/dist/{chunk-2MCXIY4B.js → chunk-B7RJV74O.js} +28 -11
  39. package/dist/{chunk-VOM2HLUI.js → chunk-BK5YCT54.js} +3 -3
  40. package/dist/{chunk-RWGASWT7.js → chunk-BL4U6U52.js} +1 -0
  41. package/dist/{chunk-T6O5OLN2.js → chunk-BYADARIC.js} +2 -2
  42. package/dist/{chunk-VNPADTDD.js → chunk-CEUBYYVJ.js} +2 -2
  43. package/dist/{chunk-JCDYDF54.js → chunk-CEZH4AQT.js} +12 -2
  44. package/dist/{chunk-BY6OQ6XP.js → chunk-CZNSLFYD.js} +3 -1
  45. package/dist/{chunk-SBBQFPCJ.js → chunk-DT3JESJ6.js} +1 -1
  46. package/dist/{chunk-3CXIX6XS.js → chunk-DVQDBWQG.js} +4 -4
  47. package/dist/{chunk-K2AKVYNR.js → chunk-EB3XXHNO.js} +2 -2
  48. package/dist/{chunk-3FV5BVWS.js → chunk-EY7GKVPS.js} +2 -2
  49. package/dist/{chunk-W24SZ5FL.js → chunk-F2ASNL2K.js} +6 -9
  50. package/dist/{chunk-ODBYZIOH.js → chunk-F3B7CE3Q.js} +14 -14
  51. package/dist/{chunk-E3P3LJG6.js → chunk-FLREUEHW.js} +28 -11
  52. package/dist/{chunk-6XVKMBUA.js → chunk-FUA22HO4.js} +1 -1
  53. package/dist/{chunk-AEXVVABM.js → chunk-GAFEU6AB.js} +13 -10
  54. package/dist/{chunk-DIKAPMMF.js → chunk-GQVTTWZF.js} +144 -39
  55. package/dist/{chunk-7LLRMYP6.js → chunk-HCLBM2LQ.js} +2 -2
  56. package/dist/{chunk-AMZJFCOX.js → chunk-HG5ECUOR.js} +5 -5
  57. package/dist/{chunk-KZOZN4PI.js → chunk-HPGQPRHY.js} +3 -3
  58. package/dist/{chunk-BPKLUHFT.js → chunk-HQD7ODQB.js} +5 -5
  59. package/dist/{chunk-SK7TR7BL.js → chunk-JU4T4VAA.js} +4 -4
  60. package/dist/{chunk-MGBUWPXX.js → chunk-JVTWX5G3.js} +33 -8
  61. package/dist/{chunk-2J3NA3OB.js → chunk-JXTPNUSO.js} +83 -51
  62. package/dist/{chunk-2VXY3PEF.js → chunk-K2VXPQKC.js} +107 -94
  63. package/dist/chunk-K4MJX7SR.js +17 -0
  64. package/dist/{chunk-XX2PA4L3.js → chunk-KDEV5RIE.js} +7 -3
  65. package/dist/{chunk-MVIJTXN5.js → chunk-LMIDZIW2.js} +12 -12
  66. package/dist/{chunk-6WNLQI63.js → chunk-LOGKDQ3G.js} +3 -3
  67. package/dist/{chunk-IW5G323T.js → chunk-LTGTN2TH.js} +8 -9
  68. package/dist/{chunk-MEE4NTPZ.js → chunk-LZ4WPR3B.js} +2 -2
  69. package/dist/{chunk-32NB4VMH.js → chunk-M2VXARYK.js} +3 -2
  70. package/dist/{chunk-7RSY7SZN.js → chunk-MCFPMUMT.js} +2 -2
  71. package/dist/{chunk-BEOK6F26.js → chunk-MGSNFWGR.js} +2 -2
  72. package/dist/{chunk-ZEMDV6W2.js → chunk-MO6RTNYD.js} +1 -1
  73. package/dist/{chunk-7JJMT6LN.js → chunk-N33FO44R.js} +1 -1
  74. package/dist/{chunk-A4OI5ZNX.js → chunk-N3M3IU6S.js} +1 -1
  75. package/dist/{chunk-CXRZBWSH.js → chunk-NVVIFW3C.js} +10 -10
  76. package/dist/{chunk-E5V6WEMK.js → chunk-O2ILONGK.js} +10 -10
  77. package/dist/{chunk-4HCJOFMB.js → chunk-OJNNKHAZ.js} +94 -22
  78. package/dist/{chunk-QWLES6YV.js → chunk-PEHST4UY.js} +3 -3
  79. package/dist/{chunk-BV6YE455.js → chunk-POFJH2IS.js} +1 -1
  80. package/dist/{chunk-AR46ND2Q.js → chunk-PXK3ICU6.js} +1 -1
  81. package/dist/{chunk-LOKCBZYF.js → chunk-Q4HKC3O7.js} +3 -3
  82. package/dist/{chunk-J2BSUF6X.js → chunk-QJQTWTM7.js} +8 -3
  83. package/dist/{chunk-QFPBRZJD.js → chunk-ROEW726S.js} +1 -1
  84. package/dist/{chunk-OQL4AJ4X.js → chunk-RUPGFW5B.js} +6 -6
  85. package/dist/{chunk-5TRFLZ5Z.js → chunk-RZWJJCI7.js} +2 -2
  86. package/dist/{chunk-2HP5GIQ3.js → chunk-SNECH6QA.js} +1 -1
  87. package/dist/{chunk-REUL2KH2.js → chunk-ST35C4K6.js} +1 -1
  88. package/dist/{chunk-4E75LHAL.js → chunk-ST4SHO3S.js} +1 -1
  89. package/dist/{chunk-ULTKB5FC.js → chunk-TDYKVJTU.js} +548 -429
  90. package/dist/{chunk-WOKVXK4J.js → chunk-VHIBBDEI.js} +1 -1
  91. package/dist/{chunk-EKGGSAWR.js → chunk-VPON6DF2.js} +5 -5
  92. package/dist/{chunk-VRAXIQ6I.js → chunk-XYGULBFV.js} +2 -2
  93. package/dist/{chunk-PFRG5P32.js → chunk-Y3BT27Y7.js} +1 -1
  94. package/dist/{clean-2RNCTDBT.js → clean-NS2SDRK7.js} +21 -20
  95. package/dist/cli.js +54 -54
  96. package/dist/{cloud-NFIKESNZ.js → cloud-K4XQPWTY.js} +4 -4
  97. package/dist/{cloudrun-7224BCX3.js → cloudrun-BKOKXTXV.js} +6 -6
  98. package/dist/{compare-HL44MXVX.js → compare-ZAV773OL.js} +31 -30
  99. package/dist/{compiler-WF5QTXV7.js → compiler-CWHFCE3H.js} +5 -5
  100. package/dist/{component-ZBZXSJBR.js → component-OXA2ZWX3.js} +3 -3
  101. package/dist/{compositions-76P7LDDX.js → compositions-NKRVWCPE.js} +12 -11
  102. package/dist/{contactSheet-43ISAESM.js → contactSheet-5APX35L3.js} +1 -1
  103. package/dist/{delete-4YZBYOHJ.js → delete-HZ2LBCLC.js} +2 -2
  104. package/dist/{deploy-UGUUGYLF.js → deploy-FNDTZFF7.js} +1 -1
  105. package/dist/{deterministicFonts-RO2TCMLZ.js → deterministicFonts-RADD3BSX.js} +2 -2
  106. package/dist/{dist-5KKCRFPT.js → dist-2YTN2UGY.js} +3 -3
  107. package/dist/{dist-QQ26RUDV.js → dist-7OCZHNLY.js} +1 -1
  108. package/dist/{doctor-GGVUK4NB.js → doctor-6QWJGO5P.js} +14 -13
  109. package/dist/{events-V2VU4J3B.js → events-HTHOBIUN.js} +3 -3
  110. package/dist/{events-OXPTHVDB.js → events-MBKHVGXX.js} +2 -2
  111. package/dist/{feedback-HFZ5SCUK.js → feedback-X5QWTLEX.js} +8 -8
  112. package/dist/{ffmpeg-3VHY7GO3.js → ffmpeg-7GESJCCT.js} +9 -8
  113. package/dist/{figma-7SEZTLBJ.js → figma-SXOHFVJI.js} +3 -3
  114. package/dist/fontLocalizeCli.js +11 -10
  115. package/dist/{get-Y2S2PXCM.js → get-T2HI5FCK.js} +2 -2
  116. package/dist/{gpuPolicy-UHPOWRV5.js → gpuPolicy-5FABKW5G.js} +8 -7
  117. package/dist/{grade-compare-4VTXSQM5.js → grade-compare-JATGHA6Q.js} +37 -35
  118. package/dist/{gsapParser-UP3PNPC2.js → gsapParser-IEUSLYDJ.js} +11 -11
  119. package/dist/{gsapParserAcorn-OOTY2MVN.js → gsapParserAcorn-LZJKCFQI.js} +1 -1
  120. package/dist/{help-HXNOACHI.js → help-G6CIKCGS.js} +1 -1
  121. package/dist/{history-XDJUI4LC.js → history-CSJUHYTD.js} +9 -8
  122. package/dist/hyperframe.manifest.json +1 -1
  123. package/dist/hyperframe.runtime.iife.js +71 -65
  124. package/dist/hyperframes-player.global.js +3 -3
  125. package/dist/hyperframes-slideshow.global.js +1 -1
  126. package/dist/{info-KYRI3EZV.js → info-MTTUMW2C.js} +8 -8
  127. package/dist/{init-IL7EWMT5.js → init-LJYNI5EK.js} +30 -29
  128. package/dist/{inspect-TBNH23UC.js → inspect-HGDM2VJE.js} +31 -30
  129. package/dist/{installer-O2YMFSI4.js → installer-3XHURUDG.js} +5 -5
  130. package/dist/{keyframes-4GF62KAJ.js → keyframes-MSU7N53X.js} +59 -33
  131. package/dist/{lambda-JFL6M4XZ.js → lambda-2I2TIUSD.js} +8 -8
  132. package/dist/{layout-7MAEFR65.js → layout-KWOXZMN7.js} +31 -30
  133. package/dist/{lint-4AYHKYAM.js → lint-N53TLHFG.js} +7 -7
  134. package/dist/{lintProject-52SLJPRC.js → lintProject-EOUZA4EG.js} +1 -1
  135. package/dist/{list-3DP3D3MW.js → list-SHYPQC7U.js} +2 -2
  136. package/dist/{login-T54WQYRQ.js → login-TEB6PA3Y.js} +4 -4
  137. package/dist/{manager-MZIJY73J.js → manager-COSJVRAE.js} +2 -2
  138. package/dist/{manager-QROK2IH3.js → manager-PLRSZH5G.js} +10 -9
  139. package/dist/{media-treatment-4CXF7MSG.js → media-treatment-XTUKMIGE.js} +15 -14
  140. package/dist/{models-IS3I6JKU.js → models-4WKAPP2L.js} +14 -13
  141. package/dist/{motionShot-DVYJZOTQ.js → motionShot-PTKB4ILH.js} +17 -16
  142. package/dist/{normalize-audio-4527JIK4.js → normalize-audio-3NG326I2.js} +6 -6
  143. package/dist/{open-5JE46SAX.js → open-6S2LMF7R.js} +12 -12
  144. package/dist/{parakeetRunner-7JIJGJJ7.js → parakeetRunner-OEI35DVO.js} +15 -14
  145. package/dist/{pipeline-YEN3WFD2.js → pipeline-543FUKH4.js} +10 -9
  146. package/dist/{play-WFX67I7M.js → play-ETEGHP3B.js} +21 -21
  147. package/dist/{preflight-D377HVUZ.js → preflight-Y5IYUF2T.js} +11 -10
  148. package/dist/{present-XTSEKAC7.js → present-ZRSLMJ6J.js} +17 -17
  149. package/dist/{preview-5XH7EK6O.js → preview-CEJ3SVTY.js} +100 -65
  150. package/dist/{producer-TFFYF4ZM.js → producer-JFVFIV26.js} +1 -1
  151. package/dist/{projectConfig-6YUJHMCL.js → projectConfig-7EK3BS72.js} +7 -7
  152. package/dist/{publication-JK33Y55E.js → publication-Y54GYFMV.js} +3 -3
  153. package/dist/{publish-JHDGXWXU.js → publish-S3UJTPCV.js} +10 -10
  154. package/dist/{remove-background-P44MYAPJ.js → remove-background-YTATNQSI.js} +11 -10
  155. package/dist/{render-RBINWWP5.js → render-IIPXMSBO.js} +35 -34
  156. package/dist/{render-RJ3I4E3A.js → render-RN3W6YL4.js} +17 -16
  157. package/dist/{render-HJ34EGMN.js → render-WNIG4B3J.js} +6 -6
  158. package/dist/{render-batch-3D6XQYUC.js → render-batch-OYS3UQDB.js} +6 -6
  159. package/dist/renderSetupWorker.js +42 -4
  160. package/dist/{resolver-HCLTFZUW.js → resolver-OVCXVEDX.js} +5 -5
  161. package/dist/{sherpa-IPOUJM6Q.js → sherpa-NCSFD7S3.js} +14 -13
  162. package/dist/skills/hyperframes/references/format.md +1 -0
  163. package/dist/skills/media-use/scripts/lib/duck.mjs +18 -2
  164. package/dist/skills/media-use/scripts/lib/duck.test.mjs +79 -0
  165. package/dist/{skills-P67QEERC.js → skills-IUV3K3X7.js} +5 -5
  166. package/dist/{skillsUpdateCheck-IFMLRVIF.js → skillsUpdateCheck-NACBXMWW.js} +3 -3
  167. package/dist/{snapshot-4YM4NNWJ.js → snapshot-7S5USJ2I.js} +52 -46
  168. package/dist/{src-DCD3YMXX.js → src-CAR6PHI4.js} +10 -9
  169. package/dist/{src-SSV66L3F.js → src-HITT6NWG.js} +19 -6
  170. package/dist/{staticProjectServer-C7PPGLEQ.js → staticProjectServer-QR6VZBPT.js} +18 -18
  171. package/dist/studio/assets/{hyperframes-player-ChN3cOr0.js → hyperframes-player-DLOUZUct.js} +1 -1
  172. package/dist/studio/assets/{index-CHu83hHM.js → index-CAQ7OcNJ.js} +163 -163
  173. package/dist/studio/assets/{index-BYbFcRR0.js → index-D9kA6JUX.js} +1 -1
  174. package/dist/studio/index.html +1 -1
  175. package/dist/{studio-api-6YZ7PIQR.js → studio-api-HVNOJILH.js} +13 -11
  176. package/dist/{studioServer-EWHSE4GC.js → studioServer-3BG5FRJL.js} +53 -52
  177. package/dist/{telemetry-GGLBHZRZ.js → telemetry-PET2GFQG.js} +3 -3
  178. package/dist/{timeline-NKHQJXJ2.js → timeline-PVIC2Z5K.js} +20 -19
  179. package/dist/{tokens-FWNNDJ6R.js → tokens-4N46PWSF.js} +2 -2
  180. package/dist/{transcribe-TRPKXZ7L.js → transcribe-2DVBS7MH.js} +19 -18
  181. package/dist/{transcribe-VD2TMMC2.js → transcribe-IDC7JTM4.js} +13 -12
  182. package/dist/{updateCheck-CUPS6LU3.js → updateCheck-QRDVXU7I.js} +2 -2
  183. package/dist/{upgrade-23XO6MEX.js → upgrade-5CNE3TBH.js} +2 -2
  184. package/dist/{urlDownloader-YOAOONCK.js → urlDownloader-P2I25DFC.js} +7 -6
  185. package/dist/{validate-BWIW24G5.js → validate-CLR5PEOV.js} +25 -24
  186. package/dist/{video-XRXJS4GC.js → video-3CKZZBOB.js} +8 -7
  187. package/dist/warmCheck.js +38 -37
  188. package/package.json +1 -1
  189. package/dist/chunk-B2XLXD7V.js +0 -3897
@@ -26,7 +26,7 @@ import {
26
26
  renderFrameIdForRenderId,
27
27
  resolveAuthoredTimingWindow,
28
28
  toFps
29
- } from "./chunk-MGBUWPXX.js";
29
+ } from "./chunk-JVTWX5G3.js";
30
30
  import {
31
31
  AUDIO_GROUP_RENDER_ID_ATTR,
32
32
  COLOR_GRADING_SOURCE_HIDDEN_ATTR,
@@ -63,7 +63,7 @@ import {
63
63
  sourceTimeAt,
64
64
  timeAtSourceTime,
65
65
  volumeSegmentSampleCount
66
- } from "./chunk-B2XLXD7V.js";
66
+ } from "./chunk-2D5WP2NI.js";
67
67
  import {
68
68
  clampAudioGain,
69
69
  clipGain,
@@ -73,6 +73,9 @@ import {
73
73
  redactTelemetryString,
74
74
  redactUrlQueryStrings
75
75
  } from "./chunk-634HSJ3J.js";
76
+ import {
77
+ withHyperframesBrowserMarker
78
+ } from "./chunk-K4MJX7SR.js";
76
79
  import {
77
80
  browserPathFromEnv,
78
81
  chromeMajorCeiling,
@@ -83,7 +86,7 @@ import {
83
86
  } from "./chunk-4UMPIPCQ.js";
84
87
  import {
85
88
  resolveReferencedStart
86
- } from "./chunk-2VXY3PEF.js";
89
+ } from "./chunk-K2VXPQKC.js";
87
90
  import {
88
91
  FFMPEG_PATH_ENV,
89
92
  FFPROBE_PATH_ENV,
@@ -765,7 +768,7 @@ var BrowserLeasePool = class _BrowserLeasePool {
765
768
  for (const entry of entries) this.requestClose(entry, false);
766
769
  const settle = Promise.all(entries.map((entry) => entry.closePromise));
767
770
  const bound = new Promise(
768
- (resolve) => setTimeout(resolve, _BrowserLeasePool.DRAIN_FORCE_CLOSE_MS).unref()
771
+ (resolve2) => setTimeout(resolve2, _BrowserLeasePool.DRAIN_FORCE_CLOSE_MS).unref()
769
772
  );
770
773
  this.drainPromise = Promise.race([settle, bound]).then(() => {
771
774
  for (const entry of entries) if (this.entries.has(entry)) this.requestClose(entry, true);
@@ -864,11 +867,11 @@ var BrowserLeasePool = class _BrowserLeasePool {
864
867
  await Promise.race([
865
868
  this.options.close(result.browser).catch(() => {
866
869
  }),
867
- new Promise((resolve) => {
870
+ new Promise((resolve2) => {
868
871
  entry.forceClose = () => {
869
872
  entry.forceClose = void 0;
870
873
  this.options.forceClose(result.browser);
871
- resolve();
874
+ resolve2();
872
875
  };
873
876
  })
874
877
  ]);
@@ -918,7 +921,7 @@ async function probeHardwareWebGlInfo(ppt, options) {
918
921
  const launchOptions = {
919
922
  ...sigintLaunchOptions(),
920
923
  headless: true,
921
- args: options.args,
924
+ args: withHyperframesBrowserMarker(options.args),
922
925
  defaultViewport: { width: 64, height: 64 },
923
926
  executablePath: options.executablePath,
924
927
  env: options.env,
@@ -1366,7 +1369,7 @@ async function launchBrowser(fingerprint) {
1366
1369
  browser = await ppt.launch({
1367
1370
  ...sigintLaunchOptions(),
1368
1371
  headless: true,
1369
- args: [...fingerprint.args],
1372
+ args: withHyperframesBrowserMarker(fingerprint.args),
1370
1373
  defaultViewport: null,
1371
1374
  executablePath: fingerprint.executablePath,
1372
1375
  env,
@@ -1396,7 +1399,7 @@ async function launchBrowser(fingerprint) {
1396
1399
  browser = await ppt.launch({
1397
1400
  ...sigintLaunchOptions(),
1398
1401
  headless: true,
1399
- args: stripBeginFrameFlags([...fingerprint.args]),
1402
+ args: withHyperframesBrowserMarker(stripBeginFrameFlags([...fingerprint.args])),
1400
1403
  defaultViewport: null,
1401
1404
  executablePath: fingerprint.executablePath,
1402
1405
  env,
@@ -1477,6 +1480,7 @@ function getLowMemoryFlags() {
1477
1480
  }
1478
1481
  var CANVAS_DRAW_ELEMENT_FEATURE_FLAG = "--enable-features=CanvasDrawElement";
1479
1482
  var WEBGPU_FLAG = "--enable-unsafe-webgpu";
1483
+ var DISABLE_DXC_FLAG = "--disable-dawn-features=use_dxc";
1480
1484
  function usesSoftwareWebGpu(requiresWebGpu, config) {
1481
1485
  return !!requiresWebGpu && !!config?.allowSoftwareWebGpu && !(config.disableGpu ?? DEFAULT_CONFIG.disableGpu) && (config.browserGpuMode ?? DEFAULT_CONFIG.browserGpuMode) === "software";
1482
1486
  }
@@ -1532,6 +1536,9 @@ function buildChromeArgs(options, config) {
1532
1536
  ];
1533
1537
  if (browserGpuMode !== "software" || options.requiresWebGpu) {
1534
1538
  chromeArgs.push(WEBGPU_FLAG);
1539
+ if (platform === "win32") {
1540
+ chromeArgs.push(DISABLE_DXC_FLAG);
1541
+ }
1535
1542
  }
1536
1543
  if (softwareWebGpu) chromeArgs.push("--use-vulkan=swiftshader");
1537
1544
  if (browserGpuMode === "software" && !softwareWebGpu) {
@@ -1580,7 +1587,7 @@ async function assertWebGpuAdapterAvailable(page, requiresWebGpu, softwareWebGpu
1580
1587
  try {
1581
1588
  const adapter = await Promise.race([
1582
1589
  navigator.gpu.requestAdapter(),
1583
- new Promise((resolve) => setTimeout(() => resolve(null), timeoutMs))
1590
+ new Promise((resolve2) => setTimeout(() => resolve2(null), timeoutMs))
1584
1591
  ]);
1585
1592
  return !!adapter && (acceptFallback || !adapter.info.isFallbackAdapter);
1586
1593
  } catch {
@@ -2583,8 +2590,8 @@ async function describePageMotionBlur(page) {
2583
2590
  }
2584
2591
  async function describePageMotionBlurAtEnd(page, timeoutMs = 1500) {
2585
2592
  let timer;
2586
- const stuck = new Promise((resolve) => {
2587
- timer = setTimeout(() => resolve(null), timeoutMs);
2593
+ const stuck = new Promise((resolve2) => {
2594
+ timer = setTimeout(() => resolve2(null), timeoutMs);
2588
2595
  });
2589
2596
  try {
2590
2597
  const r = await Promise.race([readPageMotionBlur(page), stuck]);
@@ -2703,8 +2710,8 @@ async function probeBeginFrameLiveness(page, timeoutMs, frameTimeTicks, interval
2703
2710
  try {
2704
2711
  return await Promise.race([
2705
2712
  client.send("HeadlessExperimental.beginFrame", params).then(() => true).catch(() => false),
2706
- new Promise((resolve) => {
2707
- timer = setTimeout(() => resolve(false), timeoutMs);
2713
+ new Promise((resolve2) => {
2714
+ timer = setTimeout(() => resolve2(false), timeoutMs);
2708
2715
  })
2709
2716
  ]);
2710
2717
  } finally {
@@ -3503,7 +3510,7 @@ async function produceDrawElementFrame(page, width, height, quality = 80, syncTo
3503
3510
  );
3504
3511
  }
3505
3512
  const frameId = ++state.nextId;
3506
- const encodeResult = new Promise((resolve, reject) => {
3513
+ const encodeResult = new Promise((resolve2, reject) => {
3507
3514
  const timer = setTimeout(() => {
3508
3515
  if (state.pending.delete(frameId)) {
3509
3516
  reject(new Error(`drawElement worker encode timed out (frame ${frameId})`));
@@ -3512,7 +3519,7 @@ async function produceDrawElementFrame(page, width, height, quality = 80, syncTo
3512
3519
  state.pending.set(frameId, {
3513
3520
  resolve: (b) => {
3514
3521
  clearTimeout(timer);
3515
- resolve(b);
3522
+ resolve2(b);
3516
3523
  },
3517
3524
  reject: (e) => {
3518
3525
  clearTimeout(timer);
@@ -3668,7 +3675,7 @@ async function produceDrawElementFrameBatch(page, times, width, height, quality
3668
3675
  for (let i = 0; i < times.length; i++) {
3669
3676
  const frameId = ++state.nextId;
3670
3677
  fids.push(frameId);
3671
- const p = new Promise((resolve, reject) => {
3678
+ const p = new Promise((resolve2, reject) => {
3672
3679
  const timer = setTimeout(() => {
3673
3680
  if (state.pending.delete(frameId)) {
3674
3681
  reject(new Error(`drawElement worker encode timed out (frame ${frameId})`));
@@ -3677,7 +3684,7 @@ async function produceDrawElementFrameBatch(page, times, width, height, quality
3677
3684
  state.pending.set(frameId, {
3678
3685
  resolve: (b) => {
3679
3686
  clearTimeout(timer);
3680
- resolve(b);
3687
+ resolve2(b);
3681
3688
  },
3682
3689
  reject: (e) => {
3683
3690
  clearTimeout(timer);
@@ -3952,9 +3959,9 @@ async function initThreeDProjectionInPage() {
3952
3959
  const toDataUrl = async (url) => {
3953
3960
  const resp = await fetch(url);
3954
3961
  const blob = await resp.blob();
3955
- return new Promise((resolve, reject) => {
3962
+ return new Promise((resolve2, reject) => {
3956
3963
  const r = new FileReader();
3957
- r.onload = () => resolve(String(r.result));
3964
+ r.onload = () => resolve2(String(r.result));
3958
3965
  r.onerror = () => reject(new Error(`FileReader failed for ${url}`));
3959
3966
  r.readAsDataURL(blob);
3960
3967
  });
@@ -4798,6 +4805,7 @@ var CaptureFailure = class extends Error {
4798
4805
  kind;
4799
4806
  cause;
4800
4807
  workerDiagnostics;
4808
+ pageErrorLines;
4801
4809
  constructor(input) {
4802
4810
  super(input.message);
4803
4811
  this.name = "CaptureFailure";
@@ -4808,6 +4816,7 @@ var CaptureFailure = class extends Error {
4808
4816
  (diagnostic) => Object.freeze({ ...diagnostic, lines: Object.freeze([...diagnostic.lines]) })
4809
4817
  )
4810
4818
  );
4819
+ this.pageErrorLines = Object.freeze([...input.pageErrorLines ?? []]);
4811
4820
  if (input.cause instanceof Error && input.cause.stack) this.stack = input.cause.stack;
4812
4821
  }
4813
4822
  };
@@ -4893,32 +4902,37 @@ function ioError(error, message) {
4893
4902
  )
4894
4903
  ) || BROKEN_PIPE_MESSAGE.test(message) || hasIoOperationFailure(message);
4895
4904
  }
4905
+ var ORDERED_KIND_RULES = [
4906
+ [
4907
+ "memory_exhaustion",
4908
+ (message) => BUN_MEMORY_EXHAUSTION_EXACT_MESSAGE.test(message.trim()) || BUN_MEMORY_EXHAUSTION_WRAPPED_WORKER_MESSAGE.test(message) || matchesAny(message, MEMORY_EXHAUSTION_ERROR_PATTERNS)
4909
+ ],
4910
+ ["verification", (message) => matchesAny(message, VERIFICATION_ERROR_PATTERNS)],
4911
+ ["protocol_timeout", (message) => matchesAny(message, PROTOCOL_TIMEOUT_PATTERNS)],
4912
+ ["transient_browser", (message) => matchesAny(message, TRANSIENT_BROWSER_ERROR_PATTERNS)],
4913
+ ["authoring", (message) => matchesAny(message, AUTHORING_ERROR_PATTERNS)]
4914
+ ];
4915
+ function classifyKind(error, message, signal) {
4916
+ if (signal?.aborted || /(?:render|capture)?_?cancelled|AbortError/i.test(message)) {
4917
+ return "cancelled";
4918
+ }
4919
+ const rule = ORDERED_KIND_RULES.find(([, matches]) => matches(message));
4920
+ if (rule) return rule[0];
4921
+ return ioError(error, message) ? "io" : "authoring";
4922
+ }
4896
4923
  function classifyCaptureFailure(error, options = {}) {
4897
- if (error instanceof CaptureFailure && !options.workerDiagnostics && !options.signal?.aborted) {
4898
- return error;
4924
+ const prior = error instanceof CaptureFailure ? error : void 0;
4925
+ if (prior && !(options.workerDiagnostics || options.pageErrorLines || options.signal?.aborted)) {
4926
+ return prior;
4899
4927
  }
4900
4928
  const message = messageOf(error);
4901
- let kind;
4902
- if (options.signal?.aborted || /(?:render|capture)?_?cancelled|AbortError/i.test(message)) {
4903
- kind = "cancelled";
4904
- } else if (BUN_MEMORY_EXHAUSTION_EXACT_MESSAGE.test(message.trim()) || BUN_MEMORY_EXHAUSTION_WRAPPED_WORKER_MESSAGE.test(message) || matchesAny(message, MEMORY_EXHAUSTION_ERROR_PATTERNS)) {
4905
- kind = "memory_exhaustion";
4906
- } else if (matchesAny(message, VERIFICATION_ERROR_PATTERNS)) {
4907
- kind = "verification";
4908
- } else if (matchesAny(message, PROTOCOL_TIMEOUT_PATTERNS)) {
4909
- kind = "protocol_timeout";
4910
- } else if (matchesAny(message, TRANSIENT_BROWSER_ERROR_PATTERNS)) {
4911
- kind = "transient_browser";
4912
- } else if (matchesAny(message, AUTHORING_ERROR_PATTERNS)) {
4913
- kind = "authoring";
4914
- } else {
4915
- kind = ioError(error, message) ? "io" : "authoring";
4916
- }
4929
+ const kind = classifyKind(error, message, options.signal);
4917
4930
  return new CaptureFailure({
4918
4931
  kind,
4919
4932
  message,
4920
4933
  cause: error,
4921
- workerDiagnostics: options.workerDiagnostics ?? (error instanceof CaptureFailure ? error.workerDiagnostics : void 0)
4934
+ workerDiagnostics: options.workerDiagnostics ?? prior?.workerDiagnostics,
4935
+ pageErrorLines: options.pageErrorLines ?? prior?.pageErrorLines
4922
4936
  });
4923
4937
  }
4924
4938
  function isTransientBrowserError(error) {
@@ -5139,7 +5153,7 @@ function formatHttpErrorDiagnostic(input) {
5139
5153
  return `[Browser:HTTP${input.status}] ${input.method} ${sanitizeDiagnosticUrl(input.url)} resource=${input.resourceType}${statusText}`;
5140
5154
  }
5141
5155
  var LOCKED_WARMUP_TICKS = 60;
5142
- var realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5156
+ var realSleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
5143
5157
  function warmupFrameTimeTicks(state, intervalMs) {
5144
5158
  return state.ticks * intervalMs;
5145
5159
  }
@@ -5203,12 +5217,14 @@ async function driveWarmupTicks(options, state) {
5203
5217
  } else {
5204
5218
  if (!state.running) return;
5205
5219
  }
5220
+ let ticked = false;
5206
5221
  try {
5207
5222
  await options.tick(state.ticks * options.intervalMs, options.intervalMs);
5208
5223
  state.ticks += 1;
5224
+ ticked = true;
5209
5225
  } catch {
5210
5226
  }
5211
- await sleep(options.intervalMs);
5227
+ if (!(options.lockWarmupTicks && !state.running && ticked)) await sleep(options.intervalMs);
5212
5228
  }
5213
5229
  }
5214
5230
  function resolveCaptureSessionOptions(options, browserVersion, platform = process.platform) {
@@ -5225,10 +5241,10 @@ async function waitForCloseWithTimeout(promise) {
5225
5241
  () => void 0,
5226
5242
  () => void 0
5227
5243
  ),
5228
- new Promise((resolve) => {
5244
+ new Promise((resolve2) => {
5229
5245
  timer = setTimeout(() => {
5230
5246
  timedOut = true;
5231
- resolve();
5247
+ resolve2();
5232
5248
  }, CAPTURE_SESSION_CLOSE_TIMEOUT_MS);
5233
5249
  })
5234
5250
  ]);
@@ -5717,7 +5733,7 @@ async function pollHfReady(page, timeoutMs, intervalMs = 100) {
5717
5733
  }
5718
5734
  }
5719
5735
  }
5720
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
5736
+ await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
5721
5737
  }
5722
5738
  const diag = await evaluateHfDiagnostic(page);
5723
5739
  if (diag.hasSeek && diag.duration === 0) {
@@ -5847,7 +5863,7 @@ async function pollSubCompositionTimelines(page, timeoutMs, {
5847
5863
  );
5848
5864
  break;
5849
5865
  }
5850
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
5866
+ await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
5851
5867
  }
5852
5868
  const pendingIds = ready && knownUnregisteredIds.length === 0 ? [] : await listUnregisteredTimelineIds(page);
5853
5869
  if (ready && pendingIds.length > 0 && (getScriptLoadFailures?.() ?? []).length > 0) {
@@ -5891,7 +5907,7 @@ async function pollVideosReady(page, skipIds, timeoutMs, intervalMs = 100) {
5891
5907
  const deadline = Date.now() + timeoutMs;
5892
5908
  while (Date.now() < deadline) {
5893
5909
  if (await check()) return true;
5894
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
5910
+ await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
5895
5911
  }
5896
5912
  return check();
5897
5913
  }
@@ -5914,7 +5930,7 @@ async function pollImagesReady(page, timeoutMs, intervalMs = 100) {
5914
5930
  const deadline = Date.now() + timeoutMs;
5915
5931
  while (Date.now() < deadline) {
5916
5932
  if (await check()) return true;
5917
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
5933
+ await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
5918
5934
  }
5919
5935
  return check();
5920
5936
  }
@@ -6095,7 +6111,7 @@ async function waitForOptionalTailwindReady(page, timeoutMs) {
6095
6111
  page.evaluate(
6096
6112
  `Promise.resolve(window.__tailwindReady).then(() => true, () => false)`
6097
6113
  ),
6098
- new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs))
6114
+ new Promise((resolve2) => setTimeout(() => resolve2(false), timeoutMs))
6099
6115
  ]);
6100
6116
  if (!ready) {
6101
6117
  throw new Error(
@@ -7838,7 +7854,7 @@ import {
7838
7854
  writeFileSync as writeFileSync2,
7839
7855
  writeSync
7840
7856
  } from "fs";
7841
- import { join as join6, dirname as dirname2, extname } from "path";
7857
+ import { join as join6, dirname as dirname2, extname, resolve } from "path";
7842
7858
 
7843
7859
  // ../engine/src/utils/gpuEncoder.ts
7844
7860
  import { spawn } from "child_process";
@@ -7854,8 +7870,8 @@ var ManagedChildProcess = class {
7854
7870
  this.options = options;
7855
7871
  this.now = options.now ?? Date.now;
7856
7872
  this.startedAtMs = this.now();
7857
- this.outcomePromise = new Promise((resolve) => {
7858
- this.resolveOutcome = resolve;
7873
+ this.outcomePromise = new Promise((resolve2) => {
7874
+ this.resolveOutcome = resolve2;
7859
7875
  });
7860
7876
  child.stderr?.on("data", this.onStderr);
7861
7877
  child.once("spawn", this.onSpawn);
@@ -8608,6 +8624,10 @@ var withoutQuery = (url) => url.split(/[?#]/, 1)[0] ?? url;
8608
8624
  function declareContentAddressedUrl(url, sha256) {
8609
8625
  contentAddressedUrls.set(withoutQuery(url), sha256);
8610
8626
  }
8627
+ var probeFactsUrls = /* @__PURE__ */ new Map();
8628
+ function declareProbeFactsUrl(url, factsUrl) {
8629
+ probeFactsUrls.set(withoutQuery(url), factsUrl);
8630
+ }
8611
8631
  function mediaFileIdentity(filePath) {
8612
8632
  if (/^https?:\/\//i.test(filePath)) {
8613
8633
  const sha256 = contentAddressedUrls.get(withoutQuery(filePath));
@@ -8636,6 +8656,75 @@ function writeMetadataCache(cache, key, identity, promise) {
8636
8656
  }
8637
8657
  );
8638
8658
  }
8659
+ var PROBE_FACTS_VERSION = "v2";
8660
+ var PROBE_JSON_ARGS = ["-print_format", "json", "-show_format", "-show_streams"];
8661
+ var storedFacts = /* @__PURE__ */ new Map();
8662
+ function readStoredFacts(filePath) {
8663
+ if (!/^https?:\/\//i.test(filePath)) return void 0;
8664
+ const factsUrl = probeFactsUrls.get(withoutQuery(filePath));
8665
+ if (!factsUrl) return void 0;
8666
+ let facts = storedFacts.get(factsUrl);
8667
+ if (!facts) {
8668
+ facts = (async () => {
8669
+ try {
8670
+ const response = await fetch(factsUrl, { signal: AbortSignal.timeout(1e4) });
8671
+ if (!response.ok) return null;
8672
+ const parsed = JSON.parse(await response.text());
8673
+ return Array.isArray(parsed.ffprobe?.streams) ? parsed : null;
8674
+ } catch {
8675
+ return null;
8676
+ }
8677
+ })();
8678
+ storedFacts.set(factsUrl, facts);
8679
+ }
8680
+ return facts;
8681
+ }
8682
+ function readProbeJson(filePath, signal) {
8683
+ const pending = readStoredFacts(filePath);
8684
+ if (!pending) return runFfprobe(filePath, PROBE_JSON_ARGS, signal);
8685
+ return pending.then(
8686
+ (stored) => stored ? JSON.stringify(stored.ffprobe) : runFfprobe(filePath, PROBE_JSON_ARGS, signal)
8687
+ );
8688
+ }
8689
+ var runtimeFfprobeMajor;
8690
+ function ffprobeMajor() {
8691
+ runtimeFfprobeMajor ??= new Promise((resolve2) => {
8692
+ let out = "";
8693
+ const binary = getFfprobeBinary();
8694
+ const proc = spawn3(binary, ["-version"], { stdio: ["ignore", "pipe", "ignore"] });
8695
+ proc.stdout.on("data", (chunk) => out += String(chunk));
8696
+ proc.on("error", () => resolve2(void 0));
8697
+ proc.on("close", () => resolve2(Number(/version n?(\d+)/.exec(out)?.[1]) || void 0));
8698
+ });
8699
+ return runtimeFfprobeMajor;
8700
+ }
8701
+ async function buildProbeFactsText(filePath, signal) {
8702
+ const facts = {
8703
+ ffprobe: parseProbeJson(await runFfprobe(filePath, PROBE_JSON_ARGS, signal)),
8704
+ ffprobeMajor: await ffprobeMajor()
8705
+ };
8706
+ try {
8707
+ const metadata = await extractMediaMetadata(filePath);
8708
+ const window2 = resolveStreamWindow(filePath, {
8709
+ videoStreamStartSeconds: metadata.videoStreamStartSeconds,
8710
+ videoStreamDurationSeconds: resolvePlayableVideoDuration(metadata) - (metadata.videoStreamLeadSeconds ?? 0)
8711
+ });
8712
+ if (window2.videoStreamDurationSeconds > 0) {
8713
+ facts.finalFrame = {
8714
+ streamStart: window2.videoStreamStartSeconds,
8715
+ streamDuration: window2.videoStreamDurationSeconds,
8716
+ seconds: await extractFinalVideoFrameTimestamp(filePath, window2, signal),
8717
+ lastPacketSeconds: await extractFinalPacketDuration(filePath, window2, signal)
8718
+ };
8719
+ }
8720
+ } catch {
8721
+ if (signal?.aborted) throw signal.reason;
8722
+ }
8723
+ return JSON.stringify(facts);
8724
+ }
8725
+ function resolvePlayableVideoDuration(metadata) {
8726
+ return Number.isFinite(metadata.videoStreamDurationSeconds) && metadata.videoStreamDurationSeconds > 0 ? (metadata.videoStreamLeadSeconds ?? 0) + metadata.videoStreamDurationSeconds : metadata.durationSeconds;
8727
+ }
8639
8728
  async function probeMediaOutput(filePath, signal) {
8640
8729
  let cache = mediaProbeOutputCache;
8641
8730
  if (signal) {
@@ -8651,11 +8740,7 @@ async function probeMediaOutput(filePath, signal) {
8651
8740
  }
8652
8741
  return cached.promise;
8653
8742
  }
8654
- const promise = runFfprobe(
8655
- filePath,
8656
- ["-print_format", "json", "-show_format", "-show_streams"],
8657
- signal
8658
- ).then(parseProbeJson);
8743
+ const promise = readProbeJson(filePath, signal).then(parseProbeJson);
8659
8744
  if (identity !== null) {
8660
8745
  cache.set(filePath, { identity, promise });
8661
8746
  if (!signal && cache.size > MEDIA_PROBE_OUTPUT_CACHE_MAX_ENTRIES) {
@@ -8911,6 +8996,43 @@ function resolveStreamWindow(filePath, metadata) {
8911
8996
  const cacheKey = `${filePath}\0${String(videoStreamStartSeconds)}\0${String(videoStreamDurationSeconds)}`;
8912
8997
  return { videoStreamStartSeconds, videoStreamDurationSeconds, cacheKey };
8913
8998
  }
8999
+ function readStoredFinalFrame(filePath, metadata) {
9000
+ const { videoStreamStartSeconds, videoStreamDurationSeconds } = resolveStreamWindow(
9001
+ filePath,
9002
+ metadata
9003
+ );
9004
+ return readStoredFacts(filePath)?.then(async (facts) => {
9005
+ const stored = facts?.finalFrame;
9006
+ if (facts?.ffprobeMajor !== void 0 && facts.ffprobeMajor !== await ffprobeMajor())
9007
+ return void 0;
9008
+ return stored && stored.streamStart === videoStreamStartSeconds && stored.streamDuration === videoStreamDurationSeconds ? stored : void 0;
9009
+ });
9010
+ }
9011
+ async function extractFinalPacketDuration(filePath, window2, signal) {
9012
+ const streamEnd = window2.videoStreamStartSeconds + window2.videoStreamDurationSeconds;
9013
+ const intervalStart = Math.max(window2.videoStreamStartSeconds, streamEnd - 1);
9014
+ const stdout = await runFfprobe(
9015
+ filePath,
9016
+ [
9017
+ "-select_streams",
9018
+ "v:0",
9019
+ "-read_intervals",
9020
+ `${intervalStart}%${streamEnd}`,
9021
+ "-show_entries",
9022
+ "packet=pts_time,duration_time",
9023
+ "-of",
9024
+ "csv=p=0"
9025
+ ],
9026
+ signal,
9027
+ { retainTail: true, maxChars: 64 * 1024 }
9028
+ );
9029
+ const packets = stdout.split("\n").map((line) => line.trim().split(",").map(Number)).filter(([pts, duration]) => Number.isFinite(pts) && Number.isFinite(duration));
9030
+ const last = packets.reduce(
9031
+ (best, packet) => !best || packet[0] > best[0] ? packet : best,
9032
+ void 0
9033
+ );
9034
+ return last?.[1];
9035
+ }
8914
9036
  async function extractFinalVideoFrameTimestamp(filePath, metadata, signal) {
8915
9037
  const {
8916
9038
  videoStreamStartSeconds,
@@ -8926,6 +9048,9 @@ async function extractFinalVideoFrameTimestamp(filePath, metadata, signal) {
8926
9048
  const cached = readMetadataCache(probeCache, cacheKey, identity);
8927
9049
  if (cached) return cached;
8928
9050
  const probePromise = (async () => {
9051
+ const pendingStored = readStoredFinalFrame(filePath, metadata);
9052
+ const stored = pendingStored && await pendingStored;
9053
+ if (stored) return stored.seconds;
8929
9054
  if (!(videoDurationSeconds > 0) || !Number.isFinite(videoDurationSeconds)) {
8930
9055
  throw new Error(
8931
9056
  `[FFmpeg] Cannot locate final video frame for invalid duration ${String(videoDurationSeconds)}`
@@ -9570,7 +9695,7 @@ var concatListSeq = 0;
9570
9695
  function writeConcatList(dir, inputPaths) {
9571
9696
  concatListSeq += 1;
9572
9697
  const listPath = join6(dir, `concat-list-${process.pid}-${concatListSeq}.txt`);
9573
- const body = inputPaths.map((p) => `file '${p.replace(/'/g, "'\\''")}'`).join("\n");
9698
+ const body = inputPaths.map((p) => `file '${resolve(p).replace(/'/g, "'\\''")}'`).join("\n");
9574
9699
  writeFileSync2(listPath, body, "utf-8");
9575
9700
  return listPath;
9576
9701
  }
@@ -9931,12 +10056,12 @@ function createFrameReorderBuffer(startFrame, endFrame) {
9931
10056
  let cursor = startFrame;
9932
10057
  let aborted = null;
9933
10058
  const pending = /* @__PURE__ */ new Map();
9934
- const enqueueAt = (frame, resolve, reject) => {
10059
+ const enqueueAt = (frame, resolve2, reject) => {
9935
10060
  const list = pending.get(frame);
9936
10061
  if (list === void 0) {
9937
- pending.set(frame, [{ resolve, reject }]);
10062
+ pending.set(frame, [{ resolve: resolve2, reject }]);
9938
10063
  } else {
9939
- list.push({ resolve, reject });
10064
+ list.push({ resolve: resolve2, reject });
9940
10065
  }
9941
10066
  };
9942
10067
  const flushAt = (frame) => {
@@ -9945,31 +10070,31 @@ function createFrameReorderBuffer(startFrame, endFrame) {
9945
10070
  pending.delete(frame);
9946
10071
  for (const waiter of list) waiter.resolve();
9947
10072
  };
9948
- const waitForFrame = (frame) => new Promise((resolve, reject) => {
10073
+ const waitForFrame = (frame) => new Promise((resolve2, reject) => {
9949
10074
  if (aborted) {
9950
10075
  reject(aborted);
9951
10076
  return;
9952
10077
  }
9953
10078
  if (frame === cursor) {
9954
- resolve();
10079
+ resolve2();
9955
10080
  return;
9956
10081
  }
9957
- enqueueAt(frame, resolve, reject);
10082
+ enqueueAt(frame, resolve2, reject);
9958
10083
  });
9959
10084
  const advanceTo = (frame) => {
9960
10085
  cursor = frame;
9961
10086
  flushAt(frame);
9962
10087
  };
9963
- const waitForAllDone = () => new Promise((resolve, reject) => {
10088
+ const waitForAllDone = () => new Promise((resolve2, reject) => {
9964
10089
  if (aborted) {
9965
10090
  reject(aborted);
9966
10091
  return;
9967
10092
  }
9968
10093
  if (cursor >= endFrame) {
9969
- resolve();
10094
+ resolve2();
9970
10095
  return;
9971
10096
  }
9972
- enqueueAt(endFrame, resolve, reject);
10097
+ enqueueAt(endFrame, resolve2, reject);
9973
10098
  });
9974
10099
  const abort = (err) => {
9975
10100
  if (aborted) return;
@@ -10264,8 +10389,8 @@ async function spawnStreamingEncoder(outputPath, options, signal, config) {
10264
10389
  }
10265
10390
  const stdin = ffmpeg.stdin;
10266
10391
  if (stdin && !stdin.destroyed) {
10267
- await new Promise((resolve) => {
10268
- stdin.end(() => resolve());
10392
+ await new Promise((resolve2) => {
10393
+ stdin.end(() => resolve2());
10269
10394
  });
10270
10395
  }
10271
10396
  const outcome = await exitPromise;
@@ -10403,14 +10528,14 @@ import { cpus } from "os";
10403
10528
  function createConcurrencyLimit(limit) {
10404
10529
  let active = 0;
10405
10530
  const waiting = [];
10406
- const waitForSlot = (signal) => new Promise((resolve) => {
10531
+ const waitForSlot = (signal) => new Promise((resolve2) => {
10407
10532
  const granted = () => {
10408
10533
  signal?.removeEventListener("abort", aborted);
10409
- resolve(true);
10534
+ resolve2(true);
10410
10535
  };
10411
10536
  const aborted = () => {
10412
10537
  waiting.splice(waiting.indexOf(granted), 1);
10413
- resolve(false);
10538
+ resolve2(false);
10414
10539
  };
10415
10540
  waiting.push(granted);
10416
10541
  signal?.addEventListener("abort", aborted, { once: true });
@@ -10713,10 +10838,10 @@ async function waitForCacheLock(signal) {
10713
10838
  if (signal?.aborted) {
10714
10839
  throw new UrlDownloadError("cancelled", false, "Download cancelled");
10715
10840
  }
10716
- await new Promise((resolve, reject) => {
10841
+ await new Promise((resolve2, reject) => {
10717
10842
  const timeout = setTimeout(() => {
10718
10843
  signal?.removeEventListener("abort", onAbort);
10719
- resolve();
10844
+ resolve2();
10720
10845
  }, CACHE_LOCK_POLL_MS);
10721
10846
  const onAbort = () => {
10722
10847
  clearTimeout(timeout);
@@ -11528,12 +11653,52 @@ import {
11528
11653
  lstatSync as lstatSync2,
11529
11654
  mkdirSync as mkdirSync5,
11530
11655
  readdirSync as readdirSync5,
11531
- renameSync,
11532
11656
  rmSync as rmSync3,
11533
11657
  statSync as statSync6,
11534
11658
  utimesSync,
11535
11659
  writeFileSync as writeFileSync3
11536
11660
  } from "fs";
11661
+
11662
+ // ../engine/src/utils/renameWithRetry.ts
11663
+ import { renameSync } from "fs";
11664
+ import { rename } from "fs/promises";
11665
+ var RETRYABLE = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
11666
+ var BACKOFF_MS = [10, 20, 40, 80, 160, 320, 640];
11667
+ function isRetryable(error, platform) {
11668
+ if (platform !== "win32") return false;
11669
+ return RETRYABLE.has(error?.code ?? "");
11670
+ }
11671
+ function sleepSync(ms) {
11672
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
11673
+ }
11674
+ function renameWithRetry(from, to, options = {}) {
11675
+ const doRename = options.rename ?? renameSync;
11676
+ const platform = options.platform ?? process.platform;
11677
+ for (let attempt = 0; ; attempt++) {
11678
+ try {
11679
+ doRename(from, to);
11680
+ return;
11681
+ } catch (error) {
11682
+ if (attempt >= BACKOFF_MS.length || !isRetryable(error, platform)) throw error;
11683
+ sleepSync(BACKOFF_MS[attempt]);
11684
+ }
11685
+ }
11686
+ }
11687
+ async function renameWithRetryAsync(from, to, options = {}) {
11688
+ const doRename = options.rename ?? rename;
11689
+ const platform = options.platform ?? process.platform;
11690
+ for (let attempt = 0; ; attempt++) {
11691
+ try {
11692
+ await doRename(from, to);
11693
+ return;
11694
+ } catch (error) {
11695
+ if (attempt >= BACKOFF_MS.length || !isRetryable(error, platform)) throw error;
11696
+ await new Promise((resolve2) => setTimeout(resolve2, BACKOFF_MS[attempt]));
11697
+ }
11698
+ }
11699
+ }
11700
+
11701
+ // ../engine/src/services/extractionCache.ts
11537
11702
  import { join as join9 } from "path";
11538
11703
  var COMPLETE_SENTINEL = ".hf-complete";
11539
11704
  var GC_MARKER = ".hf-last-gc";
@@ -11608,7 +11773,7 @@ function publishCacheEntry(entry, partialDir) {
11608
11773
  return { dir: partialDir, published: false };
11609
11774
  }
11610
11775
  try {
11611
- renameSync(partialDir, entry.dir);
11776
+ renameWithRetry(partialDir, entry.dir);
11612
11777
  return { dir: entry.dir, published: true };
11613
11778
  } catch (err) {
11614
11779
  if (!isTargetExistsRenameError(err)) return { dir: partialDir, published: false };
@@ -11621,7 +11786,7 @@ function publishCacheEntry(entry, partialDir) {
11621
11786
  return { dir: partialDir, published: false };
11622
11787
  }
11623
11788
  try {
11624
- renameSync(partialDir, entry.dir);
11789
+ renameWithRetry(partialDir, entry.dir);
11625
11790
  return { dir: entry.dir, published: true };
11626
11791
  } catch {
11627
11792
  return adoptPublishedWinner(entry, partialDir) ?? { dir: partialDir, published: false };
@@ -11806,6 +11971,24 @@ function extractionFrameCountForDuration(durationSeconds, fps, isVFR) {
11806
11971
  const frames = Number(frameCount);
11807
11972
  return Math.max(1, Number.isSafeInteger(frames) ? frames : Number.MAX_SAFE_INTEGER);
11808
11973
  }
11974
+ function exactSourceRate(probed) {
11975
+ const nominal = Math.round(probed * 1.001);
11976
+ return [nominal, nominal * 1e3 / 1001].find((rate) => Math.abs(rate - probed) <= 5e-3 + 1e-9) ?? null;
11977
+ }
11978
+ function tailFramesFromFinalFrame(input) {
11979
+ const sourceRate = exactSourceRate(input.sourceFps);
11980
+ if (!sourceRate || !(input.outputFps > 0)) return null;
11981
+ const lead = input.streamLeadSeconds;
11982
+ if (lead !== 0 && !(Math.abs((input.lastPacketSeconds ?? NaN) - 1 / sourceRate) <= 1e-4)) {
11983
+ return null;
11984
+ }
11985
+ const seek = input.startTime + input.firstFrame / input.outputFps;
11986
+ const slots = (lead + input.finalFrameSeconds + 1 / sourceRate - seek) * input.outputFps;
11987
+ const distanceToSlot = Math.abs(slots - Math.round(slots));
11988
+ if (distanceToSlot >= 5e-5 && distanceToSlot < 5e-4) return null;
11989
+ const count = Math.min(input.tailFrames, Math.ceil(slots - 5e-5));
11990
+ return count > 0 ? count : null;
11991
+ }
11809
11992
  var DOWNLOAD_SUBDIR = "_downloads";
11810
11993
  var EXTRACT_CACHE_MIN_AGE_MS = 60 * 60 * 1e3;
11811
11994
  var GC_STALENESS_MS = 24 * 60 * 60 * 1e3;
@@ -12180,6 +12363,8 @@ function undoTickRoundingOnTheSourceFrameGrid(seek, lead) {
12180
12363
  }
12181
12364
  var EXTRACTION_SLOTS = Math.max(1, Math.floor(cpus().length / 2));
12182
12365
  var inExtractionSlot = createConcurrencyLimit(EXTRACTION_SLOTS);
12366
+ var TAIL_PROBE_SLOTS = Math.max(1, Number(process.env.HF_TAIL_PROBE_SLOTS) || 16);
12367
+ var inTailProbeSlot = createConcurrencyLimit(TAIL_PROBE_SLOTS);
12183
12368
  function splitFrameRanges(ranges, segmentFrames) {
12184
12369
  const segments = [];
12185
12370
  for (const range of ranges) {
@@ -12193,7 +12378,7 @@ function splitFrameRanges(ranges, segmentFrames) {
12193
12378
  return segments;
12194
12379
  }
12195
12380
  async function runSegmentedExtraction(job) {
12196
- const { decodeArgs, filterAndEncodeArgs, videoPath, startTime, fps, segments } = job;
12381
+ const { decodeArgs, filterAndEncodeArgs, videoPath, startTime, fps, segments, gate } = job;
12197
12382
  const segmentCount = segments.length;
12198
12383
  const failed = new AbortController();
12199
12384
  const signal = job.runOptions.signal ? AbortSignal.any([job.runOptions.signal, failed.signal]) : failed.signal;
@@ -12204,7 +12389,7 @@ async function runSegmentedExtraction(job) {
12204
12389
  const index = next++;
12205
12390
  const { firstFrame, frames } = segments[index];
12206
12391
  const seek = startTime + firstFrame / fps;
12207
- const result = await inExtractionSlot(
12392
+ const result = await gate(
12208
12393
  () => runFfmpeg(
12209
12394
  [
12210
12395
  ...decodeArgs,
@@ -12355,6 +12540,7 @@ async function extractVideoFramesRangeUnredacted(videoPath, videoId, startTime,
12355
12540
  videoPath,
12356
12541
  startTime,
12357
12542
  fps,
12543
+ gate: options.tailProbe ? inTailProbeSlot : inExtractionSlot,
12358
12544
  segments: splitFrameRanges(
12359
12545
  options.frameRanges ?? [{ firstFrame: 0, frames: totalFrames }],
12360
12546
  segmentFrames
@@ -12455,9 +12641,6 @@ function resolveSegmentDuration(requested, mediaStart, sourceDuration) {
12455
12641
  const sourceRemaining = sourceDuration - mediaStart;
12456
12642
  return sourceRemaining > 0 ? sourceRemaining : sourceDuration;
12457
12643
  }
12458
- function resolvePlayableVideoDuration(metadata) {
12459
- return Number.isFinite(metadata.videoStreamDurationSeconds) && metadata.videoStreamDurationSeconds > 0 ? (metadata.videoStreamLeadSeconds ?? 0) + metadata.videoStreamDurationSeconds : metadata.durationSeconds;
12460
- }
12461
12644
  function canHoldFinalFramePastEof(video) {
12462
12645
  const timelineDuration = video.end - video.start;
12463
12646
  return !video.loop && Number.isFinite(timelineDuration) && timelineDuration > 0;
@@ -13136,23 +13319,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
13136
13319
  );
13137
13320
  const tailFrames = Math.min(expectedFrames, Math.ceil(fps));
13138
13321
  if (expectedFrames <= tailFrames) return null;
13139
- const probeDir = join10(options.outputDir, `${work.video.id}.tail-probe`);
13140
- try {
13141
- const tail = await extractVideoFramesRange(
13142
- work.videoPath,
13143
- work.video.id,
13144
- work.extractionMediaStart,
13145
- work.videoDuration,
13146
- {
13147
- ...scopedExtractionOptions(work),
13148
- frameRanges: [{ firstFrame: expectedFrames - tailFrames, frames: tailFrames }]
13149
- },
13150
- signal,
13151
- config,
13152
- probeDir
13153
- );
13154
- const totalFrames = expectedFrames - tailFrames + tail.totalFrames;
13155
- if (totalFrames <= expectedFrames * 0.6) return null;
13322
+ const deferred = (totalFrames) => {
13156
13323
  const outputDir = join10(options.outputDir, work.video.id);
13157
13324
  mkdirSync6(outputDir, { recursive: true });
13158
13325
  return {
@@ -13170,6 +13337,45 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
13170
13337
  format: work.format
13171
13338
  }
13172
13339
  };
13340
+ };
13341
+ if (work.extractionMediaStart + work.videoDuration + 1 <= resolvePlayableVideoDuration(work.metadata)) {
13342
+ return deferred(expectedFrames);
13343
+ }
13344
+ const firstTailFrame = expectedFrames - tailFrames;
13345
+ const storedFinalFrame = await readStoredFinalFrame(work.videoPath, work.metadata);
13346
+ const storedTailFrames = storedFinalFrame === void 0 ? null : tailFramesFromFinalFrame({
13347
+ startTime: work.extractionMediaStart,
13348
+ firstFrame: firstTailFrame,
13349
+ tailFrames,
13350
+ outputFps: fps,
13351
+ sourceFps: work.metadata.fps,
13352
+ finalFrameSeconds: storedFinalFrame.seconds,
13353
+ lastPacketSeconds: storedFinalFrame.lastPacketSeconds,
13354
+ streamLeadSeconds: work.metadata.videoStreamLeadSeconds ?? 0
13355
+ });
13356
+ if (storedTailFrames !== null) {
13357
+ const totalFrames = firstTailFrame + storedTailFrames;
13358
+ return totalFrames <= expectedFrames * 0.6 ? null : deferred(totalFrames);
13359
+ }
13360
+ const probeDir = join10(options.outputDir, `${work.video.id}.tail-probe`);
13361
+ try {
13362
+ const tail = await extractVideoFramesRange(
13363
+ work.videoPath,
13364
+ work.video.id,
13365
+ work.extractionMediaStart,
13366
+ work.videoDuration,
13367
+ {
13368
+ ...scopedExtractionOptions(work),
13369
+ frameRanges: [{ firstFrame: firstTailFrame, frames: tailFrames }],
13370
+ tailProbe: isHttpUrl(work.videoPath)
13371
+ },
13372
+ signal,
13373
+ config,
13374
+ probeDir
13375
+ );
13376
+ const totalFrames = firstTailFrame + tail.totalFrames;
13377
+ if (totalFrames <= expectedFrames * 0.6) return null;
13378
+ return deferred(totalFrames);
13173
13379
  } catch {
13174
13380
  return null;
13175
13381
  } finally {
@@ -14048,16 +14254,7 @@ async function queryElementStacking(page, nativeHdrIds) {
14048
14254
  }
14049
14255
 
14050
14256
  // ../engine/src/services/audioMixer.ts
14051
- import {
14052
- closeSync as closeSync4,
14053
- existsSync as existsSync11,
14054
- mkdirSync as mkdirSync7,
14055
- mkdtempSync as mkdtempSync7,
14056
- openSync as openSync4,
14057
- renameSync as renameSync3,
14058
- rmSync as rmSync8,
14059
- writeFileSync as writeFileSync7
14060
- } from "fs";
14257
+ import { closeSync as closeSync4, existsSync as existsSync11, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync7, openSync as openSync4, rmSync as rmSync8, writeFileSync as writeFileSync7 } from "fs";
14061
14258
  import { join as join14, dirname as dirname7, isAbsolute, relative } from "path";
14062
14259
 
14063
14260
  // ../engine/src/utils/notMediaPayload.ts
@@ -14176,6 +14373,7 @@ function clampFadesToDuration(fades, duration) {
14176
14373
  import { cpus as cpus2 } from "os";
14177
14374
 
14178
14375
  // ../engine/src/services/aacEncode.ts
14376
+ import { execFile as execFile3 } from "child_process";
14179
14377
  import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync5, rmSync as rmSync5, writeFileSync as writeFileSync4 } from "fs";
14180
14378
  import { dirname as dirname5, join as join11 } from "path";
14181
14379
  var SAMPLE_RATE = 48e3;
@@ -14211,12 +14409,35 @@ function planSegments(totalDuration, count) {
14211
14409
  return { trim, keepFrom: cut - firstFrame, keepTo: next - firstFrame };
14212
14410
  });
14213
14411
  }
14412
+ var settsDurationSupport = /* @__PURE__ */ new Map();
14413
+ function supportsSettsDuration(binary = getFfmpegBinary()) {
14414
+ let supported = settsDurationSupport.get(binary);
14415
+ if (!supported) {
14416
+ supported = new Promise((resolve2) => {
14417
+ execFile3(binary, ["-hide_banner", "-h", "bsf=setts"], (error, stdout) => {
14418
+ resolve2(error !== null || stdout.includes("duration"));
14419
+ });
14420
+ });
14421
+ settsDurationSupport.set(binary, supported);
14422
+ }
14423
+ return supported;
14424
+ }
14425
+ function encodeInOnePass(input, outputPath, { signal, timeout, filter }) {
14426
+ const filters = [filter, `aresample=${SAMPLE_RATE}`].filter(Boolean).join(",");
14427
+ return runFfmpeg(["-i", input, "-af", filters, ...AAC_ARGS, "-y", outputPath], {
14428
+ signal,
14429
+ timeout
14430
+ });
14431
+ }
14214
14432
  async function encodeAac(input, outputPath, totalDuration, {
14215
14433
  signal,
14216
14434
  timeout,
14217
14435
  filter,
14218
14436
  segments: count = aacSegmentCount(totalDuration)
14219
14437
  }) {
14438
+ if (!await supportsSettsDuration()) {
14439
+ return encodeInOnePass(input, outputPath, { signal, timeout, filter });
14440
+ }
14220
14441
  const dir = mkdtempSync4(join11(dirname5(outputPath), ".aac-segments-"));
14221
14442
  try {
14222
14443
  const segments = planSegments(totalDuration, count).map((segment, k) => ({
@@ -14382,7 +14603,7 @@ function audioFailureDiagnostics(values) {
14382
14603
  }
14383
14604
 
14384
14605
  // ../engine/src/services/audioVolumeEnvelope.ts
14385
- import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync6, renameSync as renameSync2, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "fs";
14606
+ import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync6, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "fs";
14386
14607
  import { dirname as dirname6, join as join12 } from "path";
14387
14608
 
14388
14609
  // ../core/dist/runtime/mediaVolumeEnvelope.js
@@ -14512,7 +14733,7 @@ function applyVolumeEnvelopeToWav(wavPath, keyframes, trackStart, baseVolume) {
14512
14733
  stagingDir = mkdtempSync5(join12(dirname6(wavPath), ".hf-volume-"));
14513
14734
  const tempPath = join12(stagingDir, "audio.wav");
14514
14735
  writeFileSync5(tempPath, buffer, { flag: "wx" });
14515
- renameSync2(tempPath, wavPath);
14736
+ renameWithRetry(tempPath, wavPath);
14516
14737
  return true;
14517
14738
  } catch {
14518
14739
  return false;
@@ -15502,6 +15723,9 @@ function volumeLaneKeyframes(automation, trackStart, duration, gain, gainAhead =
15502
15723
  function parseMasterFxChain(html) {
15503
15724
  return readMasterFxChain(parseHTML(unwrapTemplate(html)).document);
15504
15725
  }
15726
+ function videoAudioId(videoId) {
15727
+ return `${videoId}-audio`;
15728
+ }
15505
15729
  function parseAudioElements(html) {
15506
15730
  const elements = [];
15507
15731
  const { document: document2 } = parseHTML(unwrapTemplate(html));
@@ -15564,7 +15788,7 @@ function parseAudioElements(html) {
15564
15788
  const src = resolveMediaElementSrc(el);
15565
15789
  if (!id || !src || isHidden(el) || memberGroupHidden(el)) continue;
15566
15790
  if (isKnownInactiveTimelineWindow(el, resolveStart(el))) continue;
15567
- elements.push(build(el, `${id}-audio`, src, "video", true));
15791
+ elements.push(build(el, videoAudioId(id), src, "video", true));
15568
15792
  }
15569
15793
  return elements;
15570
15794
  }
@@ -16010,7 +16234,7 @@ async function mixGroupMembers(memberTracks, outputPath, totalDuration, signal,
16010
16234
  try {
16011
16235
  const summed = await sumInSlices(memberTracks, scratchDir, totalDuration, signal, config);
16012
16236
  if (!summed.success) return summed;
16013
- renameSync3(summed.track.srcPath, outputPath);
16237
+ renameWithRetry(summed.track.srcPath, outputPath);
16014
16238
  return { success: true, degradedAutomation: summed.degradedAutomation };
16015
16239
  } finally {
16016
16240
  rmSync8(scratchDir, { recursive: true, force: true });
@@ -16052,12 +16276,15 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
16052
16276
  }
16053
16277
  async function mixThroughFloatSum(tracks, masterChain, outputPath, workDir, totalDuration, signal, config) {
16054
16278
  const sumPath = join14(workDir, "master-sum.wav");
16279
+ const mixStart = Date.now();
16055
16280
  const sum = await mixAudioTracks(tracks, sumPath, totalDuration, signal, config);
16056
16281
  if (!sum.success) return { ...sum, outputPath };
16282
+ const masterStart = Date.now();
16057
16283
  const encoderInput = masterChain ? (await applyAudioFxChain(sumPath, masterChain, join14(workDir, "master-fx.wav"), {
16058
16284
  trackId: "master",
16059
16285
  signal
16060
16286
  })).path : sumPath;
16287
+ const encodeStart = Date.now();
16061
16288
  const encoded = await encodeAac(encoderInput, outputPath, totalDuration, {
16062
16289
  signal,
16063
16290
  timeout: config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout
@@ -16077,8 +16304,17 @@ async function mixThroughFloatSum(tracks, masterChain, outputPath, workDir, tota
16077
16304
  failures: [failure]
16078
16305
  };
16079
16306
  }
16080
- if (config?.keepEncoderInputAt) renameSync3(encoderInput, config.keepEncoderInputAt);
16081
- return { ...sum, outputPath, durationMs: sum.durationMs + encoded.durationMs };
16307
+ if (config?.keepEncoderInputAt) renameWithRetry(encoderInput, config.keepEncoderInputAt);
16308
+ return {
16309
+ ...sum,
16310
+ outputPath,
16311
+ durationMs: sum.durationMs + encoded.durationMs,
16312
+ phaseMs: {
16313
+ mix: masterStart - mixStart,
16314
+ master: encodeStart - masterStart,
16315
+ encode: Date.now() - encodeStart
16316
+ }
16317
+ };
16082
16318
  }
16083
16319
  async function processCompositionAudio(elements, baseDir, workDir, outputPath, totalDuration, signal, config, compiledDir) {
16084
16320
  const startMs = Date.now();
@@ -16363,6 +16599,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16363
16599
  failures
16364
16600
  };
16365
16601
  };
16602
+ const prepareMs = Date.now() - startMs;
16366
16603
  if (failures.length > 0) return bail();
16367
16604
  let masterChain;
16368
16605
  const masterFxJson = config?.masterFxChain;
@@ -16473,6 +16710,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16473
16710
  }
16474
16711
  }
16475
16712
  if (failures.length > 0) return bail();
16713
+ const groupsMs = Date.now() - startMs - prepareMs;
16476
16714
  let mixResult;
16477
16715
  try {
16478
16716
  mixResult = tracks.length > 0 ? await mixThroughFloatSum(
@@ -16491,6 +16729,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16491
16729
  return {
16492
16730
  ...mixResult,
16493
16731
  durationMs: Date.now() - startMs,
16732
+ phaseMs: { prepare: prepareMs, groups: groupsMs, ...mixResult.phaseMs },
16494
16733
  // Both, when both degraded. `mixResult.error ?? degradedNote` reported only
16495
16734
  // the outer mix and dropped the one that names which GROUPS lost their
16496
16735
  // members' automation — two different losses, and the operator needs to
@@ -16502,18 +16741,18 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16502
16741
  // ../engine/src/services/parallelCoordinator.ts
16503
16742
  import { cpus as cpus3, freemem } from "os";
16504
16743
  import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync6 } from "fs";
16505
- import { copyFile, readFile as readFile2, rename } from "fs/promises";
16744
+ import { copyFile, readFile as readFile2 } from "fs/promises";
16506
16745
  import { join as join16 } from "path";
16507
16746
  import { getHeapStatistics } from "v8";
16508
16747
 
16509
16748
  // ../engine/src/utils/psnr.ts
16510
- import { execFile as execFile3 } from "child_process";
16749
+ import { execFile as execFile4 } from "child_process";
16511
16750
  import { mkdtemp, rm, writeFile } from "fs/promises";
16512
16751
  import { tmpdir as tmpdir4 } from "os";
16513
16752
  import { join as join15 } from "path";
16514
16753
  import { promisify as promisify3 } from "util";
16515
16754
  async function psnrDb(a, b) {
16516
- const execFileP = promisify3(execFile3);
16755
+ const execFileP = promisify3(execFile4);
16517
16756
  const dir = await mkdtemp(join15(tmpdir4(), "hf-de-verify-"));
16518
16757
  try {
16519
16758
  const pa = join15(dir, "a.jpg");
@@ -16766,7 +17005,7 @@ function shouldVerifyWorkerGpu(workerId, config) {
16766
17005
  }
16767
17006
  function withParallelWorkerDeadline(promise, diagnostic, timeoutMs, signal) {
16768
17007
  if (signal?.aborted) return Promise.reject(new Error("Parallel worker cancelled"));
16769
- return new Promise((resolve, reject) => {
17008
+ return new Promise((resolve2, reject) => {
16770
17009
  let timer;
16771
17010
  const cleanup = () => {
16772
17011
  if (timer) clearTimeout(timer);
@@ -16791,7 +17030,7 @@ function withParallelWorkerDeadline(promise, diagnostic, timeoutMs, signal) {
16791
17030
  promise.then(
16792
17031
  (value) => {
16793
17032
  cleanup();
16794
- resolve(value);
17033
+ resolve2(value);
16795
17034
  },
16796
17035
  (error) => {
16797
17036
  cleanup();
@@ -17047,7 +17286,8 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
17047
17286
  endFrame: task.endFrame,
17048
17287
  frameStride: task.frameStride,
17049
17288
  durationMs: Date.now() - startTime,
17050
- perf
17289
+ perf,
17290
+ pageErrorLines: pageErrorLinesOf(activeSession)
17051
17291
  };
17052
17292
  } catch (error) {
17053
17293
  const diagnostics = session ? selectWorkerDiagnostics(session.browserConsoleBuffer) : [];
@@ -17060,7 +17300,8 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
17060
17300
  };
17061
17301
  const failure = classifyCaptureFailure(error, {
17062
17302
  signal,
17063
- workerDiagnostics: [workerDiagnostic]
17303
+ workerDiagnostics: [workerDiagnostic],
17304
+ pageErrorLines: session ? pageErrorLinesOf(session) : void 0
17064
17305
  });
17065
17306
  onFailure?.(failure);
17066
17307
  return {
@@ -17073,6 +17314,7 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
17073
17314
  perf,
17074
17315
  error: failure.message,
17075
17316
  diagnostics: diagnostics.length > 0 ? diagnostics : void 0,
17317
+ pageErrorLines: session ? pageErrorLinesOf(session) : void 0,
17076
17318
  failure
17077
17319
  };
17078
17320
  } finally {
@@ -17089,6 +17331,9 @@ function isPoolFatalWorkerFailure(failure, streaming) {
17089
17331
  if (streaming) return failure.kind !== "cancelled";
17090
17332
  return isFatalCaptureFailure(failure);
17091
17333
  }
17334
+ function pageErrorLinesOf(session) {
17335
+ return session.browserConsoleBuffer.filter((line) => line.includes("PAGEERROR"));
17336
+ }
17092
17337
  function createPoolFailureHandler(args) {
17093
17338
  let firstFatalFailure;
17094
17339
  return {
@@ -17180,7 +17425,8 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
17180
17425
  kind: representative?.kind ?? "io",
17181
17426
  message: `[Parallel] Capture failed: ${errorMessages}`,
17182
17427
  cause: representative,
17183
- workerDiagnostics
17428
+ workerDiagnostics,
17429
+ pageErrorLines: [...new Set(results.flatMap((result) => result.pageErrorLines ?? []))]
17184
17430
  });
17185
17431
  }
17186
17432
  return results;
@@ -17198,7 +17444,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
17198
17444
  const sourcePath = join16(task.outputDir, file);
17199
17445
  const targetPath = join16(outputDir, file);
17200
17446
  try {
17201
- await rename(sourcePath, targetPath);
17447
+ await renameWithRetryAsync(sourcePath, targetPath);
17202
17448
  } catch {
17203
17449
  await copyFile(sourcePath, targetPath);
17204
17450
  }
@@ -17300,11 +17546,11 @@ function createFileServer(options) {
17300
17546
  headers: { "Content-Type": contentType }
17301
17547
  });
17302
17548
  });
17303
- return new Promise((resolve) => {
17549
+ return new Promise((resolve2) => {
17304
17550
  const server = serve({ fetch: app.fetch, port }, (info) => {
17305
17551
  const actualPort = info.port;
17306
17552
  const url = `http://localhost:${actualPort}`;
17307
- resolve({
17553
+ resolve2({
17308
17554
  url,
17309
17555
  port: actualPort,
17310
17556
  close: () => server.close()
@@ -17607,7 +17853,7 @@ async function launchHdrBrowser(width, height) {
17607
17853
  ...sigintLaunchOptions(),
17608
17854
  headless: false,
17609
17855
  executablePath: chromePath,
17610
- args: buildHdrChromeArgs(width, height)
17856
+ args: withHyperframesBrowserMarker(buildHdrChromeArgs(width, height))
17611
17857
  });
17612
17858
  const page = await browser.newPage();
17613
17859
  await page.setViewport({ width, height });
@@ -17747,6 +17993,10 @@ export {
17747
17993
  describeFfmpegFailure,
17748
17994
  runFfmpeg,
17749
17995
  declareContentAddressedUrl,
17996
+ declareProbeFactsUrl,
17997
+ PROBE_FACTS_VERSION,
17998
+ buildProbeFactsText,
17999
+ resolvePlayableVideoDuration,
17750
18000
  probeMediaProfile,
17751
18001
  extractMediaMetadata,
17752
18002
  extractFinalVideoFrameTimestamp,
@@ -17785,6 +18035,8 @@ export {
17785
18035
  fetchPublicHttpsText,
17786
18036
  downloadToTemp,
17787
18037
  isHttpUrl,
18038
+ renameWithRetry,
18039
+ renameWithRetryAsync,
17788
18040
  directorySizeBytes,
17789
18041
  gcExtractionCache,
17790
18042
  VIDEO_FRAME_FORMATS,
@@ -17799,7 +18051,6 @@ export {
17799
18051
  parseVideoElements,
17800
18052
  parseImageElements,
17801
18053
  extractVideoFramesRange,
17802
- resolvePlayableVideoDuration,
17803
18054
  isVideoPastTimelineEnd,
17804
18055
  rebaseVideoToWindow,
17805
18056
  resolveTimelineExtractionWindow,
@@ -17828,6 +18079,7 @@ export {
17828
18079
  audioFailureDiagnostics,
17829
18080
  MIXED_AUDIO_FILENAME,
17830
18081
  parseMasterFxChain,
18082
+ videoAudioId,
17831
18083
  parseAudioElements,
17832
18084
  processCompositionAudio,
17833
18085
  psnrDb,