hyperframes 0.8.176 → 0.8.178

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 (175) hide show
  1. package/bin/hyperframes.mjs +3 -0
  2. package/dist/{add-YZGUHLDP.js → add-C4GN5ZDP.js} +12 -12
  3. package/dist/{animatedGifPrep-6SPYXSHE.js → animatedGifPrep-S6XXOOXK.js} +7 -7
  4. package/dist/api.d.ts +2 -0
  5. package/dist/api.js +15 -15
  6. package/dist/{asset-YPC34MTV.js → asset-WTZ44Q7G.js} +2 -2
  7. package/dist/{assetCataloger-5GGNQC3Y.js → assetCataloger-MSAMR77T.js} +7 -7
  8. package/dist/{audio-33JHU37L.js → audio-ZSWOKO3D.js} +14 -14
  9. package/dist/{auth-UUIHOS2D.js → auth-EUSWPXME.js} +1 -1
  10. package/dist/{autoUpdate-F747BE3R.js → autoUpdate-WWXRJ2W7.js} +2 -2
  11. package/dist/{backgroundChecks-3YLO2CSC.js → backgroundChecks-B2IJHAP6.js} +3 -3
  12. package/dist/backgroundChecksWorker.js +3 -3
  13. package/dist/{batchRender-KXXTVNPB.js → batchRender-OOQYGH5A.js} +4 -4
  14. package/dist/{beats-DQDV2ZFS.js → beats-OJT75KQY.js} +5 -5
  15. package/dist/{benchmark-ZPPZEIHZ.js → benchmark-EZTB4ITW.js} +9 -9
  16. package/dist/{browser-ZFLEP3E6.js → browser-DNHBS5C7.js} +9 -8
  17. package/dist/{bundleWithLocalizedFonts-PMRGOQWD.js → bundleWithLocalizedFonts-GJAML42J.js} +2 -2
  18. package/dist/{capture-6XCCIPT4.js → capture-YRS6SZ6B.js} +11 -11
  19. package/dist/{capture-5OW6VNXU.js → capture-ZBGAJYVH.js} +2 -2
  20. package/dist/captureCompositionFrame-Z33NWUED.js +88 -0
  21. package/dist/{catalog-3A6KKCWF.js → catalog-YF23PXV2.js} +25 -17
  22. package/dist/{catch-up-KPGCLN4C.js → catch-up-YZZDUDRQ.js} +5 -5
  23. package/dist/{check-I3XLXS77.js → check-NVGQ5PMF.js} +60 -49
  24. package/dist/{checkBrowser-KX7LNAFA.js → checkBrowser-JX22QQDH.js} +79 -59
  25. package/dist/{chunk-42T7OP4O.js → chunk-32GKQ73S.js} +1 -1
  26. package/dist/{chunk-3Q4Y33FT.js → chunk-3EJYUZHW.js} +20 -18
  27. package/dist/{chunk-L6XT6GSV.js → chunk-52L2L46Q.js} +1 -1
  28. package/dist/chunk-537IYAEE.js +80 -0
  29. package/dist/{chunk-USEUH5VV.js → chunk-5PK3RLSB.js} +2 -2
  30. package/dist/{chunk-GVIH4ZQY.js → chunk-5RS2FIZU.js} +1 -1
  31. package/dist/{chunk-VER46LXI.js → chunk-62OXHKLS.js} +2 -2
  32. package/dist/{chunk-T76PLPD6.js → chunk-634HSJ3J.js} +2 -1
  33. package/dist/{chunk-HVMHVW5G.js → chunk-74Z2T3YM.js} +1 -1
  34. package/dist/{chunk-5TGVURKQ.js → chunk-7IAVKLNC.js} +1 -1
  35. package/dist/{chunk-L3LJVYXS.js → chunk-A2BB2XQU.js} +2 -2
  36. package/dist/{chunk-DQY6WTF7.js → chunk-A3RUVTGB.js} +1 -1
  37. package/dist/{chunk-OYEDHVSI.js → chunk-AFKVI7FJ.js} +1 -1
  38. package/dist/{chunk-VEQ7DKPG.js → chunk-AHS5QYKF.js} +1 -1
  39. package/dist/{chunk-FFDC5OWV.js → chunk-ALVXFXUG.js} +5 -3
  40. package/dist/{chunk-OMUKSCWE.js → chunk-AR5MS234.js} +13 -13
  41. package/dist/{chunk-R2TVJ4DW.js → chunk-AYEWZYYC.js} +1 -1
  42. package/dist/{chunk-TNDNFZOK.js → chunk-BGKZ37BC.js} +2 -2
  43. package/dist/{chunk-LY2GLSOS.js → chunk-BJJ3QF7T.js} +1 -1
  44. package/dist/{chunk-5EA4C6RA.js → chunk-BNGRVR3Y.js} +6 -6
  45. package/dist/{chunk-EEVCXPUA.js → chunk-C4FH67KI.js} +2 -2
  46. package/dist/{chunk-MG66UO4N.js → chunk-CJRGV2JW.js} +1 -1
  47. package/dist/{chunk-7LU4ZHYV.js → chunk-DKGZR7QA.js} +1 -1
  48. package/dist/{chunk-XRKMITSS.js → chunk-E24HSMZV.js} +12 -51
  49. package/dist/{chunk-44XBAKKT.js → chunk-EBKIF46T.js} +2 -2
  50. package/dist/{chunk-RBOVQRMR.js → chunk-EINNFZAW.js} +7 -13
  51. package/dist/{chunk-EOOEC32M.js → chunk-EVMY7IPL.js} +22 -0
  52. package/dist/{chunk-PL4WM5XE.js → chunk-FIAQ4J45.js} +2 -2
  53. package/dist/{chunk-J53AJK3Q.js → chunk-FTWOVWHR.js} +2 -2
  54. package/dist/{chunk-X6ZRZWPZ.js → chunk-G3M4BIFN.js} +1 -1
  55. package/dist/{chunk-VDUTZXIJ.js → chunk-HFUMZZ4T.js} +5 -5
  56. package/dist/{chunk-MDTMWUJI.js → chunk-HNMRB77F.js} +1 -1
  57. package/dist/{chunk-GMJ3ILLW.js → chunk-ICMXC3MI.js} +7 -24
  58. package/dist/{chunk-LZT3NUTE.js → chunk-IE6O2VXV.js} +1 -1
  59. package/dist/{chunk-HTC3VGU3.js → chunk-J4GE3BCG.js} +29 -10
  60. package/dist/{chunk-X4PK5ZXP.js → chunk-LO4DHZLH.js} +3 -3
  61. package/dist/{chunk-NGRNAF5X.js → chunk-N66NVE65.js} +1 -1
  62. package/dist/{chunk-7XX4QGQV.js → chunk-N6S6V2DY.js} +52 -16
  63. package/dist/{chunk-LEILKM2N.js → chunk-O7PFPCQF.js} +193 -65
  64. package/dist/{chunk-KUOUUG33.js → chunk-ORM7SJ7K.js} +85 -43
  65. package/dist/chunk-PLNQW2C6.js +3805 -0
  66. package/dist/{chunk-JNL3RMDG.js → chunk-PU33GPG4.js} +1 -1
  67. package/dist/{chunk-W47D3KOB.js → chunk-RHWJKSGH.js} +1 -1
  68. package/dist/{chunk-B7DJQFAC.js → chunk-RTABHL2G.js} +3 -3
  69. package/dist/{chunk-K535ASAM.js → chunk-TINAVSGR.js} +1 -1
  70. package/dist/{chunk-C6TPGUWD.js → chunk-TTVHYD5R.js} +2 -2
  71. package/dist/{chunk-GOOB64LO.js → chunk-U2AIXPAQ.js} +2 -2
  72. package/dist/{chunk-BVXZYFAL.js → chunk-UIXHQ4QG.js} +7 -7
  73. package/dist/{chunk-QWCXGTOH.js → chunk-UOHQV6AV.js} +24 -12
  74. package/dist/{chunk-SURF34CK.js → chunk-UQEBSY5U.js} +1 -1
  75. package/dist/{chunk-5ZSLJXQX.js → chunk-UWPUEI5U.js} +2 -2
  76. package/dist/{chunk-BTCHRQNV.js → chunk-V6WIQWUB.js} +3 -3
  77. package/dist/{chunk-OUMYTLPP.js → chunk-VCDWVVDV.js} +11 -7
  78. package/dist/{chunk-YWSXFFO3.js → chunk-VU4JLRNH.js} +156 -76
  79. package/dist/{chunk-MLRCTTSD.js → chunk-XBZOYP4D.js} +96 -11
  80. package/dist/{chunk-X6HYBA4A.js → chunk-XSQWXUK2.js} +1 -1
  81. package/dist/{chunk-SSE6NWZI.js → chunk-Y6JLEN3P.js} +14 -14
  82. package/dist/{chunk-KRKSY2AE.js → chunk-YAPJOCSH.js} +1 -1
  83. package/dist/{chunk-NWEER3QY.js → chunk-YH7VQAKX.js} +2 -2
  84. package/dist/{chunk-DZMWNCHM.js → chunk-ZAJO3YCQ.js} +2 -2
  85. package/dist/{chunk-T6NA6TR3.js → chunk-ZAO7FTQM.js} +2 -2
  86. package/dist/{clean-6REGQY3I.js → clean-ODNP4ELD.js} +23 -23
  87. package/dist/cli.js +53 -53
  88. package/dist/{cloud-RAQZPMNP.js → cloud-2DACBBEP.js} +4 -4
  89. package/dist/{cloudrun-P35BPQCO.js → cloudrun-QSVGI2TT.js} +5 -5
  90. package/dist/commands/contrast-audit.browser.js +166 -22
  91. package/dist/{compare-XYFSHHMQ.js → compare-HMMGOM4F.js} +34 -34
  92. package/dist/{compiler-5TFPJPQQ.js → compiler-CQ6OKYT5.js} +2 -2
  93. package/dist/{component-CRAO6Q2E.js → component-C6OLXSIK.js} +3 -3
  94. package/dist/{compositions-4SHILZZX.js → compositions-MOGZ4ASK.js} +11 -11
  95. package/dist/{delete-ZS4AHMTY.js → delete-MDAYHORQ.js} +2 -2
  96. package/dist/{dist-U2HCECNB.js → dist-MHJYD5IZ.js} +6 -4
  97. package/dist/{doctor-OL4FYABY.js → doctor-VEKKYMQT.js} +12 -12
  98. package/dist/{events-Z3XZCRFZ.js → events-CSKJXRJU.js} +4 -4
  99. package/dist/{events-LIJBGTTX.js → events-SKMTX6HF.js} +2 -2
  100. package/dist/{feedback-OE6SB2VE.js → feedback-64AKUFHZ.js} +7 -7
  101. package/dist/{ffmpeg-CSJLJAQ3.js → ffmpeg-64E4VH6W.js} +7 -7
  102. package/dist/{figma-DMUCMO67.js → figma-YEY76ZPG.js} +3 -3
  103. package/dist/fontLocalizeCli.js +10 -10
  104. package/dist/{get-NQOQVUI5.js → get-YJS76PGZ.js} +2 -2
  105. package/dist/{gpuPolicy-C6JWEX7F.js → gpuPolicy-IGZOHHMX.js} +7 -7
  106. package/dist/{grade-compare-HLTHHQGH.js → grade-compare-35UEA52Z.js} +35 -35
  107. package/dist/{help-ZAXWHAYF.js → help-I5TCDUVH.js} +1 -1
  108. package/dist/{history-CMY7ZEEW.js → history-7BKIWSP2.js} +11 -11
  109. package/dist/hyperframe-runtime.js +57 -55
  110. package/dist/hyperframe.manifest.json +1 -1
  111. package/dist/hyperframe.runtime.iife.js +57 -55
  112. package/dist/hyperframes-player.global.js +1 -1
  113. package/dist/{info-STR7EYI3.js → info-UEPOM2LV.js} +8 -8
  114. package/dist/{init-YSMKK5VG.js → init-HIB66K2S.js} +27 -27
  115. package/dist/{inspect-QV6DC6GO.js → inspect-634XIKDS.js} +33 -33
  116. package/dist/{installer-NY5E5HCO.js → installer-ADKWK4I4.js} +5 -5
  117. package/dist/{keyframes-HN3DW5FG.js → keyframes-7BJX3EVE.js} +7 -7
  118. package/dist/{lambda-PG3JKNWS.js → lambda-Q4TRSMHZ.js} +8 -8
  119. package/dist/{layout-O4QAR2XY.js → layout-6DUVSHEB.js} +33 -33
  120. package/dist/{lint-AY55R4UR.js → lint-UPFD4JQZ.js} +7 -7
  121. package/dist/{list-TH2KCVNN.js → list-M6OMQXJX.js} +2 -2
  122. package/dist/{login-TRCMRV4B.js → login-QH6JDXDP.js} +4 -4
  123. package/dist/{manager-2J4XGDZ3.js → manager-B4MSVFMK.js} +12 -10
  124. package/dist/{manager-HEUPD2YB.js → manager-V2QCCPOJ.js} +4 -3
  125. package/dist/{media-treatment-ET5QQSWP.js → media-treatment-SHFTIG4K.js} +14 -14
  126. package/dist/{models-RFUUSCG6.js → models-USEFHJFY.js} +11 -11
  127. package/dist/{motionShot-2ET565ZV.js → motionShot-HRM6NMT4.js} +15 -15
  128. package/dist/{normalize-audio-LUOJSD3W.js → normalize-audio-EP3HPQZB.js} +9 -9
  129. package/dist/{open-MVEOYQRQ.js → open-HXZEXQ4X.js} +12 -12
  130. package/dist/{parakeetRunner-3TG7EHWA.js → parakeetRunner-D5RSHQB2.js} +12 -12
  131. package/dist/{pipeline-JWGTH2BJ.js → pipeline-BDG52SPL.js} +8 -8
  132. package/dist/{play-I3WJPYXK.js → play-LSRQ6R66.js} +24 -24
  133. package/dist/{preflight-4WTT4D5X.js → preflight-GBPRLIM6.js} +9 -9
  134. package/dist/{present-DUZBKUYH.js → present-2VKAE63Q.js} +19 -19
  135. package/dist/{preview-7J5TBTRP.js → preview-MWH5CHTN.js} +18 -18
  136. package/dist/{producer-UZZQX6IJ.js → producer-W24FRIN7.js} +1 -1
  137. package/dist/{projectConfig-HDALEM6S.js → projectConfig-NQQDEDAK.js} +7 -7
  138. package/dist/{publication-NX4VC7UU.js → publication-7DW4IJPC.js} +3 -3
  139. package/dist/{publish-AZRRQUXM.js → publish-FJKJ74IF.js} +10 -10
  140. package/dist/{remove-background-OX5WZTXY.js → remove-background-JBOJAUIM.js} +9 -9
  141. package/dist/{render-HGT3EGIK.js → render-5TTZDI5N.js} +7 -14
  142. package/dist/{render-IYTGM6DE.js → render-BROS2AIU.js} +9 -9
  143. package/dist/{render-JUS2ROIN.js → render-JCYFNDWT.js} +42 -42
  144. package/dist/{render-batch-MUCDZ2WF.js → render-batch-FW56ZFGW.js} +8 -17
  145. package/dist/renderSetupWorker.js +2 -2
  146. package/dist/{resolver-FLQ42X2Y.js → resolver-UW6NYBJA.js} +5 -5
  147. package/dist/{sherpa-PRI3JLUP.js → sherpa-GWYCXYEP.js} +11 -11
  148. package/dist/skills/media-use/references/operations.md +3 -1
  149. package/dist/{skills-CZ6VW5SZ.js → skills-YNM5SIHQ.js} +6 -6
  150. package/dist/{skillsUpdateCheck-K4UKUAOC.js → skillsUpdateCheck-FNC6VALY.js} +3 -3
  151. package/dist/{snapshot-MPE4GIMJ.js → snapshot-6EMEL4O3.js} +44 -44
  152. package/dist/{src-SGPA7DM7.js → src-VUIKXEFU.js} +9 -9
  153. package/dist/{src-JGPFLYBL.js → src-XRFOS5LP.js} +6 -6
  154. package/dist/{staticProjectServer-DG4VZO4G.js → staticProjectServer-COEAKTGH.js} +17 -17
  155. package/dist/studio/assets/{hyperframes-player-DBHpVw8L.js → hyperframes-player-Dfw61RJK.js} +1 -1
  156. package/dist/studio/assets/{index-BkDF4Z-5.js → index-Bi6yVTq9.js} +118 -117
  157. package/dist/studio/assets/{index-DHRXpmtI.js → index-eTRj5rY2.js} +1 -1
  158. package/dist/studio/index.html +1 -1
  159. package/dist/{studio-api-RGNBVLLL.js → studio-api-455XWQPD.js} +12 -12
  160. package/dist/{studioServer-FWACRD3Y.js → studioServer-ZP2LJT7H.js} +57 -72
  161. package/dist/{telemetry-CHJA5JFQ.js → telemetry-HJQ7IO6R.js} +4 -4
  162. package/dist/{timeline-TZDMQBSM.js → timeline-CYW3YKMX.js} +23 -23
  163. package/dist/{tokens-B5KI7FBA.js → tokens-VOARLAAH.js} +2 -2
  164. package/dist/{transcribe-M7NO6XBP.js → transcribe-F6UOG57Z.js} +12 -12
  165. package/dist/{transcribe-VHUDXZET.js → transcribe-FJGNOR6R.js} +17 -16
  166. package/dist/{updateCheck-NMD6AFFG.js → updateCheck-IOLCO3XV.js} +2 -2
  167. package/dist/{upgrade-WGFMGJ5O.js → upgrade-BVW67SB7.js} +2 -2
  168. package/dist/{urlDownloader-FZ5ISJES.js → urlDownloader-QF7EBQC2.js} +6 -6
  169. package/dist/{validate-NM3GLUWX.js → validate-3NHIT4VT.js} +25 -25
  170. package/dist/{video-7CDAIWYC.js → video-2KGC3RIQ.js} +7 -7
  171. package/package.json +1 -2
  172. package/dist/chunk-EEXE43II.js +0 -3805
  173. package/dist/chunk-TWWSYAKJ.js +0 -24
  174. package/dist/{deploy-NKWMPAMH.js → deploy-3TTQZGTF.js} +4 -4
  175. package/dist/{destroy-UKP522AE.js → destroy-BEL232I5.js} +3 -3
@@ -8,8 +8,9 @@ import {
8
8
  parseEncoderOptions
9
9
  } from "./chunk-KLIKCX6Q.js";
10
10
  import {
11
+ RENDER_TEMP_DIR,
11
12
  createStudioPositionSeekReapplyScript
12
- } from "./chunk-EOOEC32M.js";
13
+ } from "./chunk-EVMY7IPL.js";
13
14
  import {
14
15
  GENERIC_FAMILIES,
15
16
  collectFontFamilyCustomProperties,
@@ -22,7 +23,7 @@ import {
22
23
  EncoderInterruptedError,
23
24
  encoderFailureError,
24
25
  prepareAnimatedGifInputs
25
- } from "./chunk-PL4WM5XE.js";
26
+ } from "./chunk-FIAQ4J45.js";
26
27
  import {
27
28
  BROWSER_GPU_NOT_SOFTWARE,
28
29
  CaptureFailure,
@@ -151,7 +152,7 @@ import {
151
152
  validateEngineConfigSnapshot,
152
153
  verifyDiskDrawElementSamples,
153
154
  writeCapturedFrame
154
- } from "./chunk-YWSXFFO3.js";
155
+ } from "./chunk-VU4JLRNH.js";
155
156
  import {
156
157
  assignBundledRuntimeCompositionIds,
157
158
  buildVariablesByCompScript,
@@ -164,7 +165,7 @@ import {
164
165
  isTemplateEntry,
165
166
  parsesAsScript,
166
167
  prepareFlattenedInnerRoot
167
- } from "./chunk-JNL3RMDG.js";
168
+ } from "./chunk-PU33GPG4.js";
168
169
  import {
169
170
  LOW_MEMORY_TOTAL_MB_THRESHOLD,
170
171
  getCgroupMemoryLimitMb,
@@ -190,7 +191,7 @@ import {
190
191
  resolveAbsoluteMediaStartSeconds,
191
192
  resolveAuthoredTimingWindow,
192
193
  toFps
193
- } from "./chunk-VEQ7DKPG.js";
194
+ } from "./chunk-AHS5QYKF.js";
194
195
  import {
195
196
  COMPOSITION_SOURCE_URL,
196
197
  HF_COLOR_GRADING_ATTR,
@@ -218,7 +219,7 @@ import {
218
219
  shouldClampResolvedMediaDuration,
219
220
  sourceTimeAt,
220
221
  styleElementsFor
221
- } from "./chunk-EEXE43II.js";
222
+ } from "./chunk-PLNQW2C6.js";
222
223
  import {
223
224
  MAX_AUDIO_GAIN
224
225
  } from "./chunk-UJKQWGFF.js";
@@ -236,10 +237,10 @@ import {
236
237
  import {
237
238
  redactKnownPaths,
238
239
  redactTelemetryString
239
- } from "./chunk-T76PLPD6.js";
240
+ } from "./chunk-634HSJ3J.js";
240
241
  import {
241
242
  chromeMajorCeiling
242
- } from "./chunk-TWWSYAKJ.js";
243
+ } from "./chunk-537IYAEE.js";
243
244
  import {
244
245
  lintHyperframeHtml
245
246
  } from "./chunk-GK2FIKIQ.js";
@@ -1582,7 +1583,6 @@ import { hostname, uptime } from "os";
1582
1583
  import { dirname as dirname3, join as join4 } from "path";
1583
1584
  var OWNER_FILE = "owner.json";
1584
1585
  var TRANSACTION_BACKUP = "backup";
1585
- var RENDER_TEMP_DIR = /^(work-[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}|hf-render|\..+\.hf-transaction)-[A-Za-z0-9]{6}$/;
1586
1586
  var RENDER_JOB_DIR = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/;
1587
1587
  function pidScope() {
1588
1588
  const attempt = (read) => {
@@ -5756,7 +5756,7 @@ function detectShaderTransitionUsage(html) {
5756
5756
  }
5757
5757
  return false;
5758
5758
  }
5759
- async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, downloadDir, tagName, elementIdentity, log) {
5759
+ async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, downloadDir, tagName, elementIdentity, log, urlByAbsentLocalPath) {
5760
5760
  let filePath = src;
5761
5761
  if (isHttpUrl(src)) {
5762
5762
  if (!existsSync9(downloadDir)) mkdirSync5(downloadDir, { recursive: true });
@@ -5770,8 +5770,9 @@ async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, down
5770
5770
  } else {
5771
5771
  filePath = decodedUrlPath(src);
5772
5772
  if (!filePath.startsWith("/")) filePath = join12(baseDir, filePath);
5773
+ filePath = urlByAbsentLocalPath?.get(filePath) ?? filePath;
5773
5774
  }
5774
- if (!existsSync9(filePath)) {
5775
+ if (!isHttpUrl(filePath) && !existsSync9(filePath)) {
5775
5776
  return { duration: null, resolvedPath: filePath };
5776
5777
  }
5777
5778
  const withSrcContext = (error) => {
@@ -5834,7 +5835,7 @@ function markInferredVariableMediaDurations(html, unresolvedMedia) {
5834
5835
  }
5835
5836
  return changed ? document2.toString() : html;
5836
5837
  }
5837
- async function compileHtmlFile(html, baseDir, downloadDir, log) {
5838
+ async function compileHtmlFile(html, baseDir, downloadDir, log, urlByAbsentLocalPath) {
5838
5839
  const { html: staticCompiled, unresolved } = compileTimingAttrs(html);
5839
5840
  const mediaUnresolved = unresolved.filter(
5840
5841
  (el) => (el.tagName === "video" || el.tagName === "audio") && el.src
@@ -5850,7 +5851,8 @@ async function compileHtmlFile(html, baseDir, downloadDir, log) {
5850
5851
  downloadDir,
5851
5852
  el.tagName,
5852
5853
  el.id,
5853
- log
5854
+ log,
5855
+ urlByAbsentLocalPath
5854
5856
  ).then(({ duration }) => ({ id: el.id, duration }))
5855
5857
  )
5856
5858
  );
@@ -5892,7 +5894,7 @@ async function compileHtmlFile(html, baseDir, downloadDir, log) {
5892
5894
  compiledHtml = compiledHtml.replace(/(<audio\b[^>]*)\s+crossorigin(?:=["'][^"']*["'])?/gi, "$1");
5893
5895
  return { html: compiledHtml, unresolvedCompositions };
5894
5896
  }
5895
- async function parseSubCompositions(html, projectDir, downloadDir, visited = /* @__PURE__ */ new Set()) {
5897
+ async function parseSubCompositions(html, projectDir, downloadDir, visited = /* @__PURE__ */ new Set(), urlByAbsentLocalPath) {
5896
5898
  const subCompositions = /* @__PURE__ */ new Map();
5897
5899
  const { document: document2 } = parseHTML(html);
5898
5900
  const compEls = document2.querySelectorAll("[data-composition-src]");
@@ -5918,13 +5920,16 @@ async function parseSubCompositions(html, projectDir, downloadDir, visited = /*
5918
5920
  const { html: compiledSub } = await compileHtmlFile(
5919
5921
  item.rawSubHtml,
5920
5922
  dirname5(item.filePath),
5921
- downloadDir
5923
+ downloadDir,
5924
+ void 0,
5925
+ urlByAbsentLocalPath
5922
5926
  );
5923
5927
  const nested = await parseSubCompositions(
5924
5928
  compiledSub,
5925
5929
  projectDir,
5926
5930
  downloadDir,
5927
- item.nestedVisited
5931
+ item.nestedVisited,
5932
+ urlByAbsentLocalPath
5928
5933
  );
5929
5934
  return {
5930
5935
  srcPath: item.srcPath,
@@ -6682,9 +6687,16 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
6682
6687
  rawHtml,
6683
6688
  projectDir,
6684
6689
  downloadDir,
6685
- options.log
6690
+ options.log,
6691
+ options.urlByAbsentLocalPath
6692
+ );
6693
+ const { subCompositions } = await parseSubCompositions(
6694
+ compiledHtml,
6695
+ projectDir,
6696
+ downloadDir,
6697
+ void 0,
6698
+ options.urlByAbsentLocalPath
6686
6699
  );
6687
- const { subCompositions } = await parseSubCompositions(compiledHtml, projectDir, downloadDir);
6688
6700
  const fullHtml = ensureFullDocument(compiledHtml);
6689
6701
  const inlinedHtml = inlineSubCompositions2(
6690
6702
  fullHtml,
@@ -7180,6 +7192,7 @@ async function runCompileStage(input) {
7180
7192
  allowSystemFontCapture,
7181
7193
  abortSignal,
7182
7194
  variables: input.variables,
7195
+ urlByAbsentLocalPath: input.urlByAbsentLocalPath,
7183
7196
  animatedGifCacheDir: cfg.extractCacheDir ? join13(cfg.extractCacheDir, "animated-gif") : void 0,
7184
7197
  ffmpegProcessTimeout: cfg.ffmpegProcessTimeout
7185
7198
  });
@@ -8148,7 +8161,8 @@ async function runExtractVideosStage(input) {
8148
8161
  abortSignal,
8149
8162
  assertNotAborted,
8150
8163
  materializeSymlinks,
8151
- deferRangeExtraction
8164
+ deferRangeExtraction,
8165
+ urlByAbsentLocalPath
8152
8166
  } = input;
8153
8167
  const stage2Start = Date.now();
8154
8168
  const extractionPolicy = resolveVideoExtractionPolicy();
@@ -8242,7 +8256,8 @@ async function runExtractVideosStage(input) {
8242
8256
  maxTransientRetries: extractionPolicy.maxTransientRetries,
8243
8257
  collectProbeFailures: extractionPolicy.failureMode === "enforce",
8244
8258
  deferRangeExtraction,
8245
- contentKeyedDirs: [join15(compiledDir, REMOTE_MEDIA_SUBDIR)]
8259
+ contentKeyedDirs: [join15(compiledDir, REMOTE_MEDIA_SUBDIR)],
8260
+ urlByAbsentLocalPath
8246
8261
  },
8247
8262
  abortSignal,
8248
8263
  cfg,
@@ -8320,6 +8335,7 @@ async function runAudioStage(input) {
8320
8335
  audioGain,
8321
8336
  audios,
8322
8337
  masterFxChain,
8338
+ urlByAbsentLocalPath,
8323
8339
  abortSignal,
8324
8340
  assertNotAborted,
8325
8341
  log
@@ -8339,7 +8355,7 @@ async function runAudioStage(input) {
8339
8355
  audioOutputPath,
8340
8356
  duration,
8341
8357
  abortSignal,
8342
- { ffmpegProcessTimeout, audioGain, masterFxChain },
8358
+ { ffmpegProcessTimeout, audioGain, masterFxChain, urlByAbsentLocalPath },
8343
8359
  compiledDir
8344
8360
  );
8345
8361
  } catch (err) {
@@ -13539,6 +13555,8 @@ function buildChunkCaptureOptions(input) {
13539
13555
  // The controller's snapshot, so the first capture sees the in-process renderer's `__hfVariables`.
13540
13556
  variables: encoder.variables,
13541
13557
  subTimelineWaitMemo: {},
13558
+ skipReadinessVideoIds: input.skipReadinessVideoIds,
13559
+ videoMetadataHints: input.videoMetadataHints,
13542
13560
  ...videoCaptureBeyondViewport !== void 0 ? { captureBeyondViewport: videoCaptureBeyondViewport } : {},
13543
13561
  // A fixed warmup count keeps `beginFrameTimeTicks` host-independent.
13544
13562
  lockWarmupTicks: true,
@@ -13547,6 +13565,19 @@ function buildChunkCaptureOptions(input) {
13547
13565
  }
13548
13566
  async function extractDeferredVideoFramesForChunk(input) {
13549
13567
  const deferred = input.planVideos.extracted.filter((video) => video.deferredRange);
13568
+ const remoteSources = input.remoteSources ?? {};
13569
+ for (const path of Object.keys(remoteSources)) {
13570
+ if (!deferred.some((video) => video.deferredRange.sourcePath === path)) {
13571
+ throw new RenderChunkValidationError(
13572
+ MISSING_PLAN_ARTIFACT,
13573
+ `[renderChunk] ${path} is read by URL but no deferred video uses it`
13574
+ );
13575
+ }
13576
+ defaultLogger.info("[renderChunk] reading video by URL", {
13577
+ path,
13578
+ url: remoteSources[path].split("?")[0]
13579
+ });
13580
+ }
13550
13581
  if (deferred.length === 0) return [];
13551
13582
  const table = createFrameLookupTable(
13552
13583
  input.planVideos.videos,
@@ -13574,8 +13605,9 @@ async function extractDeferredVideoFramesForChunk(input) {
13574
13605
  return { ...video, outputDir, framePaths: /* @__PURE__ */ new Map(), ownedByLookup: false };
13575
13606
  }
13576
13607
  const range = video.deferredRange;
13577
- const sourcePath = join27(input.planDir, ...range.sourcePath.split("/"));
13578
- if (!existsSync17(sourcePath)) {
13608
+ const remoteUrl = remoteSources[range.sourcePath];
13609
+ const sourcePath = remoteUrl ?? join27(input.planDir, ...range.sourcePath.split("/"));
13610
+ if (remoteUrl === void 0 && !existsSync17(sourcePath)) {
13579
13611
  throw new RenderChunkValidationError(
13580
13612
  MISSING_PLAN_ARTIFACT,
13581
13613
  `[renderChunk] planDir is missing the source for video ${JSON.stringify(video.videoId)}: ${range.sourcePath}`
@@ -13915,6 +13947,16 @@ function collectPlanAssetShas(planDir, digests) {
13915
13947
  }
13916
13948
  return { compositionHtml, assets };
13917
13949
  }
13950
+ var PLAN_REMOTE_FILES_RELATIVE_PATH = "meta/remote-files.json";
13951
+ function writePlanRemoteFiles(planDir, files) {
13952
+ if (files.length === 0) return;
13953
+ const sorted = [...files].sort((a, b) => a.path < b.path ? -1 : 1);
13954
+ writeFileSync6(join29(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
13955
+ }
13956
+ function readPlanRemoteFiles(planDir) {
13957
+ const path = join29(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
13958
+ return existsSync18(path) ? JSON.parse(readFileSync9(path, "utf-8")) : [];
13959
+ }
13918
13960
  function recomputePlanHashFromPlanDir(planDir, digests) {
13919
13961
  const planJsonPath = join29(planDir, "plan.json");
13920
13962
  const encoderJsonPath = join29(planDir, "meta", "encoder.json");
@@ -14496,7 +14538,7 @@ function createVideoSourceShipper(input) {
14496
14538
  let result = null;
14497
14539
  for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
14498
14540
  const rel = pathInside(root, srcPath);
14499
- if (rel !== null && existsSync19(join31(input.planDir, "compiled", rel))) {
14541
+ if (rel !== null && (existsSync19(join31(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
14500
14542
  result = ["compiled", ...rel.split(sep2)].join("/");
14501
14543
  break;
14502
14544
  }
@@ -14574,8 +14616,17 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
14574
14616
  logPlanStage(log, "copy", stageStarted);
14575
14617
  const finalCompiledDir = join31(planDir, "compiled");
14576
14618
  const needsAlpha = outputNeedsAlpha(config.format);
14619
+ const remoteFiles = Object.entries(options.remoteFiles ?? {});
14620
+ const remoteLocalPath = (rel) => join31(projectDir, ...rel.split("/"));
14621
+ const urlByAbsentLocalPath = new Map(
14622
+ remoteFiles.map(([rel, file]) => [remoteLocalPath(rel), file.url])
14623
+ );
14624
+ const localPathByUrl = new Map(
14625
+ remoteFiles.map(([rel, file]) => [file.url, remoteLocalPath(rel)])
14626
+ );
14577
14627
  stageStarted = Date.now();
14578
14628
  const compileResult = await runCompileStage({
14629
+ urlByAbsentLocalPath,
14579
14630
  projectDir,
14580
14631
  workDir,
14581
14632
  htmlPath,
@@ -14635,7 +14686,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
14635
14686
  if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
14636
14687
  if (probeResult.probeSession) {
14637
14688
  try {
14638
- const { closeCaptureSession: closeCaptureSession2 } = await import("./src-JGPFLYBL.js");
14689
+ const { closeCaptureSession: closeCaptureSession2 } = await import("./src-XRFOS5LP.js");
14639
14690
  await closeCaptureSession2(probeResult.probeSession);
14640
14691
  } catch (err) {
14641
14692
  log.warn("[plan] probe session close failed", {
@@ -14663,7 +14714,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
14663
14714
  abortSignal,
14664
14715
  assertNotAborted,
14665
14716
  materializeSymlinks: true,
14666
- deferRangeExtraction: options.deferVideoExtraction
14717
+ deferRangeExtraction: options.deferVideoExtraction,
14718
+ urlByAbsentLocalPath
14667
14719
  });
14668
14720
  logPlanStage(log, "extract", stageStarted);
14669
14721
  if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
@@ -14686,7 +14738,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
14686
14738
  planDir,
14687
14739
  projectDir,
14688
14740
  workCompiledDir: compiledDir,
14689
- workVideoFramesDir: stagedVideoFrames
14741
+ workVideoFramesDir: stagedVideoFrames,
14742
+ isRemote: (srcPath) => urlByAbsentLocalPath.has(srcPath)
14690
14743
  });
14691
14744
  const sourceRoots = [
14692
14745
  [stagedVideoFrames, "video-frames"],
@@ -14696,17 +14749,28 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
14696
14749
  const planVideosJson = buildPlanVideosJson({
14697
14750
  videos: composition.videos,
14698
14751
  compositionEnd: job.duration ?? Number.NaN,
14699
- extracted: (extractResult.extractionResult?.extracted ?? []).map((ext) => ({
14700
- videoId: ext.videoId,
14701
- srcPath: stableSourcePath(sourceRoots, ext.srcPath),
14702
- framePattern: ext.framePattern,
14703
- fps: ext.fps,
14704
- totalFrames: ext.totalFrames,
14705
- metadata: ext.metadata,
14706
- ...ext.deferredRange ? { deferredRange: { ...ext.deferredRange, sourcePath: shipVideoSource(ext.srcPath) } } : {}
14707
- }))
14752
+ extracted: (extractResult.extractionResult?.extracted ?? []).map((ext) => {
14753
+ const sourcePath = localPathByUrl.get(ext.srcPath) ?? ext.srcPath;
14754
+ return {
14755
+ videoId: ext.videoId,
14756
+ srcPath: stableSourcePath(sourceRoots, sourcePath),
14757
+ framePattern: ext.framePattern,
14758
+ fps: ext.fps,
14759
+ totalFrames: ext.totalFrames,
14760
+ metadata: ext.metadata,
14761
+ ...ext.deferredRange ? { deferredRange: { ...ext.deferredRange, sourcePath: shipVideoSource(sourcePath) } } : {}
14762
+ };
14763
+ })
14708
14764
  });
14709
14765
  mkdirSync10(join31(planDir, "meta"), { recursive: true });
14766
+ writePlanRemoteFiles(
14767
+ planDir,
14768
+ remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
14769
+ path: `compiled/${rel}`,
14770
+ sha256,
14771
+ sizeBytes
14772
+ }))
14773
+ );
14710
14774
  writeFileSync7(
14711
14775
  join31(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
14712
14776
  JSON.stringify(planVideosJson, null, 2),
@@ -14721,6 +14785,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
14721
14785
  projectDir,
14722
14786
  workDir,
14723
14787
  compiledDir: finalCompiledDir,
14788
+ urlByAbsentLocalPath,
14724
14789
  duration: audioSeconds,
14725
14790
  ffmpegProcessTimeout: cfg.ffmpegProcessTimeout,
14726
14791
  audioGain: cfg.audioGain,
@@ -16205,7 +16270,7 @@ function startServer(options = {}) {
16205
16270
  });
16206
16271
  async function shutdown(signal) {
16207
16272
  log.info(`Received ${signal}, shutting down`);
16208
- const { drainBrowserPool } = await import("./src-JGPFLYBL.js");
16273
+ const { drainBrowserPool } = await import("./src-XRFOS5LP.js");
16209
16274
  await drainBrowserPool().catch(() => {
16210
16275
  });
16211
16276
  const handle = await Promise.race([
@@ -16472,17 +16537,20 @@ function artifactTargets(path, videoDependencies, chunksCarryAudio2) {
16472
16537
  if (path === "plan.json" || path === "meta/chunks.json" || path === "meta/encoder.json") {
16473
16538
  return { chunks: "all", assembler: true };
16474
16539
  }
16475
- if (path === "meta/composition.json" || path === "meta/videos.json" || path.startsWith("compiled/")) {
16476
- return { chunks: "all", assembler: false };
16477
- }
16478
- if (path.startsWith("video-frames/") || path.startsWith("video-sources/")) {
16540
+ if (path.startsWith("video-frames/") || path.startsWith("video-sources/") || path.startsWith("compiled/") && videoDependencies?.has(path)) {
16479
16541
  return {
16480
16542
  chunks: videoDependencies === null ? "all" : videoDependencies.get(path) ?? [],
16481
16543
  assembler: false
16482
16544
  };
16483
16545
  }
16546
+ if (path === "meta/composition.json" || path === "meta/videos.json" || path.startsWith("compiled/")) {
16547
+ return { chunks: "all", assembler: false };
16548
+ }
16484
16549
  return { chunks: "all", assembler: true };
16485
16550
  }
16551
+ function isPlanV2DeferredSourceArtifact(artifact) {
16552
+ return artifact.path.startsWith("compiled/") && artifact.chunks !== "all";
16553
+ }
16486
16554
  function listVideoFramePaths(executionPlanDir, videos) {
16487
16555
  return videos.extracted.map((video) => {
16488
16556
  const outputDir = resolveExtractedVideoOutputDir(executionPlanDir, video.videoId);
@@ -16645,14 +16713,17 @@ function publishBlobFor(absolutePath, digests) {
16645
16713
  };
16646
16714
  }
16647
16715
  async function putBlobs(publisher, blobs) {
16716
+ await putTasks(blobs.map((blob) => () => publisher.putBlob(blob)));
16717
+ }
16718
+ async function putTasks(tasks) {
16648
16719
  const uploadSlots = 32;
16649
16720
  let next = 0;
16650
16721
  let failure;
16651
16722
  const upload = async () => {
16652
- while (!failure && next < blobs.length) {
16653
- const blob = blobs[next++];
16723
+ while (!failure && next < tasks.length) {
16724
+ const task = tasks[next++];
16654
16725
  try {
16655
- await publisher.putBlob(blob);
16726
+ await task();
16656
16727
  } catch (reason) {
16657
16728
  failure ??= { reason };
16658
16729
  }
@@ -16707,6 +16778,15 @@ function buildPlanV2Publication(executionPlanDir, digests) {
16707
16778
  ...targets
16708
16779
  });
16709
16780
  }
16781
+ const storedBlobs = /* @__PURE__ */ new Map();
16782
+ for (const remote of readPlanRemoteFiles(executionPlanDir)) {
16783
+ const { sha256, sizeBytes } = remote;
16784
+ if (!blobs.has(sha256)) storedBlobs.set(sha256, { sha256, sizeBytes });
16785
+ artifacts.push({
16786
+ ...remote,
16787
+ ...artifactTargets(remote.path, videoDependencyPlan.dependencies, chunksCarryAudio2)
16788
+ });
16789
+ }
16710
16790
  const base = {
16711
16791
  protocol: PLAN_PROTOCOL_V2,
16712
16792
  // Retain the established manifest key byte-for-byte. It now acts as the
@@ -16728,7 +16808,8 @@ function buildPlanV2Publication(executionPlanDir, digests) {
16728
16808
  ...base,
16729
16809
  planHash: computeManifestHash(base)
16730
16810
  },
16731
- blobs: [...blobs.values()]
16811
+ blobs: [...blobs.values()],
16812
+ storedBlobs: [...storedBlobs.values()]
16732
16813
  };
16733
16814
  }
16734
16815
  function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
@@ -16736,6 +16817,9 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
16736
16817
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
16737
16818
  }
16738
16819
  const publication = buildPlanV2Publication(executionPlanDir);
16820
+ if (publication.storedBlobs.length > 0) {
16821
+ throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
16822
+ }
16739
16823
  mkdirSync13(dirname14(planV2Dir), { recursive: true });
16740
16824
  const tempDir = mkdtempSync6(join37(dirname14(planV2Dir), ".plan-v2-build-"));
16741
16825
  try {
@@ -16765,8 +16849,14 @@ async function publishExecutionPlan(executionPlanDir, publisher, { digests, log
16765
16849
  let stageStarted = Date.now();
16766
16850
  const publication = buildPlanV2Publication(executionPlanDir, digests);
16767
16851
  logPlanStage(log, "publication", stageStarted);
16852
+ if (publication.storedBlobs.length > 0 && !publisher.referenceStoredBlob) {
16853
+ throw new PlanV2IntegrityError("this publisher cannot reference remote files");
16854
+ }
16768
16855
  stageStarted = Date.now();
16769
- await putBlobs(publisher, publication.blobs);
16856
+ await putTasks([
16857
+ ...publication.blobs.map((blob) => () => publisher.putBlob(blob)),
16858
+ ...publication.storedBlobs.map((blob) => () => publisher.referenceStoredBlob(blob))
16859
+ ]);
16770
16860
  logPlanStage(log, "upload", stageStarted);
16771
16861
  stageStarted = Date.now();
16772
16862
  await publisher.commitManifest(canonicalJsonStringify(publication.manifest));
@@ -16790,6 +16880,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
16790
16880
  await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
16791
16881
  executionPlanSizeLimitBytes: Number.MAX_SAFE_INTEGER,
16792
16882
  deferVideoExtraction: true,
16883
+ remoteFiles: options.remoteFiles,
16793
16884
  digests,
16794
16885
  // artifactTargets ships every compiled/ file to all chunks, so each is in the manifest.
16795
16886
  whileAudioMixes: () => putBlobs(
@@ -16992,14 +17083,16 @@ function verifyBlob(planV2Dir, artifact) {
16992
17083
  }
16993
17084
  return sourcePath;
16994
17085
  }
16995
- function materializePlanV2Target(planV2Dir, target, destinationDir) {
17086
+ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}) {
16996
17087
  if (existsSync24(destinationDir)) {
16997
17088
  throw new PlanV2IntegrityError(`materialization destination already exists: ${destinationDir}`);
16998
17089
  }
16999
17090
  const manifest = readPlanV2Manifest(planV2Dir);
17000
17091
  const artifacts = listPlanV2ArtifactsForTarget(manifest, target);
17092
+ const remoteSources = options.remoteSources ?? {};
17093
+ assertRemoteSources(remoteSources, artifacts);
17001
17094
  const audioArtifact = artifacts.find((artifact) => isPlanAudioArtifactPath(artifact.path));
17002
- const verified = artifacts.map((artifact) => ({
17095
+ const verified = artifacts.filter((artifact) => !Object.hasOwn(remoteSources, artifact.path)).map((artifact) => ({
17003
17096
  artifact,
17004
17097
  sourcePath: verifyBlob(planV2Dir, artifact)
17005
17098
  }));
@@ -17014,7 +17107,11 @@ function materializePlanV2Target(planV2Dir, target, destinationDir) {
17014
17107
  if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
17015
17108
  writeFileSync10(
17016
17109
  join37(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
17017
- canonicalJsonStringify({ manifest, target }),
17110
+ canonicalJsonStringify({
17111
+ manifest,
17112
+ target,
17113
+ ...Object.keys(remoteSources).length > 0 ? { remoteSources } : {}
17114
+ }),
17018
17115
  "utf-8"
17019
17116
  );
17020
17117
  renameSync6(tempDir, destinationDir);
@@ -17035,7 +17132,22 @@ function materializePlanV2Target(planV2Dir, target, destinationDir) {
17035
17132
  audioPath: target.role === "assembler" ? audioArtifact ? join37(destinationDir, audioArtifact.path) : null : null
17036
17133
  };
17037
17134
  }
17135
+ function assertRemoteSources(remoteSources, artifacts) {
17136
+ if (!isRecord3(remoteSources)) throw new PlanV2IntegrityError("remoteSources must be an object");
17137
+ for (const [path, url] of Object.entries(remoteSources)) {
17138
+ const artifact = artifacts.find((candidate) => candidate.path === path);
17139
+ if (!artifact || !isPlanV2DeferredSourceArtifact(artifact)) {
17140
+ throw new PlanV2IntegrityError(`remote source is not a selected deferred video: ${path}`);
17141
+ }
17142
+ if (typeof url !== "string" || !/^https?:\/\//.test(url)) {
17143
+ throw new PlanV2IntegrityError(`remote source for ${path} must be an http(s) URL`);
17144
+ }
17145
+ }
17146
+ }
17038
17147
  function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
17148
+ return readValidatedPlanV2Materialization(planDir, expectedTarget)?.manifest ?? null;
17149
+ }
17150
+ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
17039
17151
  const markerPath = join37(planDir, PLAN_V2_MATERIALIZATION_MARKER);
17040
17152
  if (!existsSync24(markerPath)) return null;
17041
17153
  const marker = readJsonFile(markerPath, "materialization marker");
@@ -17050,7 +17162,10 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
17050
17162
  }
17051
17163
  const manifest = parsePlanV2Manifest(marker.manifest);
17052
17164
  const required = listPlanV2ArtifactsForTarget(manifest, expectedTarget);
17165
+ const remoteSources = marker.remoteSources ?? {};
17166
+ assertRemoteSources(remoteSources, required);
17053
17167
  for (const artifact of required) {
17168
+ if (Object.hasOwn(remoteSources, artifact.path)) continue;
17054
17169
  const path = join37(planDir, ...artifact.path.split("/"));
17055
17170
  if (!existsSync24(path) || statSync9(path).size !== artifact.sizeBytes) {
17056
17171
  throw new PlanV2IntegrityError(
@@ -17061,7 +17176,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
17061
17176
  throw new PlanV2IntegrityError(`materialized artifact hash mismatch: ${artifact.path}`);
17062
17177
  }
17063
17178
  }
17064
- return manifest;
17179
+ return { manifest, remoteSources };
17065
17180
  }
17066
17181
 
17067
17182
  // ../producer/src/services/distributed/planV2Execution.ts
@@ -17909,10 +18024,12 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
17909
18024
  const plan2 = JSON.parse(readFileSync13(planJsonPath, "utf-8"));
17910
18025
  readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.chunk);
17911
18026
  const planHashStarted = Date.now();
17912
- const v2Manifest = validatePlanV2MaterializedTarget(planDir, {
18027
+ const v2Materialization = readValidatedPlanV2Materialization(planDir, {
17913
18028
  role: "chunk",
17914
18029
  chunkIndex
17915
18030
  });
18031
+ const v2Manifest = v2Materialization?.manifest ?? null;
18032
+ const remoteSources = v2Materialization?.remoteSources ?? {};
17916
18033
  for (const required of [encoderJsonPath, chunksJsonPath]) {
17917
18034
  if (!existsSync26(required)) {
17918
18035
  throw new RenderChunkValidationError(
@@ -18014,6 +18131,24 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
18014
18131
  const framesDir = join40(workDir, "captured-frames");
18015
18132
  mkdirSync16(framesDir, { recursive: true });
18016
18133
  const videoFramesDir = `${workDir}.video-frames`;
18134
+ const deferredVideoFrames = planVideos ? await extractDeferredVideoFramesForChunk({
18135
+ planDir,
18136
+ planVideos,
18137
+ frames: Array.from(
18138
+ { length: slice.endFrame - slice.startFrame },
18139
+ (_, i) => slice.startFrame + i
18140
+ ),
18141
+ fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
18142
+ outputRoot: videoFramesDir,
18143
+ cfg,
18144
+ remoteSources
18145
+ }) : [];
18146
+ const remoteVideoIds = new Set(
18147
+ planVideos?.extracted.filter(
18148
+ (video) => video.deferredRange && Object.hasOwn(remoteSources, video.deferredRange.sourcePath)
18149
+ ).map((video) => video.videoId)
18150
+ );
18151
+ const remoteVideos = deferredVideoFrames.filter((video) => remoteVideoIds.has(video.videoId));
18017
18152
  const videoFrameLookup = planVideos && planVideos.extracted.length > 0 ? createFrameLookupTable(
18018
18153
  planVideos.videos,
18019
18154
  [
@@ -18022,17 +18157,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
18022
18157
  planVideos.extracted.filter((video) => !video.deferredRange),
18023
18158
  v2Manifest === null ? "dense-v1" : "sparse-v2"
18024
18159
  ),
18025
- ...await extractDeferredVideoFramesForChunk({
18026
- planDir,
18027
- planVideos,
18028
- frames: Array.from(
18029
- { length: slice.endFrame - slice.startFrame },
18030
- (_, i) => slice.startFrame + i
18031
- ),
18032
- fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
18033
- outputRoot: videoFramesDir,
18034
- cfg
18035
- })
18160
+ ...deferredVideoFrames
18036
18161
  ],
18037
18162
  resolveRenderFpsConfig(job.config.fps).value
18038
18163
  ) : null;
@@ -18050,7 +18175,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
18050
18175
  dimensions: plan2.dimensions,
18051
18176
  encoder,
18052
18177
  videoCount: planVideos?.videos.length ?? 0,
18053
- html: readFileSync13(join40(compiledDir, "index.html"), "utf-8")
18178
+ html: readFileSync13(join40(compiledDir, "index.html"), "utf-8"),
18179
+ // The plan ships a deferred source only to chunks that show it; don't wait on the rest.
18180
+ skipReadinessVideoIds: deferredVideoFrames.filter((video) => video.framePaths.size === 0 || remoteVideoIds.has(video.videoId)).map((video) => video.videoId),
18181
+ videoMetadataHints: collectVideoMetadataHints(remoteVideos)
18054
18182
  });
18055
18183
  const chunkWorkerCount = calculateOptimalWorkers(framesInChunk, void 0, cfg);
18056
18184
  let session = null;
@@ -18369,9 +18497,9 @@ async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
18369
18497
  }
18370
18498
 
18371
18499
  // ../producer/src/services/distributed/projectHash.ts
18372
- import { readdirSync as readdirSync12, readFileSync as readFileSync14 } from "fs";
18500
+ import { readdirSync as readdirSync12, readFileSync as readFileSync14, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
18373
18501
  import { createHash as createHash7 } from "crypto";
18374
- import { join as join42, relative as relative8 } from "path";
18502
+ import { join as join42 } from "path";
18375
18503
 
18376
18504
  export {
18377
18505
  createConsoleLogger,