@osmo.inc/cli 0.1.15

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 (949) hide show
  1. package/DEPLOY.md +87 -0
  2. package/README.md +243 -0
  3. package/RELEASE.md +164 -0
  4. package/SETUP.md +60 -0
  5. package/THIRD_PARTY_NOTICES.md +18 -0
  6. package/bin/osmo.mjs +12 -0
  7. package/dist/osmo.js +7817 -0
  8. package/node_modules/@esbuild/darwin-arm64/README.md +3 -0
  9. package/node_modules/@esbuild/darwin-arm64/bin/esbuild +0 -0
  10. package/node_modules/@esbuild/darwin-arm64/package.json +20 -0
  11. package/node_modules/esbuild/LICENSE.md +21 -0
  12. package/node_modules/esbuild/README.md +3 -0
  13. package/node_modules/esbuild/bin/esbuild +223 -0
  14. package/node_modules/esbuild/install.js +289 -0
  15. package/node_modules/esbuild/lib/main.d.ts +716 -0
  16. package/node_modules/esbuild/lib/main.js +2532 -0
  17. package/node_modules/esbuild/package.json +49 -0
  18. package/node_modules/fflate/LICENSE +21 -0
  19. package/node_modules/fflate/esm/index.mjs +2710 -0
  20. package/node_modules/fflate/package.json +128 -0
  21. package/node_modules/typescript/LICENSE.txt +55 -0
  22. package/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  23. package/node_modules/typescript/lib/lib.d.ts +22 -0
  24. package/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  25. package/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  26. package/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  27. package/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  28. package/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  29. package/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  30. package/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  31. package/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  32. package/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  33. package/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  34. package/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  35. package/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  36. package/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  37. package/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  38. package/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  39. package/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  40. package/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  41. package/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  42. package/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  43. package/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  44. package/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  45. package/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  46. package/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  47. package/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  48. package/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  49. package/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  50. package/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  51. package/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  52. package/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  53. package/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  54. package/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  55. package/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  56. package/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  57. package/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  58. package/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  59. package/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  60. package/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  61. package/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  62. package/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  63. package/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  64. package/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  65. package/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  66. package/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  67. package/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  68. package/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  69. package/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  70. package/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  71. package/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  72. package/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  73. package/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  74. package/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  75. package/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  76. package/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  77. package/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  78. package/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  79. package/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  80. package/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  81. package/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  82. package/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  83. package/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  84. package/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  85. package/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  86. package/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  87. package/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  88. package/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  89. package/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  90. package/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  91. package/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  92. package/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  93. package/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  94. package/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  95. package/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  96. package/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  97. package/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  98. package/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  99. package/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  100. package/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  101. package/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  102. package/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  103. package/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  104. package/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  105. package/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  106. package/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  107. package/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  108. package/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  109. package/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  110. package/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  111. package/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  112. package/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
  113. package/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  114. package/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  115. package/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  116. package/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  117. package/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  118. package/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  119. package/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  120. package/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  121. package/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  122. package/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  123. package/node_modules/typescript/lib/typescript.js +382 -0
  124. package/node_modules/typescript/package.json +57 -0
  125. package/package.json +54 -0
  126. package/release.json +136 -0
  127. package/runtime/apps/native/tools/compile.mjs +217 -0
  128. package/runtime/packages/scene/scripts/validate-strict.mjs +246 -0
  129. package/runtime/packages/scene/src/clip.d.mts +14 -0
  130. package/runtime/packages/scene/src/clip.mjs +15 -0
  131. package/runtime/packages/scene/src/color-value.d.mts +5 -0
  132. package/runtime/packages/scene/src/color-value.mjs +19 -0
  133. package/runtime/packages/scene/src/color.ts +1 -0
  134. package/runtime/packages/scene/src/effects.ts +213 -0
  135. package/runtime/packages/scene/src/elements.ts +491 -0
  136. package/runtime/packages/scene/src/evaluate.ts +919 -0
  137. package/runtime/packages/scene/src/index.ts +69 -0
  138. package/runtime/packages/scene/src/jsx-runtime.ts +73 -0
  139. package/runtime/packages/scene/src/knob-schema.ts +115 -0
  140. package/runtime/packages/scene/src/knobs.ts +118 -0
  141. package/runtime/packages/scene/src/mask.d.mts +6 -0
  142. package/runtime/packages/scene/src/mask.mjs +17 -0
  143. package/runtime/packages/scene/src/metadata.d.mts +23 -0
  144. package/runtime/packages/scene/src/metadata.mjs +44 -0
  145. package/runtime/packages/scene/src/motion-sampling.d.mts +2 -0
  146. package/runtime/packages/scene/src/motion-sampling.mjs +50 -0
  147. package/runtime/packages/scene/src/motion.ts +121 -0
  148. package/runtime/packages/scene/src/shader.ts +57 -0
  149. package/src/resource-examples/example-image/landscape.svg +7 -0
  150. package/src/resource-examples/example-image/resource.json +8 -0
  151. package/src/resource-examples/example-model/gem.glb +0 -0
  152. package/src/resource-examples/example-model/preview.svg +1 -0
  153. package/src/resource-examples/example-model/resource.json +7 -0
  154. package/src/resource-examples/example-scene/resource.json +1 -0
  155. package/src/resource-examples/example-scene/scene.tsx +8 -0
  156. package/src/resource-examples/example-shader/effect.wgsl +7 -0
  157. package/src/resource-examples/example-shader/preview.svg +1 -0
  158. package/src/resource-examples/example-shader/resource.json +27 -0
  159. package/src/resource-examples/example-shader/tint.wgsl +7 -0
  160. package/src/resource-examples/example-video/ambient.mp4 +0 -0
  161. package/src/resource-examples/example-video/resource.json +9 -0
  162. package/src/starter/scene.tsx +20 -0
  163. package/studio/index.html +2 -0
  164. package/studio/public/check-circle-filled.svg +3 -0
  165. package/studio/public/comment-cursor/active-outer.svg +3 -0
  166. package/studio/public/comment-cursor/default.svg +6 -0
  167. package/studio/public/osmo-studio-logo.svg +12 -0
  168. package/studio/public/pencil-simple.svg +5 -0
  169. package/studio/src/active-outer-TVYUEURE.svg +3 -0
  170. package/studio/src/app.css +4 -0
  171. package/studio/src/app.js +705 -0
  172. package/studio/src/default-6CTRH4V5.svg +6 -0
  173. package/studio/src/engine_bg.wasm +0 -0
  174. package/studio/src/inter-cyrillic-ext-wght-normal-IYF56FF6.woff2 +0 -0
  175. package/studio/src/inter-cyrillic-wght-normal-JEOLYBOO.woff2 +0 -0
  176. package/studio/src/inter-greek-ext-wght-normal-EOVOK2B5.woff2 +0 -0
  177. package/studio/src/inter-greek-wght-normal-IRE366VL.woff2 +0 -0
  178. package/studio/src/inter-latin-ext-wght-normal-HA22NDSG.woff2 +0 -0
  179. package/studio/src/inter-latin-wght-normal-NRMW37G5.woff2 +0 -0
  180. package/studio/src/inter-vietnamese-wght-normal-CE5GGD3W.woff2 +0 -0
  181. package/studio/src/osmo-studio-logo-D5R2V77B.svg +12 -0
  182. package/third-party/cargo/adler2@2.0.1/Cargo.toml +91 -0
  183. package/third-party/cargo/adler2@2.0.1/LICENSE-0BSD +12 -0
  184. package/third-party/cargo/adler2@2.0.1/LICENSE-APACHE +201 -0
  185. package/third-party/cargo/adler2@2.0.1/LICENSE-MIT +23 -0
  186. package/third-party/cargo/allocator-api2@0.2.21/Cargo.toml +48 -0
  187. package/third-party/cargo/allocator-api2@0.2.21/LICENSE-APACHE +176 -0
  188. package/third-party/cargo/allocator-api2@0.2.21/LICENSE-MIT +23 -0
  189. package/third-party/cargo/arrayref@0.3.9/Cargo.toml +23 -0
  190. package/third-party/cargo/arrayref@0.3.9/LICENSE +26 -0
  191. package/third-party/cargo/arrayvec@0.7.8/Cargo.toml +112 -0
  192. package/third-party/cargo/arrayvec@0.7.8/LICENSE-APACHE +201 -0
  193. package/third-party/cargo/arrayvec@0.7.8/LICENSE-MIT +25 -0
  194. package/third-party/cargo/ascii@1.1.0/Cargo.toml +41 -0
  195. package/third-party/cargo/ascii@1.1.0/LICENSE-APACHE +201 -0
  196. package/third-party/cargo/ascii@1.1.0/LICENSE-MIT +22 -0
  197. package/third-party/cargo/ash@0.38.0+1.3.281/Cargo.toml +66 -0
  198. package/third-party/cargo/ash@0.38.0+1.3.281/LICENSE-APACHE +67 -0
  199. package/third-party/cargo/ash@0.38.0+1.3.281/LICENSE-MIT +25 -0
  200. package/third-party/cargo/autocfg@1.5.1/Cargo.toml +75 -0
  201. package/third-party/cargo/autocfg@1.5.1/LICENSE-APACHE +201 -0
  202. package/third-party/cargo/autocfg@1.5.1/LICENSE-MIT +25 -0
  203. package/third-party/cargo/base64@0.13.1/Cargo.toml +53 -0
  204. package/third-party/cargo/base64@0.13.1/LICENSE-APACHE +201 -0
  205. package/third-party/cargo/base64@0.13.1/LICENSE-MIT +21 -0
  206. package/third-party/cargo/base64@0.22.1/Cargo.toml +85 -0
  207. package/third-party/cargo/base64@0.22.1/LICENSE-APACHE +201 -0
  208. package/third-party/cargo/base64@0.22.1/LICENSE-MIT +21 -0
  209. package/third-party/cargo/bit-set@0.10.0/Cargo.toml +108 -0
  210. package/third-party/cargo/bit-set@0.10.0/LICENSE-APACHE +201 -0
  211. package/third-party/cargo/bit-set@0.10.0/LICENSE-MIT +25 -0
  212. package/third-party/cargo/bit-vec@0.9.1/Cargo.toml +94 -0
  213. package/third-party/cargo/bit-vec@0.9.1/LICENSE-APACHE +201 -0
  214. package/third-party/cargo/bit-vec@0.9.1/LICENSE-MIT +25 -0
  215. package/third-party/cargo/bitflags@2.13.0/Cargo.toml +120 -0
  216. package/third-party/cargo/bitflags@2.13.0/LICENSE-APACHE +201 -0
  217. package/third-party/cargo/bitflags@2.13.0/LICENSE-MIT +25 -0
  218. package/third-party/cargo/block2@0.6.2/Cargo.toml +115 -0
  219. package/third-party/cargo/block2@0.6.2/MIT-terms.txt +22 -0
  220. package/third-party/cargo/block2@0.6.2/madsmtm-objc2-b4167b582b2f-LICENSE.md +34 -0
  221. package/third-party/cargo/bumpalo@3.20.3/Cargo.toml +99 -0
  222. package/third-party/cargo/bumpalo@3.20.3/LICENSE-APACHE +201 -0
  223. package/third-party/cargo/bumpalo@3.20.3/LICENSE-MIT +25 -0
  224. package/third-party/cargo/bytemuck@1.25.1/Cargo.toml +153 -0
  225. package/third-party/cargo/bytemuck@1.25.1/LICENSE-APACHE +61 -0
  226. package/third-party/cargo/bytemuck@1.25.1/LICENSE-MIT +9 -0
  227. package/third-party/cargo/bytemuck@1.25.1/LICENSE-ZLIB +11 -0
  228. package/third-party/cargo/bytemuck_derive@1.11.0/Cargo.toml +60 -0
  229. package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-APACHE +61 -0
  230. package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-MIT +9 -0
  231. package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-ZLIB +11 -0
  232. package/third-party/cargo/byteorder-lite@0.1.0/Cargo.toml +57 -0
  233. package/third-party/cargo/byteorder-lite@0.1.0/LICENSE-MIT +21 -0
  234. package/third-party/cargo/byteorder-lite@0.1.0/UNLICENSE +24 -0
  235. package/third-party/cargo/byteorder@1.5.0/COPYING +3 -0
  236. package/third-party/cargo/byteorder@1.5.0/Cargo.toml +54 -0
  237. package/third-party/cargo/byteorder@1.5.0/LICENSE-MIT +21 -0
  238. package/third-party/cargo/byteorder@1.5.0/UNLICENSE +24 -0
  239. package/third-party/cargo/cfg-if@1.0.4/Cargo.toml +47 -0
  240. package/third-party/cargo/cfg-if@1.0.4/LICENSE-APACHE +201 -0
  241. package/third-party/cargo/cfg-if@1.0.4/LICENSE-MIT +25 -0
  242. package/third-party/cargo/cfg_aliases@0.2.1/Cargo.toml +43 -0
  243. package/third-party/cargo/cfg_aliases@0.2.1/LICENSE +9 -0
  244. package/third-party/cargo/chunked_transfer@1.5.0/Cargo.toml +27 -0
  245. package/third-party/cargo/chunked_transfer@1.5.0/LICENSE-APACHE +201 -0
  246. package/third-party/cargo/chunked_transfer@1.5.0/LICENSE-MIT +22 -0
  247. package/third-party/cargo/codespan-reporting@0.13.1/Cargo.toml +115 -0
  248. package/third-party/cargo/codespan-reporting@0.13.1/LICENSE +201 -0
  249. package/third-party/cargo/color_quant@1.1.0/Cargo.toml +20 -0
  250. package/third-party/cargo/color_quant@1.1.0/LICENSE +21 -0
  251. package/third-party/cargo/console_error_panic_hook@0.1.7/Cargo.toml +27 -0
  252. package/third-party/cargo/console_error_panic_hook@0.1.7/LICENSE-APACHE +201 -0
  253. package/third-party/cargo/console_error_panic_hook@0.1.7/LICENSE-MIT +25 -0
  254. package/third-party/cargo/core_maths@0.1.1/Cargo.toml +37 -0
  255. package/third-party/cargo/core_maths@0.1.1/LICENSE +21 -0
  256. package/third-party/cargo/cosmic-text@0.19.0/Cargo.toml +214 -0
  257. package/third-party/cargo/cosmic-text@0.19.0/LICENSE-APACHE +201 -0
  258. package/third-party/cargo/cosmic-text@0.19.0/LICENSE-MIT +21 -0
  259. package/third-party/cargo/crc32fast@1.5.0/Cargo.toml +68 -0
  260. package/third-party/cargo/crc32fast@1.5.0/LICENSE-APACHE +202 -0
  261. package/third-party/cargo/crc32fast@1.5.0/LICENSE-MIT +21 -0
  262. package/third-party/cargo/data-url@0.3.2/Cargo.toml +63 -0
  263. package/third-party/cargo/data-url@0.3.2/LICENSE-APACHE +201 -0
  264. package/third-party/cargo/data-url@0.3.2/LICENSE-MIT +25 -0
  265. package/third-party/cargo/dispatch2@0.3.1/Cargo.toml +122 -0
  266. package/third-party/cargo/dispatch2@0.3.1/MIT-terms.txt +22 -0
  267. package/third-party/cargo/dispatch2@0.3.1/madsmtm-objc2-8852b424193c-LICENSE.md +34 -0
  268. package/third-party/cargo/dlib@0.5.3/Cargo.toml +43 -0
  269. package/third-party/cargo/dlib@0.5.3/LICENSE.txt +19 -0
  270. package/third-party/cargo/document-features@0.2.12/Cargo.toml +51 -0
  271. package/third-party/cargo/document-features@0.2.12/LICENSE-APACHE +73 -0
  272. package/third-party/cargo/document-features@0.2.12/LICENSE-MIT +19 -0
  273. package/third-party/cargo/equivalent@1.0.2/Cargo.toml +37 -0
  274. package/third-party/cargo/equivalent@1.0.2/LICENSE-APACHE +201 -0
  275. package/third-party/cargo/equivalent@1.0.2/LICENSE-MIT +25 -0
  276. package/third-party/cargo/errno@0.3.14/Cargo.toml +67 -0
  277. package/third-party/cargo/errno@0.3.14/LICENSE-APACHE +201 -0
  278. package/third-party/cargo/errno@0.3.14/LICENSE-MIT +25 -0
  279. package/third-party/cargo/etagere@0.3.0/Cargo.toml +57 -0
  280. package/third-party/cargo/etagere@0.3.0/LICENSE-APACHE +13 -0
  281. package/third-party/cargo/etagere@0.3.0/LICENSE-MIT +20 -0
  282. package/third-party/cargo/euclid@0.22.14/COPYRIGHT +5 -0
  283. package/third-party/cargo/euclid@0.22.14/Cargo.toml +66 -0
  284. package/third-party/cargo/euclid@0.22.14/LICENSE-APACHE +201 -0
  285. package/third-party/cargo/euclid@0.22.14/LICENSE-MIT +25 -0
  286. package/third-party/cargo/fastrand@2.5.0/Cargo.toml +89 -0
  287. package/third-party/cargo/fastrand@2.5.0/LICENSE-APACHE +201 -0
  288. package/third-party/cargo/fastrand@2.5.0/LICENSE-MIT +23 -0
  289. package/third-party/cargo/fdeflate@0.3.7/Cargo.toml +55 -0
  290. package/third-party/cargo/fdeflate@0.3.7/LICENSE-APACHE +177 -0
  291. package/third-party/cargo/fdeflate@0.3.7/LICENSE-MIT +25 -0
  292. package/third-party/cargo/flate2@1.1.9/Cargo.toml +274 -0
  293. package/third-party/cargo/flate2@1.1.9/LICENSE-APACHE +201 -0
  294. package/third-party/cargo/flate2@1.1.9/LICENSE-MIT +25 -0
  295. package/third-party/cargo/float-cmp@0.9.0/Cargo.toml +39 -0
  296. package/third-party/cargo/float-cmp@0.9.0/LICENSE +19 -0
  297. package/third-party/cargo/float_next_after@1.0.0/Cargo.toml +43 -0
  298. package/third-party/cargo/float_next_after@1.0.0/LICENSE +23 -0
  299. package/third-party/cargo/foldhash@0.2.0/Cargo.toml +80 -0
  300. package/third-party/cargo/foldhash@0.2.0/LICENSE +19 -0
  301. package/third-party/cargo/font-types@0.11.3/Cargo.toml +55 -0
  302. package/third-party/cargo/font-types@0.11.3/LICENSE-APACHE +67 -0
  303. package/third-party/cargo/font-types@0.11.3/LICENSE-MIT +25 -0
  304. package/third-party/cargo/fontdb@0.23.0/Cargo.toml +83 -0
  305. package/third-party/cargo/fontdb@0.23.0/LICENSE +21 -0
  306. package/third-party/cargo/futures-core@0.3.32/Cargo.toml +66 -0
  307. package/third-party/cargo/futures-core@0.3.32/LICENSE-APACHE +202 -0
  308. package/third-party/cargo/futures-core@0.3.32/LICENSE-MIT +26 -0
  309. package/third-party/cargo/futures-task@0.3.32/Cargo.toml +58 -0
  310. package/third-party/cargo/futures-task@0.3.32/LICENSE-APACHE +202 -0
  311. package/third-party/cargo/futures-task@0.3.32/LICENSE-MIT +26 -0
  312. package/third-party/cargo/futures-util@0.3.32/Cargo.toml +181 -0
  313. package/third-party/cargo/futures-util@0.3.32/LICENSE-APACHE +202 -0
  314. package/third-party/cargo/futures-util@0.3.32/LICENSE-MIT +26 -0
  315. package/third-party/cargo/getrandom@0.4.3/Cargo.toml +165 -0
  316. package/third-party/cargo/getrandom@0.4.3/LICENSE-APACHE +201 -0
  317. package/third-party/cargo/getrandom@0.4.3/LICENSE-MIT +26 -0
  318. package/third-party/cargo/gif@0.14.2/Cargo.toml +84 -0
  319. package/third-party/cargo/gif@0.14.2/LICENSE-APACHE +201 -0
  320. package/third-party/cargo/gif@0.14.2/LICENSE-MIT +21 -0
  321. package/third-party/cargo/glam@0.33.2/Cargo.toml +354 -0
  322. package/third-party/cargo/glam@0.33.2/LICENSE-APACHE +201 -0
  323. package/third-party/cargo/glam@0.33.2/LICENSE-MIT +23 -0
  324. package/third-party/cargo/glow@0.17.0/Cargo.toml +122 -0
  325. package/third-party/cargo/glow@0.17.0/LICENSE-APACHE +201 -0
  326. package/third-party/cargo/glow@0.17.0/LICENSE-MIT +23 -0
  327. package/third-party/cargo/glow@0.17.0/LICENSE-ZLIB +15 -0
  328. package/third-party/cargo/gltf-derive@1.4.1/Cargo.toml +34 -0
  329. package/third-party/cargo/gltf-derive@1.4.1/LICENSE-APACHE +202 -0
  330. package/third-party/cargo/gltf-derive@1.4.1/LICENSE-MIT +26 -0
  331. package/third-party/cargo/gltf-json@1.4.1/Cargo.toml +50 -0
  332. package/third-party/cargo/gltf-json@1.4.1/LICENSE-APACHE +202 -0
  333. package/third-party/cargo/gltf-json@1.4.1/LICENSE-MIT +26 -0
  334. package/third-party/cargo/gltf@1.4.1/Cargo.toml +122 -0
  335. package/third-party/cargo/gltf@1.4.1/LICENSE-APACHE +202 -0
  336. package/third-party/cargo/gltf@1.4.1/LICENSE-MIT +26 -0
  337. package/third-party/cargo/glyphon@0.12.0/Cargo.toml +35 -0
  338. package/third-party/cargo/glyphon@0.12.0/LICENSE-APACHE +201 -0
  339. package/third-party/cargo/glyphon@0.12.0/LICENSE-MIT +23 -0
  340. package/third-party/cargo/glyphon@0.12.0/LICENSE-ZLIB +15 -0
  341. package/third-party/cargo/gpu-allocator@0.28.0/Cargo.toml +180 -0
  342. package/third-party/cargo/gpu-allocator@0.28.0/LICENSE-APACHE +201 -0
  343. package/third-party/cargo/gpu-allocator@0.28.0/LICENSE-MIT +7 -0
  344. package/third-party/cargo/grid@1.0.1/Cargo.toml +77 -0
  345. package/third-party/cargo/grid@1.0.1/LICENSE +21 -0
  346. package/third-party/cargo/half@2.7.1/Cargo.toml +137 -0
  347. package/third-party/cargo/half@2.7.1/LICENSE-APACHE +176 -0
  348. package/third-party/cargo/half@2.7.1/LICENSE-MIT +19 -0
  349. package/third-party/cargo/harfrust@0.5.2/Cargo.toml +115 -0
  350. package/third-party/cargo/harfrust@0.5.2/harfbuzz-harfrust-efdae3142ab7-LICENSE +22 -0
  351. package/third-party/cargo/hashbrown@0.16.1/Cargo.toml +180 -0
  352. package/third-party/cargo/hashbrown@0.16.1/LICENSE-APACHE +201 -0
  353. package/third-party/cargo/hashbrown@0.16.1/LICENSE-MIT +25 -0
  354. package/third-party/cargo/hashbrown@0.17.1/Cargo.toml +201 -0
  355. package/third-party/cargo/hashbrown@0.17.1/LICENSE-APACHE +201 -0
  356. package/third-party/cargo/hashbrown@0.17.1/LICENSE-MIT +25 -0
  357. package/third-party/cargo/httpdate@1.0.3/Cargo.toml +35 -0
  358. package/third-party/cargo/httpdate@1.0.3/LICENSE-APACHE +201 -0
  359. package/third-party/cargo/httpdate@1.0.3/LICENSE-MIT +19 -0
  360. package/third-party/cargo/image-webp@0.2.4/Cargo.toml +63 -0
  361. package/third-party/cargo/image-webp@0.2.4/LICENSE-APACHE +177 -0
  362. package/third-party/cargo/image-webp@0.2.4/LICENSE-MIT +25 -0
  363. package/third-party/cargo/image@0.25.10/Cargo.toml +248 -0
  364. package/third-party/cargo/image@0.25.10/LICENSE-APACHE +177 -0
  365. package/third-party/cargo/image@0.25.10/LICENSE-MIT +25 -0
  366. package/third-party/cargo/imagesize@0.14.0/Cargo.toml +104 -0
  367. package/third-party/cargo/imagesize@0.14.0/LICENSE +21 -0
  368. package/third-party/cargo/indexmap@2.14.0/Cargo.toml +167 -0
  369. package/third-party/cargo/indexmap@2.14.0/LICENSE-APACHE +201 -0
  370. package/third-party/cargo/indexmap@2.14.0/LICENSE-MIT +25 -0
  371. package/third-party/cargo/inflections@1.1.1/Cargo.toml +21 -0
  372. package/third-party/cargo/inflections@1.1.1/LICENSE +20 -0
  373. package/third-party/cargo/itoa@1.0.18/Cargo.toml +66 -0
  374. package/third-party/cargo/itoa@1.0.18/LICENSE-APACHE +176 -0
  375. package/third-party/cargo/itoa@1.0.18/LICENSE-MIT +23 -0
  376. package/third-party/cargo/js-sys@0.3.103/Cargo.toml +98 -0
  377. package/third-party/cargo/js-sys@0.3.103/LICENSE-APACHE +201 -0
  378. package/third-party/cargo/js-sys@0.3.103/LICENSE-MIT +25 -0
  379. package/third-party/cargo/khronos-egl@6.0.0/Cargo.toml +82 -0
  380. package/third-party/cargo/khronos-egl@6.0.0/LICENSE-APACHE +201 -0
  381. package/third-party/cargo/khronos-egl@6.0.0/LICENSE-MIT +23 -0
  382. package/third-party/cargo/kurbo@0.13.1/Cargo.toml +230 -0
  383. package/third-party/cargo/kurbo@0.13.1/LICENSE-APACHE +202 -0
  384. package/third-party/cargo/kurbo@0.13.1/LICENSE-MIT +25 -0
  385. package/third-party/cargo/lazy_static@1.5.0/Cargo.toml +46 -0
  386. package/third-party/cargo/lazy_static@1.5.0/LICENSE-APACHE +201 -0
  387. package/third-party/cargo/lazy_static@1.5.0/LICENSE-MIT +25 -0
  388. package/third-party/cargo/libc@0.2.186/Cargo.toml +229 -0
  389. package/third-party/cargo/libc@0.2.186/LICENSE-APACHE +176 -0
  390. package/third-party/cargo/libc@0.2.186/LICENSE-MIT +25 -0
  391. package/third-party/cargo/libloading@0.8.9/Cargo.toml +90 -0
  392. package/third-party/cargo/libloading@0.8.9/LICENSE +12 -0
  393. package/third-party/cargo/libm@0.2.16/Cargo.toml +61 -0
  394. package/third-party/cargo/libm@0.2.16/LICENSE.txt +258 -0
  395. package/third-party/cargo/linebender_resource_handle@0.1.1/Cargo.toml +107 -0
  396. package/third-party/cargo/linebender_resource_handle@0.1.1/LICENSE-APACHE +176 -0
  397. package/third-party/cargo/linebender_resource_handle@0.1.1/LICENSE-MIT +19 -0
  398. package/third-party/cargo/litrs@1.0.0/Cargo.toml +63 -0
  399. package/third-party/cargo/litrs@1.0.0/LICENSE-APACHE +176 -0
  400. package/third-party/cargo/litrs@1.0.0/LICENSE-MIT +25 -0
  401. package/third-party/cargo/lock_api@0.4.14/Cargo.toml +68 -0
  402. package/third-party/cargo/lock_api@0.4.14/LICENSE-APACHE +201 -0
  403. package/third-party/cargo/lock_api@0.4.14/LICENSE-MIT +25 -0
  404. package/third-party/cargo/log@0.4.33/Cargo.toml +152 -0
  405. package/third-party/cargo/log@0.4.33/LICENSE-APACHE +201 -0
  406. package/third-party/cargo/log@0.4.33/LICENSE-MIT +25 -0
  407. package/third-party/cargo/lru@0.16.4/Cargo.toml +47 -0
  408. package/third-party/cargo/lru@0.16.4/LICENSE +21 -0
  409. package/third-party/cargo/lyon_geom@1.0.19/Cargo.toml +69 -0
  410. package/third-party/cargo/lyon_geom@1.0.19/nical-lyon-56219c95c658-LICENSE-APACHE +13 -0
  411. package/third-party/cargo/lyon_geom@1.0.19/nical-lyon-56219c95c658-LICENSE-MIT +20 -0
  412. package/third-party/cargo/lyon_path@1.0.19/Cargo.toml +58 -0
  413. package/third-party/cargo/lyon_path@1.0.19/nical-lyon-56219c95c658-LICENSE-APACHE +13 -0
  414. package/third-party/cargo/lyon_path@1.0.19/nical-lyon-56219c95c658-LICENSE-MIT +20 -0
  415. package/third-party/cargo/lyon_tessellation@1.0.20/Cargo.toml +71 -0
  416. package/third-party/cargo/lyon_tessellation@1.0.20/nical-lyon-7fa75ea8eea3-LICENSE-APACHE +13 -0
  417. package/third-party/cargo/lyon_tessellation@1.0.20/nical-lyon-7fa75ea8eea3-LICENSE-MIT +20 -0
  418. package/third-party/cargo/memchr@2.8.3/COPYING +3 -0
  419. package/third-party/cargo/memchr@2.8.3/Cargo.toml +89 -0
  420. package/third-party/cargo/memchr@2.8.3/LICENSE-MIT +21 -0
  421. package/third-party/cargo/memchr@2.8.3/UNLICENSE +24 -0
  422. package/third-party/cargo/memmap2@0.9.11/Cargo.toml +59 -0
  423. package/third-party/cargo/memmap2@0.9.11/LICENSE-APACHE +201 -0
  424. package/third-party/cargo/memmap2@0.9.11/LICENSE-MIT +26 -0
  425. package/third-party/cargo/miniz_oxide@0.8.9/Cargo.toml +91 -0
  426. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE +25 -0
  427. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-APACHE.md +177 -0
  428. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-MIT.md +24 -0
  429. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-ZLIB.md +14 -0
  430. package/third-party/cargo/moxcms@0.8.1/Cargo.toml +113 -0
  431. package/third-party/cargo/moxcms@0.8.1/LICENSE-APACHE.md +201 -0
  432. package/third-party/cargo/moxcms@0.8.1/LICENSE.md +26 -0
  433. package/third-party/cargo/naga-types@30.0.0/Cargo.toml +94 -0
  434. package/third-party/cargo/naga-types@30.0.0/LICENSE.APACHE +176 -0
  435. package/third-party/cargo/naga-types@30.0.0/LICENSE.MIT +21 -0
  436. package/third-party/cargo/naga@30.0.0/Cargo.toml +246 -0
  437. package/third-party/cargo/naga@30.0.0/LICENSE.APACHE +176 -0
  438. package/third-party/cargo/naga@30.0.0/LICENSE.MIT +21 -0
  439. package/third-party/cargo/num-traits@0.2.19/Cargo.toml +54 -0
  440. package/third-party/cargo/num-traits@0.2.19/LICENSE-APACHE +201 -0
  441. package/third-party/cargo/num-traits@0.2.19/LICENSE-MIT +25 -0
  442. package/third-party/cargo/objc2-core-foundation@0.3.2/Cargo.toml +221 -0
  443. package/third-party/cargo/objc2-core-foundation@0.3.2/MIT-terms.txt +22 -0
  444. package/third-party/cargo/objc2-core-foundation@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  445. package/third-party/cargo/objc2-core-graphics@0.3.2/Cargo.toml +331 -0
  446. package/third-party/cargo/objc2-core-graphics@0.3.2/MIT-terms.txt +22 -0
  447. package/third-party/cargo/objc2-core-graphics@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  448. package/third-party/cargo/objc2-encode@4.1.0/Cargo.toml +81 -0
  449. package/third-party/cargo/objc2-encode@4.1.0/MIT-terms.txt +22 -0
  450. package/third-party/cargo/objc2-encode@4.1.0/madsmtm-objc2-8d214f547736-LICENSE.md +34 -0
  451. package/third-party/cargo/objc2-foundation@0.3.2/Cargo.toml +529 -0
  452. package/third-party/cargo/objc2-foundation@0.3.2/MIT-terms.txt +22 -0
  453. package/third-party/cargo/objc2-foundation@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  454. package/third-party/cargo/objc2-io-surface@0.3.2/Cargo.toml +139 -0
  455. package/third-party/cargo/objc2-io-surface@0.3.2/MIT-terms.txt +22 -0
  456. package/third-party/cargo/objc2-io-surface@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  457. package/third-party/cargo/objc2-metal@0.3.2/Cargo.toml +601 -0
  458. package/third-party/cargo/objc2-metal@0.3.2/MIT-terms.txt +22 -0
  459. package/third-party/cargo/objc2-metal@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  460. package/third-party/cargo/objc2-quartz-core@0.3.2/Cargo.toml +302 -0
  461. package/third-party/cargo/objc2-quartz-core@0.3.2/MIT-terms.txt +22 -0
  462. package/third-party/cargo/objc2-quartz-core@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  463. package/third-party/cargo/objc2@0.6.4/Cargo.toml +232 -0
  464. package/third-party/cargo/objc2@0.6.4/MIT-terms.txt +22 -0
  465. package/third-party/cargo/objc2@0.6.4/madsmtm-objc2-8852b424193c-LICENSE.md +34 -0
  466. package/third-party/cargo/once_cell@1.21.4/Cargo.toml +119 -0
  467. package/third-party/cargo/once_cell@1.21.4/LICENSE-APACHE +201 -0
  468. package/third-party/cargo/once_cell@1.21.4/LICENSE-MIT +23 -0
  469. package/third-party/cargo/ordered-float@5.3.0/Cargo.toml +162 -0
  470. package/third-party/cargo/ordered-float@5.3.0/LICENSE-MIT +25 -0
  471. package/third-party/cargo/parking_lot@0.12.5/Cargo.toml +87 -0
  472. package/third-party/cargo/parking_lot@0.12.5/LICENSE-APACHE +201 -0
  473. package/third-party/cargo/parking_lot@0.12.5/LICENSE-MIT +25 -0
  474. package/third-party/cargo/parking_lot_core@0.9.12/Cargo.toml +72 -0
  475. package/third-party/cargo/parking_lot_core@0.9.12/LICENSE-APACHE +201 -0
  476. package/third-party/cargo/parking_lot_core@0.9.12/LICENSE-MIT +25 -0
  477. package/third-party/cargo/pico-args@0.5.0/Cargo.toml +32 -0
  478. package/third-party/cargo/pico-args@0.5.0/LICENSE +20 -0
  479. package/third-party/cargo/pin-project-lite@0.2.17/Cargo.toml +198 -0
  480. package/third-party/cargo/pin-project-lite@0.2.17/LICENSE-APACHE +177 -0
  481. package/third-party/cargo/pin-project-lite@0.2.17/LICENSE-MIT +23 -0
  482. package/third-party/cargo/pkg-config@0.3.33/Cargo.toml +43 -0
  483. package/third-party/cargo/pkg-config@0.3.33/LICENSE-APACHE +201 -0
  484. package/third-party/cargo/pkg-config@0.3.33/LICENSE-MIT +25 -0
  485. package/third-party/cargo/png@0.18.1/Cargo.toml +130 -0
  486. package/third-party/cargo/png@0.18.1/LICENSE-APACHE +201 -0
  487. package/third-party/cargo/png@0.18.1/LICENSE-MIT +25 -0
  488. package/third-party/cargo/pollster@0.4.0/Cargo.toml +53 -0
  489. package/third-party/cargo/pollster@0.4.0/LICENSE-APACHE +201 -0
  490. package/third-party/cargo/pollster@0.4.0/LICENSE-MIT +25 -0
  491. package/third-party/cargo/polycool@0.4.0/Cargo.toml +83 -0
  492. package/third-party/cargo/polycool@0.4.0/LICENSE-APACHE +202 -0
  493. package/third-party/cargo/polycool@0.4.0/LICENSE-MIT +25 -0
  494. package/third-party/cargo/pp-rs@0.2.1/Cargo.toml +23 -0
  495. package/third-party/cargo/pp-rs@0.2.1/LICENSE +29 -0
  496. package/third-party/cargo/presser@0.3.1/Cargo.toml +58 -0
  497. package/third-party/cargo/presser@0.3.1/LICENSE-APACHE +201 -0
  498. package/third-party/cargo/presser@0.3.1/LICENSE-MIT +25 -0
  499. package/third-party/cargo/proc-macro2@1.0.106/Cargo.toml +105 -0
  500. package/third-party/cargo/proc-macro2@1.0.106/LICENSE-APACHE +176 -0
  501. package/third-party/cargo/proc-macro2@1.0.106/LICENSE-MIT +23 -0
  502. package/third-party/cargo/profiling@1.0.18/Cargo.toml +96 -0
  503. package/third-party/cargo/profiling@1.0.18/aclysma-profiling-8271551172eb-LICENSE-APACHE +201 -0
  504. package/third-party/cargo/profiling@1.0.18/aclysma-profiling-8271551172eb-LICENSE-MIT +21 -0
  505. package/third-party/cargo/pxfm@0.1.30/Cargo.toml +53 -0
  506. package/third-party/cargo/pxfm@0.1.30/LICENSE-APACHE.md +201 -0
  507. package/third-party/cargo/pxfm@0.1.30/LICENSE.md +26 -0
  508. package/third-party/cargo/quick-error@2.0.1/Cargo.toml +24 -0
  509. package/third-party/cargo/quick-error@2.0.1/LICENSE-APACHE +202 -0
  510. package/third-party/cargo/quick-error@2.0.1/LICENSE-MIT +19 -0
  511. package/third-party/cargo/quote@1.0.46/Cargo.toml +70 -0
  512. package/third-party/cargo/quote@1.0.46/LICENSE-APACHE +176 -0
  513. package/third-party/cargo/quote@1.0.46/LICENSE-MIT +23 -0
  514. package/third-party/cargo/rangemap@1.7.1/Cargo.toml +91 -0
  515. package/third-party/cargo/rangemap@1.7.1/LICENSE-APACHE +191 -0
  516. package/third-party/cargo/rangemap@1.7.1/LICENSE-MIT +7 -0
  517. package/third-party/cargo/raw-window-handle@0.6.2/Cargo.toml +56 -0
  518. package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-APACHE.md +177 -0
  519. package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-MIT.md +21 -0
  520. package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-ZLIB.md +11 -0
  521. package/third-party/cargo/raw-window-metal@1.1.0/Cargo.toml +111 -0
  522. package/third-party/cargo/raw-window-metal@1.1.0/LICENSE-APACHE +202 -0
  523. package/third-party/cargo/raw-window-metal@1.1.0/LICENSE-MIT +17 -0
  524. package/third-party/cargo/read-fonts@0.37.0/Cargo.toml +95 -0
  525. package/third-party/cargo/read-fonts@0.37.0/LICENSE-APACHE +67 -0
  526. package/third-party/cargo/read-fonts@0.37.0/LICENSE-MIT +25 -0
  527. package/third-party/cargo/read-fonts@0.39.2/Cargo.toml +96 -0
  528. package/third-party/cargo/read-fonts@0.39.2/LICENSE-APACHE +67 -0
  529. package/third-party/cargo/read-fonts@0.39.2/LICENSE-MIT +25 -0
  530. package/third-party/cargo/renderdoc-sys@1.1.0/Cargo.toml +39 -0
  531. package/third-party/cargo/renderdoc-sys@1.1.0/LICENSE-APACHE +201 -0
  532. package/third-party/cargo/renderdoc-sys@1.1.0/LICENSE-MIT +25 -0
  533. package/third-party/cargo/resvg@0.47.0/Cargo.toml +112 -0
  534. package/third-party/cargo/resvg@0.47.0/LICENSE-APACHE +176 -0
  535. package/third-party/cargo/resvg@0.47.0/LICENSE-MIT +25 -0
  536. package/third-party/cargo/rgb@0.8.53/Cargo.toml +110 -0
  537. package/third-party/cargo/rgb@0.8.53/LICENSE +21 -0
  538. package/third-party/cargo/roxmltree@0.21.1/Cargo.toml +75 -0
  539. package/third-party/cargo/roxmltree@0.21.1/LICENSE-APACHE +201 -0
  540. package/third-party/cargo/roxmltree@0.21.1/LICENSE-MIT +21 -0
  541. package/third-party/cargo/rustc-hash@1.1.0/Cargo.toml +25 -0
  542. package/third-party/cargo/rustc-hash@1.1.0/LICENSE-APACHE +201 -0
  543. package/third-party/cargo/rustc-hash@1.1.0/LICENSE-MIT +23 -0
  544. package/third-party/cargo/rustc-hash@2.1.3/Cargo.toml +50 -0
  545. package/third-party/cargo/rustc-hash@2.1.3/LICENSE-APACHE +176 -0
  546. package/third-party/cargo/rustc-hash@2.1.3/LICENSE-MIT +23 -0
  547. package/third-party/cargo/rustix@1.1.4/COPYRIGHT +29 -0
  548. package/third-party/cargo/rustix@1.1.4/Cargo.toml +292 -0
  549. package/third-party/cargo/rustix@1.1.4/LICENSE-APACHE +201 -0
  550. package/third-party/cargo/rustix@1.1.4/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  551. package/third-party/cargo/rustix@1.1.4/LICENSE-MIT +23 -0
  552. package/third-party/cargo/rustversion@1.0.23/Cargo.toml +69 -0
  553. package/third-party/cargo/rustversion@1.0.23/LICENSE-APACHE +176 -0
  554. package/third-party/cargo/rustversion@1.0.23/LICENSE-MIT +23 -0
  555. package/third-party/cargo/rustybuzz@0.20.1/Cargo.toml +110 -0
  556. package/third-party/cargo/rustybuzz@0.20.1/LICENSE +22 -0
  557. package/third-party/cargo/scopeguard@1.2.0/Cargo.toml +43 -0
  558. package/third-party/cargo/scopeguard@1.2.0/LICENSE-APACHE +201 -0
  559. package/third-party/cargo/scopeguard@1.2.0/LICENSE-MIT +25 -0
  560. package/third-party/cargo/self_cell@1.2.2/Cargo.toml +33 -0
  561. package/third-party/cargo/self_cell@1.2.2/LICENSE-APACHE +201 -0
  562. package/third-party/cargo/self_cell@1.2.2/LICENSE-GPLv2 +339 -0
  563. package/third-party/cargo/self_cell@1.3.0/Cargo.toml +33 -0
  564. package/third-party/cargo/self_cell@1.3.0/LICENSE-APACHE +201 -0
  565. package/third-party/cargo/self_cell@1.3.0/LICENSE-GPLv2 +339 -0
  566. package/third-party/cargo/serde@1.0.228/Cargo.toml +84 -0
  567. package/third-party/cargo/serde@1.0.228/LICENSE-APACHE +176 -0
  568. package/third-party/cargo/serde@1.0.228/LICENSE-MIT +23 -0
  569. package/third-party/cargo/serde_core@1.0.228/Cargo.toml +87 -0
  570. package/third-party/cargo/serde_core@1.0.228/LICENSE-APACHE +176 -0
  571. package/third-party/cargo/serde_core@1.0.228/LICENSE-MIT +23 -0
  572. package/third-party/cargo/serde_derive@1.0.228/Cargo.toml +87 -0
  573. package/third-party/cargo/serde_derive@1.0.228/LICENSE-APACHE +176 -0
  574. package/third-party/cargo/serde_derive@1.0.228/LICENSE-MIT +23 -0
  575. package/third-party/cargo/serde_json@1.0.150/Cargo.toml +162 -0
  576. package/third-party/cargo/serde_json@1.0.150/LICENSE-APACHE +176 -0
  577. package/third-party/cargo/serde_json@1.0.150/LICENSE-MIT +23 -0
  578. package/third-party/cargo/simd-adler32@0.3.10/Cargo.toml +68 -0
  579. package/third-party/cargo/simd-adler32@0.3.10/LICENSE.md +21 -0
  580. package/third-party/cargo/simplecss@0.2.2/Cargo.toml +146 -0
  581. package/third-party/cargo/simplecss@0.2.2/LICENSE-APACHE +201 -0
  582. package/third-party/cargo/simplecss@0.2.2/LICENSE-MIT +21 -0
  583. package/third-party/cargo/siphasher@1.0.3/COPYING +7 -0
  584. package/third-party/cargo/siphasher@1.0.3/Cargo.toml +64 -0
  585. package/third-party/cargo/skrifa@0.40.0/Cargo.toml +86 -0
  586. package/third-party/cargo/skrifa@0.40.0/LICENSE-APACHE +67 -0
  587. package/third-party/cargo/skrifa@0.40.0/LICENSE-MIT +25 -0
  588. package/third-party/cargo/skrifa@0.42.1/Cargo.toml +86 -0
  589. package/third-party/cargo/skrifa@0.42.1/LICENSE-APACHE +67 -0
  590. package/third-party/cargo/skrifa@0.42.1/LICENSE-MIT +25 -0
  591. package/third-party/cargo/slab@0.4.12/Cargo.toml +67 -0
  592. package/third-party/cargo/slab@0.4.12/LICENSE +25 -0
  593. package/third-party/cargo/slotmap@1.1.1/Cargo.toml +83 -0
  594. package/third-party/cargo/slotmap@1.1.1/LICENSE +19 -0
  595. package/third-party/cargo/smallvec@1.15.2/Cargo.toml +103 -0
  596. package/third-party/cargo/smallvec@1.15.2/LICENSE-APACHE +201 -0
  597. package/third-party/cargo/smallvec@1.15.2/LICENSE-MIT +25 -0
  598. package/third-party/cargo/smol_str@0.3.6/Cargo.toml +155 -0
  599. package/third-party/cargo/smol_str@0.3.6/LICENSE-APACHE +201 -0
  600. package/third-party/cargo/smol_str@0.3.6/LICENSE-MIT +23 -0
  601. package/third-party/cargo/spirv@0.4.0+sdk-1.4.341.0/Cargo.toml +56 -0
  602. package/third-party/cargo/spirv@0.4.0+sdk-1.4.341.0/gfx-rs-rspirv-8afc3d0ac8e1-LICENSE +202 -0
  603. package/third-party/cargo/static_assertions@1.1.0/Cargo.toml +39 -0
  604. package/third-party/cargo/static_assertions@1.1.0/LICENSE-APACHE +202 -0
  605. package/third-party/cargo/static_assertions@1.1.0/LICENSE-MIT +21 -0
  606. package/third-party/cargo/strict-num@0.1.1/Cargo.toml +35 -0
  607. package/third-party/cargo/strict-num@0.1.1/LICENSE +19 -0
  608. package/third-party/cargo/svgtypes@0.16.1/Cargo.toml +57 -0
  609. package/third-party/cargo/svgtypes@0.16.1/LICENSE-APACHE +201 -0
  610. package/third-party/cargo/svgtypes@0.16.1/LICENSE-MIT +20 -0
  611. package/third-party/cargo/swash@0.2.9/Cargo.toml +93 -0
  612. package/third-party/cargo/swash@0.2.9/LICENSE-APACHE +201 -0
  613. package/third-party/cargo/swash@0.2.9/LICENSE-MIT +25 -0
  614. package/third-party/cargo/syn@2.0.118/Cargo.toml +272 -0
  615. package/third-party/cargo/syn@2.0.118/LICENSE-APACHE +176 -0
  616. package/third-party/cargo/syn@2.0.118/LICENSE-MIT +23 -0
  617. package/third-party/cargo/sys-locale@0.3.2/Cargo.toml +73 -0
  618. package/third-party/cargo/sys-locale@0.3.2/LICENSE-APACHE +201 -0
  619. package/third-party/cargo/sys-locale@0.3.2/LICENSE-MIT +21 -0
  620. package/third-party/cargo/taffy@0.12.1/Cargo.toml +171 -0
  621. package/third-party/cargo/taffy@0.12.1/DioxusLabs-taffy-1c9e37a0a1cf-LICENSE.md +25 -0
  622. package/third-party/cargo/tempfile@3.27.0/Cargo.toml +105 -0
  623. package/third-party/cargo/tempfile@3.27.0/LICENSE-APACHE +201 -0
  624. package/third-party/cargo/tempfile@3.27.0/LICENSE-MIT +25 -0
  625. package/third-party/cargo/termcolor@1.4.1/COPYING +3 -0
  626. package/third-party/cargo/termcolor@1.4.1/Cargo.toml +40 -0
  627. package/third-party/cargo/termcolor@1.4.1/LICENSE-MIT +21 -0
  628. package/third-party/cargo/termcolor@1.4.1/UNLICENSE +24 -0
  629. package/third-party/cargo/thiserror-impl@2.0.18/Cargo.toml +52 -0
  630. package/third-party/cargo/thiserror-impl@2.0.18/LICENSE-APACHE +176 -0
  631. package/third-party/cargo/thiserror-impl@2.0.18/LICENSE-MIT +23 -0
  632. package/third-party/cargo/thiserror@2.0.18/Cargo.toml +119 -0
  633. package/third-party/cargo/thiserror@2.0.18/LICENSE-APACHE +176 -0
  634. package/third-party/cargo/thiserror@2.0.18/LICENSE-MIT +23 -0
  635. package/third-party/cargo/tiny-skia-path@0.12.0/Cargo.toml +58 -0
  636. package/third-party/cargo/tiny-skia-path@0.12.0/LICENSE +30 -0
  637. package/third-party/cargo/tiny-skia@0.12.0/Cargo.toml +116 -0
  638. package/third-party/cargo/tiny-skia@0.12.0/LICENSE +30 -0
  639. package/third-party/cargo/tiny_http@0.12.0/Cargo.toml +82 -0
  640. package/third-party/cargo/tiny_http@0.12.0/LICENSE-APACHE +201 -0
  641. package/third-party/cargo/tiny_http@0.12.0/LICENSE-MIT +25 -0
  642. package/third-party/cargo/tinyvec@1.12.0/Cargo.toml +184 -0
  643. package/third-party/cargo/tinyvec@1.12.0/LICENSE-APACHE.md +202 -0
  644. package/third-party/cargo/tinyvec@1.12.0/LICENSE-MIT.md +5 -0
  645. package/third-party/cargo/tinyvec@1.12.0/LICENSE-ZLIB.md +11 -0
  646. package/third-party/cargo/tinyvec_macros@0.1.1/Cargo.toml +19 -0
  647. package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-APACHE.md +202 -0
  648. package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-MIT.md +21 -0
  649. package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-ZLIB.md +20 -0
  650. package/third-party/cargo/ttf-parser@0.25.1/Cargo.toml +101 -0
  651. package/third-party/cargo/ttf-parser@0.25.1/LICENSE-APACHE +201 -0
  652. package/third-party/cargo/ttf-parser@0.25.1/LICENSE-MIT +20 -0
  653. package/third-party/cargo/unicode-bidi-mirroring@0.4.0/Cargo.toml +22 -0
  654. package/third-party/cargo/unicode-bidi-mirroring@0.4.0/LICENSE-APACHE +201 -0
  655. package/third-party/cargo/unicode-bidi-mirroring@0.4.0/LICENSE-MIT +21 -0
  656. package/third-party/cargo/unicode-bidi@0.3.18/COPYRIGHT +8 -0
  657. package/third-party/cargo/unicode-bidi@0.3.18/Cargo.toml +90 -0
  658. package/third-party/cargo/unicode-bidi@0.3.18/LICENSE-APACHE +201 -0
  659. package/third-party/cargo/unicode-bidi@0.3.18/LICENSE-MIT +25 -0
  660. package/third-party/cargo/unicode-ccc@0.4.0/Cargo.toml +22 -0
  661. package/third-party/cargo/unicode-ccc@0.4.0/LICENSE-APACHE +201 -0
  662. package/third-party/cargo/unicode-ccc@0.4.0/LICENSE-MIT +21 -0
  663. package/third-party/cargo/unicode-ident@1.0.24/Cargo.toml +84 -0
  664. package/third-party/cargo/unicode-ident@1.0.24/LICENSE-APACHE +176 -0
  665. package/third-party/cargo/unicode-ident@1.0.24/LICENSE-MIT +23 -0
  666. package/third-party/cargo/unicode-ident@1.0.24/LICENSE-UNICODE +39 -0
  667. package/third-party/cargo/unicode-linebreak@0.1.5/Cargo.toml +32 -0
  668. package/third-party/cargo/unicode-linebreak@0.1.5/LICENSE +201 -0
  669. package/third-party/cargo/unicode-properties@0.1.4/COPYRIGHT +7 -0
  670. package/third-party/cargo/unicode-properties@0.1.4/Cargo.toml +65 -0
  671. package/third-party/cargo/unicode-properties@0.1.4/LICENSE-APACHE +201 -0
  672. package/third-party/cargo/unicode-properties@0.1.4/LICENSE-MIT +25 -0
  673. package/third-party/cargo/unicode-script@0.5.8/Cargo.toml +63 -0
  674. package/third-party/cargo/unicode-script@0.5.8/LICENSE-APACHE +201 -0
  675. package/third-party/cargo/unicode-script@0.5.8/LICENSE-MIT +27 -0
  676. package/third-party/cargo/unicode-segmentation@1.13.3/COPYRIGHT +7 -0
  677. package/third-party/cargo/unicode-segmentation@1.13.3/Cargo.toml +91 -0
  678. package/third-party/cargo/unicode-segmentation@1.13.3/LICENSE-APACHE +201 -0
  679. package/third-party/cargo/unicode-segmentation@1.13.3/LICENSE-MIT +25 -0
  680. package/third-party/cargo/unicode-vo@0.1.0/Cargo.toml +22 -0
  681. package/third-party/cargo/unicode-vo@0.1.0/LICENSE-APACHE +201 -0
  682. package/third-party/cargo/unicode-vo@0.1.0/LICENSE-MIT +21 -0
  683. package/third-party/cargo/unicode-width@0.2.2/COPYRIGHT +7 -0
  684. package/third-party/cargo/unicode-width@0.2.2/Cargo.toml +77 -0
  685. package/third-party/cargo/unicode-width@0.2.2/LICENSE-APACHE +201 -0
  686. package/third-party/cargo/unicode-width@0.2.2/LICENSE-MIT +25 -0
  687. package/third-party/cargo/unicode-xid@0.2.6/COPYRIGHT +7 -0
  688. package/third-party/cargo/unicode-xid@0.2.6/Cargo.toml +65 -0
  689. package/third-party/cargo/unicode-xid@0.2.6/LICENSE-APACHE +201 -0
  690. package/third-party/cargo/unicode-xid@0.2.6/LICENSE-MIT +25 -0
  691. package/third-party/cargo/urlencoding@2.1.3/Cargo.toml +41 -0
  692. package/third-party/cargo/urlencoding@2.1.3/LICENSE +20 -0
  693. package/third-party/cargo/usvg@0.47.0/Cargo.toml +138 -0
  694. package/third-party/cargo/usvg@0.47.0/LICENSE-APACHE +176 -0
  695. package/third-party/cargo/usvg@0.47.0/LICENSE-MIT +25 -0
  696. package/third-party/cargo/version_check@0.9.5/Cargo.toml +38 -0
  697. package/third-party/cargo/version_check@0.9.5/LICENSE-APACHE +201 -0
  698. package/third-party/cargo/version_check@0.9.5/LICENSE-MIT +19 -0
  699. package/third-party/cargo/wasm-bindgen-futures@0.4.76/Cargo.toml +88 -0
  700. package/third-party/cargo/wasm-bindgen-futures@0.4.76/LICENSE-APACHE +201 -0
  701. package/third-party/cargo/wasm-bindgen-futures@0.4.76/LICENSE-MIT +25 -0
  702. package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/Cargo.toml +83 -0
  703. package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/LICENSE-APACHE +201 -0
  704. package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/LICENSE-MIT +25 -0
  705. package/third-party/cargo/wasm-bindgen-macro@0.2.126/Cargo.toml +73 -0
  706. package/third-party/cargo/wasm-bindgen-macro@0.2.126/LICENSE-APACHE +201 -0
  707. package/third-party/cargo/wasm-bindgen-macro@0.2.126/LICENSE-MIT +25 -0
  708. package/third-party/cargo/wasm-bindgen-shared@0.2.126/Cargo.toml +66 -0
  709. package/third-party/cargo/wasm-bindgen-shared@0.2.126/LICENSE-APACHE +201 -0
  710. package/third-party/cargo/wasm-bindgen-shared@0.2.126/LICENSE-MIT +25 -0
  711. package/third-party/cargo/wasm-bindgen@0.2.126/Cargo.toml +122 -0
  712. package/third-party/cargo/wasm-bindgen@0.2.126/LICENSE-APACHE +201 -0
  713. package/third-party/cargo/wasm-bindgen@0.2.126/LICENSE-MIT +25 -0
  714. package/third-party/cargo/wayland-sys@0.31.11/Cargo.toml +81 -0
  715. package/third-party/cargo/wayland-sys@0.31.11/LICENSE.txt +19 -0
  716. package/third-party/cargo/web-sys@0.3.103/Cargo.toml +2823 -0
  717. package/third-party/cargo/web-sys@0.3.103/LICENSE-APACHE +201 -0
  718. package/third-party/cargo/web-sys@0.3.103/LICENSE-MIT +25 -0
  719. package/third-party/cargo/weezl@0.1.12/Cargo.toml +120 -0
  720. package/third-party/cargo/weezl@0.1.12/LICENSE-APACHE +201 -0
  721. package/third-party/cargo/weezl@0.1.12/LICENSE-MIT +22 -0
  722. package/third-party/cargo/wgpu-core-deps-apple@30.0.0/Cargo.toml +53 -0
  723. package/third-party/cargo/wgpu-core-deps-apple@30.0.0/LICENSE.APACHE +176 -0
  724. package/third-party/cargo/wgpu-core-deps-apple@30.0.0/LICENSE.MIT +21 -0
  725. package/third-party/cargo/wgpu-core@30.0.0/Cargo.toml +237 -0
  726. package/third-party/cargo/wgpu-core@30.0.0/LICENSE.APACHE +176 -0
  727. package/third-party/cargo/wgpu-core@30.0.0/LICENSE.MIT +21 -0
  728. package/third-party/cargo/wgpu-hal@30.0.0/Cargo.toml +541 -0
  729. package/third-party/cargo/wgpu-hal@30.0.0/LICENSE.APACHE +176 -0
  730. package/third-party/cargo/wgpu-hal@30.0.0/LICENSE.MIT +21 -0
  731. package/third-party/cargo/wgpu-naga-bridge@30.0.0/Cargo.toml +46 -0
  732. package/third-party/cargo/wgpu-naga-bridge@30.0.0/LICENSE.APACHE +176 -0
  733. package/third-party/cargo/wgpu-naga-bridge@30.0.0/LICENSE.MIT +21 -0
  734. package/third-party/cargo/wgpu-types@30.0.0/Cargo.toml +161 -0
  735. package/third-party/cargo/wgpu-types@30.0.0/LICENSE.APACHE +176 -0
  736. package/third-party/cargo/wgpu-types@30.0.0/LICENSE.MIT +21 -0
  737. package/third-party/cargo/wgpu@30.0.0/Cargo.toml +278 -0
  738. package/third-party/cargo/wgpu@30.0.0/LICENSE.APACHE +176 -0
  739. package/third-party/cargo/wgpu@30.0.0/LICENSE.MIT +21 -0
  740. package/third-party/cargo/xmlwriter@0.1.0/Cargo.toml +23 -0
  741. package/third-party/cargo/xmlwriter@0.1.0/LICENSE +21 -0
  742. package/third-party/cargo/yazi@0.2.1/Cargo.toml +45 -0
  743. package/third-party/cargo/yazi@0.2.1/LICENSE-APACHE +201 -0
  744. package/third-party/cargo/yazi@0.2.1/LICENSE-MIT +19 -0
  745. package/third-party/cargo/zeno@0.3.3/Cargo.toml +65 -0
  746. package/third-party/cargo/zeno@0.3.3/LICENSE-APACHE +201 -0
  747. package/third-party/cargo/zeno@0.3.3/LICENSE-MIT +25 -0
  748. package/third-party/cargo/zerocopy-derive@0.8.54/Cargo.toml +209 -0
  749. package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-APACHE +202 -0
  750. package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-BSD +24 -0
  751. package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-MIT +26 -0
  752. package/third-party/cargo/zerocopy@0.8.54/Cargo.toml +419 -0
  753. package/third-party/cargo/zerocopy@0.8.54/LICENSE-APACHE +202 -0
  754. package/third-party/cargo/zerocopy@0.8.54/LICENSE-BSD +24 -0
  755. package/third-party/cargo/zerocopy@0.8.54/LICENSE-MIT +26 -0
  756. package/third-party/cargo/zmij@1.0.23/Cargo.toml +90 -0
  757. package/third-party/cargo/zmij@1.0.23/LICENSE-MIT +23 -0
  758. package/third-party/cargo/zune-core@0.5.1/Cargo.toml +47 -0
  759. package/third-party/cargo/zune-core@0.5.1/LICENSE-APACHE +201 -0
  760. package/third-party/cargo/zune-core@0.5.1/LICENSE-MIT +21 -0
  761. package/third-party/cargo/zune-core@0.5.1/LICENSE-ZLIB +19 -0
  762. package/third-party/cargo/zune-jpeg@0.5.15/Cargo.toml +67 -0
  763. package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-APACHE +201 -0
  764. package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-MIT +21 -0
  765. package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-ZLIB +19 -0
  766. package/third-party/inventory.json +3614 -0
  767. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/esbuild-0.27.4-LICENSE.md +21 -0
  768. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/go-LICENSE +27 -0
  769. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/golang-x-sys-c0bba94af5f8-LICENSE +27 -0
  770. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/package.json +20 -0
  771. package/third-party/npm/@floating-ui__core@1.7.5/LICENSE +20 -0
  772. package/third-party/npm/@floating-ui__core@1.7.5/package.json +63 -0
  773. package/third-party/npm/@floating-ui__dom@1.7.6/LICENSE +20 -0
  774. package/third-party/npm/@floating-ui__dom@1.7.6/package.json +71 -0
  775. package/third-party/npm/@floating-ui__react-dom@2.1.8/LICENSE +20 -0
  776. package/third-party/npm/@floating-ui__react-dom@2.1.8/package.json +76 -0
  777. package/third-party/npm/@floating-ui__utils@0.2.11/LICENSE +20 -0
  778. package/third-party/npm/@floating-ui__utils@0.2.11/package.json +70 -0
  779. package/third-party/npm/@radix-ui__primitive@1.1.7/LICENSE +21 -0
  780. package/third-party/npm/@radix-ui__primitive@1.1.7/package.json +79 -0
  781. package/third-party/npm/@radix-ui__react-arrow@1.1.15/LICENSE +21 -0
  782. package/third-party/npm/@radix-ui__react-arrow@1.1.15/package.json +68 -0
  783. package/third-party/npm/@radix-ui__react-collection@1.1.15/LICENSE +21 -0
  784. package/third-party/npm/@radix-ui__react-collection@1.1.15/package.json +71 -0
  785. package/third-party/npm/@radix-ui__react-compose-refs@1.1.5/LICENSE +21 -0
  786. package/third-party/npm/@radix-ui__react-compose-refs@1.1.5/package.json +60 -0
  787. package/third-party/npm/@radix-ui__react-context-menu@2.3.7/LICENSE +21 -0
  788. package/third-party/npm/@radix-ui__react-context-menu@2.3.7/package.json +73 -0
  789. package/third-party/npm/@radix-ui__react-context@1.2.2/LICENSE +21 -0
  790. package/third-party/npm/@radix-ui__react-context@1.2.2/package.json +60 -0
  791. package/third-party/npm/@radix-ui__react-direction@1.1.4/LICENSE +21 -0
  792. package/third-party/npm/@radix-ui__react-direction@1.1.4/package.json +60 -0
  793. package/third-party/npm/@radix-ui__react-dismissable-layer@1.1.19/LICENSE +21 -0
  794. package/third-party/npm/@radix-ui__react-dismissable-layer@1.1.19/package.json +74 -0
  795. package/third-party/npm/@radix-ui__react-focus-guards@1.1.6/LICENSE +21 -0
  796. package/third-party/npm/@radix-ui__react-focus-guards@1.1.6/package.json +60 -0
  797. package/third-party/npm/@radix-ui__react-focus-scope@1.1.16/LICENSE +21 -0
  798. package/third-party/npm/@radix-ui__react-focus-scope@1.1.16/package.json +71 -0
  799. package/third-party/npm/@radix-ui__react-id@1.1.4/LICENSE +21 -0
  800. package/third-party/npm/@radix-ui__react-id@1.1.4/package.json +63 -0
  801. package/third-party/npm/@radix-ui__react-menu@2.1.24/LICENSE +21 -0
  802. package/third-party/npm/@radix-ui__react-menu@2.1.24/package.json +86 -0
  803. package/third-party/npm/@radix-ui__react-popper@1.3.7/LICENSE +21 -0
  804. package/third-party/npm/@radix-ui__react-popper@1.3.7/package.json +78 -0
  805. package/third-party/npm/@radix-ui__react-portal@1.1.17/LICENSE +21 -0
  806. package/third-party/npm/@radix-ui__react-portal@1.1.17/package.json +69 -0
  807. package/third-party/npm/@radix-ui__react-presence@1.1.10/LICENSE +21 -0
  808. package/third-party/npm/@radix-ui__react-presence@1.1.10/package.json +68 -0
  809. package/third-party/npm/@radix-ui__react-primitive@2.1.10/LICENSE +21 -0
  810. package/third-party/npm/@radix-ui__react-primitive@2.1.10/package.json +68 -0
  811. package/third-party/npm/@radix-ui__react-roving-focus@1.1.19/LICENSE +21 -0
  812. package/third-party/npm/@radix-ui__react-roving-focus@1.1.19/package.json +78 -0
  813. package/third-party/npm/@radix-ui__react-slot@1.3.3/LICENSE +21 -0
  814. package/third-party/npm/@radix-ui__react-slot@1.3.3/package.json +63 -0
  815. package/third-party/npm/@radix-ui__react-use-callback-ref@1.1.4/LICENSE +21 -0
  816. package/third-party/npm/@radix-ui__react-use-callback-ref@1.1.4/package.json +60 -0
  817. package/third-party/npm/@radix-ui__react-use-controllable-state@1.2.6/LICENSE +21 -0
  818. package/third-party/npm/@radix-ui__react-use-controllable-state@1.2.6/package.json +65 -0
  819. package/third-party/npm/@radix-ui__react-use-effect-event@0.0.5/LICENSE +21 -0
  820. package/third-party/npm/@radix-ui__react-use-effect-event@0.0.5/package.json +65 -0
  821. package/third-party/npm/@radix-ui__react-use-is-hydrated@0.1.3/LICENSE +21 -0
  822. package/third-party/npm/@radix-ui__react-use-is-hydrated@0.1.3/package.json +61 -0
  823. package/third-party/npm/@radix-ui__react-use-layout-effect@1.1.4/LICENSE +21 -0
  824. package/third-party/npm/@radix-ui__react-use-layout-effect@1.1.4/package.json +60 -0
  825. package/third-party/npm/@radix-ui__react-use-size@1.1.4/LICENSE +21 -0
  826. package/third-party/npm/@radix-ui__react-use-size@1.1.4/package.json +63 -0
  827. package/third-party/npm/aria-hidden@1.2.6/LICENSE +21 -0
  828. package/third-party/npm/aria-hidden@1.2.6/package.json +71 -0
  829. package/third-party/npm/detect-node-es@1.1.0/LICENSE +21 -0
  830. package/third-party/npm/detect-node-es@1.1.0/package.json +29 -0
  831. package/third-party/npm/esbuild@0.27.4/LICENSE.md +21 -0
  832. package/third-party/npm/esbuild@0.27.4/package.json +49 -0
  833. package/third-party/npm/fflate@0.8.3/LICENSE +21 -0
  834. package/third-party/npm/fflate@0.8.3/package.json +128 -0
  835. package/third-party/npm/get-nonce@1.0.1/LICENSE +21 -0
  836. package/third-party/npm/get-nonce@1.0.1/package.json +68 -0
  837. package/third-party/npm/mediabunny@1.52.2/LICENSE +373 -0
  838. package/third-party/npm/mediabunny@1.52.2/package.json +136 -0
  839. package/third-party/npm/mediabunny@1.52.2/source/LICENSE +373 -0
  840. package/third-party/npm/mediabunny@1.52.2/source/package.json +136 -0
  841. package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-demuxer.ts +400 -0
  842. package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-muxer.ts +124 -0
  843. package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-reader.ts +85 -0
  844. package/third-party/npm/mediabunny@1.52.2/source/src/aes.ts +307 -0
  845. package/third-party/npm/mediabunny@1.52.2/source/src/codec-data.ts +3178 -0
  846. package/third-party/npm/mediabunny@1.52.2/source/src/codec.ts +1154 -0
  847. package/third-party/npm/mediabunny@1.52.2/source/src/conversion.ts +2042 -0
  848. package/third-party/npm/mediabunny@1.52.2/source/src/custom-coder.ts +212 -0
  849. package/third-party/npm/mediabunny@1.52.2/source/src/decode.ts +263 -0
  850. package/third-party/npm/mediabunny@1.52.2/source/src/demuxer.ts +43 -0
  851. package/third-party/npm/mediabunny@1.52.2/source/src/encode.ts +1412 -0
  852. package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-demuxer.ts +813 -0
  853. package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-misc.ts +165 -0
  854. package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-muxer.ts +350 -0
  855. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-demuxer.ts +995 -0
  856. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-misc.ts +81 -0
  857. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-muxer.ts +1529 -0
  858. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-segmented-input.ts +772 -0
  859. package/third-party/npm/mediabunny@1.52.2/source/src/id3.ts +972 -0
  860. package/third-party/npm/mediabunny@1.52.2/source/src/index.ts +319 -0
  861. package/third-party/npm/mediabunny@1.52.2/source/src/input-format.ts +819 -0
  862. package/third-party/npm/mediabunny@1.52.2/source/src/input-track.ts +1141 -0
  863. package/third-party/npm/mediabunny@1.52.2/source/src/input.ts +571 -0
  864. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-boxes.ts +1911 -0
  865. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-demuxer.ts +3953 -0
  866. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-misc.ts +90 -0
  867. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-muxer.ts +1595 -0
  868. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-reader.ts +91 -0
  869. package/third-party/npm/mediabunny@1.52.2/source/src/logging.ts +120 -0
  870. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/ebml.ts +770 -0
  871. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-demuxer.ts +2598 -0
  872. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-misc.ts +29 -0
  873. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-muxer.ts +1360 -0
  874. package/third-party/npm/mediabunny@1.52.2/source/src/media-sink.ts +2589 -0
  875. package/third-party/npm/mediabunny@1.52.2/source/src/media-source.ts +3041 -0
  876. package/third-party/npm/mediabunny@1.52.2/source/src/metadata.ts +335 -0
  877. package/third-party/npm/mediabunny@1.52.2/source/src/misc.ts +1336 -0
  878. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-demuxer.ts +469 -0
  879. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-muxer.ts +169 -0
  880. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-reader.ts +61 -0
  881. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-writer.ts +121 -0
  882. package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-demuxer.ts +2519 -0
  883. package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-misc.ts +32 -0
  884. package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-muxer.ts +842 -0
  885. package/third-party/npm/mediabunny@1.52.2/source/src/muxer.ts +80 -0
  886. package/third-party/npm/mediabunny@1.52.2/source/src/node.ts +11 -0
  887. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-demuxer.ts +1087 -0
  888. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-misc.ts +116 -0
  889. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-muxer.ts +527 -0
  890. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-reader.ts +93 -0
  891. package/third-party/npm/mediabunny@1.52.2/source/src/output-format.ts +1425 -0
  892. package/third-party/npm/mediabunny@1.52.2/source/src/output.ts +940 -0
  893. package/third-party/npm/mediabunny@1.52.2/source/src/packet.ts +287 -0
  894. package/third-party/npm/mediabunny@1.52.2/source/src/pcm.ts +112 -0
  895. package/third-party/npm/mediabunny@1.52.2/source/src/reader.ts +391 -0
  896. package/third-party/npm/mediabunny@1.52.2/source/src/resample.ts +287 -0
  897. package/third-party/npm/mediabunny@1.52.2/source/src/sample.ts +3231 -0
  898. package/third-party/npm/mediabunny@1.52.2/source/src/segmented-input.ts +575 -0
  899. package/third-party/npm/mediabunny@1.52.2/source/src/source.ts +2588 -0
  900. package/third-party/npm/mediabunny@1.52.2/source/src/subtitles.ts +131 -0
  901. package/third-party/npm/mediabunny@1.52.2/source/src/target.ts +871 -0
  902. package/third-party/npm/mediabunny@1.52.2/source/src/tsconfig.json +16 -0
  903. package/third-party/npm/mediabunny@1.52.2/source/src/wave/riff-writer.ts +36 -0
  904. package/third-party/npm/mediabunny@1.52.2/source/src/wave/wave-demuxer.ts +583 -0
  905. package/third-party/npm/mediabunny@1.52.2/source/src/wave/wave-muxer.ts +375 -0
  906. package/third-party/npm/mediabunny@1.52.2/source/src/writer.ts +128 -0
  907. package/third-party/npm/react-dom@19.3.0/LICENSE +21 -0
  908. package/third-party/npm/react-dom@19.3.0/package.json +117 -0
  909. package/third-party/npm/react-remove-scroll-bar@2.3.8/package.json +85 -0
  910. package/third-party/npm/react-remove-scroll-bar@2.3.8/react-remove-scroll-bar-LICENSE +21 -0
  911. package/third-party/npm/react-remove-scroll@2.7.2/LICENSE +21 -0
  912. package/third-party/npm/react-remove-scroll@2.7.2/package.json +98 -0
  913. package/third-party/npm/react-style-singleton@2.2.3/LICENSE +21 -0
  914. package/third-party/npm/react-style-singleton@2.2.3/package.json +90 -0
  915. package/third-party/npm/react@19.3.0/LICENSE +21 -0
  916. package/third-party/npm/react@19.3.0/package.json +51 -0
  917. package/third-party/npm/scheduler@0.28.0/LICENSE +21 -0
  918. package/third-party/npm/scheduler@0.28.0/package.json +27 -0
  919. package/third-party/npm/tslib@2.8.1/LICENSE.txt +12 -0
  920. package/third-party/npm/tslib@2.8.1/package.json +47 -0
  921. package/third-party/npm/typescript@5.9.3/LICENSE.txt +55 -0
  922. package/third-party/npm/typescript@5.9.3/ThirdPartyNoticeText.txt +193 -0
  923. package/third-party/npm/typescript@5.9.3/package.json +120 -0
  924. package/third-party/npm/use-callback-ref@1.3.3/LICENSE +21 -0
  925. package/third-party/npm/use-callback-ref@1.3.3/package.json +85 -0
  926. package/third-party/npm/use-sidecar@1.1.3/LICENSE +21 -0
  927. package/third-party/npm/use-sidecar@1.1.3/package.json +93 -0
  928. package/third-party/packages/render-engine/assets/OFL.txt +93 -0
  929. package/third-party/packages/studio/public/fonts/OFL.txt +93 -0
  930. package/third-party/packages/studio/vendor/osmo-icons/LICENSE +21 -0
  931. package/third-party/packages/studio/vendor/shadcn/LICENSE +21 -0
  932. package/third-party/repository-notices.md +41 -0
  933. package/third-party/rust-standard-library/COPYRIGHT-library.html +5556 -0
  934. package/third-party/rust-standard-library/licenses/Apache-2.0.txt +73 -0
  935. package/third-party/rust-standard-library/licenses/BSD-2-Clause.txt +9 -0
  936. package/third-party/rust-standard-library/licenses/CC-BY-SA-4.0.txt +427 -0
  937. package/third-party/rust-standard-library/licenses/GCC-exception-3.1.txt +30 -0
  938. package/third-party/rust-standard-library/licenses/GPL-2.0-only.txt +133 -0
  939. package/third-party/rust-standard-library/licenses/GPL-3.0-or-later.txt +202 -0
  940. package/third-party/rust-standard-library/licenses/ISC.txt +7 -0
  941. package/third-party/rust-standard-library/licenses/LLVM-exception.txt +15 -0
  942. package/third-party/rust-standard-library/licenses/MIT.txt +9 -0
  943. package/third-party/rust-standard-library/licenses/NCSA.txt +29 -0
  944. package/third-party/rust-standard-library/licenses/OFL-1.1.txt +43 -0
  945. package/third-party/rust-standard-library/licenses/Unicode-3.0.txt +39 -0
  946. package/third-party/rust-standard-library/version.txt +1 -0
  947. package/vendor/osmo-lite +0 -0
  948. package/vendor/osmo-scene-0.1.0.tgz +0 -0
  949. package/vendor/platform.json +1 -0
@@ -0,0 +1,2588 @@
1
+ /*!
2
+ * Copyright (c) 2026-present, Vanilagy and contributors
3
+ *
4
+ * This Source Code Form is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
9
+ import type { FileHandle } from 'node:fs/promises';
10
+ import {
11
+ assert,
12
+ binarySearchLessOrEqual,
13
+ clamp,
14
+ closedIntervalsOverlap,
15
+ FilePath,
16
+ isNumber,
17
+ isWebKit,
18
+ MaybePromise,
19
+ mergeRequestInit,
20
+ normalizeHeaders,
21
+ polyfillSymbolDispose,
22
+ promiseWithResolvers,
23
+ retriedFetch,
24
+ toDataView,
25
+ toUint8Array,
26
+ wait,
27
+ EventEmitter,
28
+ } from './misc';
29
+ import * as nodeAlias from './node';
30
+ import { InputDisposedError } from './input';
31
+ import { Logging } from './logging';
32
+
33
+ polyfillSymbolDispose();
34
+
35
+ const node = typeof nodeAlias !== 'undefined'
36
+ ? nodeAlias // Aliasing it prevents some bundler warnings
37
+ : undefined!;
38
+
39
+ export type ReadResult = {
40
+ bytes: Uint8Array;
41
+ view: DataView;
42
+ /** The offset of the bytes in the file. */
43
+ offset: number;
44
+ };
45
+
46
+ export const DEFAULT_MIN_READ_POSITION = 0;
47
+ export const DEFAULT_MAX_READ_POSITION = Infinity;
48
+
49
+ /**
50
+ * The events emitted by a {@link Source}, with each key being an event name and its value being the event data.
51
+ * @group Input sources
52
+ * @public
53
+ */
54
+ export type SourceEvents = {
55
+ /** Emitted each time data is retrieved from the source. */
56
+ read: {
57
+ /** The start of the retrieved range, inclusive. */
58
+ start: number;
59
+ /** The end of the retrieved range, exclusive. */
60
+ end: number;
61
+ };
62
+ };
63
+
64
+ let sourceFinalizationRegistry: FinalizationRegistry<() => unknown> | null = null;
65
+ if (typeof FinalizationRegistry !== 'undefined') {
66
+ sourceFinalizationRegistry = new FinalizationRegistry((cleanup) => {
67
+ cleanup();
68
+ });
69
+ }
70
+
71
+ /**
72
+ * The source base class, representing a resource from which bytes can be read.
73
+ * @group Input sources
74
+ * @public
75
+ */
76
+ export abstract class Source extends EventEmitter<SourceEvents> {
77
+ /** @internal */
78
+ abstract _getFileSize(): number | null | undefined;
79
+ /** @internal */
80
+ abstract _read(
81
+ start: number,
82
+ end: number,
83
+ minReadPosition: number,
84
+ maxReadPosition: number,
85
+ ): MaybePromise<ReadResult | null>;
86
+ /** @internal */
87
+ abstract _dispose(): void;
88
+ /** @internal */
89
+ _disposed = false;
90
+ /** @internal */
91
+ _refCount = 0;
92
+ /**
93
+ * Used internally to mark if a source stems from an HLS reading operation. Used to suppress certain warnings.
94
+ * @internal
95
+ */
96
+ _usedForHls = false;
97
+ /**
98
+ * FinalizationRegistry for rogue refs to this source that didn't get freed. It lives on the Source itself so that
99
+ * in case the Source transitively points back to itself and forms a cycle (for example through a custom
100
+ * CustomSource callback) that we're not leaking memory.
101
+ * @internal
102
+ */
103
+ _refFinalizationRegistry: FinalizationRegistry<Source> | null = null;
104
+
105
+ /** @internal */
106
+ private _sizePromise: Promise<number | null> | null = null;
107
+
108
+ constructor() {
109
+ super();
110
+
111
+ if (typeof FinalizationRegistry !== 'undefined') {
112
+ this._refFinalizationRegistry = new FinalizationRegistry((source) => {
113
+ source._decrementRefCount();
114
+ });
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call
120
+ * will retrieve the size.
121
+ *
122
+ * Returns null if the source is unsized.
123
+ */
124
+ async getSizeOrNull() {
125
+ if (this._disposed) {
126
+ throw new InputDisposedError();
127
+ }
128
+
129
+ return this._sizePromise ??= (async () => {
130
+ let size = this._getFileSize();
131
+ if (size !== undefined) {
132
+ return size;
133
+ }
134
+
135
+ await this._read(0, 1, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION);
136
+ size = this._getFileSize();
137
+ assert(size !== undefined);
138
+
139
+ return size;
140
+ })();
141
+ }
142
+
143
+ /**
144
+ * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call
145
+ * will retrieve the size.
146
+ *
147
+ * Throws an error if the source is unsized.
148
+ */
149
+ async getSize() {
150
+ if (this._disposed) {
151
+ throw new InputDisposedError();
152
+ }
153
+
154
+ const result = await this.getSizeOrNull();
155
+ if (result === null) {
156
+ throw new Error('Cannot determine the size of an unsized source.');
157
+ }
158
+
159
+ return result;
160
+ }
161
+
162
+ /**
163
+ * Returns a new {@link RangedSource} that maps data onto this source using the given offset and length. If a length
164
+ * is not provided, the ranged source spans until the end of this source's data.
165
+ *
166
+ * Useful for reading files that are embedded within larger files.
167
+ */
168
+ slice(offset: number, length?: number) {
169
+ if (!Number.isInteger(offset) || offset < 0) {
170
+ throw new TypeError('offset must be a non-negative integer.');
171
+ }
172
+ if (length !== undefined && (!Number.isInteger(length) || length < 0)) {
173
+ throw new TypeError('length, when provided, must be a non-negative integer.');
174
+ }
175
+
176
+ return new RangedSource(this, offset, length);
177
+ }
178
+
179
+ /**
180
+ * Called each time data is retrieved from the source. Will be called with the retrieved range (end exclusive).
181
+ *
182
+ * @deprecated Use `source.on('read', ({ start, end }) => ...)` instead.
183
+ */
184
+ onread: ((start: number, end: number) => unknown) | null = null;
185
+
186
+ /** @internal */
187
+ _dispatchRead(start: number, end: number) {
188
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
189
+ this.onread?.(start, end);
190
+ this._emit('read', { start, end });
191
+ }
192
+
193
+ /**
194
+ * Creates a new `SourceRef` pointing to this source. You are expected to call `.free()` on said `SourceRef` when
195
+ * you're done with it.
196
+ */
197
+ ref() {
198
+ return new SourceRef(this);
199
+ }
200
+
201
+ /** @internal */
202
+ _incrementRefCount() {
203
+ this._refCount++;
204
+ }
205
+
206
+ /** @internal */
207
+ _decrementRefCount() {
208
+ this._refCount--;
209
+
210
+ if (this._refCount === 0) {
211
+ this._dispose();
212
+ this._disposed = true;
213
+ }
214
+ }
215
+ }
216
+
217
+ /**
218
+ * A reference to a {@link Source}, used to manage a source's lifecycle. Creating a `SourceRef` via {@link Source.ref}
219
+ * increases that source's internal reference count. As long as a source has a non-zero reference count, it is assumed
220
+ * to still be in use. Once all references are freed via {@link SourceRef.free}, the source gets disposed.
221
+ *
222
+ * @group Input sources
223
+ * @public
224
+ */
225
+ export class SourceRef<S extends Source = Source> implements Disposable {
226
+ /** @internal */
227
+ private _source: S | null;
228
+ /** @internal */
229
+ private _freed = false;
230
+
231
+ /** @internal */
232
+ constructor(source: S) {
233
+ if (source._disposed) {
234
+ throw new Error('Cannot ref a disposed source.');
235
+ }
236
+
237
+ source._incrementRefCount();
238
+ source._refFinalizationRegistry?.register(this, source, this);
239
+
240
+ this._source = source;
241
+ }
242
+
243
+ /** The {@link Source} this ref references. Accessing this field throws an error after having freed the ref. */
244
+ get source() {
245
+ if (!this._source) {
246
+ throw new Error('Can\'t get source; ref has already been freed.');
247
+ }
248
+
249
+ return this._source;
250
+ }
251
+
252
+ /** Whether or not this reference has been freed via {@link SourceRef.free}. */
253
+ get freed() {
254
+ return this._freed;
255
+ }
256
+
257
+ /**
258
+ * Frees the ref, decrementing the source's internal reference count. If the source's internal reference count
259
+ * reaches zero, it gets disposed. To catch bugs, this method throws if the ref is already freed.
260
+ */
261
+ free() {
262
+ if (this._freed) {
263
+ throw new Error('Illegal operation: double free on SourceRef.');
264
+ }
265
+
266
+ const source = this.source;
267
+ assert(source._refCount > 0);
268
+
269
+ source._decrementRefCount();
270
+ source._refFinalizationRegistry?.unregister(this);
271
+
272
+ this._freed = true;
273
+ this._source = null;
274
+ }
275
+
276
+ /**
277
+ * Calls {@link SourceRef.free}.
278
+ */
279
+ [Symbol.dispose]() {
280
+ if (!this.freed) {
281
+ this.free();
282
+ }
283
+ }
284
+ }
285
+
286
+ /**
287
+ * A source which can create new sources from file paths. Required for multi-file inputs such as HLS playlists.
288
+ * @public
289
+ * @group Input sources
290
+ */
291
+ export abstract class PathedSource extends Source {
292
+ constructor(
293
+ /**
294
+ * The path that points to the root file; the entry file of the media.
295
+ *
296
+ * This path may be modified by the source to indicate a redirect: an updated path to perform new requests
297
+ * relative to.
298
+ */
299
+ public rootPath: FilePath,
300
+ /** The callback that is called for each requested file; must return a {@link Source} or {@link SourceRef}. */
301
+ public readonly requestHandler: (request: SourceRequest) => MaybePromise<Source | SourceRef>,
302
+ ) {
303
+ if (typeof rootPath !== 'string') {
304
+ throw new TypeError('rootPath must be a string.');
305
+ }
306
+ if (typeof requestHandler !== 'function') {
307
+ throw new TypeError('requestHandler must be a function.');
308
+ }
309
+
310
+ super();
311
+ }
312
+
313
+ /** @internal */
314
+ _resolveRequest(request: SourceRequest): MaybePromise<SourceRef> {
315
+ const result = this.requestHandler(request);
316
+
317
+ const handle = (result: Source | SourceRef) => {
318
+ if (!(result instanceof Source || result instanceof SourceRef)) {
319
+ throw new TypeError('requestHandler must return or resolve to a Source or SourceRef.');
320
+ }
321
+
322
+ const ref = result instanceof Source
323
+ ? result.ref()
324
+ : result;
325
+
326
+ ref.source._usedForHls ||= this._usedForHls;
327
+
328
+ return ref;
329
+ };
330
+
331
+ if (result instanceof Promise) {
332
+ return result.then(handle);
333
+ } else {
334
+ return handle(result);
335
+ }
336
+ }
337
+ }
338
+
339
+ /**
340
+ * A request for a {@link Source} at the given path.
341
+ * @group Input sources
342
+ * @public
343
+ */
344
+ export type SourceRequest = {
345
+ /** The requested file path. */
346
+ path: FilePath;
347
+ /** Whether the requested file is the root file. */
348
+ isRoot: boolean;
349
+ };
350
+
351
+ export const sourceRequestsAreEqual = (a: SourceRequest, b: SourceRequest) => {
352
+ return a.path === b.path;
353
+ };
354
+
355
+ /**
356
+ * A custom multi-file source where each file is uniquely identified by a {@link FilePath} and can be resolved to
357
+ * an arbitrary {@link Source}.
358
+ *
359
+ * @public
360
+ * @group Input sources
361
+ */
362
+ export class CustomPathedSource extends PathedSource {
363
+ /** @internal */
364
+ _root: SourceRef | null = null;
365
+ /** @internal */
366
+ _rootRequest: Promise<SourceRef> | null = null;
367
+
368
+ /** @internal */
369
+ override _read(
370
+ start: number,
371
+ end: number,
372
+ minReadPosition: number,
373
+ maxReadPosition: number,
374
+ ): MaybePromise<ReadResult | null> {
375
+ if (!this._root) {
376
+ if (!this._rootRequest) {
377
+ const result = this._resolveRequest({ path: this.rootPath, isRoot: true });
378
+
379
+ const handle = (result: Source | SourceRef) => {
380
+ const ref = result instanceof Source
381
+ ? result.ref()
382
+ : result;
383
+
384
+ this._root = ref;
385
+ this._rootRequest = null;
386
+
387
+ return ref;
388
+ };
389
+
390
+ if (result instanceof Promise) {
391
+ this._rootRequest = result.then(handle);
392
+ } else {
393
+ handle(result);
394
+ assert(this._root);
395
+ }
396
+ }
397
+
398
+ if (this._rootRequest) {
399
+ return this._rootRequest.then(ref => ref.source._read(start, end, minReadPosition, maxReadPosition));
400
+ }
401
+ }
402
+
403
+ return this._root!.source._read(start, end, minReadPosition, maxReadPosition);
404
+ }
405
+
406
+ /** @internal */
407
+ override _getFileSize(): number | null | undefined {
408
+ if (this._root) {
409
+ return this._root.source._getFileSize();
410
+ }
411
+
412
+ return undefined;
413
+ }
414
+
415
+ /** @internal */
416
+ override _dispose(): void {
417
+ if (this._root) {
418
+ this._root.free();
419
+ } else if (this._rootRequest) {
420
+ void this._rootRequest
421
+ .then(ref => ref.free());
422
+ }
423
+ }
424
+ }
425
+
426
+ /**
427
+ * A source backed by an ArrayBuffer or ArrayBufferView, with the entire file held in memory.
428
+ * @group Input sources
429
+ * @public
430
+ */
431
+ export class BufferSource extends Source {
432
+ /** @internal */
433
+ _bytes: Uint8Array;
434
+ /** @internal */
435
+ _view: DataView;
436
+ /** @internal */
437
+ _onreadCalled = false;
438
+
439
+ /**
440
+ * Creates a new {@link BufferSource} backed by the specified `ArrayBuffer`, `SharedArrayBuffer`,
441
+ * or `ArrayBufferView`.
442
+ */
443
+ constructor(buffer: AllowSharedBufferSource) {
444
+ if (
445
+ !(buffer instanceof ArrayBuffer)
446
+ && !(typeof SharedArrayBuffer !== 'undefined' && buffer instanceof SharedArrayBuffer)
447
+ && !ArrayBuffer.isView(buffer)
448
+ ) {
449
+ throw new TypeError('buffer must be an ArrayBuffer, SharedArrayBuffer, or ArrayBufferView.');
450
+ }
451
+
452
+ super();
453
+
454
+ this._bytes = toUint8Array(buffer);
455
+ this._view = toDataView(buffer);
456
+ }
457
+
458
+ /** @internal */
459
+ _getFileSize(): number {
460
+ return this._bytes.byteLength;
461
+ }
462
+
463
+ /** @internal */
464
+ _read(): ReadResult {
465
+ if (!this._onreadCalled) {
466
+ // We just say the first read retrieves all bytes from the source (which, I mean, it does)
467
+ this._dispatchRead(0, this._bytes.byteLength);
468
+ this._onreadCalled = true;
469
+ }
470
+
471
+ return {
472
+ bytes: this._bytes,
473
+ view: this._view,
474
+ offset: 0,
475
+ };
476
+ }
477
+
478
+ /** @internal */
479
+ _dispose() {}
480
+ }
481
+
482
+ /**
483
+ * Options for {@link BlobSource}.
484
+ * @group Input sources
485
+ * @public
486
+ */
487
+ export type BlobSourceOptions = {
488
+ /** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 8 MiB. */
489
+ maxCacheSize?: number;
490
+ /**
491
+ * Defaults to `true`. When `true`, Mediabunny will acquire a `ReadableStream` reader internally to efficiently read
492
+ * data from the blob. Since this can lead to errors in some (very) rare cases due to browser bugs, you can set this
493
+ * field to `false` to try a slower but more stable reading method.
494
+ */
495
+ useStreamReader?: boolean;
496
+ };
497
+
498
+ /**
499
+ * A source backed by a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). Since a
500
+ * [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) is also a `Blob`, this is the source to use when
501
+ * reading files off the disk.
502
+ * @group Input sources
503
+ * @public
504
+ */
505
+ export class BlobSource extends Source {
506
+ /** @internal */
507
+ _blob: Blob;
508
+ /** @internal */
509
+ _options: BlobSourceOptions;
510
+ /** @internal */
511
+ _orchestrator: ReadOrchestrator;
512
+
513
+ /**
514
+ * Creates a new {@link BlobSource} backed by the specified
515
+ * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
516
+ */
517
+ constructor(blob: Blob, options: BlobSourceOptions = {}) {
518
+ if (!(blob instanceof Blob)) {
519
+ throw new TypeError('blob must be a Blob.');
520
+ }
521
+ if (!options || typeof options !== 'object') {
522
+ throw new TypeError('options must be an object.');
523
+ }
524
+ if (
525
+ options.maxCacheSize !== undefined
526
+ && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)
527
+ ) {
528
+ throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
529
+ }
530
+ if (options.useStreamReader !== undefined && typeof options.useStreamReader !== 'boolean') {
531
+ throw new TypeError('options.useStreamReader, when provided, must be a boolean.');
532
+ }
533
+
534
+ super();
535
+
536
+ this._blob = blob;
537
+ this._options = options;
538
+
539
+ this._orchestrator = new ReadOrchestrator({
540
+ maxCacheSize: options.maxCacheSize ?? (8 * 2 ** 20 /* 8 MiB */),
541
+ maxWorkerCount: 4,
542
+ runWorker: this._runWorker.bind(this),
543
+ prefetchProfile: PREFETCH_PROFILES.fileSystem,
544
+ });
545
+
546
+ this._orchestrator.fileSize = blob.size;
547
+ }
548
+
549
+ /** @internal */
550
+ _getFileSize(): number {
551
+ return this._orchestrator.fileSize!; // Faster than blob.size
552
+ }
553
+
554
+ /** @internal */
555
+ _read(
556
+ start: number,
557
+ end: number,
558
+ minReadPosition: number,
559
+ maxReadPosition: number,
560
+ ): MaybePromise<ReadResult | null> {
561
+ return this._orchestrator.read(start, end, minReadPosition, maxReadPosition);
562
+ }
563
+
564
+ /** @internal */
565
+ _readers = new WeakMap<ReadWorker, ReadableStreamDefaultReader<Uint8Array> | null>();
566
+
567
+ /** @internal */
568
+ private async _runWorker(worker: ReadWorker) {
569
+ assert(worker.strictTarget);
570
+
571
+ let reader = this._readers.get(worker);
572
+ if (reader === undefined) {
573
+ // https://github.com/Vanilagy/mediabunny/issues/184
574
+ // WebKit has critical bugs with blob.stream():
575
+ // - WebKitBlobResource error 1 when streaming large files
576
+ // - Memory buildup and reload loops on iOS (network process crashes)
577
+ // - ReadableStream stalls under backpressure (especially video)
578
+ // Affects Safari and all iOS browsers (Chrome, Firefox, etc.).
579
+ // Use arrayBuffer() fallback for WebKit browsers.
580
+ if ('stream' in this._blob && !isWebKit() && this._options.useStreamReader !== false) {
581
+ // Get a reader of the blob starting at the required offset, and then keep it around
582
+ const slice = this._blob.slice(worker.currentPos);
583
+ reader = slice.stream().getReader();
584
+ } else {
585
+ // We'll need to use more primitive ways
586
+ reader = null;
587
+ }
588
+
589
+ this._readers.set(worker, reader);
590
+ }
591
+
592
+ while (worker.currentPos < worker.targetPos && !worker.aborted) {
593
+ if (reader) {
594
+ const { done, value } = await reader.read();
595
+ if (done) {
596
+ this._orchestrator.onWorkerFinished(worker);
597
+ throw new Error('Blob reader stopped unexpectedly before all requested data was read.');
598
+ }
599
+
600
+ if (worker.aborted) {
601
+ break;
602
+ }
603
+
604
+ this._dispatchRead(worker.currentPos, worker.currentPos + value.length);
605
+ this._orchestrator.supplyWorkerData(worker, value);
606
+ } else {
607
+ const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer();
608
+
609
+ if (worker.aborted) {
610
+ break;
611
+ }
612
+
613
+ this._dispatchRead(worker.currentPos, worker.currentPos + data.byteLength);
614
+ this._orchestrator.supplyWorkerData(worker, new Uint8Array(data));
615
+ }
616
+ }
617
+
618
+ this._orchestrator.signalWorkerStoppedRunning(worker);
619
+
620
+ if (worker.aborted) {
621
+ // MDN: "Calling this method signals a loss of interest in the stream by a consumer."
622
+ await reader?.cancel();
623
+ }
624
+ }
625
+
626
+ /** @internal */
627
+ _dispose() {
628
+ this._orchestrator.dispose();
629
+ }
630
+ }
631
+
632
+ const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; // 0.5 MiB
633
+ const DEFAULT_RETRY_DELAY
634
+ = ((previousAttempts, error, src) => {
635
+ // Check if this could be a CORS error. If so, we cannot recover from it and
636
+ // should not attempt to retry.
637
+ // CORS errors are intentionally not opaque, so we need to rely on heuristics.
638
+ const couldBeCorsError = error instanceof Error
639
+ && (
640
+ error.message.includes('Failed to fetch') // Chrome
641
+ || error.message.includes('Load failed') // Safari
642
+ || error.message.includes('NetworkError when attempting to fetch resource') // Firefox
643
+ )
644
+ && typeof window !== 'undefined'; // CORS only happens in browser environments
645
+
646
+ if (couldBeCorsError) {
647
+ let originOfSrc: string | null = null;
648
+ // Checking if the origin is different, because only then a CORS error could originate
649
+ try {
650
+ if (typeof window !== 'undefined' && typeof window.location !== 'undefined') {
651
+ originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin;
652
+ }
653
+ } catch {
654
+ // URL parse failed
655
+ }
656
+
657
+ // If user is offline, it is probably not a CORS error.
658
+ const isOnline
659
+ = typeof navigator !== 'undefined' && typeof navigator.onLine === 'boolean' ? navigator.onLine : true;
660
+
661
+ if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) {
662
+ Logging._warn(
663
+ `Request will not be retried because a CORS error was suspected due to different origins. You can`
664
+ + ` modify this behavior by providing your own function for the 'getRetryDelay' option.`,
665
+ );
666
+ return null;
667
+ }
668
+ }
669
+
670
+ return Math.min(2 ** (previousAttempts - 2), 16);
671
+ }) satisfies UrlSourceOptions['getRetryDelay'];
672
+
673
+ const warnedOrigins = new Set<string>();
674
+
675
+ /**
676
+ * Options for {@link UrlSource}.
677
+ * @group Input sources
678
+ * @public
679
+ */
680
+ export type UrlSourceOptions = {
681
+ /**
682
+ * The [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) used by the Fetch API. Can be
683
+ * used to further control the requests, such as setting custom headers.
684
+ *
685
+ * The `signal` field is not available, as Mediabunny controls request cancellation internally. If you want to
686
+ * cancel ongoing requests, use {@link Input.dispose}.
687
+ */
688
+ requestInit?: Omit<RequestInit, 'signal'>;
689
+
690
+ /**
691
+ * A function that returns the delay (in seconds) before retrying a failed request. The function is called
692
+ * with the number of previous, unsuccessful attempts, as well as with the error with which the previous request
693
+ * failed. If the function returns `null`, no more retries will be made.
694
+ *
695
+ * By default, it uses an exponential backoff algorithm that never gives up unless
696
+ * a CORS error is suspected (`fetch()` did reject, `navigator.onLine` is true and origin is different).
697
+ */
698
+ getRetryDelay?: (previousAttempts: number, error: unknown, url: string | URL | Request) => number | null;
699
+
700
+ /** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 64 MiB. */
701
+ maxCacheSize?: number;
702
+
703
+ /** The maximum number of parallel requests to use for fetching. Defaults to 2. */
704
+ parallelism?: number;
705
+
706
+ /**
707
+ * A WHATWG-compatible fetch function. You can use this field to polyfill the `fetch` function, add missing
708
+ * features, or use a custom implementation.
709
+ */
710
+ fetchFn?: typeof fetch;
711
+ };
712
+
713
+ /**
714
+ * A source backed by a URL. This is useful for reading data from the network. Requests will be made using an optimized
715
+ * reading and prefetching pattern to minimize request count and latency.
716
+ * @group Input sources
717
+ * @public
718
+ */
719
+ export class UrlSource extends PathedSource {
720
+ /** @internal */
721
+ _url: string | URL | Request;
722
+ /** @internal */
723
+ _getRetryDelay: (previousAttempts: number, error: unknown, url: string | URL | Request) => number | null;
724
+ /** @internal */
725
+ _options: UrlSourceOptions;
726
+ /** @internal */
727
+ _requestInit: RequestInit;
728
+ /** @internal */
729
+ _offset = 0;
730
+ /** @internal */
731
+ _length: number | null = null;
732
+ /** @internal */
733
+ _orchestrator: ReadOrchestrator;
734
+ /**
735
+ * Note that this value being true does NOT mean the file size can't change anymore; it just signals that we have at
736
+ * least checked if we know the file size or not.
737
+ * @internal
738
+ */
739
+ _fileSizeDetermined = false;
740
+
741
+ /**
742
+ * Creates a new {@link UrlSource} backed by the resource at the specified URL.
743
+ *
744
+ * When passing a `Request` instance, note that its `signal` will be overridden by Mediabunny; if you want to cancel
745
+ * ongoing requests, use {@link Input.dispose}.
746
+ */
747
+ constructor(
748
+ url: string | URL | Request,
749
+ options: UrlSourceOptions = {},
750
+ ) {
751
+ if (
752
+ typeof url !== 'string'
753
+ && !(url instanceof URL)
754
+ && !(typeof Request !== 'undefined' && url instanceof Request)
755
+ ) {
756
+ throw new TypeError('url must be a string, URL or Request.');
757
+ }
758
+ if (!options || typeof options !== 'object') {
759
+ throw new TypeError('options must be an object.');
760
+ }
761
+ if (options.requestInit !== undefined && (!options.requestInit || typeof options.requestInit !== 'object')) {
762
+ throw new TypeError('options.requestInit, when provided, must be an object.');
763
+ }
764
+ if (options.getRetryDelay !== undefined && typeof options.getRetryDelay !== 'function') {
765
+ throw new TypeError('options.getRetryDelay, when provided, must be a function.');
766
+ }
767
+ if (
768
+ options.maxCacheSize !== undefined
769
+ && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)
770
+ ) {
771
+ throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
772
+ }
773
+ if (options.parallelism !== undefined && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
774
+ throw new TypeError('options.parallelism, when provided, must be a positive number.');
775
+ }
776
+ if (options.fetchFn !== undefined && typeof options.fetchFn !== 'function') {
777
+ throw new TypeError('options.fetchFn, when provided, must be a function.');
778
+ // Won't bother validating this function beyond this
779
+ }
780
+
781
+ const urlString = url instanceof Request
782
+ ? url.url
783
+ : url instanceof URL
784
+ ? url.href
785
+ : url;
786
+
787
+ super(
788
+ urlString,
789
+ request => new UrlSource(request.path, this._options),
790
+ );
791
+
792
+ this._url = url;
793
+ this._options = options;
794
+ this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY;
795
+
796
+ // A user-supplied Range header is interpreted as a byte offset (and optional length) into the resource. We
797
+ // pull it out of the request and remember it for subsequent requests.
798
+ this._requestInit = { ...options.requestInit };
799
+
800
+ let rangeHeaderValue: string | null = null;
801
+
802
+ if (options.requestInit?.headers) {
803
+ const headers = { ...normalizeHeaders(options.requestInit.headers) };
804
+ const rangeKey = Object.keys(headers).find(key => key.toLowerCase() === 'range');
805
+ if (rangeKey !== undefined) {
806
+ rangeHeaderValue = headers[rangeKey]!;
807
+ delete headers[rangeKey];
808
+ this._requestInit.headers = headers;
809
+ }
810
+ }
811
+
812
+ if (url instanceof Request) {
813
+ const requestRange = url.headers.get('Range');
814
+ if (requestRange !== null) {
815
+ rangeHeaderValue ??= requestRange;
816
+
817
+ // Clone the request so we don't mutate the user's object, then strip the Range header
818
+ const strippedRequest = new Request(url);
819
+ strippedRequest.headers.delete('Range');
820
+ this._url = strippedRequest;
821
+ }
822
+ }
823
+
824
+ if (rangeHeaderValue !== null) {
825
+ const parsed = parseByteRangeHeader(rangeHeaderValue);
826
+ if (parsed) {
827
+ this._offset = parsed.offset;
828
+ this._length = parsed.length;
829
+ }
830
+ }
831
+
832
+ // Most files in the real-world have a single sequential access pattern, but having two in parallel can
833
+ // also happen
834
+ const DEFAULT_PARALLELISM = 2;
835
+
836
+ this._orchestrator = new ReadOrchestrator({
837
+ maxCacheSize: options.maxCacheSize ?? (64 * 2 ** 20 /* 64 MiB */),
838
+ maxWorkerCount: options.parallelism ?? DEFAULT_PARALLELISM,
839
+ runWorker: this._runWorker.bind(this),
840
+ prefetchProfile: PREFETCH_PROFILES.network,
841
+ });
842
+ }
843
+
844
+ /** @internal */
845
+ _getFileSize(): number | null | undefined {
846
+ if (!this._fileSizeDetermined) {
847
+ return this._length !== null ? this._length : undefined;
848
+ }
849
+
850
+ const baseSize = this._orchestrator.fileSize;
851
+ if (baseSize === null) {
852
+ return this._length !== null ? this._length : null;
853
+ }
854
+
855
+ return clamp(baseSize - this._offset, 0, this._length ?? Infinity);
856
+ }
857
+
858
+ /** @internal */
859
+ _read(
860
+ start: number,
861
+ end: number,
862
+ minReadPosition: number,
863
+ maxReadPosition: number,
864
+ ): MaybePromise<ReadResult | null> {
865
+ if (this._length !== null && end > this._length) {
866
+ return null;
867
+ }
868
+
869
+ const offset = this._offset;
870
+ const result = this._orchestrator.read(
871
+ offset + start,
872
+ offset + end,
873
+ Math.max(offset + minReadPosition, offset),
874
+ offset + Math.min(maxReadPosition, this._length ?? Infinity),
875
+ );
876
+
877
+ const processResult = (result: ReadResult | null) => {
878
+ if (!result) {
879
+ return null;
880
+ }
881
+
882
+ result.offset -= this._offset;
883
+ return result;
884
+ };
885
+
886
+ if (result instanceof Promise) {
887
+ return result.then(processResult);
888
+ } else {
889
+ return processResult(result);
890
+ }
891
+ }
892
+
893
+ /** @internal */
894
+ private async _runWorker(worker: ReadWorker) {
895
+ // The outer loop is for resuming a request if it dies mid-response
896
+ while (true) {
897
+ const abortController = new AbortController();
898
+ const response = await retriedFetch(
899
+ this._options.fetchFn ?? fetch,
900
+ this._url,
901
+ mergeRequestInit(this._requestInit, {
902
+ headers: {
903
+ // Always sending a range request is a good way to probe if the server supports them
904
+ Range: `bytes=${worker.currentPos}-`,
905
+ },
906
+ signal: abortController.signal,
907
+ }),
908
+ this._getRetryDelay,
909
+ () => this._disposed,
910
+ );
911
+
912
+ if (!response.ok) {
913
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
914
+ throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`);
915
+ }
916
+
917
+ if (response.redirected) {
918
+ // Modify our own root path so that future subrequests get made relative to the redirected URL
919
+ this.rootPath = response.url;
920
+ }
921
+
922
+ outer:
923
+ if (this._orchestrator.fileSize === null) {
924
+ // See if we can deduce the file size from the response
925
+
926
+ const contentRange = response.headers.get('Content-Range');
927
+ if (contentRange) {
928
+ const match = /\/(\d+)/.exec(contentRange);
929
+ if (match) {
930
+ this._orchestrator.supplyFileSize(Number(match[1]));
931
+ break outer;
932
+ }
933
+ }
934
+
935
+ const contentLength = response.headers.get('Content-Length');
936
+ if (contentLength) {
937
+ // Note: For range requests, this is _technically_ not correct, as the range response could contain
938
+ // less data than was requested. In practice, it seems most servers don't do this though, and the
939
+ // Content-Length header actually contains the length until the end of the file.
940
+ this._orchestrator.supplyFileSize(worker.currentPos + Number(contentLength));
941
+ }
942
+ }
943
+
944
+ this._fileSizeDetermined = true; // Yes, this is correct even if file size is still null
945
+
946
+ if (response.status !== 206) {
947
+ if (!this._usedForHls) {
948
+ const url = new URL(
949
+ this._url instanceof Request ? this._url.url : this._url,
950
+ typeof window !== 'undefined' ? window.location.href : undefined,
951
+ );
952
+
953
+ if (
954
+ url.origin !== 'null'
955
+ // Don't show the warning for M3U8 playlist files, it's irrelevant for those
956
+ && !(url.pathname.endsWith('.m3u8') || url.pathname.endsWith('.m3u'))
957
+ ) {
958
+ if (!warnedOrigins.has(url.origin)) {
959
+ Logging._warn(
960
+ `HTTP server (origin ${url.origin}) did not respond to a range request with 206 Partial`
961
+ + ' Content, meaning the entire resource will now be downloaded. To enable efficient'
962
+ + ' media file streaming across a network, please make sure your server supports'
963
+ + ' range requests.',
964
+ );
965
+ warnedOrigins.add(url.origin);
966
+ }
967
+ }
968
+ }
969
+
970
+ worker.currentPos = 0;
971
+ this._orchestrator.options.maxCacheSize = Infinity; // 🤷
972
+
973
+ if (this._orchestrator.fileSize !== null) {
974
+ worker.targetPos = this._orchestrator.fileSize;
975
+ } else {
976
+ // The server is dumb, doesn't even surface the content length, but we'll work with it.
977
+ worker.targetPos = Infinity;
978
+ worker.strictTarget = false;
979
+ }
980
+
981
+ this._orchestrator.consolidateEverythingIntoOneWorker(worker);
982
+ }
983
+
984
+ if (!response.body) {
985
+ throw new Error(
986
+ 'Missing HTTP response body stream. The used fetch function must provide the response body as a'
987
+ + ' ReadableStream.',
988
+ );
989
+ }
990
+
991
+ const reader = response.body.getReader();
992
+
993
+ while (true) {
994
+ if (worker.currentPos >= worker.targetPos || worker.aborted) {
995
+ abortController.abort();
996
+ this._orchestrator.signalWorkerStoppedRunning(worker);
997
+
998
+ return;
999
+ }
1000
+
1001
+ let readResult: ReadableStreamReadResult<Uint8Array>;
1002
+
1003
+ try {
1004
+ readResult = await reader.read();
1005
+ } catch (error) {
1006
+ if (this._disposed) {
1007
+ // No need to try to retry
1008
+ throw error;
1009
+ }
1010
+
1011
+ const retryDelayInSeconds = this._getRetryDelay(1, error, this._url);
1012
+ if (retryDelayInSeconds !== null) {
1013
+ Logging._error('Error while reading response stream. Attempting to resume.', error);
1014
+ await wait(1000 * retryDelayInSeconds);
1015
+
1016
+ break;
1017
+ } else {
1018
+ throw error;
1019
+ }
1020
+ }
1021
+
1022
+ if (worker.aborted) {
1023
+ continue; // Cleanup happens in next iteration
1024
+ }
1025
+
1026
+ const { done, value } = readResult;
1027
+
1028
+ if (done) {
1029
+ if (worker.currentPos >= worker.targetPos) {
1030
+ // All data was delivered, we're good
1031
+ this._orchestrator.onWorkerFinished(worker);
1032
+ return;
1033
+ }
1034
+
1035
+ if (worker.strictTarget) {
1036
+ // The response stopped early, before the target. This can happen if server decides to cap range
1037
+ // requests arbitrarily, even if the request had an uncapped end. In this case, let's fetch the
1038
+ // rest of the data using a new request.
1039
+ break;
1040
+ } else {
1041
+ // Assume we have simply reached the end of the resource
1042
+ this._orchestrator.onWorkerFinished(worker);
1043
+ return;
1044
+ }
1045
+ }
1046
+
1047
+ this._dispatchRead(worker.currentPos, worker.currentPos + value.length);
1048
+ this._orchestrator.supplyWorkerData(worker, value);
1049
+ }
1050
+ }
1051
+
1052
+ // The previous UrlSource had logic for circumventing https://issues.chromium.org/issues/436025873; I haven't
1053
+ // been able to observe this bug with the new UrlSource (maybe because we're using response streaming), so the
1054
+ // logic for that has vanished for now. Leaving a comment here if this becomes relevant again.
1055
+ }
1056
+
1057
+ /** @internal */
1058
+ _dispose() {
1059
+ this._orchestrator.dispose();
1060
+ }
1061
+ }
1062
+
1063
+ const BYTE_RANGE_REGEX = /^bytes=(\d+)-(\d*)$/;
1064
+ const parseByteRangeHeader = (value: string) => {
1065
+ const match = BYTE_RANGE_REGEX.exec(value.trim());
1066
+ if (!match) {
1067
+ return null;
1068
+ }
1069
+
1070
+ const offset = Number(match[1]);
1071
+ const end = match[2] === '' ? null : Number(match[2]);
1072
+
1073
+ if (end !== null && end < offset) {
1074
+ return null;
1075
+ }
1076
+
1077
+ return {
1078
+ offset,
1079
+ length: end !== null ? end - offset + 1 : null,
1080
+ };
1081
+ };
1082
+
1083
+ /**
1084
+ * Options for {@link FilePathSource}.
1085
+ * @group Input sources
1086
+ * @public
1087
+ */
1088
+ export type FilePathSourceOptions = {
1089
+ /** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 8 MiB. */
1090
+ maxCacheSize?: number;
1091
+ };
1092
+
1093
+ /**
1094
+ * A source backed by a path to a file. Intended for server-side usage in Node, Bun, or Deno.
1095
+ *
1096
+ * Make sure to call `.dispose()` on the corresponding {@link Input} when done to explicitly free the internal file
1097
+ * handle acquired by this source.
1098
+ * @group Input sources
1099
+ * @public
1100
+ */
1101
+ export class FilePathSource extends PathedSource {
1102
+ /** @internal */
1103
+ _customSource: CustomSource;
1104
+ /** @internal */
1105
+ _fileHandle: FileHandle | null = null;
1106
+
1107
+ /** Creates a new {@link FilePathSource} backed by the file at the specified file path. */
1108
+ constructor(filePath: string, options: FilePathSourceOptions = {}) {
1109
+ if (typeof filePath !== 'string') {
1110
+ throw new TypeError('filePath must be a string.');
1111
+ }
1112
+ if (!options || typeof options !== 'object') {
1113
+ throw new TypeError('options must be an object.');
1114
+ }
1115
+ if (
1116
+ options.maxCacheSize !== undefined
1117
+ && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)
1118
+ ) {
1119
+ throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
1120
+ }
1121
+
1122
+ if (!node.fs) {
1123
+ throw new Error(
1124
+ 'FilePathSource is only available in server-side environments (Node.js, Bun, Deno).',
1125
+ );
1126
+ }
1127
+
1128
+ super(filePath, request => new FilePathSource(request.path, options));
1129
+
1130
+ // Let's back this source with a CustomSource, makes the implementation very simple
1131
+ this._customSource = new CustomSource({
1132
+ getSize: async () => {
1133
+ const fileHandle = await node.fs.open(filePath, 'r');
1134
+ this._fileHandle = fileHandle;
1135
+
1136
+ sourceFinalizationRegistry?.register(this, () => {
1137
+ // If it's not closed, Node prints annoying warnings
1138
+ void fileHandle.close();
1139
+ }, this);
1140
+
1141
+ const stats = await fileHandle.stat();
1142
+ return stats.size;
1143
+ },
1144
+ read: async (start, end) => {
1145
+ assert(this._fileHandle);
1146
+
1147
+ const buffer = new Uint8Array(end - start);
1148
+ await this._fileHandle.read(buffer, 0, end - start, start);
1149
+
1150
+ return buffer;
1151
+ },
1152
+ maxCacheSize: options.maxCacheSize,
1153
+ prefetchProfile: 'fileSystem',
1154
+ });
1155
+ }
1156
+
1157
+ /** @internal */
1158
+ _read(
1159
+ start: number,
1160
+ end: number,
1161
+ minReadPosition: number,
1162
+ maxReadPosition: number,
1163
+ ): MaybePromise<ReadResult | null> {
1164
+ return this._customSource._read(start, end, minReadPosition, maxReadPosition);
1165
+ }
1166
+
1167
+ /** @internal */
1168
+ _getFileSize(): number | null | undefined {
1169
+ return this._customSource._getFileSize();
1170
+ }
1171
+
1172
+ /** @internal */
1173
+ _dispose() {
1174
+ this._customSource._dispose();
1175
+
1176
+ if (this._fileHandle) {
1177
+ void this._fileHandle.close();
1178
+ this._fileHandle = null;
1179
+ sourceFinalizationRegistry?.unregister(this);
1180
+ }
1181
+ }
1182
+ }
1183
+
1184
+ /**
1185
+ * Options for defining a {@link CustomSource}.
1186
+ * @group Input sources
1187
+ * @public
1188
+ */
1189
+ export type CustomSourceOptions = {
1190
+ /**
1191
+ * Called when the size of the entire file is requested. Must return or resolve to the size in bytes. This function
1192
+ * is guaranteed to be called before `read`.
1193
+ */
1194
+ getSize: () => MaybePromise<number>;
1195
+
1196
+ /**
1197
+ * Called when data is requested. Must return or resolve to the bytes from the specified byte range, or a stream
1198
+ * that yields these bytes.
1199
+ *
1200
+ * You are guaranteed that `0 <= start < end < fileSize`.
1201
+ */
1202
+ read: (start: number, end: number) => MaybePromise<Uint8Array | ReadableStream<Uint8Array>>;
1203
+
1204
+ /**
1205
+ * Called when the {@link Input} driven by this source is disposed.
1206
+ */
1207
+ dispose?: () => unknown;
1208
+
1209
+ /** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 8 MiB. */
1210
+ maxCacheSize?: number;
1211
+
1212
+ /**
1213
+ * Specifies the prefetch profile that the reader should use with this source. A prefetch profile specifies the
1214
+ * pattern with which bytes outside of the requested range are preloaded to reduce latency for future reads.
1215
+ *
1216
+ * - `'none'` (default): No prefetching; only the data needed in the moment is requested.
1217
+ * - `'fileSystem'`: File system-optimized prefetching: a small amount of data is prefetched bidirectionally,
1218
+ * aligned with page boundaries.
1219
+ * - `'network'`: Network-optimized prefetching, or more generally, prefetching optimized for any high-latency
1220
+ * environment: tries to minimize the amount of read calls and aggressively prefetches data when sequential access
1221
+ * patterns are detected.
1222
+ */
1223
+ prefetchProfile?: 'none' | 'fileSystem' | 'network';
1224
+ };
1225
+
1226
+ /**
1227
+ * A general-purpose, callback-driven source that can get its data from anywhere. Use this source to implement your own
1228
+ * custom source if the other sources don't cover your case.
1229
+ * @group Input sources
1230
+ * @public
1231
+ */
1232
+ export class CustomSource extends Source {
1233
+ /** @internal */
1234
+ _options: CustomSourceOptions;
1235
+ /** @internal */
1236
+ _orchestrator: ReadOrchestrator;
1237
+
1238
+ /** Creates a new {@link CustomSource} whose behavior is specified by `options`. */
1239
+ constructor(options: CustomSourceOptions) {
1240
+ if (!options || typeof options !== 'object') {
1241
+ throw new TypeError('options must be an object.');
1242
+ }
1243
+ if (typeof options.getSize !== 'function') {
1244
+ throw new TypeError('options.getSize must be a function.');
1245
+ }
1246
+ if (typeof options.read !== 'function') {
1247
+ throw new TypeError('options.read must be a function.');
1248
+ }
1249
+ if (options.dispose !== undefined && typeof options.dispose !== 'function') {
1250
+ throw new TypeError('options.dispose, when provided, must be a function.');
1251
+ }
1252
+ if (
1253
+ options.maxCacheSize !== undefined
1254
+ && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)
1255
+ ) {
1256
+ throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
1257
+ }
1258
+ if (options.prefetchProfile && !['none', 'fileSystem', 'network'].includes(options.prefetchProfile)) {
1259
+ throw new TypeError(
1260
+ 'options.prefetchProfile, when provided, must be one of \'none\', \'fileSystem\' or \'network\'.',
1261
+ );
1262
+ }
1263
+
1264
+ super();
1265
+
1266
+ this._options = options;
1267
+
1268
+ this._orchestrator = new ReadOrchestrator({
1269
+ maxCacheSize: options.maxCacheSize ?? (8 * 2 ** 20 /* 8 MiB */),
1270
+ maxWorkerCount: 2, // Fixed for now, *should* be fine
1271
+ prefetchProfile: PREFETCH_PROFILES[options.prefetchProfile ?? 'none'],
1272
+ runWorker: this._runWorker.bind(this),
1273
+ });
1274
+ }
1275
+
1276
+ /** @internal */
1277
+ _getFileSize(): number | null | undefined {
1278
+ return this._orchestrator.fileSize ?? undefined;
1279
+ }
1280
+
1281
+ /** @internal */
1282
+ _read(
1283
+ start: number,
1284
+ end: number,
1285
+ minReadPosition: number,
1286
+ maxReadPosition: number,
1287
+ ): MaybePromise<ReadResult | null> {
1288
+ if (this._orchestrator.fileSize !== null) {
1289
+ return this._orchestrator.read(start, end, minReadPosition, maxReadPosition);
1290
+ }
1291
+
1292
+ const result = this._options.getSize();
1293
+
1294
+ if (result instanceof Promise) {
1295
+ return result.then((size) => {
1296
+ if (!Number.isInteger(size) || size < 0) {
1297
+ throw new TypeError('options.getSize must return or resolve to a non-negative integer.');
1298
+ }
1299
+
1300
+ this._orchestrator.fileSize = size;
1301
+ return this._orchestrator.read(start, end, minReadPosition, maxReadPosition);
1302
+ });
1303
+ } else {
1304
+ if (!Number.isInteger(result) || result < 0) {
1305
+ throw new TypeError('options.getSize must return or resolve to a non-negative integer.');
1306
+ }
1307
+
1308
+ this._orchestrator.fileSize = result;
1309
+ return this._orchestrator.read(start, end, minReadPosition, maxReadPosition);
1310
+ }
1311
+ }
1312
+
1313
+ /** @internal */
1314
+ private async _runWorker(worker: ReadWorker) {
1315
+ while (worker.currentPos < worker.targetPos && !worker.aborted) {
1316
+ const originalCurrentPos = worker.currentPos;
1317
+ const originalTargetPos = worker.targetPos;
1318
+
1319
+ let data = this._options.read(worker.currentPos, originalTargetPos);
1320
+ if (data instanceof Promise) data = await data;
1321
+
1322
+ if (worker.aborted) {
1323
+ break;
1324
+ }
1325
+
1326
+ if (data instanceof Uint8Array) {
1327
+ data = toUint8Array(data); // Normalize things like Node.js Buffer to Uint8Array
1328
+
1329
+ if (data.length !== originalTargetPos - worker.currentPos) {
1330
+ // Yes, we're that strict
1331
+ throw new Error(
1332
+ `options.read returned a Uint8Array with unexpected length: Requested ${
1333
+ originalTargetPos - worker.currentPos
1334
+ } bytes, but got ${data.length}.`,
1335
+ );
1336
+ }
1337
+
1338
+ this._dispatchRead(worker.currentPos, worker.currentPos + data.length);
1339
+ this._orchestrator.supplyWorkerData(worker, data);
1340
+ } else if (data instanceof ReadableStream) {
1341
+ const reader = data.getReader();
1342
+
1343
+ while (worker.currentPos < originalTargetPos && !worker.aborted) {
1344
+ const { done, value } = await reader.read();
1345
+ if (done) {
1346
+ if (worker.currentPos < originalTargetPos) {
1347
+ // Yes, we're *that* strict
1348
+ throw new Error(
1349
+ `ReadableStream returned by options.read ended before supplying enough data.`
1350
+ + ` Requested ${originalTargetPos - originalCurrentPos} bytes, but got ${
1351
+ worker.currentPos - originalCurrentPos
1352
+ }`,
1353
+ );
1354
+ }
1355
+
1356
+ break;
1357
+ }
1358
+
1359
+ if (!(value instanceof Uint8Array)) {
1360
+ throw new TypeError('ReadableStream returned by options.read must yield Uint8Array chunks.');
1361
+ }
1362
+
1363
+ if (worker.aborted) {
1364
+ break;
1365
+ }
1366
+
1367
+ const data = toUint8Array(value); // Normalize things like Node.js Buffer to Uint8Array
1368
+
1369
+ this._dispatchRead(worker.currentPos, worker.currentPos + data.length);
1370
+ this._orchestrator.supplyWorkerData(worker, data);
1371
+ }
1372
+ } else {
1373
+ throw new TypeError('options.read must return or resolve to a Uint8Array or a ReadableStream.');
1374
+ }
1375
+ }
1376
+
1377
+ this._orchestrator.signalWorkerStoppedRunning(worker);
1378
+ }
1379
+
1380
+ /** @internal */
1381
+ _dispose() {
1382
+ this._orchestrator.dispose();
1383
+ this._options.dispose?.();
1384
+ }
1385
+ }
1386
+
1387
+ /**
1388
+ * An alias for {@link CustomSource}.
1389
+ * @deprecated This name is misleading and will be removed in a future release. Please use {@link CustomSource} instead.
1390
+ *
1391
+ * @group Input sources
1392
+ * @public
1393
+ */
1394
+ export const StreamSource = CustomSource;
1395
+
1396
+ /**
1397
+ * An alias for {@link CustomSourceOptions}.
1398
+ * @deprecated This name is misleading and will be removed in a future release. Please use
1399
+ * {@link CustomSourceOptions} instead.
1400
+ *
1401
+ * @group Input sources
1402
+ * @public
1403
+ */
1404
+ export type StreamSourceOptions = CustomSourceOptions;
1405
+
1406
+ type ReadableStreamSourcePendingSlice = {
1407
+ start: number;
1408
+ end: number;
1409
+ bytes: Uint8Array;
1410
+ resolve: (bytes: ReadResult | null) => void;
1411
+ reject: (error: unknown) => void;
1412
+ };
1413
+
1414
+ /**
1415
+ * Options for {@link ReadableStreamSource}.
1416
+ * @group Input sources
1417
+ * @public
1418
+ */
1419
+ export type ReadableStreamSourceOptions = {
1420
+ /** The maximum number of bytes the cache is allowed to hold in memory. Defaults to 32 MiB. */
1421
+ maxCacheSize?: number;
1422
+ };
1423
+
1424
+ /**
1425
+ * A source backed by a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) of
1426
+ * `Uint8Array`, representing an append-only byte stream of unknown length. This is the source to use for incrementally
1427
+ * streaming in input files that are still being constructed and whose size we don't yet know, like for example the
1428
+ * output chunks of [MediaRecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder).
1429
+ *
1430
+ * This source is *unsized*, meaning calls to `.getSize()` will throw and readers are more limited due to the
1431
+ * lack of random file access. You should only use this source with sequential access patterns, such as reading all
1432
+ * packets from start to end. This source does not work well with random access patterns unless you increase its
1433
+ * max cache size.
1434
+ *
1435
+ * @group Input sources
1436
+ * @public
1437
+ */
1438
+ export class ReadableStreamSource extends Source {
1439
+ /** @internal */
1440
+ _stream: ReadableStream<Uint8Array>;
1441
+ /** @internal */
1442
+ _reader: ReadableStreamDefaultReader<Uint8Array> | null = null;
1443
+ /** @internal */
1444
+ _cache: CacheEntry[] = [];
1445
+ /** @internal */
1446
+ _maxCacheSize: number;
1447
+ /** @internal */
1448
+ _pendingSlices: ReadableStreamSourcePendingSlice[] = [];
1449
+ /** @internal */
1450
+ _currentIndex = 0;
1451
+ /** @internal */
1452
+ _targetIndex = 0;
1453
+ /** @internal */
1454
+ _maxRequestedIndex = 0;
1455
+ /** @internal */
1456
+ _endIndex: number | null = null;
1457
+ /** @internal */
1458
+ _pulling = false;
1459
+
1460
+ /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream<Uint8Array>`. */
1461
+ constructor(stream: ReadableStream<Uint8Array>, options: ReadableStreamSourceOptions = {}) {
1462
+ if (!(stream instanceof ReadableStream)) {
1463
+ throw new TypeError('stream must be a ReadableStream.');
1464
+ }
1465
+ if (!options || typeof options !== 'object') {
1466
+ throw new TypeError('options must be an object.');
1467
+ }
1468
+ if (
1469
+ options.maxCacheSize !== undefined
1470
+ && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)
1471
+ ) {
1472
+ throw new TypeError('options.maxCacheSize, when provided, must be a non-negative number.');
1473
+ }
1474
+
1475
+ super();
1476
+
1477
+ this._stream = stream;
1478
+ this._maxCacheSize = options.maxCacheSize ?? (32 * 2 ** 20 /* 32 MiB */);
1479
+ }
1480
+
1481
+ /** @internal */
1482
+ _getFileSize(): number | null {
1483
+ return this._endIndex; // Starts out as null, meaning this source is unsized
1484
+ }
1485
+
1486
+ /** @internal */
1487
+ _read(start: number, end: number): MaybePromise<ReadResult | null> {
1488
+ if (this._endIndex !== null && end > this._endIndex) {
1489
+ return null;
1490
+ }
1491
+
1492
+ this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end);
1493
+
1494
+ const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, x => x.start);
1495
+ const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex]! : null;
1496
+
1497
+ if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) {
1498
+ // The request can be satisfied with a single cache entry
1499
+ return {
1500
+ bytes: cacheStartEntry.bytes,
1501
+ view: cacheStartEntry.view,
1502
+ offset: cacheStartEntry.start,
1503
+ };
1504
+ }
1505
+
1506
+ let lastEnd = start;
1507
+ const bytes = new Uint8Array(end - start);
1508
+
1509
+ if (cacheStartIndex !== -1) {
1510
+ // Walk over the cache to see if we can satisfy the request using multiple cache entries
1511
+ for (let i = cacheStartIndex; i < this._cache.length; i++) {
1512
+ const cacheEntry = this._cache[i]!;
1513
+ if (cacheEntry.start >= end) {
1514
+ break;
1515
+ }
1516
+
1517
+ const cappedStart = Math.max(start, cacheEntry.start);
1518
+ if (cappedStart > lastEnd) {
1519
+ // We're too far behind
1520
+ this._throwDueToCacheMiss();
1521
+ }
1522
+
1523
+ const cappedEnd = Math.min(end, cacheEntry.end);
1524
+
1525
+ if (cappedStart < cappedEnd) {
1526
+ bytes.set(
1527
+ cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start),
1528
+ cappedStart - start,
1529
+ );
1530
+
1531
+ lastEnd = cappedEnd;
1532
+ }
1533
+ }
1534
+ }
1535
+
1536
+ if (lastEnd === end) {
1537
+ return {
1538
+ bytes,
1539
+ view: toDataView(bytes),
1540
+ offset: start,
1541
+ };
1542
+ }
1543
+
1544
+ // We need to pull more data
1545
+
1546
+ if (this._currentIndex > lastEnd) {
1547
+ // We're too far behind
1548
+ this._throwDueToCacheMiss();
1549
+ }
1550
+
1551
+ const { promise, resolve, reject } = promiseWithResolvers<ReadResult | null>();
1552
+
1553
+ this._pendingSlices.push({
1554
+ start,
1555
+ end,
1556
+ bytes,
1557
+ resolve,
1558
+ reject,
1559
+ });
1560
+
1561
+ this._targetIndex = Math.max(this._targetIndex, end);
1562
+
1563
+ // Start pulling from the stream if we're not already doing it
1564
+ if (!this._pulling) {
1565
+ this._pulling = true;
1566
+ void this._pull()
1567
+ .catch((error) => {
1568
+ this._pulling = false;
1569
+
1570
+ if (this._pendingSlices.length > 0) {
1571
+ this._pendingSlices.forEach(x => x.reject(error)); // Make sure to propagate any errors
1572
+ this._pendingSlices.length = 0;
1573
+ } else {
1574
+ throw error; // So it doesn't get swallowed
1575
+ }
1576
+ });
1577
+ }
1578
+
1579
+ return promise;
1580
+ }
1581
+
1582
+ /** @internal */
1583
+ _throwDueToCacheMiss() {
1584
+ throw new Error(
1585
+ 'Read is before the cached region. With ReadableStreamSource, you must access the data more'
1586
+ + ' sequentially or increase the size of its cache.',
1587
+ );
1588
+ }
1589
+
1590
+ /** @internal */
1591
+ async _pull() {
1592
+ this._reader ??= this._stream.getReader();
1593
+
1594
+ // This is the loop that keeps pulling data from the stream until a target index is reached, filling requests
1595
+ // in the process
1596
+ while (this._currentIndex < this._targetIndex && !this._disposed) {
1597
+ const { done, value } = await this._reader.read();
1598
+ if (done) {
1599
+ for (const pendingSlice of this._pendingSlices) {
1600
+ pendingSlice.resolve(null);
1601
+ }
1602
+ this._pendingSlices.length = 0;
1603
+ this._endIndex = this._currentIndex; // We know how long the file is now!
1604
+
1605
+ break;
1606
+ }
1607
+
1608
+ const startIndex = this._currentIndex;
1609
+ const endIndex = this._currentIndex + value.byteLength;
1610
+
1611
+ this._dispatchRead(startIndex, endIndex);
1612
+
1613
+ // Fill the pending slices with the data
1614
+ for (let i = 0; i < this._pendingSlices.length; i++) {
1615
+ const pendingSlice = this._pendingSlices[i]!;
1616
+
1617
+ const cappedStart = Math.max(startIndex, pendingSlice.start);
1618
+ const cappedEnd = Math.min(endIndex, pendingSlice.end);
1619
+
1620
+ if (cappedStart < cappedEnd) {
1621
+ pendingSlice.bytes.set(
1622
+ value.subarray(cappedStart - startIndex, cappedEnd - startIndex),
1623
+ cappedStart - pendingSlice.start,
1624
+ );
1625
+ if (cappedEnd === pendingSlice.end) {
1626
+ // Pending slice fully filled
1627
+ pendingSlice.resolve({
1628
+ bytes: pendingSlice.bytes,
1629
+ view: toDataView(pendingSlice.bytes),
1630
+ offset: pendingSlice.start,
1631
+ });
1632
+ this._pendingSlices.splice(i, 1);
1633
+ i--;
1634
+ }
1635
+ }
1636
+ }
1637
+
1638
+ this._cache.push({
1639
+ start: startIndex,
1640
+ end: endIndex,
1641
+ bytes: value,
1642
+ view: toDataView(value),
1643
+ age: 0, // Unused
1644
+ });
1645
+
1646
+ // Do cache eviction, based on the distance from the last-requested index. It's important that we do it like
1647
+ // this and not based on where the reader is at, because if the reader is fast, we'll unnecessarily evict
1648
+ // data that we still might need.
1649
+ while (this._cache.length > 0) {
1650
+ const firstEntry = this._cache[0]!;
1651
+ const distance = this._maxRequestedIndex - firstEntry.end;
1652
+
1653
+ if (distance <= this._maxCacheSize) {
1654
+ break;
1655
+ }
1656
+
1657
+ this._cache.shift();
1658
+ }
1659
+
1660
+ this._currentIndex += value.byteLength;
1661
+ }
1662
+
1663
+ this._pulling = false;
1664
+ }
1665
+
1666
+ /** @internal */
1667
+ _dispose() {
1668
+ for (const pendingSlice of this._pendingSlices) {
1669
+ pendingSlice.reject(new InputDisposedError());
1670
+ }
1671
+
1672
+ this._pendingSlices.length = 0;
1673
+ this._cache.length = 0;
1674
+ void this._reader?.cancel();
1675
+ }
1676
+ }
1677
+
1678
+ type PrefetchProfile = (start: number, end: number, workers: ReadWorker[]) => {
1679
+ start: number;
1680
+ end: number;
1681
+ };
1682
+
1683
+ const PREFETCH_PROFILES = {
1684
+ none: (start, end) => ({ start, end }),
1685
+ fileSystem: (start, end) => {
1686
+ const padding = 2 ** 16;
1687
+
1688
+ start = Math.floor((start - padding) / padding) * padding;
1689
+ end = Math.ceil((end + padding) / padding) * padding;
1690
+
1691
+ return { start, end };
1692
+ },
1693
+ network: (start, end, workers) => {
1694
+ // Add a slight bit of start padding because backwards reading is painful
1695
+ const paddingStart = 2 ** 16;
1696
+ start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart);
1697
+
1698
+ // Remote resources have extreme latency (relatively speaking), so the benefit from intelligent
1699
+ // prefetching is great. The network prefetch strategy is as follows: When we notice
1700
+ // successive reads to a worker's read region, we prefetch more data at the end of that region,
1701
+ // growing exponentially (up to a cap). This performs well for real-world use cases: Either we read a
1702
+ // small part of the file once and then never need it again, in which case the requested about of data
1703
+ // is small. Or, we're repeatedly doing a sequential access pattern (common in media files), in which
1704
+ // case we can become more and more confident to prefetch more and more data.
1705
+ for (const worker of workers) {
1706
+ const maxExtensionAmount = 8 * 2 ** 20; // 8 MiB
1707
+
1708
+ // When the read region cross the threshold point, we trigger a prefetch. This point is typically
1709
+ // in the middle of the worker's read region, or a fixed offset from the end if the region has grown
1710
+ // really large.
1711
+ const thresholdPoint = Math.max(
1712
+ (worker.startPos + worker.targetPos) / 2,
1713
+ worker.targetPos - maxExtensionAmount,
1714
+ );
1715
+
1716
+ if (closedIntervalsOverlap(
1717
+ start, end,
1718
+ thresholdPoint, worker.targetPos,
1719
+ )) {
1720
+ const size = worker.targetPos - worker.startPos;
1721
+
1722
+ // If we extend by maxExtensionAmount
1723
+ const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount;
1724
+ // If we extend to the next power of 2
1725
+ const b = 2 ** Math.ceil(Math.log2(size + 1));
1726
+
1727
+ const extent = Math.min(b, a);
1728
+ end = Math.max(end, worker.startPos + extent);
1729
+ }
1730
+ }
1731
+
1732
+ end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT);
1733
+
1734
+ return {
1735
+ start,
1736
+ end,
1737
+ };
1738
+ },
1739
+ } satisfies Record<string, PrefetchProfile>;
1740
+
1741
+ type PendingSlice = {
1742
+ start: number;
1743
+ bytes: Uint8Array;
1744
+ holes: Hole[];
1745
+ resolve: (bytes: Uint8Array | null) => void;
1746
+ reject: (error: unknown) => void;
1747
+ };
1748
+
1749
+ type Hole = {
1750
+ start: number;
1751
+ end: number;
1752
+ };
1753
+
1754
+ type CacheEntry = {
1755
+ start: number;
1756
+ end: number;
1757
+ bytes: Uint8Array;
1758
+ view: DataView;
1759
+ age: number;
1760
+ };
1761
+
1762
+ type ReadWorker = {
1763
+ startPos: number;
1764
+ currentPos: number;
1765
+ targetPos: number;
1766
+ /** The target is considered _strict_ when it is an error for the worker to terminate before reaching the target. */
1767
+ strictTarget: boolean;
1768
+ running: boolean;
1769
+ aborted: boolean;
1770
+ pendingSlices: PendingSlice[];
1771
+ age: number;
1772
+ };
1773
+
1774
+ /**
1775
+ * Godclass for orchestrating complex, cached read operations. The reading model is as follows: Any reading task is
1776
+ * delegated to a *worker*, which is a sequential reader positioned somewhere along the file. All workers run in
1777
+ * parallel and can be stopped and resumed in their forward movement. When read requests come in, this orchestrator will
1778
+ * first try to satisfy the request with only the cached data. If this isn't possible, workers are spun up for all
1779
+ * missing parts (or existing workers are repurposed), and these workers will then fill the holes in the data as they
1780
+ * march along the file.
1781
+ */
1782
+ class ReadOrchestrator {
1783
+ fileSize: number | null = null;
1784
+ nextAge = 0; // Used for multiple things
1785
+ workers: ReadWorker[] = [];
1786
+ cache: CacheEntry[] = [];
1787
+ currentCacheSize = 0;
1788
+ disposed = false;
1789
+ queuedReads: {
1790
+ hole: Hole;
1791
+ strictTarget: boolean;
1792
+ pendingSlices: PendingSlice[];
1793
+ age: number;
1794
+ }[] = [];
1795
+
1796
+ constructor(public options: {
1797
+ maxCacheSize: number;
1798
+ runWorker: (worker: ReadWorker) => Promise<void>;
1799
+ prefetchProfile: PrefetchProfile;
1800
+ maxWorkerCount: number;
1801
+ }) {}
1802
+
1803
+ read(
1804
+ innerStart: number,
1805
+ innerEnd: number,
1806
+ minReadPosition: number,
1807
+ maxReadPosition: number,
1808
+ ): MaybePromise<ReadResult | null> {
1809
+ assert(!this.disposed);
1810
+
1811
+ const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers);
1812
+ const outerStart = Math.max(prefetchRange.start, minReadPosition);
1813
+ const outerEnd = Math.min(prefetchRange.end, this.fileSize ?? Infinity, maxReadPosition);
1814
+ assert(outerStart <= innerStart && innerEnd <= outerEnd);
1815
+
1816
+ let result: MaybePromise<ReadResult | null> | null = null;
1817
+
1818
+ const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, x => x.start);
1819
+ const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null;
1820
+
1821
+ // See if the read request can be satisfied by a single cache entry
1822
+ if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) {
1823
+ innerStartEntry.age = this.nextAge++;
1824
+
1825
+ result = {
1826
+ bytes: innerStartEntry.bytes,
1827
+ view: innerStartEntry.view,
1828
+ offset: innerStartEntry.start,
1829
+ };
1830
+ // Can't return yet though, still need to check if the prefetch range might lie outside the cached area
1831
+ }
1832
+
1833
+ const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, x => x.start);
1834
+
1835
+ const bytes = result ? null : new Uint8Array(innerEnd - innerStart);
1836
+ let contiguousBytesWriteEnd = 0; // Used to track if the cache is able to completely cover the bytes
1837
+
1838
+ let lastEnd = outerStart;
1839
+ // The "holes" in the cache (the parts we need to load)
1840
+ const outerHoles: Hole[] = [];
1841
+
1842
+ // Loop over the cache and build up the list of holes
1843
+ if (outerCacheStartIndex !== -1) {
1844
+ for (let i = outerCacheStartIndex; i < this.cache.length; i++) {
1845
+ const entry = this.cache[i]!;
1846
+ if (entry.start >= outerEnd) {
1847
+ break;
1848
+ }
1849
+ if (entry.end <= outerStart) {
1850
+ continue;
1851
+ }
1852
+
1853
+ const cappedOuterStart = Math.max(outerStart, entry.start);
1854
+ const cappedOuterEnd = Math.min(outerEnd, entry.end);
1855
+ assert(cappedOuterStart <= cappedOuterEnd);
1856
+
1857
+ if (lastEnd < cappedOuterStart) {
1858
+ outerHoles.push({ start: lastEnd, end: cappedOuterStart });
1859
+ }
1860
+ lastEnd = cappedOuterEnd;
1861
+
1862
+ if (bytes) {
1863
+ const cappedInnerStart = Math.max(innerStart, entry.start);
1864
+ const cappedInnerEnd = Math.min(innerEnd, entry.end);
1865
+
1866
+ if (cappedInnerStart < cappedInnerEnd) {
1867
+ const relativeOffset = cappedInnerStart - innerStart;
1868
+
1869
+ // Fill the relevant section of the bytes with the cached data
1870
+ bytes.set(
1871
+ entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start),
1872
+ relativeOffset,
1873
+ );
1874
+
1875
+ if (relativeOffset === contiguousBytesWriteEnd) {
1876
+ contiguousBytesWriteEnd = cappedInnerEnd - innerStart;
1877
+ }
1878
+ }
1879
+ }
1880
+ entry.age = this.nextAge++;
1881
+ }
1882
+
1883
+ if (lastEnd < outerEnd) {
1884
+ outerHoles.push({ start: lastEnd, end: outerEnd });
1885
+ }
1886
+ } else {
1887
+ outerHoles.push({ start: outerStart, end: outerEnd });
1888
+ }
1889
+
1890
+ if (bytes && contiguousBytesWriteEnd >= bytes.length) {
1891
+ // Multiple cache entries were able to completely cover the requested bytes!
1892
+ result = {
1893
+ bytes,
1894
+ view: toDataView(bytes),
1895
+ offset: innerStart,
1896
+ };
1897
+ }
1898
+
1899
+ if (outerHoles.length === 0) {
1900
+ assert(result);
1901
+ return result;
1902
+ }
1903
+
1904
+ // We need to read more data, so now we're in async land
1905
+ const { promise, resolve, reject } = promiseWithResolvers<Uint8Array | null>();
1906
+
1907
+ const innerHoles: typeof outerHoles = [];
1908
+ for (const outerHole of outerHoles) {
1909
+ const cappedStart = Math.max(innerStart, outerHole.start);
1910
+ const cappedEnd = Math.min(innerEnd, outerHole.end);
1911
+
1912
+ if (cappedStart === outerHole.start && cappedEnd === outerHole.end) {
1913
+ innerHoles.push(outerHole); // Can reuse without allocating a new object
1914
+ } else if (cappedStart < cappedEnd) {
1915
+ innerHoles.push({ start: cappedStart, end: cappedEnd });
1916
+ }
1917
+ }
1918
+
1919
+ const pendingSlice: PendingSlice | null = bytes && {
1920
+ start: innerStart,
1921
+ bytes,
1922
+ holes: innerHoles,
1923
+ resolve,
1924
+ reject,
1925
+ };
1926
+
1927
+ // Fire off workers to take care of patching the holes
1928
+ outer:
1929
+ for (const outerHole of outerHoles) {
1930
+ for (const worker of this.workers) {
1931
+ const addedToWorker = this.checkHoleAgainstWorker(
1932
+ worker,
1933
+ outerHole,
1934
+ pendingSlice ? [pendingSlice] : [],
1935
+ );
1936
+
1937
+ if (addedToWorker) {
1938
+ this.checkQueuedReadsAgainstWorker(worker);
1939
+ continue outer;
1940
+ }
1941
+ }
1942
+
1943
+ // We need to spawn a new worker
1944
+ const strictTarget = outerHole.end < outerEnd || this.fileSize !== null;
1945
+ const newWorker = this.createWorker(outerHole.start, outerHole.end, strictTarget);
1946
+
1947
+ if (newWorker) {
1948
+ if (pendingSlice) {
1949
+ newWorker.pendingSlices = [pendingSlice];
1950
+ }
1951
+
1952
+ this.runWorker(newWorker);
1953
+ } else {
1954
+ // Max worker count has been reached, let's queue a read for later
1955
+
1956
+ let index = binarySearchLessOrEqual(this.queuedReads, outerHole.start, x => x.hole.start);
1957
+ let entry = index !== -1
1958
+ ? this.queuedReads[index]!
1959
+ : null;
1960
+
1961
+ if (entry && outerHole.start <= entry.hole.end) {
1962
+ entry.hole.end = Math.max(entry.hole.end, outerHole.end);
1963
+ entry.strictTarget &&= strictTarget;
1964
+
1965
+ if (pendingSlice) {
1966
+ entry.pendingSlices.push(pendingSlice);
1967
+ }
1968
+ } else {
1969
+ index++;
1970
+ entry = {
1971
+ hole: {
1972
+ // Clone the hole because it might be mutated later
1973
+ start: outerHole.start,
1974
+ end: outerHole.end,
1975
+ },
1976
+ strictTarget,
1977
+ pendingSlices: pendingSlice ? [pendingSlice] : [],
1978
+ age: this.nextAge++,
1979
+ };
1980
+ this.queuedReads.splice(index, 0, entry);
1981
+ }
1982
+
1983
+ // Merge with any subsequent entries that overlap
1984
+ while (index + 1 < this.queuedReads.length) {
1985
+ const nextEntry = this.queuedReads[index + 1]!;
1986
+ if (nextEntry.hole.start > entry.hole.end) {
1987
+ break;
1988
+ }
1989
+
1990
+ entry.hole.end = Math.max(entry.hole.end, nextEntry.hole.end);
1991
+ entry.pendingSlices.push(...nextEntry.pendingSlices);
1992
+ entry.strictTarget &&= nextEntry.strictTarget;
1993
+ entry.age = Math.min(entry.age, nextEntry.age);
1994
+ this.queuedReads.splice(index + 1, 1);
1995
+ }
1996
+ }
1997
+ }
1998
+
1999
+ if (!result) {
2000
+ assert(bytes);
2001
+
2002
+ result = promise.then(bytes => bytes && ({
2003
+ bytes,
2004
+ view: toDataView(bytes),
2005
+ offset: innerStart,
2006
+ } satisfies ReadResult));
2007
+ } else {
2008
+ // The requested region was satisfied by the cache, but the entire prefetch region was not
2009
+ promise.catch((error) => {
2010
+ if (this.disposed) {
2011
+ return; // Swallow the error
2012
+ }
2013
+
2014
+ // Nobody's awaiting this result but an errored read is still notable
2015
+ throw error;
2016
+ });
2017
+ }
2018
+
2019
+ return result;
2020
+ }
2021
+
2022
+ checkHoleAgainstWorker(worker: ReadWorker, hole: Hole, pendingSlices: PendingSlice[]) {
2023
+ // A small tolerance in the case that the requested region is *just* after the target position of an
2024
+ // existing worker. In that case, it's probably more efficient to repurpose that worker than to spawn
2025
+ // another one so close to it
2026
+ const gapTolerance = 2 ** 17;
2027
+
2028
+ // This check also implies worker.currentPos <= hole.start, a critical condition
2029
+ if (closedIntervalsOverlap(
2030
+ hole.start - gapTolerance, hole.start,
2031
+ worker.currentPos, worker.targetPos,
2032
+ )) {
2033
+ worker.targetPos = Math.max(worker.targetPos, hole.end); // Update the worker's target position
2034
+
2035
+ for (let i = 0; i < pendingSlices.length; i++) {
2036
+ const pendingSlice = pendingSlices[i]!;
2037
+ if (!worker.pendingSlices.includes(pendingSlice)) {
2038
+ worker.pendingSlices.push(pendingSlice);
2039
+ }
2040
+ }
2041
+
2042
+ if (!worker.running) {
2043
+ // Kick it off if it's idle
2044
+ this.runWorker(worker);
2045
+ }
2046
+
2047
+ return true;
2048
+ }
2049
+
2050
+ return false;
2051
+ }
2052
+
2053
+ checkQueuedReadsAgainstWorker(worker: ReadWorker) {
2054
+ let wasTrueOnce = false;
2055
+
2056
+ for (let i = 0; i < this.queuedReads.length; i++) {
2057
+ const queuedRead = this.queuedReads[i]!;
2058
+ const result = this.checkHoleAgainstWorker(worker, queuedRead.hole, queuedRead.pendingSlices);
2059
+
2060
+ if (result) {
2061
+ this.queuedReads.splice(i, 1);
2062
+ i--;
2063
+ wasTrueOnce = true;
2064
+ } else if (wasTrueOnce) {
2065
+ // We can stop since the holes are sorted
2066
+ break;
2067
+ }
2068
+ }
2069
+ }
2070
+
2071
+ createWorker(startPos: number, targetPos: number, strictTarget: boolean) {
2072
+ if (this.workers.length >= this.options.maxWorkerCount) {
2073
+ let oldestWorker: ReadWorker | null = null;
2074
+ let oldestIndex: number | null = null;
2075
+
2076
+ for (let i = 0; i < this.workers.length; i++) {
2077
+ const worker = this.workers[i]!;
2078
+
2079
+ if (
2080
+ !worker.running
2081
+ && worker.pendingSlices.length === 0
2082
+ && (!oldestWorker || worker.age < oldestWorker.age)
2083
+ ) {
2084
+ oldestIndex = i;
2085
+ oldestWorker = worker;
2086
+ }
2087
+ }
2088
+
2089
+ if (oldestWorker) {
2090
+ // LRU eviction
2091
+ assert(oldestIndex !== null);
2092
+ assert(oldestWorker.pendingSlices.length === 0);
2093
+ this.workers.splice(oldestIndex, 1);
2094
+ } else {
2095
+ return null; // All workers are still running, we can't create a new one
2096
+ }
2097
+ }
2098
+
2099
+ const worker: ReadWorker = {
2100
+ startPos,
2101
+ currentPos: startPos,
2102
+ targetPos,
2103
+ strictTarget,
2104
+ running: false,
2105
+ // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of
2106
+ // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then
2107
+ // shut itself down.
2108
+ aborted: this.disposed,
2109
+ pendingSlices: [],
2110
+ age: this.nextAge++,
2111
+ };
2112
+ this.workers.push(worker);
2113
+
2114
+ return worker;
2115
+ }
2116
+
2117
+ runWorker(worker: ReadWorker) {
2118
+ assert(!worker.running);
2119
+ assert(worker.currentPos < worker.targetPos);
2120
+
2121
+ worker.running = true;
2122
+ worker.age = this.nextAge++;
2123
+
2124
+ void this.options.runWorker(worker)
2125
+ .catch((error) => {
2126
+ worker.running = false;
2127
+
2128
+ if (worker.pendingSlices.length > 0) {
2129
+ worker.pendingSlices.forEach(x => x.reject(error)); // Make sure to propagate any errors
2130
+ worker.pendingSlices.length = 0;
2131
+ } else if (!worker.aborted && !this.disposed) {
2132
+ throw error; // So it doesn't get swallowed
2133
+ }
2134
+ })
2135
+ .finally(() => {
2136
+ if (worker.running) {
2137
+ // Rare, but can happen with multiple concurrent reads. In this case, don't do anything.
2138
+ return;
2139
+ }
2140
+
2141
+ if (this.queuedReads.length > 0) {
2142
+ let oldestIndex = 0;
2143
+ for (let i = 1; i < this.queuedReads.length; i++) {
2144
+ const queuedRead = this.queuedReads[i]!;
2145
+ if (queuedRead.age < this.queuedReads[oldestIndex]!.age) {
2146
+ oldestIndex = i;
2147
+ }
2148
+ }
2149
+
2150
+ const queuedRead = this.queuedReads[oldestIndex]!;
2151
+
2152
+ const newWorker = this.createWorker(
2153
+ queuedRead.hole.start,
2154
+ queuedRead.hole.end,
2155
+ queuedRead.strictTarget,
2156
+ );
2157
+ if (!newWorker) {
2158
+ // In high-contention cases, it could be that we've already reached max worker count, so in this
2159
+ // case we don't do anything.
2160
+ return;
2161
+ }
2162
+
2163
+ this.queuedReads.splice(oldestIndex, 1);
2164
+ newWorker.pendingSlices = queuedRead.pendingSlices;
2165
+ this.runWorker(newWorker);
2166
+ }
2167
+ });
2168
+ }
2169
+
2170
+ consolidateEverythingIntoOneWorker(worker: ReadWorker) {
2171
+ // Here we merge everything into one "megaworker" that spans the entire file. We assume the passed-in worker
2172
+ // is already configured to be a megaworker.
2173
+
2174
+ const uniqueSlices = new Set(worker.pendingSlices);
2175
+
2176
+ for (let i = 0; i < this.workers.length; i++) {
2177
+ const otherWorker = this.workers[i]!;
2178
+ if (otherWorker === worker) {
2179
+ continue;
2180
+ }
2181
+
2182
+ for (const slice of otherWorker.pendingSlices) {
2183
+ uniqueSlices.add(slice);
2184
+ }
2185
+
2186
+ otherWorker.aborted = true;
2187
+ otherWorker.pendingSlices.length = 0;
2188
+ this.workers.splice(i, 1);
2189
+ i--;
2190
+ }
2191
+
2192
+ for (let i = 0; i < this.queuedReads.length; i++) {
2193
+ const queuedRead = this.queuedReads[i]!;
2194
+
2195
+ for (const slice of queuedRead.pendingSlices) {
2196
+ uniqueSlices.add(slice);
2197
+ }
2198
+ }
2199
+
2200
+ worker.pendingSlices = [...uniqueSlices];
2201
+ this.queuedReads.length = 0;
2202
+ }
2203
+
2204
+ /** Called by a worker when it has read some data. */
2205
+ supplyWorkerData(worker: ReadWorker, bytes: Uint8Array) {
2206
+ assert(!worker.aborted);
2207
+
2208
+ const start = worker.currentPos;
2209
+ const end = start + bytes.length;
2210
+
2211
+ this.insertIntoCache({
2212
+ start,
2213
+ end,
2214
+ bytes,
2215
+ view: toDataView(bytes),
2216
+ age: this.nextAge++,
2217
+ });
2218
+ worker.currentPos += bytes.length;
2219
+
2220
+ if (worker.currentPos > worker.targetPos) {
2221
+ // In case it overshoots
2222
+ worker.targetPos = worker.currentPos;
2223
+ this.checkQueuedReadsAgainstWorker(worker);
2224
+ }
2225
+
2226
+ // Now, let's see if we can use the read bytes to fill any pending slice
2227
+ for (let i = 0; i < worker.pendingSlices.length; i++) {
2228
+ const pendingSlice = worker.pendingSlices[i]!;
2229
+
2230
+ const clampedStart = Math.max(start, pendingSlice.start);
2231
+ const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length);
2232
+
2233
+ if (clampedStart < clampedEnd) {
2234
+ pendingSlice.bytes.set(
2235
+ bytes.subarray(clampedStart - start, clampedEnd - start),
2236
+ clampedStart - pendingSlice.start,
2237
+ );
2238
+ }
2239
+
2240
+ for (let j = 0; j < pendingSlice.holes.length; j++) {
2241
+ // The hole is intentionally not modified here if the read section starts somewhere in the middle of
2242
+ // the hole. We don't need to do "hole splitting", since the workers are spawned *by* the holes,
2243
+ // meaning there's always a worker which will consume the hole left to right.
2244
+ const hole = pendingSlice.holes[j]!;
2245
+ if (start <= hole.start && end > hole.start) {
2246
+ hole.start = end;
2247
+ }
2248
+
2249
+ if (hole.end <= hole.start) {
2250
+ pendingSlice.holes.splice(j, 1);
2251
+ j--;
2252
+ }
2253
+ }
2254
+
2255
+ if (pendingSlice.holes.length === 0) {
2256
+ // The slice has been fulfilled, everything has been read. Let's resolve the promise
2257
+ pendingSlice.resolve(pendingSlice.bytes);
2258
+ worker.pendingSlices.splice(i, 1);
2259
+ i--;
2260
+ }
2261
+ }
2262
+
2263
+ // Remove other idle workers if we "ate" into their territory
2264
+ for (let i = 0; i < this.workers.length; i++) {
2265
+ const otherWorker = this.workers[i]!;
2266
+ if (worker === otherWorker || otherWorker.running) {
2267
+ continue;
2268
+ }
2269
+
2270
+ if (closedIntervalsOverlap(
2271
+ start, end,
2272
+ otherWorker.currentPos, otherWorker.targetPos, // These should typically be equal when the worker's idle
2273
+ )) {
2274
+ this.workers.splice(i, 1);
2275
+ i--;
2276
+ }
2277
+ }
2278
+ }
2279
+
2280
+ supplyFileSize(size: number) {
2281
+ assert(this.fileSize === null);
2282
+
2283
+ this.fileSize = size;
2284
+
2285
+ // Trim the workers with this new information
2286
+ for (const worker of this.workers) {
2287
+ worker.targetPos = Math.min(worker.targetPos, size);
2288
+ worker.strictTarget = true;
2289
+
2290
+ for (let i = 0; i < worker.pendingSlices.length; i++) {
2291
+ const pendingSlice = worker.pendingSlices[i]!;
2292
+
2293
+ for (const hole of pendingSlice.holes) {
2294
+ if (hole.end > size) {
2295
+ // Can't satisfy this slice anymore
2296
+ pendingSlice.resolve(null);
2297
+ worker.pendingSlices.splice(i, 1);
2298
+ i--;
2299
+
2300
+ break;
2301
+ }
2302
+ }
2303
+ }
2304
+ }
2305
+
2306
+ // Trim the queued reads as well
2307
+ for (let i = 0; i < this.queuedReads.length; i++) {
2308
+ const queuedRead = this.queuedReads[i]!;
2309
+ if (queuedRead.hole.start >= size) {
2310
+ // Entirely out of bounds
2311
+ for (const slice of queuedRead.pendingSlices) slice.resolve(null);
2312
+ this.queuedReads.splice(i, 1);
2313
+ i--;
2314
+ } else if (queuedRead.hole.end > size) {
2315
+ // Partially out of bounds
2316
+ queuedRead.hole.end = size;
2317
+ queuedRead.strictTarget = true;
2318
+
2319
+ for (let j = 0; j < queuedRead.pendingSlices.length; j++) {
2320
+ const slice = queuedRead.pendingSlices[j]!;
2321
+ // If the slice itself is out of bounds, resolve it
2322
+ if (slice.start >= size) {
2323
+ slice.resolve(null);
2324
+ queuedRead.pendingSlices.splice(j, 1);
2325
+ j--;
2326
+ }
2327
+ }
2328
+ }
2329
+ }
2330
+ }
2331
+
2332
+ signalWorkerStoppedRunning(worker: ReadWorker) {
2333
+ worker.running = false;
2334
+
2335
+ if (!worker.aborted) {
2336
+ // When a worker stops running, that means it has hit its targetPos. It might still have pendingSlices
2337
+ // assigned, but this is because those pending slices cover data that other workers are assigned to fill.
2338
+ // Since targetPos has been reached, we can confidently say that this worker has completed its share of work
2339
+ // on the pending slices and must no longer care about them.
2340
+ worker.pendingSlices.length = 0;
2341
+ }
2342
+ }
2343
+
2344
+ /** Called when a worker reaches the end of the underlying data and must be cleaned up. */
2345
+ onWorkerFinished(worker: ReadWorker) {
2346
+ const index = this.workers.indexOf(worker);
2347
+ assert(index !== -1);
2348
+
2349
+ worker.running = false;
2350
+ this.workers.splice(index, 1);
2351
+
2352
+ if (this.fileSize === null) {
2353
+ // We can now deduce the file size!
2354
+ this.supplyFileSize(worker.currentPos);
2355
+ }
2356
+
2357
+ for (const pendingSlice of worker.pendingSlices) {
2358
+ pendingSlice.resolve(null);
2359
+ }
2360
+ }
2361
+
2362
+ insertIntoCache(entry: CacheEntry) {
2363
+ if (this.options.maxCacheSize === 0) {
2364
+ return; // No caching
2365
+ }
2366
+
2367
+ let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, x => x.start) + 1;
2368
+
2369
+ if (insertionIndex > 0) {
2370
+ const previous = this.cache[insertionIndex - 1]!;
2371
+ if (previous.end >= entry.end) {
2372
+ // Previous entry swallows the one to be inserted; we don't need to do anything
2373
+ return;
2374
+ }
2375
+
2376
+ if (previous.end > entry.start) {
2377
+ // Partial overlap with the previous entry, let's join
2378
+ const joined = new Uint8Array(entry.end - previous.start);
2379
+ joined.set(previous.bytes, 0);
2380
+ joined.set(entry.bytes, entry.start - previous.start);
2381
+
2382
+ this.currentCacheSize += entry.end - previous.end;
2383
+
2384
+ previous.bytes = joined;
2385
+ previous.view = toDataView(joined);
2386
+ previous.end = entry.end;
2387
+
2388
+ // Do the rest of the logic with the previous entry instead
2389
+ insertionIndex--;
2390
+ entry = previous;
2391
+ } else {
2392
+ this.cache.splice(insertionIndex, 0, entry);
2393
+ this.currentCacheSize += entry.bytes.length;
2394
+ }
2395
+ } else {
2396
+ this.cache.splice(insertionIndex, 0, entry);
2397
+ this.currentCacheSize += entry.bytes.length;
2398
+ }
2399
+
2400
+ for (let i = insertionIndex + 1; i < this.cache.length; i++) {
2401
+ const next = this.cache[i]!;
2402
+ if (entry.end <= next.start) {
2403
+ // Even if they touch, we don't wanna merge them, no need
2404
+ break;
2405
+ }
2406
+
2407
+ if (entry.end >= next.end) {
2408
+ // The inserted entry completely swallows the next entry
2409
+ this.cache.splice(i, 1);
2410
+ this.currentCacheSize -= next.bytes.length;
2411
+ i--;
2412
+ continue;
2413
+ }
2414
+
2415
+ // Partial overlap, let's join
2416
+ const joined = new Uint8Array(next.end - entry.start);
2417
+ joined.set(entry.bytes, 0);
2418
+ joined.set(next.bytes, next.start - entry.start);
2419
+
2420
+ this.currentCacheSize -= entry.end - next.start; // Subtract the overlap
2421
+
2422
+ entry.bytes = joined;
2423
+ entry.view = toDataView(joined);
2424
+ entry.end = next.end;
2425
+ this.cache.splice(i, 1);
2426
+
2427
+ break; // After the join case, we're done: the next entry cannot possibly overlap with the inserted one.
2428
+ }
2429
+
2430
+ // LRU eviction of cache entries
2431
+ while (this.currentCacheSize > this.options.maxCacheSize) {
2432
+ let oldestIndex = 0;
2433
+ let oldestEntry = this.cache[0]!;
2434
+
2435
+ for (let i = 1; i < this.cache.length; i++) {
2436
+ const entry = this.cache[i]!;
2437
+
2438
+ if (entry.age < oldestEntry.age) {
2439
+ oldestIndex = i;
2440
+ oldestEntry = entry;
2441
+ }
2442
+ }
2443
+
2444
+ if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) {
2445
+ // Don't evict if it would shrink the cache below the max size
2446
+ break;
2447
+ }
2448
+
2449
+ this.cache.splice(oldestIndex, 1);
2450
+ this.currentCacheSize -= oldestEntry.bytes.length;
2451
+ }
2452
+ }
2453
+
2454
+ dispose() {
2455
+ for (const worker of this.workers) {
2456
+ for (const slice of worker.pendingSlices) {
2457
+ slice.reject(new InputDisposedError());
2458
+ }
2459
+
2460
+ worker.pendingSlices.length = 0;
2461
+ worker.aborted = true;
2462
+ }
2463
+
2464
+ for (const queuedRead of this.queuedReads) {
2465
+ for (const slice of queuedRead.pendingSlices) {
2466
+ slice.reject(new InputDisposedError());
2467
+ }
2468
+ }
2469
+
2470
+ this.workers.length = 0;
2471
+ this.cache.length = 0;
2472
+ this.queuedReads.length = 0;
2473
+ this.disposed = true;
2474
+ }
2475
+ }
2476
+
2477
+ /**
2478
+ * A dummy source from which no data can be read. Can be used in conjunction with input formats that get their data
2479
+ * from another source.
2480
+ */
2481
+ export class NullSource extends Source {
2482
+ override _getFileSize(): number | null {
2483
+ return null;
2484
+ }
2485
+
2486
+ override _read(): MaybePromise<ReadResult | null> {
2487
+ return null;
2488
+ }
2489
+
2490
+ override _dispose(): void {
2491
+ // Do nothing
2492
+ }
2493
+ }
2494
+
2495
+ /**
2496
+ * A source that covers a range (offset + length) of another source. Useful for reading files that are embedded within
2497
+ * larger files.
2498
+ *
2499
+ * @group Input sources
2500
+ * @public
2501
+ */
2502
+ export class RangedSource extends Source {
2503
+ /** @internal */
2504
+ _baseSource: Source;
2505
+ /** @internal */
2506
+ _ref: SourceRef | null = null;
2507
+ /** @internal */
2508
+ _offset: number;
2509
+ /** @internal */
2510
+ _length: number | null;
2511
+
2512
+ /** @internal */
2513
+ constructor(baseSource: Source, offset: number, length?: number) {
2514
+ super();
2515
+
2516
+ if (baseSource._disposed) {
2517
+ throw new Error('Cannot create a slice of a disposed source.');
2518
+ }
2519
+
2520
+ this._baseSource = baseSource;
2521
+ this._offset = offset;
2522
+ this._length = length ?? null;
2523
+ }
2524
+
2525
+ /** @internal */
2526
+ override _getFileSize(): number | null | undefined {
2527
+ const baseSize = this._baseSource._getFileSize();
2528
+ if (baseSize === undefined) {
2529
+ return this._length !== null
2530
+ ? this._length
2531
+ : undefined;
2532
+ }
2533
+
2534
+ if (baseSize === null) {
2535
+ if (this._length !== null) {
2536
+ return this._length;
2537
+ } else {
2538
+ return null;
2539
+ }
2540
+ }
2541
+
2542
+ return clamp(baseSize - this._offset, 0, this._length ?? Infinity);
2543
+ }
2544
+
2545
+ /** @internal */
2546
+ override _read(
2547
+ start: number,
2548
+ end: number,
2549
+ minReadPosition: number,
2550
+ maxReadPosition: number,
2551
+ ): MaybePromise<ReadResult | null> {
2552
+ if (this._length !== null && end > this._length) {
2553
+ return null;
2554
+ }
2555
+
2556
+ const result = this._baseSource._read(
2557
+ this._offset + start,
2558
+ this._offset + end,
2559
+ this._offset + minReadPosition,
2560
+ this._offset + maxReadPosition,
2561
+ );
2562
+
2563
+ const processResult = (result: ReadResult | null) => {
2564
+ if (!result) {
2565
+ return null;
2566
+ }
2567
+
2568
+ result.offset -= this._offset;
2569
+ return result;
2570
+ };
2571
+
2572
+ if (result instanceof Promise) {
2573
+ return result.then(processResult);
2574
+ } else {
2575
+ return processResult(result);
2576
+ }
2577
+ }
2578
+
2579
+ /** @internal */
2580
+ override _dispose(): void {
2581
+ this._ref?.free();
2582
+ }
2583
+
2584
+ override ref() {
2585
+ this._ref ??= this._baseSource.ref();
2586
+ return super.ref();
2587
+ }
2588
+ }