@meframe/core 0.0.1

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 (352) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +22 -0
  3. package/README.md +396 -0
  4. package/dist/Meframe.d.ts +82 -0
  5. package/dist/Meframe.d.ts.map +1 -0
  6. package/dist/Meframe.js +290 -0
  7. package/dist/Meframe.js.map +1 -0
  8. package/dist/_virtual/mp4box.all.js +5 -0
  9. package/dist/_virtual/mp4box.all.js.map +1 -0
  10. package/dist/cache/BatchWriter.d.ts +25 -0
  11. package/dist/cache/BatchWriter.d.ts.map +1 -0
  12. package/dist/cache/CacheManager.d.ts +115 -0
  13. package/dist/cache/CacheManager.d.ts.map +1 -0
  14. package/dist/cache/CacheManager.js +388 -0
  15. package/dist/cache/CacheManager.js.map +1 -0
  16. package/dist/cache/CacheStatsDecorator.d.ts +27 -0
  17. package/dist/cache/CacheStatsDecorator.d.ts.map +1 -0
  18. package/dist/cache/L2Cache.d.ts +39 -0
  19. package/dist/cache/L2Cache.d.ts.map +1 -0
  20. package/dist/cache/L2Cache.js +282 -0
  21. package/dist/cache/L2Cache.js.map +1 -0
  22. package/dist/cache/index.d.ts +7 -0
  23. package/dist/cache/index.d.ts.map +1 -0
  24. package/dist/cache/l1/AudioL1Cache.d.ts +30 -0
  25. package/dist/cache/l1/AudioL1Cache.d.ts.map +1 -0
  26. package/dist/cache/l1/AudioL1Cache.js +306 -0
  27. package/dist/cache/l1/AudioL1Cache.js.map +1 -0
  28. package/dist/cache/l1/MixedAudioL1Cache.d.ts +13 -0
  29. package/dist/cache/l1/MixedAudioL1Cache.d.ts.map +1 -0
  30. package/dist/cache/l1/MixedAudioL1Cache.js +52 -0
  31. package/dist/cache/l1/MixedAudioL1Cache.js.map +1 -0
  32. package/dist/cache/l1/VideoL1Cache.d.ts +69 -0
  33. package/dist/cache/l1/VideoL1Cache.d.ts.map +1 -0
  34. package/dist/cache/l1/VideoL1Cache.js +318 -0
  35. package/dist/cache/l1/VideoL1Cache.js.map +1 -0
  36. package/dist/cache/l1/gop-utils.d.ts +10 -0
  37. package/dist/cache/l1/gop-utils.d.ts.map +1 -0
  38. package/dist/cache/l1/gop-utils.js +78 -0
  39. package/dist/cache/l1/gop-utils.js.map +1 -0
  40. package/dist/cache/l1/index.d.ts +4 -0
  41. package/dist/cache/l1/index.d.ts.map +1 -0
  42. package/dist/cache/l1/types.d.ts +17 -0
  43. package/dist/cache/l1/types.d.ts.map +1 -0
  44. package/dist/cache/types.d.ts +93 -0
  45. package/dist/cache/types.d.ts.map +1 -0
  46. package/dist/config/ConfigLoader.d.ts +69 -0
  47. package/dist/config/ConfigLoader.d.ts.map +1 -0
  48. package/dist/config/ConfigLoader.js +133 -0
  49. package/dist/config/ConfigLoader.js.map +1 -0
  50. package/dist/config/defaults.d.ts +125 -0
  51. package/dist/config/defaults.d.ts.map +1 -0
  52. package/dist/config/defaults.js +191 -0
  53. package/dist/config/defaults.js.map +1 -0
  54. package/dist/config/index.d.ts +6 -0
  55. package/dist/config/index.d.ts.map +1 -0
  56. package/dist/config/presets.d.ts +32 -0
  57. package/dist/config/presets.d.ts.map +1 -0
  58. package/dist/config/presets.js +11 -0
  59. package/dist/config/presets.js.map +1 -0
  60. package/dist/config/types.d.ts +199 -0
  61. package/dist/config/types.d.ts.map +1 -0
  62. package/dist/config/validation.d.ts +19 -0
  63. package/dist/config/validation.d.ts.map +1 -0
  64. package/dist/config/validation.js +232 -0
  65. package/dist/config/validation.js.map +1 -0
  66. package/dist/controllers/PlaybackController.d.ts +55 -0
  67. package/dist/controllers/PlaybackController.d.ts.map +1 -0
  68. package/dist/controllers/PlaybackController.js +369 -0
  69. package/dist/controllers/PlaybackController.js.map +1 -0
  70. package/dist/controllers/PreRenderService.d.ts +34 -0
  71. package/dist/controllers/PreRenderService.d.ts.map +1 -0
  72. package/dist/controllers/PreRenderService.js +83 -0
  73. package/dist/controllers/PreRenderService.js.map +1 -0
  74. package/dist/controllers/PreRenderTaskQueue.d.ts +21 -0
  75. package/dist/controllers/PreRenderTaskQueue.d.ts.map +1 -0
  76. package/dist/controllers/PreviewHandle.d.ts +23 -0
  77. package/dist/controllers/PreviewHandle.d.ts.map +1 -0
  78. package/dist/controllers/PreviewHandle.js +39 -0
  79. package/dist/controllers/PreviewHandle.js.map +1 -0
  80. package/dist/controllers/index.d.ts +8 -0
  81. package/dist/controllers/index.d.ts.map +1 -0
  82. package/dist/controllers/types.d.ts +102 -0
  83. package/dist/controllers/types.d.ts.map +1 -0
  84. package/dist/event/EventBus.d.ts +42 -0
  85. package/dist/event/EventBus.d.ts.map +1 -0
  86. package/dist/event/EventBus.js +94 -0
  87. package/dist/event/EventBus.js.map +1 -0
  88. package/dist/event/events.d.ts +371 -0
  89. package/dist/event/events.d.ts.map +1 -0
  90. package/dist/event/events.js +71 -0
  91. package/dist/event/events.js.map +1 -0
  92. package/dist/event/index.d.ts +4 -0
  93. package/dist/event/index.d.ts.map +1 -0
  94. package/dist/index.d.ts +14 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +15 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/model/CompositionModel.d.ts +48 -0
  99. package/dist/model/CompositionModel.d.ts.map +1 -0
  100. package/dist/model/CompositionModel.js +197 -0
  101. package/dist/model/CompositionModel.js.map +1 -0
  102. package/dist/model/RcFrame.d.ts +34 -0
  103. package/dist/model/RcFrame.d.ts.map +1 -0
  104. package/dist/model/RcFrame.js +97 -0
  105. package/dist/model/RcFrame.js.map +1 -0
  106. package/dist/model/dirty-range.d.ts +5 -0
  107. package/dist/model/dirty-range.d.ts.map +1 -0
  108. package/dist/model/dirty-range.js +220 -0
  109. package/dist/model/dirty-range.js.map +1 -0
  110. package/dist/model/index.d.ts +7 -0
  111. package/dist/model/index.d.ts.map +1 -0
  112. package/dist/model/patch.d.ts +5 -0
  113. package/dist/model/patch.d.ts.map +1 -0
  114. package/dist/model/patch.js +250 -0
  115. package/dist/model/patch.js.map +1 -0
  116. package/dist/model/types.d.ts +135 -0
  117. package/dist/model/types.d.ts.map +1 -0
  118. package/dist/model/types.js +5 -0
  119. package/dist/model/types.js.map +1 -0
  120. package/dist/model/validation.d.ts +15 -0
  121. package/dist/model/validation.d.ts.map +1 -0
  122. package/dist/model/validation.js +74 -0
  123. package/dist/model/validation.js.map +1 -0
  124. package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js +7046 -0
  125. package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +1 -0
  126. package/dist/orchestrator/ClipSessionManager.d.ts +75 -0
  127. package/dist/orchestrator/ClipSessionManager.d.ts.map +1 -0
  128. package/dist/orchestrator/ClipSessionManager.js +160 -0
  129. package/dist/orchestrator/ClipSessionManager.js.map +1 -0
  130. package/dist/orchestrator/CompositionPlanner.d.ts +55 -0
  131. package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -0
  132. package/dist/orchestrator/CompositionPlanner.js +411 -0
  133. package/dist/orchestrator/CompositionPlanner.js.map +1 -0
  134. package/dist/orchestrator/Orchestrator.d.ts +59 -0
  135. package/dist/orchestrator/Orchestrator.d.ts.map +1 -0
  136. package/dist/orchestrator/Orchestrator.js +390 -0
  137. package/dist/orchestrator/Orchestrator.js.map +1 -0
  138. package/dist/orchestrator/VideoClipSession.d.ts +64 -0
  139. package/dist/orchestrator/VideoClipSession.d.ts.map +1 -0
  140. package/dist/orchestrator/VideoClipSession.js +309 -0
  141. package/dist/orchestrator/VideoClipSession.js.map +1 -0
  142. package/dist/orchestrator/index.d.ts +5 -0
  143. package/dist/orchestrator/index.d.ts.map +1 -0
  144. package/dist/orchestrator/types.d.ts +64 -0
  145. package/dist/orchestrator/types.d.ts.map +1 -0
  146. package/dist/plugins/BackpressureMonitor.d.ts +33 -0
  147. package/dist/plugins/BackpressureMonitor.d.ts.map +1 -0
  148. package/dist/plugins/BackpressureMonitor.js +62 -0
  149. package/dist/plugins/BackpressureMonitor.js.map +1 -0
  150. package/dist/plugins/PluginManager.d.ts +37 -0
  151. package/dist/plugins/PluginManager.d.ts.map +1 -0
  152. package/dist/plugins/PluginManager.js +66 -0
  153. package/dist/plugins/PluginManager.js.map +1 -0
  154. package/dist/plugins/types.d.ts +60 -0
  155. package/dist/plugins/types.d.ts.map +1 -0
  156. package/dist/stages/compose/AudioDucker.d.ts +59 -0
  157. package/dist/stages/compose/AudioDucker.d.ts.map +1 -0
  158. package/dist/stages/compose/AudioDucker.js +161 -0
  159. package/dist/stages/compose/AudioDucker.js.map +1 -0
  160. package/dist/stages/compose/AudioMixer.d.ts +29 -0
  161. package/dist/stages/compose/AudioMixer.d.ts.map +1 -0
  162. package/dist/stages/compose/AudioMixer.js +373 -0
  163. package/dist/stages/compose/AudioMixer.js.map +1 -0
  164. package/dist/stages/compose/FilterProcessor.d.ts +41 -0
  165. package/dist/stages/compose/FilterProcessor.d.ts.map +1 -0
  166. package/dist/stages/compose/FilterProcessor.js +226 -0
  167. package/dist/stages/compose/FilterProcessor.js.map +1 -0
  168. package/dist/stages/compose/GlobalAudioSession.d.ts +38 -0
  169. package/dist/stages/compose/GlobalAudioSession.d.ts.map +1 -0
  170. package/dist/stages/compose/GlobalAudioSession.js +122 -0
  171. package/dist/stages/compose/GlobalAudioSession.js.map +1 -0
  172. package/dist/stages/compose/LayerRenderer.d.ts +30 -0
  173. package/dist/stages/compose/LayerRenderer.d.ts.map +1 -0
  174. package/dist/stages/compose/LayerRenderer.js +215 -0
  175. package/dist/stages/compose/LayerRenderer.js.map +1 -0
  176. package/dist/stages/compose/OfflineAudioMixer.d.ts +14 -0
  177. package/dist/stages/compose/OfflineAudioMixer.d.ts.map +1 -0
  178. package/dist/stages/compose/OfflineAudioMixer.js +68 -0
  179. package/dist/stages/compose/OfflineAudioMixer.js.map +1 -0
  180. package/dist/stages/compose/TransitionProcessor.d.ts +30 -0
  181. package/dist/stages/compose/TransitionProcessor.d.ts.map +1 -0
  182. package/dist/stages/compose/TransitionProcessor.js +189 -0
  183. package/dist/stages/compose/TransitionProcessor.js.map +1 -0
  184. package/dist/stages/compose/VideoComposer.d.ts +30 -0
  185. package/dist/stages/compose/VideoComposer.d.ts.map +1 -0
  186. package/dist/stages/compose/VideoComposer.js +186 -0
  187. package/dist/stages/compose/VideoComposer.js.map +1 -0
  188. package/dist/stages/compose/audio-compose.worker.d.ts +79 -0
  189. package/dist/stages/compose/audio-compose.worker.d.ts.map +1 -0
  190. package/dist/stages/compose/audio-compose.worker.js +541 -0
  191. package/dist/stages/compose/audio-compose.worker.js.map +1 -0
  192. package/dist/stages/compose/instructions.d.ts +95 -0
  193. package/dist/stages/compose/instructions.d.ts.map +1 -0
  194. package/dist/stages/compose/types.d.ts +245 -0
  195. package/dist/stages/compose/types.d.ts.map +1 -0
  196. package/dist/stages/compose/video-compose.worker.d.ts +60 -0
  197. package/dist/stages/compose/video-compose.worker.d.ts.map +1 -0
  198. package/dist/stages/compose/video-compose.worker.js +369 -0
  199. package/dist/stages/compose/video-compose.worker.js.map +1 -0
  200. package/dist/stages/decode/AudioChunkDecoder.d.ts +41 -0
  201. package/dist/stages/decode/AudioChunkDecoder.d.ts.map +1 -0
  202. package/dist/stages/decode/AudioChunkDecoder.js +83 -0
  203. package/dist/stages/decode/AudioChunkDecoder.js.map +1 -0
  204. package/dist/stages/decode/BaseDecoder.d.ts +35 -0
  205. package/dist/stages/decode/BaseDecoder.d.ts.map +1 -0
  206. package/dist/stages/decode/BaseDecoder.js +130 -0
  207. package/dist/stages/decode/BaseDecoder.js.map +1 -0
  208. package/dist/stages/decode/VideoChunkDecoder.d.ts +54 -0
  209. package/dist/stages/decode/VideoChunkDecoder.d.ts.map +1 -0
  210. package/dist/stages/decode/VideoChunkDecoder.js +209 -0
  211. package/dist/stages/decode/VideoChunkDecoder.js.map +1 -0
  212. package/dist/stages/decode/decode.worker.d.ts +70 -0
  213. package/dist/stages/decode/decode.worker.d.ts.map +1 -0
  214. package/dist/stages/decode/decode.worker.js +436 -0
  215. package/dist/stages/decode/decode.worker.js.map +1 -0
  216. package/dist/stages/decode/index.d.ts +5 -0
  217. package/dist/stages/decode/index.d.ts.map +1 -0
  218. package/dist/stages/decode/types.d.ts +108 -0
  219. package/dist/stages/decode/types.d.ts.map +1 -0
  220. package/dist/stages/demux/MP3FrameParser.d.ts +33 -0
  221. package/dist/stages/demux/MP3FrameParser.d.ts.map +1 -0
  222. package/dist/stages/demux/MP3FrameParser.js +186 -0
  223. package/dist/stages/demux/MP3FrameParser.js.map +1 -0
  224. package/dist/stages/demux/MP4Demuxer.d.ts +45 -0
  225. package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -0
  226. package/dist/stages/demux/MP4Demuxer.js +227 -0
  227. package/dist/stages/demux/MP4Demuxer.js.map +1 -0
  228. package/dist/stages/demux/aac-esds-extractor.d.ts +7 -0
  229. package/dist/stages/demux/aac-esds-extractor.d.ts.map +1 -0
  230. package/dist/stages/demux/audio-demux.worker.d.ts +51 -0
  231. package/dist/stages/demux/audio-demux.worker.d.ts.map +1 -0
  232. package/dist/stages/demux/audio-demux.worker.js +312 -0
  233. package/dist/stages/demux/audio-demux.worker.js.map +1 -0
  234. package/dist/stages/demux/types.d.ts +77 -0
  235. package/dist/stages/demux/types.d.ts.map +1 -0
  236. package/dist/stages/demux/video-demux.worker.d.ts +48 -0
  237. package/dist/stages/demux/video-demux.worker.d.ts.map +1 -0
  238. package/dist/stages/demux/video-demux.worker.js +173 -0
  239. package/dist/stages/demux/video-demux.worker.js.map +1 -0
  240. package/dist/stages/encode/AudioChunkEncoder.d.ts +21 -0
  241. package/dist/stages/encode/AudioChunkEncoder.d.ts.map +1 -0
  242. package/dist/stages/encode/AudioChunkEncoder.js +37 -0
  243. package/dist/stages/encode/AudioChunkEncoder.js.map +1 -0
  244. package/dist/stages/encode/BaseEncoder.d.ts +44 -0
  245. package/dist/stages/encode/BaseEncoder.d.ts.map +1 -0
  246. package/dist/stages/encode/BaseEncoder.js +164 -0
  247. package/dist/stages/encode/BaseEncoder.js.map +1 -0
  248. package/dist/stages/encode/EncoderPool.d.ts +28 -0
  249. package/dist/stages/encode/EncoderPool.d.ts.map +1 -0
  250. package/dist/stages/encode/VideoChunkEncoder.d.ts +26 -0
  251. package/dist/stages/encode/VideoChunkEncoder.d.ts.map +1 -0
  252. package/dist/stages/encode/VideoChunkEncoder.js +50 -0
  253. package/dist/stages/encode/VideoChunkEncoder.js.map +1 -0
  254. package/dist/stages/encode/encode.worker.d.ts +3 -0
  255. package/dist/stages/encode/encode.worker.d.ts.map +1 -0
  256. package/dist/stages/encode/encode.worker.js +318 -0
  257. package/dist/stages/encode/encode.worker.js.map +1 -0
  258. package/dist/stages/encode/index.d.ts +6 -0
  259. package/dist/stages/encode/index.d.ts.map +1 -0
  260. package/dist/stages/encode/types.d.ts +127 -0
  261. package/dist/stages/encode/types.d.ts.map +1 -0
  262. package/dist/stages/load/EventHandlers.d.ts +35 -0
  263. package/dist/stages/load/EventHandlers.d.ts.map +1 -0
  264. package/dist/stages/load/EventHandlers.js +65 -0
  265. package/dist/stages/load/EventHandlers.js.map +1 -0
  266. package/dist/stages/load/ResourceLoader.d.ts +36 -0
  267. package/dist/stages/load/ResourceLoader.d.ts.map +1 -0
  268. package/dist/stages/load/ResourceLoader.js +184 -0
  269. package/dist/stages/load/ResourceLoader.js.map +1 -0
  270. package/dist/stages/load/StreamFactory.d.ts +42 -0
  271. package/dist/stages/load/StreamFactory.d.ts.map +1 -0
  272. package/dist/stages/load/StreamFactory.js +201 -0
  273. package/dist/stages/load/StreamFactory.js.map +1 -0
  274. package/dist/stages/load/TaskManager.d.ts +50 -0
  275. package/dist/stages/load/TaskManager.d.ts.map +1 -0
  276. package/dist/stages/load/TaskManager.js +103 -0
  277. package/dist/stages/load/TaskManager.js.map +1 -0
  278. package/dist/stages/load/WindowByteRangeResolver.d.ts +47 -0
  279. package/dist/stages/load/WindowByteRangeResolver.d.ts.map +1 -0
  280. package/dist/stages/load/WindowByteRangeResolver.js +270 -0
  281. package/dist/stages/load/WindowByteRangeResolver.js.map +1 -0
  282. package/dist/stages/load/index.d.ts +11 -0
  283. package/dist/stages/load/index.d.ts.map +1 -0
  284. package/dist/stages/load/types.d.ts +177 -0
  285. package/dist/stages/load/types.d.ts.map +1 -0
  286. package/dist/stages/mux/MP4Muxer.d.ts +44 -0
  287. package/dist/stages/mux/MP4Muxer.d.ts.map +1 -0
  288. package/dist/stages/mux/MP4Muxer.js +262 -0
  289. package/dist/stages/mux/MP4Muxer.js.map +1 -0
  290. package/dist/stages/mux/OPFSWriter.d.ts +46 -0
  291. package/dist/stages/mux/OPFSWriter.d.ts.map +1 -0
  292. package/dist/stages/mux/index.d.ts +5 -0
  293. package/dist/stages/mux/index.d.ts.map +1 -0
  294. package/dist/stages/mux/mux.worker.d.ts +65 -0
  295. package/dist/stages/mux/mux.worker.d.ts.map +1 -0
  296. package/dist/stages/mux/mux.worker.js +219 -0
  297. package/dist/stages/mux/mux.worker.js.map +1 -0
  298. package/dist/stages/mux/types.d.ts +95 -0
  299. package/dist/stages/mux/types.d.ts.map +1 -0
  300. package/dist/stages/mux/utils.d.ts +32 -0
  301. package/dist/stages/mux/utils.d.ts.map +1 -0
  302. package/dist/stages/mux/utils.js +34 -0
  303. package/dist/stages/mux/utils.js.map +1 -0
  304. package/dist/types.d.ts +25 -0
  305. package/dist/types.d.ts.map +1 -0
  306. package/dist/utils/BackpressureAdapter.d.ts +26 -0
  307. package/dist/utils/BackpressureAdapter.d.ts.map +1 -0
  308. package/dist/utils/binary-search.d.ts +33 -0
  309. package/dist/utils/binary-search.d.ts.map +1 -0
  310. package/dist/utils/binary-search.js +62 -0
  311. package/dist/utils/binary-search.js.map +1 -0
  312. package/dist/utils/canvas-utils.d.ts +96 -0
  313. package/dist/utils/canvas-utils.d.ts.map +1 -0
  314. package/dist/utils/canvas-utils.js +58 -0
  315. package/dist/utils/canvas-utils.js.map +1 -0
  316. package/dist/utils/object-utils.d.ts +34 -0
  317. package/dist/utils/object-utils.d.ts.map +1 -0
  318. package/dist/utils/object-utils.js +22 -0
  319. package/dist/utils/object-utils.js.map +1 -0
  320. package/dist/utils/time-utils.d.ts +10 -0
  321. package/dist/utils/time-utils.d.ts.map +1 -0
  322. package/dist/utils/time-utils.js +60 -0
  323. package/dist/utils/time-utils.js.map +1 -0
  324. package/dist/worker/BaseWorker.d.ts +44 -0
  325. package/dist/worker/BaseWorker.d.ts.map +1 -0
  326. package/dist/worker/BaseWorker.js +98 -0
  327. package/dist/worker/BaseWorker.js.map +1 -0
  328. package/dist/worker/WorkerChannel.d.ts +105 -0
  329. package/dist/worker/WorkerChannel.d.ts.map +1 -0
  330. package/dist/worker/WorkerChannel.js +355 -0
  331. package/dist/worker/WorkerChannel.js.map +1 -0
  332. package/dist/worker/WorkerPool.d.ts +52 -0
  333. package/dist/worker/WorkerPool.d.ts.map +1 -0
  334. package/dist/worker/WorkerPool.js +124 -0
  335. package/dist/worker/WorkerPool.js.map +1 -0
  336. package/dist/worker/index.d.ts +11 -0
  337. package/dist/worker/index.d.ts.map +1 -0
  338. package/dist/worker/transferable-helper.d.ts +89 -0
  339. package/dist/worker/transferable-helper.d.ts.map +1 -0
  340. package/dist/worker/transferable-helper.js +44 -0
  341. package/dist/worker/transferable-helper.js.map +1 -0
  342. package/dist/worker/types.d.ts +179 -0
  343. package/dist/worker/types.d.ts.map +1 -0
  344. package/dist/worker/types.js +50 -0
  345. package/dist/worker/types.js.map +1 -0
  346. package/dist/worker/worker-event-whitelist.d.ts +23 -0
  347. package/dist/worker/worker-event-whitelist.d.ts.map +1 -0
  348. package/dist/worker/worker-retry.d.ts +36 -0
  349. package/dist/worker/worker-retry.d.ts.map +1 -0
  350. package/dist/worker/worker-retry.js +55 -0
  351. package/dist/worker/worker-retry.js.map +1 -0
  352. package/package.json +105 -0
@@ -0,0 +1,184 @@
1
+ import { TaskManager } from "./TaskManager.js";
2
+ import { StreamFactory } from "./StreamFactory.js";
3
+ import { EventHandlers } from "./EventHandlers.js";
4
+ import { MeframeEvent } from "../../event/events.js";
5
+ import { WindowByteRangeResolver } from "./WindowByteRangeResolver.js";
6
+ class ResourceLoader {
7
+ orchestrator;
8
+ model;
9
+ taskManager;
10
+ streamFactory;
11
+ eventHandlers;
12
+ eventBus;
13
+ onStateChange;
14
+ byteRangeResolver;
15
+ constructor(options) {
16
+ const maxConcurrent = options?.config?.maxConcurrent ?? 4;
17
+ this.taskManager = new TaskManager(maxConcurrent);
18
+ this.streamFactory = new StreamFactory(options?.onProgress, options?.config);
19
+ this.eventBus = options?.eventBus;
20
+ this.onStateChange = options?.onStateChange;
21
+ this.byteRangeResolver = new WindowByteRangeResolver();
22
+ if (options?.orchestrator) {
23
+ this.bind(options.orchestrator);
24
+ }
25
+ }
26
+ /**
27
+ * Bind to Orchestrator event system
28
+ */
29
+ bind(orchestrator) {
30
+ this.unbind();
31
+ this.orchestrator = orchestrator;
32
+ this.eventHandlers = new EventHandlers(
33
+ orchestrator,
34
+ (resource, priority) => this.enqueueLoad(resource, priority),
35
+ (resourceId) => this.cancel(resourceId),
36
+ (model) => this.handleModelSet(model)
37
+ );
38
+ }
39
+ /**
40
+ * Unbind from Orchestrator
41
+ */
42
+ unbind() {
43
+ this.eventHandlers?.dispose();
44
+ this.eventHandlers = void 0;
45
+ this.orchestrator = void 0;
46
+ }
47
+ handleModelSet(model) {
48
+ this.model = model;
49
+ }
50
+ enqueueLoad(resource, priority = "normal", range) {
51
+ if (this.taskManager.hasActiveTask(resource.id)) {
52
+ return;
53
+ }
54
+ if (resource.type === "json" || resource.type === "text") {
55
+ this.loadNonStreamingResource(resource);
56
+ return;
57
+ }
58
+ const task = this.taskManager.enqueue(resource, priority);
59
+ if (task && range) {
60
+ task.range = range;
61
+ }
62
+ this.processQueue();
63
+ }
64
+ processQueue() {
65
+ while (this.taskManager.canProcess) {
66
+ const task = this.taskManager.getNextTask();
67
+ if (!task) break;
68
+ this.startLoad(task);
69
+ }
70
+ }
71
+ async startLoad(task) {
72
+ this.taskManager.activateTask(task);
73
+ try {
74
+ this.updateResourceState(task.resourceId, "loading");
75
+ task.controller = new AbortController();
76
+ const stream = await this.streamFactory.createRegularStream(task);
77
+ if (!stream) {
78
+ throw new Error(`Failed to create stream for ${task.resourceId}`);
79
+ }
80
+ task.stream = stream;
81
+ if (task.resource.type === "video" || task.resource.type === "audio") {
82
+ await this.transferToDemuxWorker(task);
83
+ }
84
+ this.updateResourceState(task.resourceId, "ready");
85
+ } catch (error) {
86
+ task.error = error;
87
+ this.updateResourceState(task.resourceId, "error");
88
+ } finally {
89
+ this.taskManager.completeTask(task.resourceId);
90
+ this.processQueue();
91
+ }
92
+ }
93
+ async loadNonStreamingResource(resource) {
94
+ try {
95
+ this.updateResourceState(resource.id, "loading");
96
+ const response = await fetch(resource.uri);
97
+ if (!response.ok) {
98
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
99
+ }
100
+ this.updateResourceState(resource.id, "ready");
101
+ } catch {
102
+ this.updateResourceState(resource.id, "error");
103
+ }
104
+ }
105
+ async transferToDemuxWorker(task) {
106
+ if (!task.stream || !this.orchestrator) return;
107
+ const workerType = task.resource.type === "video" ? "videoDemux" : "audioDemux";
108
+ const demuxWorker = await this.orchestrator.workers.get(workerType, task.resourceId, {
109
+ lazy: true
110
+ });
111
+ const clipIds = this.model?.getClipIdsByResourceId?.(task.resourceId) || [];
112
+ const clipId = clipIds[0];
113
+ await demuxWorker.sendStream(task.stream, {
114
+ resourceId: task.resourceId,
115
+ clipId,
116
+ ...task.metadata,
117
+ ...task.range && { range: task.range }
118
+ });
119
+ }
120
+ updateResourceState(resourceId, state) {
121
+ const resource = this.model?.resources.get(resourceId);
122
+ if (resource) {
123
+ const oldState = resource.state;
124
+ resource.state = state;
125
+ if (this.orchestrator) {
126
+ this.eventBus?.emit(MeframeEvent.ResourceStageChange, {
127
+ type: MeframeEvent.ResourceStageChange,
128
+ resourceId,
129
+ oldState,
130
+ newState: state
131
+ });
132
+ }
133
+ }
134
+ this.onStateChange?.(resourceId, state);
135
+ }
136
+ async fetch(resourceId, options) {
137
+ if (!resourceId) {
138
+ return;
139
+ }
140
+ const resource = this.model?.resources.get(resourceId);
141
+ if (!resource) {
142
+ console.warn(`Resource ${resourceId} not found in model`);
143
+ return;
144
+ }
145
+ this.enqueueLoad(resource, options?.priority || "normal", options?.range);
146
+ }
147
+ cancel(resourceId) {
148
+ this.taskManager.cancelTask(resourceId);
149
+ this.processQueue();
150
+ }
151
+ pause(resourceId) {
152
+ const task = this.taskManager.getActiveTask(resourceId);
153
+ if (task) {
154
+ task.controller?.abort();
155
+ }
156
+ }
157
+ async resume(resourceId, options) {
158
+ const resource = this.model?.getResource(resourceId);
159
+ if (!resource) {
160
+ throw new Error(`Resource ${resourceId} not found`);
161
+ }
162
+ const pausedTask = this.taskManager.getActiveTask(resourceId);
163
+ if (pausedTask?.pausedAt !== void 0) {
164
+ this.enqueueLoad(resource, options?.priority || "normal");
165
+ } else {
166
+ await this.fetch(resourceId, options);
167
+ }
168
+ }
169
+ get activeTasks() {
170
+ return this.taskManager.activeTasks;
171
+ }
172
+ get taskQueue() {
173
+ return this.taskManager.taskQueue;
174
+ }
175
+ dispose() {
176
+ this.taskManager.clear();
177
+ this.byteRangeResolver.dispose();
178
+ this.unbind();
179
+ }
180
+ }
181
+ export {
182
+ ResourceLoader
183
+ };
184
+ //# sourceMappingURL=ResourceLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResourceLoader.js","sources":["../../../src/stages/load/ResourceLoader.ts"],"sourcesContent":["import type { Resource, CompositionModel } from '../../model';\nimport type { Orchestrator, ResourceLoadOptions, LoadTask, ResourceLoaderOptions } from './types';\nimport { TaskManager } from './TaskManager';\nimport { StreamFactory } from './StreamFactory';\nimport { EventHandlers } from './EventHandlers';\nimport { EventPayloadMap, MeframeEvent } from '../../event/events';\nimport { EventBus } from '../../event/EventBus';\nimport { WindowByteRangeResolver } from './WindowByteRangeResolver';\n\nexport class ResourceLoader {\n private orchestrator?: Orchestrator;\n private model?: CompositionModel;\n private taskManager: TaskManager;\n private streamFactory: StreamFactory;\n private eventHandlers?: EventHandlers;\n private eventBus?: EventBus<EventPayloadMap>;\n private onStateChange?: (resourceId: string, state: Resource['state']) => void;\n private byteRangeResolver: WindowByteRangeResolver;\n\n constructor(options?: ResourceLoaderOptions) {\n const maxConcurrent = options?.config?.maxConcurrent ?? 4;\n this.taskManager = new TaskManager(maxConcurrent);\n this.streamFactory = new StreamFactory(options?.onProgress, options?.config);\n this.eventBus = options?.eventBus;\n this.onStateChange = options?.onStateChange;\n this.byteRangeResolver = new WindowByteRangeResolver();\n\n if (options?.orchestrator) {\n this.bind(options.orchestrator);\n }\n }\n\n /**\n * Bind to Orchestrator event system\n */\n bind(orchestrator: Orchestrator): void {\n this.unbind();\n this.orchestrator = orchestrator;\n\n this.eventHandlers = new EventHandlers(\n orchestrator,\n (resource, priority) => this.enqueueLoad(resource, priority),\n (resourceId) => this.cancel(resourceId),\n (model) => this.handleModelSet(model)\n );\n }\n\n /**\n * Unbind from Orchestrator\n */\n unbind(): void {\n this.eventHandlers?.dispose();\n this.eventHandlers = undefined;\n this.orchestrator = undefined;\n }\n\n private handleModelSet(model: CompositionModel): void {\n this.model = model;\n }\n\n private enqueueLoad(\n resource: Resource,\n priority: 'high' | 'normal' | 'low' = 'normal',\n range?: { start: number; end: number }\n ): void {\n if (this.taskManager.hasActiveTask(resource.id)) {\n return;\n }\n\n if (resource.type === 'json' || resource.type === 'text') {\n this.loadNonStreamingResource(resource);\n return;\n }\n\n const task = this.taskManager.enqueue(resource, priority);\n if (task && range) {\n task.range = range;\n }\n this.processQueue();\n }\n\n private processQueue(): void {\n while (this.taskManager.canProcess) {\n const task = this.taskManager.getNextTask();\n if (!task) break;\n this.startLoad(task);\n }\n }\n\n private async startLoad(task: LoadTask): Promise<void> {\n this.taskManager.activateTask(task);\n\n try {\n this.updateResourceState(task.resourceId, 'loading');\n task.controller = new AbortController();\n\n // const metadata = await this.streamFactory.fetchMetadata(\n // task.resource.uri,\n // task.controller.signal\n // );\n\n // if (metadata) {\n // task.metadata = metadata;\n // task.totalBytes = metadata.contentLength;\n // }\n\n // let stream =\n // metadata?.acceptRanges && task.pausedAt !== undefined\n // ? this.streamFactory.createResumableStream(task)\n // : await this.streamFactory.createRegularStream(task);\n\n const stream = await this.streamFactory.createRegularStream(task);\n\n if (!stream) {\n throw new Error(`Failed to create stream for ${task.resourceId}`);\n }\n\n task.stream = stream;\n\n if (task.resource.type === 'video' || task.resource.type === 'audio') {\n await this.transferToDemuxWorker(task);\n }\n this.updateResourceState(task.resourceId, 'ready');\n } catch (error) {\n task.error = error as Error;\n this.updateResourceState(task.resourceId, 'error');\n } finally {\n this.taskManager.completeTask(task.resourceId);\n this.processQueue();\n }\n }\n\n private async loadNonStreamingResource(resource: Resource): Promise<void> {\n try {\n this.updateResourceState(resource.id, 'loading');\n const response = await fetch(resource.uri);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n this.updateResourceState(resource.id, 'ready');\n } catch {\n this.updateResourceState(resource.id, 'error');\n }\n }\n\n private async transferToDemuxWorker(task: LoadTask): Promise<void> {\n if (!task.stream || !this.orchestrator) return;\n\n const workerType = task.resource.type === 'video' ? 'videoDemux' : 'audioDemux';\n // use lazy mode to avoid initializing worker when not needed\n const demuxWorker = await this.orchestrator.workers.get(workerType, task.resourceId, {\n lazy: true,\n });\n\n const clipIds = this.model?.getClipIdsByResourceId?.(task.resourceId) || [];\n const clipId = clipIds[0];\n\n await demuxWorker.sendStream(task.stream, {\n resourceId: task.resourceId,\n clipId,\n ...task.metadata,\n ...(task.range && { range: task.range }),\n });\n }\n\n private updateResourceState(resourceId: string, state: Resource['state']): void {\n const resource = this.model?.resources.get(resourceId);\n if (resource) {\n const oldState = resource.state;\n resource.state = state;\n if (this.orchestrator) {\n this.eventBus?.emit(MeframeEvent.ResourceStageChange, {\n type: MeframeEvent.ResourceStageChange,\n resourceId,\n oldState,\n newState: state,\n });\n }\n }\n\n this.onStateChange?.(resourceId, state);\n }\n\n async fetch(resourceId?: string, options?: ResourceLoadOptions): Promise<void> {\n if (!resourceId) {\n return;\n }\n\n const resource = this.model?.resources.get(resourceId);\n if (!resource) {\n console.warn(`Resource ${resourceId} not found in model`);\n return;\n }\n\n this.enqueueLoad(resource, options?.priority || 'normal', options?.range);\n }\n\n cancel(resourceId: string): void {\n this.taskManager.cancelTask(resourceId);\n this.processQueue();\n }\n\n pause(resourceId: string): void {\n const task = this.taskManager.getActiveTask(resourceId);\n if (task) {\n task.controller?.abort();\n }\n }\n\n async resume(resourceId: string, options?: ResourceLoadOptions): Promise<void> {\n const resource = this.model?.getResource(resourceId);\n if (!resource) {\n throw new Error(`Resource ${resourceId} not found`);\n }\n\n const pausedTask = this.taskManager.getActiveTask(resourceId);\n\n if (pausedTask?.pausedAt !== undefined) {\n this.enqueueLoad(resource, options?.priority || 'normal');\n } else {\n await this.fetch(resourceId, options);\n }\n }\n\n get activeTasks(): Map<string, LoadTask> {\n return this.taskManager.activeTasks;\n }\n\n get taskQueue(): LoadTask[] {\n return this.taskManager.taskQueue;\n }\n\n dispose(): void {\n this.taskManager.clear();\n this.byteRangeResolver.dispose();\n this.unbind();\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { LoadTask, LoadProgress, StreamMetadata, LoaderConfig } from './types';
2
+
3
+ /**
4
+ * Factory for creating various types of streams with backpressure configuration
5
+ */
6
+ export declare class StreamFactory {
7
+ private onProgress?;
8
+ private static readonly DEFAULT_HIGH_WATER_MARK;
9
+ private static readonly DEFAULT_CHUNK_SIZE;
10
+ private static readonly DEFAULT_RETRY_COUNT;
11
+ private static readonly DEFAULT_RETRY_DELAY;
12
+ private readonly highWaterMark;
13
+ private readonly chunkSize;
14
+ private readonly retryCount;
15
+ private readonly retryDelay;
16
+ constructor(onProgress?: ((progress: LoadProgress) => void) | undefined, config?: LoaderConfig);
17
+ /**
18
+ * Fetch metadata for a resource
19
+ */
20
+ fetchMetadata(url: string, signal: AbortSignal): Promise<StreamMetadata | null>;
21
+ /**
22
+ * Create a regular (non-resumable) stream
23
+ */
24
+ createRegularStream(task: LoadTask): Promise<ReadableStream<Uint8Array> | null>;
25
+ /**
26
+ * Create a resumable stream with Range support
27
+ */
28
+ createResumableStream(task: LoadTask): ReadableStream<Uint8Array>;
29
+ /**
30
+ * Wrap stream with progress tracking
31
+ */
32
+ wrapWithProgress(stream: ReadableStream<Uint8Array>, task: LoadTask): ReadableStream<Uint8Array>;
33
+ /**
34
+ * Fetch with retry logic
35
+ */
36
+ private fetchWithRetry;
37
+ /**
38
+ * Report progress
39
+ */
40
+ private reportProgress;
41
+ }
42
+ //# sourceMappingURL=StreamFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StreamFactory.d.ts","sourceRoot":"","sources":["../../../src/stages/load/StreamFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpF;;GAEG;AACH,qBAAa,aAAa;IAatB,OAAO,CAAC,UAAU,CAAC;IAXrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAe;IAC9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAe;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAElD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAG1B,UAAU,CAAC,GAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,aAAA,EACrD,MAAM,CAAC,EAAE,YAAY;IASvB;;OAEG;IACG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAwBrF;;OAEG;IACG,mBAAmB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAuBrF;;OAEG;IACH,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC;IA8DjE;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC;IAmChG;;OAEG;YACW,cAAc;IAkC5B;;OAEG;IACH,OAAO,CAAC,cAAc;CAkBvB"}
@@ -0,0 +1,201 @@
1
+ class StreamFactory {
2
+ constructor(onProgress, config) {
3
+ this.onProgress = onProgress;
4
+ this.highWaterMark = config?.highWaterMark ?? StreamFactory.DEFAULT_HIGH_WATER_MARK;
5
+ this.chunkSize = config?.chunkSize ?? StreamFactory.DEFAULT_CHUNK_SIZE;
6
+ this.retryCount = config?.retryCount ?? StreamFactory.DEFAULT_RETRY_COUNT;
7
+ this.retryDelay = config?.retryDelay ?? StreamFactory.DEFAULT_RETRY_DELAY;
8
+ }
9
+ // Default values as fallback
10
+ static DEFAULT_HIGH_WATER_MARK = 1024 * 1024;
11
+ // 1MB
12
+ static DEFAULT_CHUNK_SIZE = 1024 * 1024;
13
+ // 1MB
14
+ static DEFAULT_RETRY_COUNT = 3;
15
+ static DEFAULT_RETRY_DELAY = 500;
16
+ // ms
17
+ highWaterMark;
18
+ chunkSize;
19
+ retryCount;
20
+ retryDelay;
21
+ /**
22
+ * Fetch metadata for a resource
23
+ */
24
+ async fetchMetadata(url, signal) {
25
+ try {
26
+ const response = await fetch(url, {
27
+ method: "HEAD",
28
+ signal
29
+ });
30
+ if (!response.ok) {
31
+ return null;
32
+ }
33
+ return {
34
+ url,
35
+ contentLength: Number(response.headers.get("content-length") || 0),
36
+ acceptRanges: response.headers.get("accept-ranges") === "bytes",
37
+ contentType: response.headers.get("content-type") || void 0,
38
+ lastModified: response.headers.get("last-modified") || void 0,
39
+ etag: response.headers.get("etag") || void 0
40
+ };
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+ /**
46
+ * Create a regular (non-resumable) stream
47
+ */
48
+ async createRegularStream(task) {
49
+ const response = await this.fetchWithRetry(task.resource.uri, {
50
+ method: "GET",
51
+ // Explicitly specify GET (vs HEAD)
52
+ signal: task.controller.signal
53
+ });
54
+ if (!response.ok) {
55
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
56
+ }
57
+ if (!response.body) {
58
+ console.warn(
59
+ `[StreamFactory] Response body is null for ${task.resource.uri}, possibly cached HEAD response`
60
+ );
61
+ return null;
62
+ }
63
+ task.totalBytes = Number(response.headers.get("content-length") || 0);
64
+ return this.wrapWithProgress(response.body, task);
65
+ }
66
+ /**
67
+ * Create a resumable stream with Range support
68
+ */
69
+ createResumableStream(task) {
70
+ let bytesReceived = task.pausedAt || 0;
71
+ const totalSize = task.metadata?.contentLength || 0;
72
+ return new ReadableStream(
73
+ {
74
+ pull: async (controller) => {
75
+ if (controller.desiredSize !== null && controller.desiredSize <= 0) {
76
+ return;
77
+ }
78
+ if (bytesReceived >= totalSize) {
79
+ controller.close();
80
+ return;
81
+ }
82
+ const end = Math.min(bytesReceived + this.chunkSize - 1, totalSize - 1);
83
+ try {
84
+ const response = await fetch(task.resource.uri, {
85
+ method: "GET",
86
+ signal: task.controller.signal,
87
+ headers: { Range: `bytes=${bytesReceived}-${end}` }
88
+ // Use default cache for Range requests
89
+ });
90
+ if (!response.ok && response.status !== 206) {
91
+ throw new Error(`Range request failed: ${response.status}`);
92
+ }
93
+ if (!response.body) {
94
+ throw new Error(`Response body is null in Range request for ${task.resource.uri}`);
95
+ }
96
+ const chunk = await response.arrayBuffer();
97
+ const uint8Array = new Uint8Array(chunk);
98
+ controller.enqueue(uint8Array);
99
+ bytesReceived += chunk.byteLength;
100
+ task.bytesLoaded = bytesReceived;
101
+ this.reportProgress(task, bytesReceived, totalSize);
102
+ } catch (error) {
103
+ if (error.name === "AbortError") {
104
+ task.pausedAt = bytesReceived;
105
+ }
106
+ controller.error(error);
107
+ }
108
+ },
109
+ cancel: () => {
110
+ task.pausedAt = bytesReceived;
111
+ }
112
+ },
113
+ {
114
+ highWaterMark: this.highWaterMark,
115
+ size: (chunk) => chunk.byteLength
116
+ }
117
+ );
118
+ }
119
+ /**
120
+ * Wrap stream with progress tracking
121
+ */
122
+ wrapWithProgress(stream, task) {
123
+ const reader = stream.getReader();
124
+ let bytesReceived = 0;
125
+ return new ReadableStream(
126
+ {
127
+ pull: async (controller) => {
128
+ while (true) {
129
+ try {
130
+ const { done, value } = await reader.read();
131
+ if (done) {
132
+ controller.close();
133
+ break;
134
+ }
135
+ bytesReceived += value.byteLength;
136
+ task.bytesLoaded = bytesReceived;
137
+ this.reportProgress(task, bytesReceived, task.totalBytes);
138
+ controller.enqueue(value);
139
+ } catch (error) {
140
+ controller.error(error);
141
+ break;
142
+ }
143
+ }
144
+ },
145
+ cancel: () => reader.cancel()
146
+ },
147
+ {
148
+ highWaterMark: this.highWaterMark,
149
+ size: (chunk) => chunk.byteLength
150
+ }
151
+ );
152
+ }
153
+ /**
154
+ * Fetch with retry logic
155
+ */
156
+ async fetchWithRetry(url, init) {
157
+ let lastError = null;
158
+ for (let i = 0; i <= this.retryCount; i++) {
159
+ try {
160
+ const response = await fetch(url, init);
161
+ if (response.ok || response.status === 206) {
162
+ return response;
163
+ }
164
+ if (response.status >= 400 && response.status < 500) {
165
+ return response;
166
+ }
167
+ lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);
168
+ } catch (error) {
169
+ lastError = error;
170
+ if (error.name === "AbortError") {
171
+ throw error;
172
+ }
173
+ }
174
+ if (i < this.retryCount) {
175
+ await new Promise((resolve) => setTimeout(resolve, this.retryDelay * Math.pow(2, i)));
176
+ }
177
+ }
178
+ throw lastError || new Error("Failed to fetch after retries");
179
+ }
180
+ /**
181
+ * Report progress
182
+ */
183
+ reportProgress(task, bytesLoaded, totalBytes) {
184
+ if (!this.onProgress || !task.resource.id) return;
185
+ const elapsedSeconds = (Date.now() - task.startTime) / 1e3;
186
+ const speed = bytesLoaded / elapsedSeconds;
187
+ const progress = {
188
+ resourceId: task.resource.id,
189
+ bytesLoaded,
190
+ totalBytes,
191
+ percentage: totalBytes > 0 ? bytesLoaded / totalBytes * 100 : 0,
192
+ speed,
193
+ estimatedTimeRemaining: speed > 0 && totalBytes > 0 ? (totalBytes - bytesLoaded) / speed * 1e3 : 0
194
+ };
195
+ this.onProgress(progress);
196
+ }
197
+ }
198
+ export {
199
+ StreamFactory
200
+ };
201
+ //# sourceMappingURL=StreamFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StreamFactory.js","sources":["../../../src/stages/load/StreamFactory.ts"],"sourcesContent":["import type { LoadTask, LoadProgress, StreamMetadata, LoaderConfig } from './types';\n\n/**\n * Factory for creating various types of streams with backpressure configuration\n */\nexport class StreamFactory {\n // Default values as fallback\n private static readonly DEFAULT_HIGH_WATER_MARK = 1024 * 1024; // 1MB\n private static readonly DEFAULT_CHUNK_SIZE = 1024 * 1024; // 1MB\n private static readonly DEFAULT_RETRY_COUNT = 3;\n private static readonly DEFAULT_RETRY_DELAY = 500; // ms\n\n private readonly highWaterMark: number;\n private readonly chunkSize: number;\n private readonly retryCount: number;\n private readonly retryDelay: number;\n\n constructor(\n private onProgress?: (progress: LoadProgress) => void,\n config?: LoaderConfig\n ) {\n // Use provided config with local defaults as fallback\n this.highWaterMark = config?.highWaterMark ?? StreamFactory.DEFAULT_HIGH_WATER_MARK;\n this.chunkSize = config?.chunkSize ?? StreamFactory.DEFAULT_CHUNK_SIZE;\n this.retryCount = config?.retryCount ?? StreamFactory.DEFAULT_RETRY_COUNT;\n this.retryDelay = config?.retryDelay ?? StreamFactory.DEFAULT_RETRY_DELAY;\n }\n\n /**\n * Fetch metadata for a resource\n */\n async fetchMetadata(url: string, signal: AbortSignal): Promise<StreamMetadata | null> {\n try {\n const response = await fetch(url, {\n method: 'HEAD',\n signal,\n });\n\n if (!response.ok) {\n return null;\n }\n\n return {\n url,\n contentLength: Number(response.headers.get('content-length') || 0),\n acceptRanges: response.headers.get('accept-ranges') === 'bytes',\n contentType: response.headers.get('content-type') || undefined,\n lastModified: response.headers.get('last-modified') || undefined,\n etag: response.headers.get('etag') || undefined,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Create a regular (non-resumable) stream\n */\n async createRegularStream(task: LoadTask): Promise<ReadableStream<Uint8Array> | null> {\n const response = await this.fetchWithRetry(task.resource.uri, {\n method: 'GET', // Explicitly specify GET (vs HEAD)\n signal: task.controller!.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n // Return null if body is empty (e.g., from cached HEAD response)\n // ResourceLoader should retry with forceFresh in this case\n if (!response.body) {\n console.warn(\n `[StreamFactory] Response body is null for ${task.resource.uri}, possibly cached HEAD response`\n );\n return null;\n }\n\n task.totalBytes = Number(response.headers.get('content-length') || 0);\n return this.wrapWithProgress(response.body, task);\n }\n\n /**\n * Create a resumable stream with Range support\n */\n createResumableStream(task: LoadTask): ReadableStream<Uint8Array> {\n let bytesReceived = task.pausedAt || 0;\n const totalSize = task.metadata?.contentLength || 0;\n\n return new ReadableStream<Uint8Array>(\n {\n pull: async (controller) => {\n // Backpressure: wait for downstream to consume\n if (controller.desiredSize !== null && controller.desiredSize <= 0) {\n return;\n }\n\n if (bytesReceived >= totalSize) {\n controller.close();\n return;\n }\n\n const end = Math.min(bytesReceived + this.chunkSize - 1, totalSize - 1);\n\n try {\n const response = await fetch(task.resource.uri, {\n method: 'GET',\n signal: task.controller!.signal,\n headers: { Range: `bytes=${bytesReceived}-${end}` },\n // Use default cache for Range requests\n });\n\n if (!response.ok && response.status !== 206) {\n throw new Error(`Range request failed: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error(`Response body is null in Range request for ${task.resource.uri}`);\n }\n\n const chunk = await response.arrayBuffer();\n const uint8Array = new Uint8Array(chunk);\n\n controller.enqueue(uint8Array);\n bytesReceived += chunk.byteLength;\n task.bytesLoaded = bytesReceived;\n\n this.reportProgress(task, bytesReceived, totalSize);\n } catch (error: any) {\n if (error.name === 'AbortError') {\n task.pausedAt = bytesReceived;\n }\n controller.error(error);\n }\n },\n\n cancel: () => {\n task.pausedAt = bytesReceived;\n },\n },\n {\n highWaterMark: this.highWaterMark,\n size: (chunk) => chunk.byteLength,\n }\n );\n }\n\n /**\n * Wrap stream with progress tracking\n */\n wrapWithProgress(stream: ReadableStream<Uint8Array>, task: LoadTask): ReadableStream<Uint8Array> {\n const reader = stream.getReader();\n let bytesReceived = 0;\n\n return new ReadableStream<Uint8Array>(\n {\n pull: async (controller) => {\n while (true) {\n try {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n break;\n }\n\n bytesReceived += value.byteLength;\n task.bytesLoaded = bytesReceived;\n this.reportProgress(task, bytesReceived, task.totalBytes);\n controller.enqueue(value);\n } catch (error) {\n controller.error(error);\n break;\n }\n }\n },\n\n cancel: () => reader.cancel(),\n },\n {\n highWaterMark: this.highWaterMark,\n size: (chunk) => chunk.byteLength,\n }\n );\n }\n\n /**\n * Fetch with retry logic\n */\n private async fetchWithRetry(url: string, init: RequestInit): Promise<Response> {\n let lastError: Error | null = null;\n\n for (let i = 0; i <= this.retryCount; i++) {\n try {\n const response = await fetch(url, init);\n if (response.ok || response.status === 206) {\n return response;\n }\n\n // Don't retry on client errors (4xx)\n if (response.status >= 400 && response.status < 500) {\n return response;\n }\n\n lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);\n } catch (error: any) {\n lastError = error;\n\n // Don't retry on abort\n if (error.name === 'AbortError') {\n throw error;\n }\n }\n\n // Exponential backoff\n if (i < this.retryCount) {\n await new Promise((resolve) => setTimeout(resolve, this.retryDelay * Math.pow(2, i)));\n }\n }\n\n throw lastError || new Error('Failed to fetch after retries');\n }\n\n /**\n * Report progress\n */\n private reportProgress(task: LoadTask, bytesLoaded: number, totalBytes: number): void {\n if (!this.onProgress || !task.resource.id) return;\n\n const elapsedSeconds = (Date.now() - task.startTime) / 1000;\n const speed = bytesLoaded / elapsedSeconds;\n\n const progress: LoadProgress = {\n resourceId: task.resource.id,\n bytesLoaded,\n totalBytes,\n percentage: totalBytes > 0 ? (bytesLoaded / totalBytes) * 100 : 0,\n speed,\n estimatedTimeRemaining:\n speed > 0 && totalBytes > 0 ? ((totalBytes - bytesLoaded) / speed) * 1000 : 0,\n };\n\n this.onProgress(progress);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { LoadTask } from './types';
2
+ import { Resource } from '../../model';
3
+
4
+ /**
5
+ * Manages resource loading tasks and queue
6
+ */
7
+ export declare class TaskManager {
8
+ activeTasks: Map<string, LoadTask>;
9
+ taskQueue: LoadTask[];
10
+ private concurrentCount;
11
+ private maxConcurrent;
12
+ constructor(maxConcurrent?: number);
13
+ /**
14
+ * Check if a resource is already being loaded
15
+ */
16
+ hasActiveTask(resourceId: string): boolean;
17
+ /**
18
+ * Create and enqueue a new task
19
+ */
20
+ enqueue(resource: Resource, priority?: 'high' | 'normal' | 'low'): LoadTask;
21
+ /**
22
+ * Get next task from queue if under concurrent limit
23
+ */
24
+ getNextTask(): LoadTask | null;
25
+ /**
26
+ * Mark task as active
27
+ */
28
+ activateTask(task: LoadTask): void;
29
+ /**
30
+ * Mark task as completed
31
+ */
32
+ completeTask(resourceId: string): void;
33
+ /**
34
+ * Cancel a task
35
+ */
36
+ cancelTask(resourceId: string): boolean;
37
+ /**
38
+ * Find an active task
39
+ */
40
+ getActiveTask(resourceId: string): LoadTask | undefined;
41
+ /**
42
+ * Check if can process more tasks
43
+ */
44
+ get canProcess(): boolean;
45
+ /**
46
+ * Clear all tasks
47
+ */
48
+ clear(): void;
49
+ }
50
+ //# sourceMappingURL=TaskManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../../src/stages/load/TaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,qBAAa,WAAW;IACtB,WAAW,wBAA+B;IAC1C,SAAS,EAAE,QAAQ,EAAE,CAAM;IAC3B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,aAAa,CAAS;gBAElB,aAAa,GAAE,MAAU;IAIrC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAE,MAAM,GAAG,QAAQ,GAAG,KAAgB,GAAG,QAAQ;IAoBrF;;OAEG;IACH,WAAW,IAAI,QAAQ,GAAG,IAAI;IAQ9B;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAKlC;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAOtC;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAkBvC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvD;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;OAEG;IACH,KAAK,IAAI,IAAI;CAUd"}
@@ -0,0 +1,103 @@
1
+ class TaskManager {
2
+ activeTasks = /* @__PURE__ */ new Map();
3
+ taskQueue = [];
4
+ concurrentCount = 0;
5
+ maxConcurrent;
6
+ constructor(maxConcurrent = 4) {
7
+ this.maxConcurrent = maxConcurrent;
8
+ }
9
+ /**
10
+ * Check if a resource is already being loaded
11
+ */
12
+ hasActiveTask(resourceId) {
13
+ return this.activeTasks.has(resourceId);
14
+ }
15
+ /**
16
+ * Create and enqueue a new task
17
+ */
18
+ enqueue(resource, priority = "normal") {
19
+ const task = {
20
+ resourceId: resource.id,
21
+ resource,
22
+ bytesLoaded: 0,
23
+ totalBytes: 0,
24
+ startTime: Date.now(),
25
+ priority
26
+ };
27
+ if (priority === "high") {
28
+ this.taskQueue.unshift(task);
29
+ } else {
30
+ this.taskQueue.push(task);
31
+ }
32
+ return task;
33
+ }
34
+ /**
35
+ * Get next task from queue if under concurrent limit
36
+ */
37
+ getNextTask() {
38
+ if (this.taskQueue.length === 0 || this.concurrentCount >= this.maxConcurrent) {
39
+ return null;
40
+ }
41
+ return this.taskQueue.shift() || null;
42
+ }
43
+ /**
44
+ * Mark task as active
45
+ */
46
+ activateTask(task) {
47
+ this.activeTasks.set(task.resourceId, task);
48
+ this.concurrentCount++;
49
+ }
50
+ /**
51
+ * Mark task as completed
52
+ */
53
+ completeTask(resourceId) {
54
+ if (this.activeTasks.has(resourceId)) {
55
+ this.activeTasks.delete(resourceId);
56
+ this.concurrentCount--;
57
+ }
58
+ }
59
+ /**
60
+ * Cancel a task
61
+ */
62
+ cancelTask(resourceId) {
63
+ const task = this.activeTasks.get(resourceId);
64
+ if (task) {
65
+ task.controller?.abort();
66
+ this.completeTask(resourceId);
67
+ return true;
68
+ }
69
+ const index = this.taskQueue.findIndex((t) => t.resourceId === resourceId);
70
+ if (index >= 0) {
71
+ this.taskQueue.splice(index, 1);
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+ /**
77
+ * Find an active task
78
+ */
79
+ getActiveTask(resourceId) {
80
+ return this.activeTasks.get(resourceId);
81
+ }
82
+ /**
83
+ * Check if can process more tasks
84
+ */
85
+ get canProcess() {
86
+ return this.concurrentCount < this.maxConcurrent;
87
+ }
88
+ /**
89
+ * Clear all tasks
90
+ */
91
+ clear() {
92
+ for (const task of this.activeTasks.values()) {
93
+ task.controller?.abort();
94
+ }
95
+ this.activeTasks.clear();
96
+ this.taskQueue = [];
97
+ this.concurrentCount = 0;
98
+ }
99
+ }
100
+ export {
101
+ TaskManager
102
+ };
103
+ //# sourceMappingURL=TaskManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskManager.js","sources":["../../../src/stages/load/TaskManager.ts"],"sourcesContent":["import type { LoadTask } from './types';\nimport type { Resource } from '../../model';\n\n/**\n * Manages resource loading tasks and queue\n */\nexport class TaskManager {\n activeTasks = new Map<string, LoadTask>();\n taskQueue: LoadTask[] = [];\n private concurrentCount = 0;\n private maxConcurrent: number;\n\n constructor(maxConcurrent: number = 4) {\n this.maxConcurrent = maxConcurrent;\n }\n\n /**\n * Check if a resource is already being loaded\n */\n hasActiveTask(resourceId: string): boolean {\n return this.activeTasks.has(resourceId);\n }\n\n /**\n * Create and enqueue a new task\n */\n enqueue(resource: Resource, priority: 'high' | 'normal' | 'low' = 'normal'): LoadTask {\n const task: LoadTask = {\n resourceId: resource.id,\n resource,\n bytesLoaded: 0,\n totalBytes: 0,\n startTime: Date.now(),\n priority,\n };\n\n // Add to queue based on priority\n if (priority === 'high') {\n this.taskQueue.unshift(task);\n } else {\n this.taskQueue.push(task);\n }\n\n return task;\n }\n\n /**\n * Get next task from queue if under concurrent limit\n */\n getNextTask(): LoadTask | null {\n if (this.taskQueue.length === 0 || this.concurrentCount >= this.maxConcurrent) {\n return null;\n }\n\n return this.taskQueue.shift() || null;\n }\n\n /**\n * Mark task as active\n */\n activateTask(task: LoadTask): void {\n this.activeTasks.set(task.resourceId, task);\n this.concurrentCount++;\n }\n\n /**\n * Mark task as completed\n */\n completeTask(resourceId: string): void {\n if (this.activeTasks.has(resourceId)) {\n this.activeTasks.delete(resourceId);\n this.concurrentCount--;\n }\n }\n\n /**\n * Cancel a task\n */\n cancelTask(resourceId: string): boolean {\n const task = this.activeTasks.get(resourceId);\n if (task) {\n task.controller?.abort();\n this.completeTask(resourceId);\n return true;\n }\n\n // Also remove from queue\n const index = this.taskQueue.findIndex((t) => t.resourceId === resourceId);\n if (index >= 0) {\n this.taskQueue.splice(index, 1);\n return true;\n }\n\n return false;\n }\n\n /**\n * Find an active task\n */\n getActiveTask(resourceId: string): LoadTask | undefined {\n return this.activeTasks.get(resourceId);\n }\n\n /**\n * Check if can process more tasks\n */\n get canProcess(): boolean {\n return this.concurrentCount < this.maxConcurrent;\n }\n\n /**\n * Clear all tasks\n */\n clear(): void {\n // Cancel all active tasks\n for (const task of this.activeTasks.values()) {\n task.controller?.abort();\n }\n\n this.activeTasks.clear();\n this.taskQueue = [];\n this.concurrentCount = 0;\n }\n}\n"],"names":[],"mappings":"AAMO,MAAM,YAAY;AAAA,EACvB,kCAAkB,IAAA;AAAA,EAClB,YAAwB,CAAA;AAAA,EAChB,kBAAkB;AAAA,EAClB;AAAA,EAER,YAAY,gBAAwB,GAAG;AACrC,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,YAA6B;AACzC,WAAO,KAAK,YAAY,IAAI,UAAU;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,UAAoB,WAAsC,UAAoB;AACpF,UAAM,OAAiB;AAAA,MACrB,YAAY,SAAS;AAAA,MACrB;AAAA,MACA,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,WAAW,KAAK,IAAA;AAAA,MAChB;AAAA,IAAA;AAIF,QAAI,aAAa,QAAQ;AACvB,WAAK,UAAU,QAAQ,IAAI;AAAA,IAC7B,OAAO;AACL,WAAK,UAAU,KAAK,IAAI;AAAA,IAC1B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,cAA+B;AAC7B,QAAI,KAAK,UAAU,WAAW,KAAK,KAAK,mBAAmB,KAAK,eAAe;AAC7E,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,UAAU,MAAA,KAAW;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,MAAsB;AACjC,SAAK,YAAY,IAAI,KAAK,YAAY,IAAI;AAC1C,SAAK;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,YAA0B;AACrC,QAAI,KAAK,YAAY,IAAI,UAAU,GAAG;AACpC,WAAK,YAAY,OAAO,UAAU;AAClC,WAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,YAA6B;AACtC,UAAM,OAAO,KAAK,YAAY,IAAI,UAAU;AAC5C,QAAI,MAAM;AACR,WAAK,YAAY,MAAA;AACjB,WAAK,aAAa,UAAU;AAC5B,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,KAAK,UAAU,UAAU,CAAC,MAAM,EAAE,eAAe,UAAU;AACzE,QAAI,SAAS,GAAG;AACd,WAAK,UAAU,OAAO,OAAO,CAAC;AAC9B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,YAA0C;AACtD,WAAO,KAAK,YAAY,IAAI,UAAU;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,aAAsB;AACxB,WAAO,KAAK,kBAAkB,KAAK;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AAEZ,eAAW,QAAQ,KAAK,YAAY,OAAA,GAAU;AAC5C,WAAK,YAAY,MAAA;AAAA,IACnB;AAEA,SAAK,YAAY,MAAA;AACjB,SAAK,YAAY,CAAA;AACjB,SAAK,kBAAkB;AAAA,EACzB;AACF;"}