@videojs/spf 10.0.0-beta.30 → 10.0.0-beta.32

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 (520) hide show
  1. package/dist/default/core/actors/create-machine-actor.js +23 -25
  2. package/dist/default/core/actors/create-machine-actor.js.map +1 -1
  3. package/dist/default/core/actors/create-transition-actor.js +7 -9
  4. package/dist/default/core/actors/create-transition-actor.js.map +1 -1
  5. package/dist/default/core/composition/create-composition.js +26 -29
  6. package/dist/default/core/composition/create-composition.js.map +1 -1
  7. package/dist/default/core/composition/share-signals.js +12 -17
  8. package/dist/default/core/composition/share-signals.js.map +1 -1
  9. package/dist/default/core/machine.js +3 -4
  10. package/dist/default/core/machine.js.map +1 -1
  11. package/dist/default/core/reactors/create-machine-reactor.js +20 -19
  12. package/dist/default/core/reactors/create-machine-reactor.js.map +1 -1
  13. package/dist/default/core/signals/effect.js +24 -4
  14. package/dist/default/core/signals/effect.js.map +1 -1
  15. package/dist/default/core/signals/primitives.js +10 -14
  16. package/dist/default/core/signals/primitives.js.map +1 -1
  17. package/dist/default/core/signals/when.js +6 -8
  18. package/dist/default/core/signals/when.js.map +1 -1
  19. package/dist/default/core/tasks/delayed-reschedule.js +7 -11
  20. package/dist/default/core/tasks/delayed-reschedule.js.map +1 -1
  21. package/dist/default/core/tasks/task.js +59 -82
  22. package/dist/default/core/tasks/task.js.map +1 -1
  23. package/dist/default/hls.js +3 -1
  24. package/dist/default/index.js +2 -3
  25. package/dist/default/index.js.map +1 -1
  26. package/dist/default/media/abr/quality-selection.js +3 -7
  27. package/dist/default/media/abr/quality-selection.js.map +1 -1
  28. package/dist/default/media/buffer/back-buffer.js +15 -19
  29. package/dist/default/media/buffer/back-buffer.js.map +1 -1
  30. package/dist/default/media/buffer/forward-buffer.js +32 -41
  31. package/dist/default/media/buffer/forward-buffer.js.map +1 -1
  32. package/dist/default/media/dom/capabilities.js +26 -37
  33. package/dist/default/media/dom/capabilities.js.map +1 -1
  34. package/dist/default/media/dom/mse/append-segment.js +3 -5
  35. package/dist/default/media/dom/mse/append-segment.js.map +1 -1
  36. package/dist/default/media/dom/mse/buffer-flusher.js +5 -5
  37. package/dist/default/media/dom/mse/buffer-flusher.js.map +1 -1
  38. package/dist/default/media/dom/mse/duration.js +23 -31
  39. package/dist/default/media/dom/mse/duration.js.map +1 -1
  40. package/dist/default/media/dom/mse/end-of-stream.js +3 -6
  41. package/dist/default/media/dom/mse/end-of-stream.js.map +1 -1
  42. package/dist/default/media/dom/mse/mediasource-setup.js +65 -81
  43. package/dist/default/media/dom/mse/mediasource-setup.js.map +1 -1
  44. package/dist/default/media/dom/screen.js +37 -54
  45. package/dist/default/media/dom/screen.js.map +1 -1
  46. package/dist/default/media/dom/text/resolve-vtt-segment.js.map +1 -1
  47. package/dist/default/media/dom/text/text-track-slots.js +15 -23
  48. package/dist/default/media/dom/text/text-track-slots.js.map +1 -1
  49. package/dist/default/media/errors.js +25 -34
  50. package/dist/default/media/errors.js.map +1 -1
  51. package/dist/default/media/hls/parse-attributes.js +9 -26
  52. package/dist/default/media/hls/parse-attributes.js.map +1 -1
  53. package/dist/default/media/hls/parse-media-playlist.js +25 -33
  54. package/dist/default/media/hls/parse-media-playlist.js.map +1 -1
  55. package/dist/default/media/hls/parse-multivariant.js +3 -3
  56. package/dist/default/media/hls/parse-multivariant.js.map +1 -1
  57. package/dist/default/media/hls/reload-policy.js +19 -27
  58. package/dist/default/media/hls/reload-policy.js.map +1 -1
  59. package/dist/default/media/hls/resolve-url.js +1 -3
  60. package/dist/default/media/hls/resolve-url.js.map +1 -1
  61. package/dist/default/media/live-window.js +9 -13
  62. package/dist/default/media/live-window.js.map +1 -1
  63. package/dist/default/media/media-tracks/media-tracks.js +12 -17
  64. package/dist/default/media/media-tracks/media-tracks.js.map +1 -1
  65. package/dist/default/media/mp4/box.js +4 -5
  66. package/dist/default/media/mp4/box.js.map +1 -1
  67. package/dist/default/media/mp4/timestamp-origin.js +30 -42
  68. package/dist/default/media/mp4/timestamp-origin.js.map +1 -1
  69. package/dist/default/media/primitives/resolution.js +5 -8
  70. package/dist/default/media/primitives/resolution.js.map +1 -1
  71. package/dist/default/media/primitives/select-tracks.js +24 -34
  72. package/dist/default/media/primitives/select-tracks.js.map +1 -1
  73. package/dist/default/media/text/parse-vtt-timestamp-map.js +6 -8
  74. package/dist/default/media/text/parse-vtt-timestamp-map.js.map +1 -1
  75. package/dist/default/media/text/resolve-vtt-metadata.js +8 -9
  76. package/dist/default/media/text/resolve-vtt-metadata.js.map +1 -1
  77. package/dist/default/media/types/index.js +10 -18
  78. package/dist/default/media/types/index.js.map +1 -1
  79. package/dist/default/media/utils/cdn.js +10 -16
  80. package/dist/default/media/utils/cdn.js.map +1 -1
  81. package/dist/default/media/utils/preload.js +4 -6
  82. package/dist/default/media/utils/preload.js.map +1 -1
  83. package/dist/default/media/utils/track-selection.js +10 -14
  84. package/dist/default/media/utils/track-selection.js.map +1 -1
  85. package/dist/default/media/utils/tracks.js +56 -54
  86. package/dist/default/media/utils/tracks.js.map +1 -1
  87. package/dist/default/network/bandwidth-estimator.js +18 -19
  88. package/dist/default/network/bandwidth-estimator.js.map +1 -1
  89. package/dist/default/network/chunked-stream-iterable.js +4 -6
  90. package/dist/default/network/chunked-stream-iterable.js.map +1 -1
  91. package/dist/default/network/ewma.js +22 -25
  92. package/dist/default/network/ewma.js.map +1 -1
  93. package/dist/default/network/fetch.js +30 -37
  94. package/dist/default/network/fetch.js.map +1 -1
  95. package/dist/default/playback/actors/dom/segment-loader.js +28 -44
  96. package/dist/default/playback/actors/dom/segment-loader.js.map +1 -1
  97. package/dist/default/playback/actors/dom/source-buffer.js.map +1 -1
  98. package/dist/default/playback/actors/dom/text-tracks.js.map +1 -1
  99. package/dist/default/playback/actors/text-track-segment-loader.js +24 -35
  100. package/dist/default/playback/actors/text-track-segment-loader.js.map +1 -1
  101. package/dist/default/playback/adapters/hls-audio/adapter.js +23 -31
  102. package/dist/default/playback/adapters/hls-audio/adapter.js.map +1 -1
  103. package/dist/default/playback/adapters/hls-audio/media.js.map +1 -1
  104. package/dist/default/playback/adapters/hls-background-video/adapter.js +50 -70
  105. package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -1
  106. package/dist/default/playback/adapters/hls-background-video/host.js +12 -16
  107. package/dist/default/playback/adapters/hls-background-video/host.js.map +1 -1
  108. package/dist/default/playback/adapters/hls-background-video/media.js +5 -8
  109. package/dist/default/playback/adapters/hls-background-video/media.js.map +1 -1
  110. package/dist/default/playback/adapters/hls-video/adapter.js +43 -60
  111. package/dist/default/playback/adapters/hls-video/adapter.js.map +1 -1
  112. package/dist/default/playback/adapters/hls-video/error-surface.js +13 -18
  113. package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -1
  114. package/dist/default/playback/adapters/hls-video/media-tracks.js +4 -5
  115. package/dist/default/playback/adapters/hls-video/media-tracks.js.map +1 -1
  116. package/dist/default/playback/adapters/hls-video/media.js.map +1 -1
  117. package/dist/default/playback/adapters/mux-audio/media.js +8 -12
  118. package/dist/default/playback/adapters/mux-audio/media.js.map +1 -1
  119. package/dist/default/playback/adapters/mux-video/adapter.js +25 -33
  120. package/dist/default/playback/adapters/mux-video/adapter.js.map +1 -1
  121. package/dist/default/playback/adapters/mux-video/media.js +7 -9
  122. package/dist/default/playback/adapters/mux-video/media.js.map +1 -1
  123. package/dist/default/playback/behaviors/calculate-presentation-duration.js +5 -8
  124. package/dist/default/playback/behaviors/calculate-presentation-duration.js.map +1 -1
  125. package/dist/default/playback/behaviors/collect-errors.js +39 -52
  126. package/dist/default/playback/behaviors/collect-errors.js.map +1 -1
  127. package/dist/default/playback/behaviors/derive-cdn-priority.js +16 -23
  128. package/dist/default/playback/behaviors/derive-cdn-priority.js.map +1 -1
  129. package/dist/default/playback/behaviors/dom/airplay.js +38 -61
  130. package/dist/default/playback/behaviors/dom/airplay.js.map +1 -1
  131. package/dist/default/playback/behaviors/dom/apply-start-position.js +23 -35
  132. package/dist/default/playback/behaviors/dom/apply-start-position.js.map +1 -1
  133. package/dist/default/playback/behaviors/dom/end-of-stream.js +11 -16
  134. package/dist/default/playback/behaviors/dom/end-of-stream.js.map +1 -1
  135. package/dist/default/playback/behaviors/dom/load-segments.js +27 -39
  136. package/dist/default/playback/behaviors/dom/load-segments.js.map +1 -1
  137. package/dist/default/playback/behaviors/dom/recover-end-stall.js +21 -26
  138. package/dist/default/playback/behaviors/dom/recover-end-stall.js.map +1 -1
  139. package/dist/default/playback/behaviors/dom/seek-to-live-edge.js +41 -60
  140. package/dist/default/playback/behaviors/dom/seek-to-live-edge.js.map +1 -1
  141. package/dist/default/playback/behaviors/dom/setup-buffer-actors.js +50 -74
  142. package/dist/default/playback/behaviors/dom/setup-buffer-actors.js.map +1 -1
  143. package/dist/default/playback/behaviors/dom/setup-mediasource.js +29 -43
  144. package/dist/default/playback/behaviors/dom/setup-mediasource.js.map +1 -1
  145. package/dist/default/playback/behaviors/dom/setup-text-track-actors.js.map +1 -1
  146. package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js +3 -4
  147. package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -1
  148. package/dist/default/playback/behaviors/dom/sync-text-tracks.js +30 -45
  149. package/dist/default/playback/behaviors/dom/sync-text-tracks.js.map +1 -1
  150. package/dist/default/playback/behaviors/dom/track-current-time.js +9 -11
  151. package/dist/default/playback/behaviors/dom/track-current-time.js.map +1 -1
  152. package/dist/default/playback/behaviors/dom/track-load-triggers.js +24 -32
  153. package/dist/default/playback/behaviors/dom/track-load-triggers.js.map +1 -1
  154. package/dist/default/playback/behaviors/dom/track-playback-rate.js +6 -8
  155. package/dist/default/playback/behaviors/dom/track-playback-rate.js.map +1 -1
  156. package/dist/default/playback/behaviors/dom/track-player-resolution.js +10 -14
  157. package/dist/default/playback/behaviors/dom/track-player-resolution.js.map +1 -1
  158. package/dist/default/playback/behaviors/dom/track-screen-resolution.js +8 -9
  159. package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -1
  160. package/dist/default/playback/behaviors/dom/update-mediasource-duration.js +28 -43
  161. package/dist/default/playback/behaviors/dom/update-mediasource-duration.js.map +1 -1
  162. package/dist/default/playback/behaviors/establish-start-media-time.js +32 -42
  163. package/dist/default/playback/behaviors/establish-start-media-time.js.map +1 -1
  164. package/dist/default/playback/behaviors/resolve-presentation.js +13 -22
  165. package/dist/default/playback/behaviors/resolve-presentation.js.map +1 -1
  166. package/dist/default/playback/behaviors/resolve-track.js +5 -12
  167. package/dist/default/playback/behaviors/resolve-track.js.map +1 -1
  168. package/dist/default/playback/behaviors/select-tracks.js +77 -104
  169. package/dist/default/playback/behaviors/select-tracks.js.map +1 -1
  170. package/dist/default/playback/behaviors/setup-failover-monitor.js +11 -16
  171. package/dist/default/playback/behaviors/setup-failover-monitor.js.map +1 -1
  172. package/dist/default/playback/behaviors/sync-preload.js +9 -13
  173. package/dist/default/playback/behaviors/sync-preload.js.map +1 -1
  174. package/dist/default/playback/behaviors/track-switching.js +189 -173
  175. package/dist/default/playback/behaviors/track-switching.js.map +1 -1
  176. package/dist/default/playback/engines/hls/engine-audio-only.js +20 -24
  177. package/dist/default/playback/engines/hls/engine-audio-only.js.map +1 -1
  178. package/dist/default/playback/engines/hls/engine-background-video.js +22 -27
  179. package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -1
  180. package/dist/default/playback/engines/hls/engine.js +22 -25
  181. package/dist/default/playback/engines/hls/engine.js.map +1 -1
  182. package/dist/default/playback/primitives/error-messages.js +16 -25
  183. package/dist/default/playback/primitives/error-messages.js.map +1 -1
  184. package/dist/default/playback/primitives/failover-fetch.js +9 -14
  185. package/dist/default/playback/primitives/failover-fetch.js.map +1 -1
  186. package/dist/default/playback/primitives/head-peek.js +7 -10
  187. package/dist/default/playback/primitives/head-peek.js.map +1 -1
  188. package/dist/default/playback/primitives/live-window.js +12 -15
  189. package/dist/default/playback/primitives/live-window.js.map +1 -1
  190. package/dist/default/playback/primitives/relocation-pipelines.js +34 -46
  191. package/dist/default/playback/primitives/relocation-pipelines.js.map +1 -1
  192. package/dist/default/playback/primitives/report-track-conditions.js +26 -38
  193. package/dist/default/playback/primitives/report-track-conditions.js.map +1 -1
  194. package/dist/default/playback/primitives/segment-load-pipeline.js +15 -15
  195. package/dist/default/playback/primitives/segment-load-pipeline.js.map +1 -1
  196. package/dist/default/playback/primitives/selection-rules.js +65 -36
  197. package/dist/default/playback/primitives/selection-rules.js.map +1 -1
  198. package/dist/default/playback/primitives/text-segment-load-pipeline.js +4 -5
  199. package/dist/default/playback/primitives/text-segment-load-pipeline.js.map +1 -1
  200. package/dist/default/playback/primitives/track-types.js +10 -18
  201. package/dist/default/playback/primitives/track-types.js.map +1 -1
  202. package/dist/dev/core/actors/actor.d.ts +4 -4
  203. package/dist/dev/core/actors/actor.d.ts.map +1 -1
  204. package/dist/dev/core/actors/create-machine-actor.d.ts +38 -47
  205. package/dist/dev/core/actors/create-machine-actor.d.ts.map +1 -1
  206. package/dist/dev/core/actors/create-machine-actor.js +23 -25
  207. package/dist/dev/core/actors/create-machine-actor.js.map +1 -1
  208. package/dist/dev/core/actors/create-transition-actor.d.ts +11 -15
  209. package/dist/dev/core/actors/create-transition-actor.d.ts.map +1 -1
  210. package/dist/dev/core/actors/create-transition-actor.js +7 -9
  211. package/dist/dev/core/actors/create-transition-actor.js.map +1 -1
  212. package/dist/dev/core/composition/create-composition.d.ts +70 -102
  213. package/dist/dev/core/composition/create-composition.d.ts.map +1 -1
  214. package/dist/dev/core/composition/create-composition.js +26 -29
  215. package/dist/dev/core/composition/create-composition.js.map +1 -1
  216. package/dist/dev/core/composition/share-signals.d.ts +17 -24
  217. package/dist/dev/core/composition/share-signals.d.ts.map +1 -1
  218. package/dist/dev/core/composition/share-signals.js +12 -17
  219. package/dist/dev/core/composition/share-signals.js.map +1 -1
  220. package/dist/dev/core/machine.d.ts +4 -4
  221. package/dist/dev/core/machine.js +3 -4
  222. package/dist/dev/core/machine.js.map +1 -1
  223. package/dist/dev/core/reactors/create-machine-reactor.d.ts +33 -39
  224. package/dist/dev/core/reactors/create-machine-reactor.d.ts.map +1 -1
  225. package/dist/dev/core/reactors/create-machine-reactor.js +20 -19
  226. package/dist/dev/core/reactors/create-machine-reactor.js.map +1 -1
  227. package/dist/dev/core/signals/effect.d.ts +3 -4
  228. package/dist/dev/core/signals/effect.d.ts.map +1 -1
  229. package/dist/dev/core/signals/effect.js +24 -4
  230. package/dist/dev/core/signals/effect.js.map +1 -1
  231. package/dist/dev/core/signals/primitives.d.ts +10 -12
  232. package/dist/dev/core/signals/primitives.d.ts.map +1 -1
  233. package/dist/dev/core/signals/primitives.js +10 -14
  234. package/dist/dev/core/signals/primitives.js.map +1 -1
  235. package/dist/dev/core/signals/when.js +6 -8
  236. package/dist/dev/core/signals/when.js.map +1 -1
  237. package/dist/dev/core/tasks/delayed-reschedule.js +7 -11
  238. package/dist/dev/core/tasks/delayed-reschedule.js.map +1 -1
  239. package/dist/dev/core/tasks/task.d.ts +51 -73
  240. package/dist/dev/core/tasks/task.d.ts.map +1 -1
  241. package/dist/dev/core/tasks/task.js +59 -82
  242. package/dist/dev/core/tasks/task.js.map +1 -1
  243. package/dist/dev/hls.d.ts +3 -1
  244. package/dist/dev/hls.js +3 -1
  245. package/dist/dev/index.d.ts +2 -3
  246. package/dist/dev/index.d.ts.map +1 -1
  247. package/dist/dev/index.js +2 -3
  248. package/dist/dev/index.js.map +1 -1
  249. package/dist/dev/media/abr/quality-selection.d.ts +7 -10
  250. package/dist/dev/media/abr/quality-selection.d.ts.map +1 -1
  251. package/dist/dev/media/abr/quality-selection.js +3 -7
  252. package/dist/dev/media/abr/quality-selection.js.map +1 -1
  253. package/dist/dev/media/buffer/back-buffer.d.ts +2 -7
  254. package/dist/dev/media/buffer/back-buffer.d.ts.map +1 -1
  255. package/dist/dev/media/buffer/back-buffer.js +15 -19
  256. package/dist/dev/media/buffer/back-buffer.js.map +1 -1
  257. package/dist/dev/media/buffer/forward-buffer.d.ts +2 -7
  258. package/dist/dev/media/buffer/forward-buffer.d.ts.map +1 -1
  259. package/dist/dev/media/buffer/forward-buffer.js +32 -41
  260. package/dist/dev/media/buffer/forward-buffer.js.map +1 -1
  261. package/dist/dev/media/dom/capabilities.js +26 -37
  262. package/dist/dev/media/dom/capabilities.js.map +1 -1
  263. package/dist/dev/media/dom/mse/append-segment.d.ts +3 -5
  264. package/dist/dev/media/dom/mse/append-segment.d.ts.map +1 -1
  265. package/dist/dev/media/dom/mse/append-segment.js +3 -5
  266. package/dist/dev/media/dom/mse/append-segment.js.map +1 -1
  267. package/dist/dev/media/dom/mse/buffer-flusher.d.ts +5 -5
  268. package/dist/dev/media/dom/mse/buffer-flusher.js +5 -5
  269. package/dist/dev/media/dom/mse/buffer-flusher.js.map +1 -1
  270. package/dist/dev/media/dom/mse/duration.js +23 -31
  271. package/dist/dev/media/dom/mse/duration.js.map +1 -1
  272. package/dist/dev/media/dom/mse/end-of-stream.js +3 -6
  273. package/dist/dev/media/dom/mse/end-of-stream.js.map +1 -1
  274. package/dist/dev/media/dom/mse/mediasource-setup.js +65 -81
  275. package/dist/dev/media/dom/mse/mediasource-setup.js.map +1 -1
  276. package/dist/dev/media/dom/screen.d.ts.map +1 -1
  277. package/dist/dev/media/dom/screen.js +37 -54
  278. package/dist/dev/media/dom/screen.js.map +1 -1
  279. package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts.map +1 -1
  280. package/dist/dev/media/dom/text/resolve-vtt-segment.js.map +1 -1
  281. package/dist/dev/media/dom/text/text-track-slots.d.ts +10 -16
  282. package/dist/dev/media/dom/text/text-track-slots.d.ts.map +1 -1
  283. package/dist/dev/media/dom/text/text-track-slots.js +15 -23
  284. package/dist/dev/media/dom/text/text-track-slots.js.map +1 -1
  285. package/dist/dev/media/errors.d.ts +32 -46
  286. package/dist/dev/media/errors.d.ts.map +1 -1
  287. package/dist/dev/media/errors.js +25 -34
  288. package/dist/dev/media/errors.js.map +1 -1
  289. package/dist/dev/media/hls/parse-attributes.js +9 -26
  290. package/dist/dev/media/hls/parse-attributes.js.map +1 -1
  291. package/dist/dev/media/hls/parse-media-playlist.js +25 -33
  292. package/dist/dev/media/hls/parse-media-playlist.js.map +1 -1
  293. package/dist/dev/media/hls/parse-multivariant.js +3 -3
  294. package/dist/dev/media/hls/parse-multivariant.js.map +1 -1
  295. package/dist/dev/media/hls/reload-policy.js +19 -27
  296. package/dist/dev/media/hls/reload-policy.js.map +1 -1
  297. package/dist/dev/media/hls/resolve-url.js +1 -3
  298. package/dist/dev/media/hls/resolve-url.js.map +1 -1
  299. package/dist/dev/media/live-window.js +9 -13
  300. package/dist/dev/media/live-window.js.map +1 -1
  301. package/dist/dev/media/media-tracks/media-tracks.d.ts +8 -13
  302. package/dist/dev/media/media-tracks/media-tracks.d.ts.map +1 -1
  303. package/dist/dev/media/media-tracks/media-tracks.js +12 -17
  304. package/dist/dev/media/media-tracks/media-tracks.js.map +1 -1
  305. package/dist/dev/media/mp4/box.js +4 -5
  306. package/dist/dev/media/mp4/box.js.map +1 -1
  307. package/dist/dev/media/mp4/timestamp-origin.js +30 -42
  308. package/dist/dev/media/mp4/timestamp-origin.js.map +1 -1
  309. package/dist/dev/media/primitives/resolution.d.ts +6 -8
  310. package/dist/dev/media/primitives/resolution.d.ts.map +1 -1
  311. package/dist/dev/media/primitives/resolution.js +5 -8
  312. package/dist/dev/media/primitives/resolution.js.map +1 -1
  313. package/dist/dev/media/primitives/select-tracks.js +24 -34
  314. package/dist/dev/media/primitives/select-tracks.js.map +1 -1
  315. package/dist/dev/media/text/parse-vtt-timestamp-map.js +6 -8
  316. package/dist/dev/media/text/parse-vtt-timestamp-map.js.map +1 -1
  317. package/dist/dev/media/text/resolve-vtt-metadata.js +8 -9
  318. package/dist/dev/media/text/resolve-vtt-metadata.js.map +1 -1
  319. package/dist/dev/media/types/index.d.ts +106 -177
  320. package/dist/dev/media/types/index.d.ts.map +1 -1
  321. package/dist/dev/media/types/index.js +10 -18
  322. package/dist/dev/media/types/index.js.map +1 -1
  323. package/dist/dev/media/utils/cdn.d.ts +4 -6
  324. package/dist/dev/media/utils/cdn.d.ts.map +1 -1
  325. package/dist/dev/media/utils/cdn.js +10 -16
  326. package/dist/dev/media/utils/cdn.js.map +1 -1
  327. package/dist/dev/media/utils/preload.js +4 -6
  328. package/dist/dev/media/utils/preload.js.map +1 -1
  329. package/dist/dev/media/utils/track-selection.js +10 -14
  330. package/dist/dev/media/utils/track-selection.js.map +1 -1
  331. package/dist/dev/media/utils/tracks.js +56 -54
  332. package/dist/dev/media/utils/tracks.js.map +1 -1
  333. package/dist/dev/network/bandwidth-estimator.d.ts +7 -9
  334. package/dist/dev/network/bandwidth-estimator.d.ts.map +1 -1
  335. package/dist/dev/network/bandwidth-estimator.js +18 -19
  336. package/dist/dev/network/bandwidth-estimator.js.map +1 -1
  337. package/dist/dev/network/chunked-stream-iterable.js +4 -6
  338. package/dist/dev/network/chunked-stream-iterable.js.map +1 -1
  339. package/dist/dev/network/ewma.js +22 -25
  340. package/dist/dev/network/ewma.js.map +1 -1
  341. package/dist/dev/network/fetch.js +30 -37
  342. package/dist/dev/network/fetch.js.map +1 -1
  343. package/dist/dev/playback/actors/dom/segment-loader.d.ts +7 -11
  344. package/dist/dev/playback/actors/dom/segment-loader.d.ts.map +1 -1
  345. package/dist/dev/playback/actors/dom/segment-loader.js +28 -44
  346. package/dist/dev/playback/actors/dom/segment-loader.js.map +1 -1
  347. package/dist/dev/playback/actors/dom/source-buffer.d.ts +5 -7
  348. package/dist/dev/playback/actors/dom/source-buffer.d.ts.map +1 -1
  349. package/dist/dev/playback/actors/dom/source-buffer.js.map +1 -1
  350. package/dist/dev/playback/actors/dom/text-tracks.js.map +1 -1
  351. package/dist/dev/playback/actors/text-track-segment-loader.d.ts +10 -16
  352. package/dist/dev/playback/actors/text-track-segment-loader.d.ts.map +1 -1
  353. package/dist/dev/playback/actors/text-track-segment-loader.js +24 -35
  354. package/dist/dev/playback/actors/text-track-segment-loader.js.map +1 -1
  355. package/dist/dev/playback/actors/text-tracks.d.ts +5 -8
  356. package/dist/dev/playback/actors/text-tracks.d.ts.map +1 -1
  357. package/dist/dev/playback/adapters/hls-audio/adapter.d.ts +11 -14
  358. package/dist/dev/playback/adapters/hls-audio/adapter.d.ts.map +1 -1
  359. package/dist/dev/playback/adapters/hls-audio/adapter.js +23 -31
  360. package/dist/dev/playback/adapters/hls-audio/adapter.js.map +1 -1
  361. package/dist/dev/playback/adapters/hls-audio/media.d.ts.map +1 -1
  362. package/dist/dev/playback/adapters/hls-audio/media.js.map +1 -1
  363. package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +28 -39
  364. package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts.map +1 -1
  365. package/dist/dev/playback/adapters/hls-background-video/adapter.js +50 -70
  366. package/dist/dev/playback/adapters/hls-background-video/adapter.js.map +1 -1
  367. package/dist/dev/playback/adapters/hls-background-video/host.d.ts +12 -16
  368. package/dist/dev/playback/adapters/hls-background-video/host.d.ts.map +1 -1
  369. package/dist/dev/playback/adapters/hls-background-video/host.js +12 -16
  370. package/dist/dev/playback/adapters/hls-background-video/host.js.map +1 -1
  371. package/dist/dev/playback/adapters/hls-background-video/media.d.ts +5 -8
  372. package/dist/dev/playback/adapters/hls-background-video/media.d.ts.map +1 -1
  373. package/dist/dev/playback/adapters/hls-background-video/media.js +5 -8
  374. package/dist/dev/playback/adapters/hls-background-video/media.js.map +1 -1
  375. package/dist/dev/playback/adapters/hls-video/adapter.d.ts +12 -14
  376. package/dist/dev/playback/adapters/hls-video/adapter.d.ts.map +1 -1
  377. package/dist/dev/playback/adapters/hls-video/adapter.js +43 -60
  378. package/dist/dev/playback/adapters/hls-video/adapter.js.map +1 -1
  379. package/dist/dev/playback/adapters/hls-video/error-surface.d.ts +4 -5
  380. package/dist/dev/playback/adapters/hls-video/error-surface.d.ts.map +1 -1
  381. package/dist/dev/playback/adapters/hls-video/error-surface.js +13 -18
  382. package/dist/dev/playback/adapters/hls-video/error-surface.js.map +1 -1
  383. package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts +4 -5
  384. package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts.map +1 -1
  385. package/dist/dev/playback/adapters/hls-video/media-tracks.js +4 -5
  386. package/dist/dev/playback/adapters/hls-video/media-tracks.js.map +1 -1
  387. package/dist/dev/playback/adapters/hls-video/media.d.ts.map +1 -1
  388. package/dist/dev/playback/adapters/hls-video/media.js.map +1 -1
  389. package/dist/dev/playback/adapters/mux-audio/media.d.ts +8 -12
  390. package/dist/dev/playback/adapters/mux-audio/media.d.ts.map +1 -1
  391. package/dist/dev/playback/adapters/mux-audio/media.js +8 -12
  392. package/dist/dev/playback/adapters/mux-audio/media.js.map +1 -1
  393. package/dist/dev/playback/adapters/mux-video/adapter.d.ts +9 -11
  394. package/dist/dev/playback/adapters/mux-video/adapter.d.ts.map +1 -1
  395. package/dist/dev/playback/adapters/mux-video/adapter.js +25 -33
  396. package/dist/dev/playback/adapters/mux-video/adapter.js.map +1 -1
  397. package/dist/dev/playback/adapters/mux-video/media.d.ts +7 -9
  398. package/dist/dev/playback/adapters/mux-video/media.d.ts.map +1 -1
  399. package/dist/dev/playback/adapters/mux-video/media.js +7 -9
  400. package/dist/dev/playback/adapters/mux-video/media.js.map +1 -1
  401. package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts +5 -8
  402. package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts.map +1 -1
  403. package/dist/dev/playback/behaviors/calculate-presentation-duration.js +5 -8
  404. package/dist/dev/playback/behaviors/calculate-presentation-duration.js.map +1 -1
  405. package/dist/dev/playback/behaviors/collect-errors.d.ts +2 -0
  406. package/dist/dev/playback/behaviors/collect-errors.js +39 -52
  407. package/dist/dev/playback/behaviors/collect-errors.js.map +1 -1
  408. package/dist/dev/playback/behaviors/derive-cdn-priority.js +16 -23
  409. package/dist/dev/playback/behaviors/derive-cdn-priority.js.map +1 -1
  410. package/dist/dev/playback/behaviors/dom/airplay.js +38 -61
  411. package/dist/dev/playback/behaviors/dom/airplay.js.map +1 -1
  412. package/dist/dev/playback/behaviors/dom/apply-start-position.js +23 -35
  413. package/dist/dev/playback/behaviors/dom/apply-start-position.js.map +1 -1
  414. package/dist/dev/playback/behaviors/dom/end-of-stream.js +11 -16
  415. package/dist/dev/playback/behaviors/dom/end-of-stream.js.map +1 -1
  416. package/dist/dev/playback/behaviors/dom/load-segments.d.ts +5 -8
  417. package/dist/dev/playback/behaviors/dom/load-segments.d.ts.map +1 -1
  418. package/dist/dev/playback/behaviors/dom/load-segments.js +27 -39
  419. package/dist/dev/playback/behaviors/dom/load-segments.js.map +1 -1
  420. package/dist/dev/playback/behaviors/dom/recover-end-stall.js +21 -26
  421. package/dist/dev/playback/behaviors/dom/recover-end-stall.js.map +1 -1
  422. package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js +41 -60
  423. package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js.map +1 -1
  424. package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js +50 -74
  425. package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js.map +1 -1
  426. package/dist/dev/playback/behaviors/dom/setup-mediasource.js +29 -43
  427. package/dist/dev/playback/behaviors/dom/setup-mediasource.js.map +1 -1
  428. package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts +3 -3
  429. package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts.map +1 -1
  430. package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js.map +1 -1
  431. package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js +3 -4
  432. package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -1
  433. package/dist/dev/playback/behaviors/dom/sync-text-tracks.js +30 -45
  434. package/dist/dev/playback/behaviors/dom/sync-text-tracks.js.map +1 -1
  435. package/dist/dev/playback/behaviors/dom/track-current-time.d.ts +2 -2
  436. package/dist/dev/playback/behaviors/dom/track-current-time.d.ts.map +1 -1
  437. package/dist/dev/playback/behaviors/dom/track-current-time.js +9 -11
  438. package/dist/dev/playback/behaviors/dom/track-current-time.js.map +1 -1
  439. package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts +6 -12
  440. package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts.map +1 -1
  441. package/dist/dev/playback/behaviors/dom/track-load-triggers.js +24 -32
  442. package/dist/dev/playback/behaviors/dom/track-load-triggers.js.map +1 -1
  443. package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts +2 -2
  444. package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts.map +1 -1
  445. package/dist/dev/playback/behaviors/dom/track-playback-rate.js +6 -8
  446. package/dist/dev/playback/behaviors/dom/track-playback-rate.js.map +1 -1
  447. package/dist/dev/playback/behaviors/dom/track-player-resolution.d.ts.map +1 -1
  448. package/dist/dev/playback/behaviors/dom/track-player-resolution.js +10 -14
  449. package/dist/dev/playback/behaviors/dom/track-player-resolution.js.map +1 -1
  450. package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +8 -9
  451. package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -1
  452. package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js +28 -43
  453. package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js.map +1 -1
  454. package/dist/dev/playback/behaviors/establish-start-media-time.d.ts +15 -19
  455. package/dist/dev/playback/behaviors/establish-start-media-time.d.ts.map +1 -1
  456. package/dist/dev/playback/behaviors/establish-start-media-time.js +32 -42
  457. package/dist/dev/playback/behaviors/establish-start-media-time.js.map +1 -1
  458. package/dist/dev/playback/behaviors/resolve-presentation.d.ts.map +1 -1
  459. package/dist/dev/playback/behaviors/resolve-presentation.js +13 -22
  460. package/dist/dev/playback/behaviors/resolve-presentation.js.map +1 -1
  461. package/dist/dev/playback/behaviors/resolve-track.js +5 -12
  462. package/dist/dev/playback/behaviors/resolve-track.js.map +1 -1
  463. package/dist/dev/playback/behaviors/select-tracks.d.ts +28 -39
  464. package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -1
  465. package/dist/dev/playback/behaviors/select-tracks.js +77 -104
  466. package/dist/dev/playback/behaviors/select-tracks.js.map +1 -1
  467. package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts +1 -4
  468. package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts.map +1 -1
  469. package/dist/dev/playback/behaviors/setup-failover-monitor.js +11 -16
  470. package/dist/dev/playback/behaviors/setup-failover-monitor.js.map +1 -1
  471. package/dist/dev/playback/behaviors/sync-preload.js +9 -13
  472. package/dist/dev/playback/behaviors/sync-preload.js.map +1 -1
  473. package/dist/dev/playback/behaviors/track-switching.d.ts +110 -0
  474. package/dist/dev/playback/behaviors/track-switching.d.ts.map +1 -0
  475. package/dist/dev/playback/behaviors/track-switching.js +189 -173
  476. package/dist/dev/playback/behaviors/track-switching.js.map +1 -1
  477. package/dist/dev/playback/engines/hls/engine-audio-only.d.ts +59 -72
  478. package/dist/dev/playback/engines/hls/engine-audio-only.d.ts.map +1 -1
  479. package/dist/dev/playback/engines/hls/engine-audio-only.js +20 -24
  480. package/dist/dev/playback/engines/hls/engine-audio-only.js.map +1 -1
  481. package/dist/dev/playback/engines/hls/engine-background-video.d.ts +51 -78
  482. package/dist/dev/playback/engines/hls/engine-background-video.d.ts.map +1 -1
  483. package/dist/dev/playback/engines/hls/engine-background-video.js +22 -27
  484. package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -1
  485. package/dist/dev/playback/engines/hls/engine.d.ts +115 -155
  486. package/dist/dev/playback/engines/hls/engine.d.ts.map +1 -1
  487. package/dist/dev/playback/engines/hls/engine.js +22 -25
  488. package/dist/dev/playback/engines/hls/engine.js.map +1 -1
  489. package/dist/dev/playback/primitives/derive-start-media-time.d.ts +3 -3
  490. package/dist/dev/playback/primitives/derive-start-media-time.d.ts.map +1 -1
  491. package/dist/dev/playback/primitives/error-messages.js +16 -25
  492. package/dist/dev/playback/primitives/error-messages.js.map +1 -1
  493. package/dist/dev/playback/primitives/failover-fetch.js +9 -14
  494. package/dist/dev/playback/primitives/failover-fetch.js.map +1 -1
  495. package/dist/dev/playback/primitives/head-peek.js +7 -10
  496. package/dist/dev/playback/primitives/head-peek.js.map +1 -1
  497. package/dist/dev/playback/primitives/live-window.js +12 -15
  498. package/dist/dev/playback/primitives/live-window.js.map +1 -1
  499. package/dist/dev/playback/primitives/relocation-pipelines.js +34 -46
  500. package/dist/dev/playback/primitives/relocation-pipelines.js.map +1 -1
  501. package/dist/dev/playback/primitives/report-track-conditions.d.ts +1 -4
  502. package/dist/dev/playback/primitives/report-track-conditions.d.ts.map +1 -1
  503. package/dist/dev/playback/primitives/report-track-conditions.js +26 -38
  504. package/dist/dev/playback/primitives/report-track-conditions.js.map +1 -1
  505. package/dist/dev/playback/primitives/segment-load-pipeline.js +15 -15
  506. package/dist/dev/playback/primitives/segment-load-pipeline.js.map +1 -1
  507. package/dist/dev/playback/primitives/selection-rules.d.ts +45 -17
  508. package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -1
  509. package/dist/dev/playback/primitives/selection-rules.js +65 -36
  510. package/dist/dev/playback/primitives/selection-rules.js.map +1 -1
  511. package/dist/dev/playback/primitives/source-buffer-messages.d.ts +6 -9
  512. package/dist/dev/playback/primitives/source-buffer-messages.d.ts.map +1 -1
  513. package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts +20 -29
  514. package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts.map +1 -1
  515. package/dist/dev/playback/primitives/text-segment-load-pipeline.js +4 -5
  516. package/dist/dev/playback/primitives/text-segment-load-pipeline.js.map +1 -1
  517. package/dist/dev/playback/primitives/text-track-messages.d.ts.map +1 -1
  518. package/dist/dev/playback/primitives/track-types.js +10 -18
  519. package/dist/dev/playback/primitives/track-types.js.map +1 -1
  520. package/package.json +25 -28
@@ -3,18 +3,15 @@ import { Signal } from "signal-polyfill";
3
3
  /** Read a signal value without tracking it as a dependency. */
4
4
  const untrack = Signal.subtle.untrack;
5
5
  /**
6
- * Read a signal's current value without tracking it as a dependency. Sugar
7
- * for `untrack(() => signal.get())` to reduce boilerplate at single-read
8
- * sites. Structurally typed to accept any signal-like (Signal, Computed,
9
- * ReadonlySignal).
6
+ * Read a signal's current value without tracking it as a dependency. Sugar for `untrack(() => signal.get())` to reduce
7
+ * boilerplate at single-read sites. Structurally typed to accept any signal-like (Signal, Computed, ReadonlySignal).
10
8
  *
11
- * Accepts an optional `transform` to project the value in the same call;
12
- * the default is the identity function so the single-arg form returns `T`
13
- * unchanged.
9
+ * Accepts an optional `transform` to project the value in the same call; the default is the identity function so the
10
+ * single-arg form returns `T` unchanged.
14
11
  *
15
12
  * @example
16
- * const value = peek(someSignal);
17
- * const id = peek(presentationSignal, (p) => p?.id);
13
+ * const value = peek(someSignal);
14
+ * const id = peek(presentationSignal, (p) => p?.id);
18
15
  */
19
16
  function peek(source, transform = (v) => v) {
20
17
  return untrack(() => transform(source.get()));
@@ -36,12 +33,11 @@ function update(signal, updater) {
36
33
  });
37
34
  }
38
35
  /**
39
- * Read every signal in a map and return a plain object snapshot. Each read
40
- * tracks in the surrounding Computed/Effect — equivalent to calling `.get()`
41
- * on a single `Signal<S>` over the merged shape.
36
+ * Read every signal in a map and return a plain object snapshot. Each read tracks in the surrounding Computed/Effect —
37
+ * equivalent to calling `.get()` on a single `Signal<S>` over the merged shape.
42
38
  *
43
- * Convenience for behaviors that pass whole state/context snapshots to pure
44
- * helpers; prefer per-field reads when only a few fields are needed.
39
+ * Convenience for behaviors that pass whole state/context snapshots to pure helpers; prefer per-field reads when only a
40
+ * few fields are needed.
45
41
  */
46
42
  function snapshot(map) {
47
43
  const out = {};
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.js","names":["SignalNS"],"sources":["../../../../src/core/signals/primitives.ts"],"sourcesContent":["import { Signal as SignalNS } from 'signal-polyfill';\n\n/** Read a signal value without tracking it as a dependency. */\nexport const untrack: <T>(fn: () => T) => T = SignalNS.subtle.untrack;\n\n/**\n * Read a signal's current value without tracking it as a dependency. Sugar\n * for `untrack(() => signal.get())` to reduce boilerplate at single-read\n * sites. Structurally typed to accept any signal-like (Signal, Computed,\n * ReadonlySignal).\n *\n * Accepts an optional `transform` to project the value in the same call;\n * the default is the identity function so the single-arg form returns `T`\n * unchanged.\n *\n * @example\n * const value = peek(someSignal);\n * const id = peek(presentationSignal, (p) => p?.id);\n */\nexport function peek<T, R = T>(source: { get(): T }, transform: (value: T) => R = (v: T) => v as unknown as R): R {\n return untrack(() => transform(source.get()));\n}\n\n/** A writable reactive value (read + write). */\nexport type Signal<T> = SignalNS.State<T>;\n\n/** A derived reactive value that re-evaluates when its dependencies change (read-only). */\nexport type Computed<T> = SignalNS.Computed<T>;\n\n/** A read-only view of a reactive value. */\nexport type ReadonlySignal<T> = Omit<SignalNS.State<T>, 'set'>;\n\nexport interface SignalOptions<T> {\n equals?: (t: T, t2: T) => boolean;\n}\n\n/** Create a writable reactive value. */\nexport function signal<T>(initialValue: T, options?: SignalOptions<T>): Signal<T> {\n return new SignalNS.State(initialValue, options as SignalNS.Options<T>);\n}\n\n/** Create a computed reactive value. */\nexport function computed<T>(fn: () => T, options?: SignalOptions<T>): Computed<T> {\n return new SignalNS.Computed(fn, options as SignalNS.Options<T>);\n}\n\n/**\n * Update a writable signal. Two forms:\n *\n * - **Updater function** `(current) => next`. Works for any signal type,\n * including `Signal<T | undefined>` — handle undefined in the updater.\n * - **Partial object** to merge into the current state. Requires\n * `T extends object`.\n *\n * @example\n * update(state, { playbackRate: 2 });\n * update(state, (s) => ({ ...s, count: s.count + 1 }));\n * update(maybeUndefinedSignal, (current) => current ?? defaultValue);\n */\nexport function update<T>(signal: Signal<T>, updater: (current: T) => T): void;\nexport function update<T extends object>(signal: Signal<T>, updater: Partial<T>): void;\nexport function update<T>(signal: Signal<T>, updater: ((current: T) => T) | object): void {\n const current = untrack(() => signal.get());\n if (typeof updater === 'function') {\n signal.set((updater as (current: T) => T)(current));\n } else {\n // Partial<T> form — `T extends object` enforced by the public overload.\n signal.set({ ...(current as object), ...updater } as T);\n }\n}\n\n/**\n * Equality comparator for objects with an optional `id` field. Designed for\n * use as a `computed` `equals` option when reacting to identity changes\n * (Ham-shaped objects, JSON-API-shaped resources) while filtering internal\n * updates that preserve the id.\n *\n * Handles undefined inputs symmetrically: both undefined → equal; one\n * undefined → different.\n *\n * @example\n * const presentationById = computed(() => state.presentation.get(), {\n * equals: equalsById,\n * });\n */\nexport function equalsById<T extends { id?: string }>(a: T | undefined, b: T | undefined): boolean {\n return a?.id === b?.id;\n}\n\n/**\n * Read every signal in a map and return a plain object snapshot. Each read\n * tracks in the surrounding Computed/Effect equivalent to calling `.get()`\n * on a single `Signal<S>` over the merged shape.\n *\n * Convenience for behaviors that pass whole state/context snapshots to pure\n * helpers; prefer per-field reads when only a few fields are needed.\n */\nexport function snapshot<M extends Record<string, ReadonlySignal<unknown>>>(\n map: M\n): { [K in keyof M]: M[K] extends { get(): infer V } ? V : never } {\n const out = {} as { [K in keyof M]: M[K] extends { get(): infer V } ? V : never };\n for (const key in map) {\n out[key] = map[key]!.get() as never;\n }\n return out;\n}\n"],"mappings":";;;AAGA,MAAa,UAAiCA,OAAS,OAAO;;;;;;;;;;;;;;;AAgB9D,SAAgB,KAAe,QAAsB,aAA8B,MAAS,GAAsB;CAChH,OAAO,cAAc,UAAU,OAAO,IAAI,CAAC,CAAC;AAC9C;;AAgBA,SAAgB,OAAU,cAAiB,SAAuC;CAChF,OAAO,IAAIA,OAAS,MAAM,cAAc,OAA8B;AACxE;;AAGA,SAAgB,SAAY,IAAa,SAAyC;CAChF,OAAO,IAAIA,OAAS,SAAS,IAAI,OAA8B;AACjE;AAiBA,SAAgB,OAAU,QAAmB,SAA6C;CACxF,MAAM,UAAU,cAAc,OAAO,IAAI,CAAC;CAC1C,IAAI,OAAO,YAAY,YACrB,OAAO,IAAK,QAA8B,OAAO,CAAC;MAGlD,OAAO,IAAI;EAAE,GAAI;EAAoB,GAAG;CAAQ,CAAM;AAE1D;;;;;;;;;AA4BA,SAAgB,SACd,KACiE;CACjE,MAAM,MAAM,CAAC;CACb,KAAK,MAAM,OAAO,KAChB,IAAI,OAAO,IAAI,IAAI,CAAE,IAAI;CAE3B,OAAO;AACT"}
1
+ {"version":3,"file":"primitives.js","names":["SignalNS"],"sources":["../../../../src/core/signals/primitives.ts"],"sourcesContent":["import { Signal as SignalNS } from 'signal-polyfill';\n\n/** Read a signal value without tracking it as a dependency. */\nexport const untrack: <T>(fn: () => T) => T = SignalNS.subtle.untrack;\n\n/**\n * Read a signal's current value without tracking it as a dependency. Sugar for `untrack(() => signal.get())` to reduce\n * boilerplate at single-read sites. Structurally typed to accept any signal-like (Signal, Computed, ReadonlySignal).\n *\n * Accepts an optional `transform` to project the value in the same call; the default is the identity function so the\n * single-arg form returns `T` unchanged.\n *\n * @example\n * const value = peek(someSignal);\n * const id = peek(presentationSignal, (p) => p?.id);\n */\nexport function peek<T, R = T>(source: { get(): T }, transform: (value: T) => R = (v: T) => v as unknown as R): R {\n return untrack(() => transform(source.get()));\n}\n\n/** A writable reactive value (read + write). */\nexport type Signal<T> = SignalNS.State<T>;\n\n/** A derived reactive value that re-evaluates when its dependencies change (read-only). */\nexport type Computed<T> = SignalNS.Computed<T>;\n\n/** A read-only view of a reactive value. */\nexport type ReadonlySignal<T> = Omit<SignalNS.State<T>, 'set'>;\n\nexport interface SignalOptions<T> {\n equals?: (t: T, t2: T) => boolean;\n}\n\n/** Create a writable reactive value. */\nexport function signal<T>(initialValue: T, options?: SignalOptions<T>): Signal<T> {\n return new SignalNS.State(initialValue, options as SignalNS.Options<T>);\n}\n\n/** Create a computed reactive value. */\nexport function computed<T>(fn: () => T, options?: SignalOptions<T>): Computed<T> {\n return new SignalNS.Computed(fn, options as SignalNS.Options<T>);\n}\n\n/**\n * Update a writable signal. Two forms:\n *\n * - **Updater function** `(current) => next`. Works for any signal type, including `Signal<T | undefined>` — handle\n * undefined in the updater.\n * - **Partial object** to merge into the current state. Requires `T extends object`.\n *\n * @example\n * update(state, { playbackRate: 2 });\n * update(state, (s) => ({ ...s, count: s.count + 1 }));\n * update(maybeUndefinedSignal, (current) => current ?? defaultValue);\n */\nexport function update<T>(signal: Signal<T>, updater: (current: T) => T): void;\nexport function update<T extends object>(signal: Signal<T>, updater: Partial<T>): void;\nexport function update<T>(signal: Signal<T>, updater: ((current: T) => T) | object): void {\n const current = untrack(() => signal.get());\n\n if (typeof updater === 'function') {\n signal.set((updater as (current: T) => T)(current));\n } else {\n // Partial<T> form — `T extends object` enforced by the public overload.\n signal.set({ ...(current as object), ...updater } as T);\n }\n}\n\n/**\n * Equality comparator for objects with an optional `id` field. Designed for use as a `computed` `equals` option when\n * reacting to identity changes (Ham-shaped objects, JSON-API-shaped resources) while filtering internal updates that\n * preserve the id.\n *\n * Handles undefined inputs symmetrically: both undefined → equal; one undefined → different.\n *\n * @example\n * const presentationById = computed(() => state.presentation.get(), {\n * equals: equalsById,\n * });\n */\nexport function equalsById<T extends { id?: string }>(a: T | undefined, b: T | undefined): boolean {\n return a?.id === b?.id;\n}\n\n/**\n * Read every signal in a map and return a plain object snapshot. Each read tracks in the surrounding Computed/Effect —\n * equivalent to calling `.get()` on a single `Signal<S>` over the merged shape.\n *\n * Convenience for behaviors that pass whole state/context snapshots to pure helpers; prefer per-field reads when only a\n * few fields are needed.\n */\nexport function snapshot<M extends Record<string, ReadonlySignal<unknown>>>(\n map: M\n): { [K in keyof M]: M[K] extends { get(): infer V } ? V : never } {\n const out = {} as { [K in keyof M]: M[K] extends { get(): infer V } ? V : never };\n\n for (const key in map) {\n out[key] = map[key]!.get() as never;\n }\n\n return out;\n}\n"],"mappings":";;;AAGA,MAAa,UAAiCA,OAAS,OAAO;;;;;;;;;;;;AAa9D,SAAgB,KAAe,QAAsB,aAA8B,MAAS,GAAsB;CAChH,OAAO,cAAc,UAAU,OAAO,IAAI,CAAC,CAAC;AAC9C;;AAgBA,SAAgB,OAAU,cAAiB,SAAuC;CAChF,OAAO,IAAIA,OAAS,MAAM,cAAc,OAA8B;AACxE;;AAGA,SAAgB,SAAY,IAAa,SAAyC;CAChF,OAAO,IAAIA,OAAS,SAAS,IAAI,OAA8B;AACjE;AAgBA,SAAgB,OAAU,QAAmB,SAA6C;CACxF,MAAM,UAAU,cAAc,OAAO,IAAI,CAAC;CAE1C,IAAI,OAAO,YAAY,YACrB,OAAO,IAAK,QAA8B,OAAO,CAAC;MAGlD,OAAO,IAAI;EAAE,GAAI;EAAoB,GAAG;CAAQ,CAAM;AAE1D;;;;;;;;AAyBA,SAAgB,SACd,KACiE;CACjE,MAAM,MAAM,CAAC;CAEb,KAAK,MAAM,OAAO,KAChB,IAAI,OAAO,IAAI,IAAI,CAAE,IAAI;CAG3B,OAAO;AACT"}
@@ -1,15 +1,13 @@
1
1
  import { effect } from "./effect.js";
2
2
  //#region src/core/signals/when.ts
3
3
  /**
4
- * Resolve once `condition` returns true. The condition is a tracked read — it
5
- * re-evaluates whenever a signal it read changes so this is the promise
6
- * bridge from signal space into async task bodies (await a state condition
7
- * mid-task without polling).
4
+ * Resolve once `condition` returns true. The condition is a tracked read — it re-evaluates whenever a signal it read
5
+ * changes so this is the promise bridge from signal space into async task bodies (await a state condition mid-task
6
+ * without polling).
8
7
  *
9
- * Settles synchronously when the condition already holds. Rejects with the
10
- * abort reason when `signal` aborts first (an already-aborted signal rejects
11
- * without evaluating the condition), so a task awaiting a condition dies with
12
- * its runner instead of leaking the subscription.
8
+ * Settles synchronously when the condition already holds. Rejects with the abort reason when `signal` aborts first (an
9
+ * already-aborted signal rejects without evaluating the condition), so a task awaiting a condition dies with its runner
10
+ * instead of leaking the subscription.
13
11
  */
14
12
  function when(condition, options = {}) {
15
13
  const { signal } = options;
@@ -1 +1 @@
1
- {"version":3,"file":"when.js","names":[],"sources":["../../../../src/core/signals/when.ts"],"sourcesContent":["import { effect } from './effect';\n\n/**\n * Resolve once `condition` returns true. The condition is a tracked read — it\n * re-evaluates whenever a signal it read changes — so this is the promise\n * bridge from signal space into async task bodies (await a state condition\n * mid-task without polling).\n *\n * Settles synchronously when the condition already holds. Rejects with the\n * abort reason when `signal` aborts first (an already-aborted signal rejects\n * without evaluating the condition), so a task awaiting a condition dies with\n * its runner instead of leaking the subscription.\n */\nexport function when(condition: () => boolean, options: { signal?: AbortSignal } = {}): Promise<void> {\n const { signal } = options;\n if (signal?.aborted) return Promise.reject(signal.reason);\n\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const settle = (complete: () => void) => {\n if (settled) return;\n settled = true;\n complete();\n // Deferred: on the effect's synchronous initial run `stop` isn't\n // assigned yet, and stopping an effect from inside its own body is\n // undefined behavior for the scheduler either way.\n queueMicrotask(() => {\n signal?.removeEventListener('abort', onAbort);\n stop();\n });\n };\n const onAbort = () => settle(() => reject(signal?.reason));\n signal?.addEventListener('abort', onAbort, { once: true });\n const stop = effect(() => {\n if (!settled && condition()) settle(resolve);\n });\n });\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,KAAK,WAA0B,UAAoC,CAAC,GAAkB;CACpG,MAAM,EAAE,WAAW;CACnB,IAAI,QAAQ,SAAS,OAAO,QAAQ,OAAO,OAAO,MAAM;CAExD,OAAO,IAAI,SAAe,SAAS,WAAW;EAC5C,IAAI,UAAU;EACd,MAAM,UAAU,aAAyB;GACvC,IAAI,SAAS;GACb,UAAU;GACV,SAAS;GAIT,qBAAqB;IACnB,QAAQ,oBAAoB,SAAS,OAAO;IAC5C,KAAK;GACP,CAAC;EACH;EACA,MAAM,gBAAgB,aAAa,OAAO,QAAQ,MAAM,CAAC;EACzD,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACzD,MAAM,OAAO,aAAa;GACxB,IAAI,CAAC,WAAW,UAAU,GAAG,OAAO,OAAO;EAC7C,CAAC;CACH,CAAC;AACH"}
1
+ {"version":3,"file":"when.js","names":[],"sources":["../../../../src/core/signals/when.ts"],"sourcesContent":["import { effect } from './effect';\n\n/**\n * Resolve once `condition` returns true. The condition is a tracked read — it re-evaluates whenever a signal it read\n * changes — so this is the promise bridge from signal space into async task bodies (await a state condition mid-task\n * without polling).\n *\n * Settles synchronously when the condition already holds. Rejects with the abort reason when `signal` aborts first (an\n * already-aborted signal rejects without evaluating the condition), so a task awaiting a condition dies with its runner\n * instead of leaking the subscription.\n */\nexport function when(condition: () => boolean, options: { signal?: AbortSignal } = {}): Promise<void> {\n const { signal } = options;\n if (signal?.aborted) return Promise.reject(signal.reason);\n\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const settle = (complete: () => void) => {\n if (settled) return;\n\n settled = true;\n complete();\n // Deferred: on the effect's synchronous initial run `stop` isn't\n // assigned yet, and stopping an effect from inside its own body is\n // undefined behavior for the scheduler either way.\n queueMicrotask(() => {\n signal?.removeEventListener('abort', onAbort);\n stop();\n });\n };\n const onAbort = () => settle(() => reject(signal?.reason));\n\n signal?.addEventListener('abort', onAbort, { once: true });\n const stop = effect(() => {\n if (!settled && condition()) settle(resolve);\n });\n });\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,KAAK,WAA0B,UAAoC,CAAC,GAAkB;CACpG,MAAM,EAAE,WAAW;CACnB,IAAI,QAAQ,SAAS,OAAO,QAAQ,OAAO,OAAO,MAAM;CAExD,OAAO,IAAI,SAAe,SAAS,WAAW;EAC5C,IAAI,UAAU;EACd,MAAM,UAAU,aAAyB;GACvC,IAAI,SAAS;GAEb,UAAU;GACV,SAAS;GAIT,qBAAqB;IACnB,QAAQ,oBAAoB,SAAS,OAAO;IAC5C,KAAK;GACP,CAAC;EACH;EACA,MAAM,gBAAgB,aAAa,OAAO,QAAQ,MAAM,CAAC;EAEzD,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACzD,MAAM,OAAO,aAAa;GACxB,IAAI,CAAC,WAAW,UAAU,GAAG,OAAO,OAAO;EAC7C,CAAC;CACH,CAAC;AACH"}
@@ -1,19 +1,15 @@
1
1
  import { sleep } from "@videojs/utils/time";
2
2
  //#region src/core/tasks/delayed-reschedule.ts
3
3
  /**
4
- * Build a {@link Reschedule} from a pure cadence function — the common
5
- * timer-based, *start-anchored* implementation.
4
+ * Build a {@link Reschedule} from a pure cadence function — the common timer-based, _start-anchored_ implementation.
6
5
  *
7
- * Invoked concurrently with the run, it observes the result, then waits
8
- * `cadence(current, previous)` milliseconds **measured from when it was invoked**
9
- * (≈ the run's start): it subtracts the run's own elapsed time, so consecutive
10
- * runs begin one cadence apart regardless of how long each run takes (per
11
- * RFC 8216 §6.3.4's "measured from the last time the client began loading"). If
12
- * the run takes longer than the cadence, the next run starts immediately.
6
+ * Invoked concurrently with the run, it observes the result, then waits `cadence(current, previous)` milliseconds
7
+ * **measured from when it was invoked** (≈ the run's start): it subtracts the run's own elapsed time, so consecutive
8
+ * runs begin one cadence apart regardless of how long each run takes (per RFC 8216 §6.3.4's "measured from the last
9
+ * time the client began loading"). If the run takes longer than the cadence, the next run starts immediately.
13
10
  *
14
- * A `null` cadence stops the recurrence. A rejected run rejects this reschedule,
15
- * which the `RecurringRunner` propagates as the recurrence's failure — error
16
- * recovery (e.g. retrying transient fetch failures) belongs below, at the fetch
11
+ * A `null` cadence stops the recurrence. A rejected run rejects this reschedule, which the `RecurringRunner` propagates
12
+ * as the recurrence's failure — error recovery (e.g. retrying transient fetch failures) belongs below, at the fetch
17
13
  * layer, not in the cadence.
18
14
  */
19
15
  function delayedReschedule(cadence) {
@@ -1 +1 @@
1
- {"version":3,"file":"delayed-reschedule.js","names":[],"sources":["../../../../src/core/tasks/delayed-reschedule.ts"],"sourcesContent":["import { sleep } from '@videojs/utils/time';\nimport type { Reschedule } from './task';\n\n/**\n * Build a {@link Reschedule} from a pure cadence function — the common\n * timer-based, *start-anchored* implementation.\n *\n * Invoked concurrently with the run, it observes the result, then waits\n * `cadence(current, previous)` milliseconds **measured from when it was invoked**\n * (≈ the run's start): it subtracts the run's own elapsed time, so consecutive\n * runs begin one cadence apart regardless of how long each run takes (per\n * RFC 8216 §6.3.4's \"measured from the last time the client began loading\"). If\n * the run takes longer than the cadence, the next run starts immediately.\n *\n * A `null` cadence stops the recurrence. A rejected run rejects this reschedule,\n * which the `RecurringRunner` propagates as the recurrence's failure — error\n * recovery (e.g. retrying transient fetch failures) belongs below, at the fetch\n * layer, not in the cadence.\n */\nexport function delayedReschedule<TValue>(\n cadence: (current: TValue, previous: TValue | undefined) => number | null\n): Reschedule<TValue> {\n return async (task) => {\n const startedAt = Date.now();\n const current = await task.run();\n // `task.previous` is the prior successful value (carried by the runner's\n // clone); read-only for the cadence, hence the cast off `DeepReadonly`.\n const ms = cadence(current, task.previous as TValue | undefined);\n if (ms === null) return false;\n await sleep(Math.max(0, ms - (Date.now() - startedAt)), task.signal);\n return true;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,SAAgB,kBACd,SACoB;CACpB,OAAO,OAAO,SAAS;EACrB,MAAM,YAAY,KAAK,IAAI;EAI3B,MAAM,KAAK,QAAQ,MAHG,KAAK,IAAI,GAGH,KAAK,QAA8B;EAC/D,IAAI,OAAO,MAAM,OAAO;EACxB,MAAM,MAAM,KAAK,IAAI,GAAG,MAAM,KAAK,IAAI,IAAI,UAAU,GAAG,KAAK,MAAM;EACnE,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"delayed-reschedule.js","names":[],"sources":["../../../../src/core/tasks/delayed-reschedule.ts"],"sourcesContent":["import { sleep } from '@videojs/utils/time';\n\nimport type { Reschedule } from './task';\n\n/**\n * Build a {@link Reschedule} from a pure cadence function — the common timer-based, _start-anchored_ implementation.\n *\n * Invoked concurrently with the run, it observes the result, then waits `cadence(current, previous)` milliseconds\n * **measured from when it was invoked** (≈ the run's start): it subtracts the run's own elapsed time, so consecutive\n * runs begin one cadence apart regardless of how long each run takes (per RFC 8216 §6.3.4's \"measured from the last\n * time the client began loading\"). If the run takes longer than the cadence, the next run starts immediately.\n *\n * A `null` cadence stops the recurrence. A rejected run rejects this reschedule, which the `RecurringRunner` propagates\n * as the recurrence's failure — error recovery (e.g. retrying transient fetch failures) belongs below, at the fetch\n * layer, not in the cadence.\n */\nexport function delayedReschedule<TValue>(\n cadence: (current: TValue, previous: TValue | undefined) => number | null\n): Reschedule<TValue> {\n return async (task) => {\n const startedAt = Date.now();\n const current = await task.run();\n // `task.previous` is the prior successful value (carried by the runner's\n // clone); read-only for the cadence, hence the cast off `DeepReadonly`.\n const ms = cadence(current, task.previous as TValue | undefined);\n if (ms === null) return false;\n\n await sleep(Math.max(0, ms - (Date.now() - startedAt)), task.signal);\n return true;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAgBA,SAAgB,kBACd,SACoB;CACpB,OAAO,OAAO,SAAS;EACrB,MAAM,YAAY,KAAK,IAAI;EAI3B,MAAM,KAAK,QAAQ,MAHG,KAAK,IAAI,GAGH,KAAK,QAA8B;EAC/D,IAAI,OAAO,MAAM,OAAO;EAExB,MAAM,MAAM,KAAK,IAAI,GAAG,MAAM,KAAK,IAAI,IAAI,UAAU,GAAG,KAAK,MAAM;EACnE,OAAO;CACT;AACF"}
@@ -4,19 +4,16 @@ import { generateId } from "@videojs/utils/string";
4
4
  /**
5
5
  * Generic reusable task that wraps an async run function.
6
6
  *
7
- * Owns its own AbortController so it can always be aborted independently.
8
- * Optionally composes an external AbortSignal so that a parent's cancellation
9
- * propagates into the task's work without requiring the caller to track the
10
- * task separately.
7
+ * Owns its own AbortController so it can always be aborted independently. Optionally composes an external AbortSignal
8
+ * so that a parent's cancellation propagates into the task's work without requiring the caller to track the task
9
+ * separately.
11
10
  *
12
- * `run()` is memoized: the work runs at most once per instance, and every call
13
- * returns the same promise (so observers can `await run()` to read the result
14
- * without re-triggering the work). To re-run the *same* work, take a `clone()`
15
- * a fresh instance with its own AbortController and a pending state.
11
+ * `run()` is memoized: the work runs at most once per instance, and every call returns the same promise (so observers
12
+ * can `await run()` to read the result without re-triggering the work). To re-run the _same_ work, take a `clone()` — a
13
+ * fresh instance with its own AbortController and a pending state.
16
14
  *
17
- * Ordering guarantee: `value` is written before `status` transitions to `'done'`;
18
- * `error` is written before `status` transitions to `'error'`. Any reader
19
- * observing `status === 'done'` is guaranteed `value` is already present.
15
+ * Ordering guarantee: `value` is written before `status` transitions to `'done'`; `error` is written before `status`
16
+ * transitions to `'error'`. Any reader observing `status === 'done'` is guaranteed `value` is already present.
20
17
  */
21
18
  var Task = class Task {
22
19
  id;
@@ -72,14 +69,12 @@ var Task = class Task {
72
69
  this.#abortController.abort();
73
70
  }
74
71
  /**
75
- * A fresh task with the same work, id, and external signal, in a pending state
76
- * (its own AbortController, no memoized result) — so it can be run again. Used
77
- * to re-run structurally identical work (e.g. `RecurringRunner` reloads).
72
+ * A fresh task with the same work, id, and external signal, in a pending state (its own AbortController, no memoized
73
+ * result) — so it can be run again. Used to re-run structurally identical work (e.g. `RecurringRunner` reloads).
78
74
  *
79
- * The clone inherits this run's value as its `previous` (or this run's own
80
- * `previous` if it never produced one e.g. it errored), so a recurrence's
81
- * `previous` always tracks the last *successful* value across the lineage with
82
- * no bookkeeping in the runner.
75
+ * The clone inherits this run's value as its `previous` (or this run's own `previous` if it never produced one — e.g.
76
+ * it errored), so a recurrence's `previous` always tracks the last _successful_ value across the lineage with no
77
+ * bookkeeping in the runner.
83
78
  */
84
79
  clone() {
85
80
  const cloned = new Task(this.#runFn, {
@@ -93,9 +88,8 @@ var Task = class Task {
93
88
  /**
94
89
  * Runs tasks concurrently, deduplicated by task id.
95
90
  *
96
- * If a task with a given id is already in flight, subsequent schedule() calls
97
- * for that id are silently ignored until the first completes. Tasks are stored
98
- * so abortAll() can cancel any in-flight work (e.g. on engine cleanup).
91
+ * If a task with a given id is already in flight, subsequent schedule() calls for that id are silently ignored until
92
+ * the first completes. Tasks are stored so abortAll() can cancel any in-flight work (e.g. on engine cleanup).
99
93
  */
100
94
  var ConcurrentRunner = class {
101
95
  #pending = /* @__PURE__ */ new Map();
@@ -126,10 +120,9 @@ var ConcurrentRunner = class {
126
120
  return promise;
127
121
  }
128
122
  /**
129
- * Registers a callback to fire when all currently in-flight tasks settle.
130
- * If the runner is already idle, the callback is never called. If abortAll()
131
- * is called before the batch settles, the callback is superseded and silently
132
- * dropped — no stale callbacks, no generation token required by the caller.
123
+ * Registers a callback to fire when all currently in-flight tasks settle. If the runner is already idle, the callback
124
+ * is never called. If abortAll() is called before the batch settles, the callback is superseded and silently dropped
125
+ * no stale callbacks, no generation token required by the caller.
133
126
  */
134
127
  whenSettled(callback) {
135
128
  if (this.#pending.size === 0) return;
@@ -154,16 +147,14 @@ var ConcurrentRunner = class {
154
147
  /**
155
148
  * Runs tasks one at a time in submission order.
156
149
  *
157
- * Each schedule() call returns a Promise that resolves or rejects with the
158
- * task's result when it is eventually executed. Tasks wait in queue until the
159
- * prior task completes.
150
+ * Each schedule() call returns a Promise that resolves or rejects with the task's result when it is eventually
151
+ * executed. Tasks wait in queue until the prior task completes.
160
152
  *
161
- * Serialization is achieved by chaining each task's run() onto the tail of a
162
- * shared promise chain — no explicit queue or drain loop needed.
153
+ * Serialization is achieved by chaining each task's run() onto the tail of a shared promise chain — no explicit queue
154
+ * or drain loop needed.
163
155
  *
164
- * abortAll() aborts all pending (not yet started) tasks and the currently
165
- * in-flight task. Pending tasks still run briefly but receive an aborted
166
- * signal and are expected to exit early.
156
+ * AbortAll() aborts all pending (not yet started) tasks and the currently in-flight task. Pending tasks still run
157
+ * briefly but receive an aborted signal and are expected to exit early.
167
158
  */
168
159
  var SerialRunner = class {
169
160
  #chain = Promise.resolve();
@@ -185,20 +176,17 @@ var SerialRunner = class {
185
176
  return result;
186
177
  }
187
178
  /**
188
- * A promise that resolves when all currently-scheduled tasks have settled.
189
- * Use the reference as a generation token: capture it after scheduling a
190
- * batch, then check identity in the resolution callback to detect whether
191
- * a subsequent abortAll() + new batch has superseded this one.
179
+ * A promise that resolves when all currently-scheduled tasks have settled. Use the reference as a generation token:
180
+ * capture it after scheduling a batch, then check identity in the resolution callback to detect whether a subsequent
181
+ * abortAll() + new batch has superseded this one.
192
182
  */
193
183
  get settled() {
194
184
  return this.#chain;
195
185
  }
196
186
  /**
197
- * Registers a callback to fire when all currently-pending tasks settle.
198
- * If the runner is already idle (no pending or running tasks), the callback
199
- * is never called. If new tasks are scheduled before the current batch
200
- * settles, the callback is superseded and silently dropped — no stale
201
- * callbacks, no generation token required by the caller.
187
+ * Registers a callback to fire when all currently-pending tasks settle. If the runner is already idle (no pending or
188
+ * running tasks), the callback is never called. If new tasks are scheduled before the current batch settles, the
189
+ * callback is superseded and silently dropped no stale callbacks, no generation token required by the caller.
202
190
  */
203
191
  whenSettled(callback) {
204
192
  if (this.#pending.size === 0 && this.#current === null) return;
@@ -223,39 +211,32 @@ var SerialRunner = class {
223
211
  }
224
212
  };
225
213
  /**
226
- * A {@link Reschedule} that never recurs — the task runs exactly once. Pass it to
227
- * a {@link RecurringRunner} for non-recurring, run-once work (e.g. resolving a
228
- * complete VoD playlist that can never go stale).
214
+ * A {@link Reschedule} that never recurs — the task runs exactly once. Pass it to a {@link RecurringRunner} for
215
+ * non-recurring, run-once work (e.g. resolving a complete VoD playlist that can never go stale).
229
216
  */
230
217
  const runOnce = () => Promise.resolve(false);
231
218
  /**
232
- * Runs a task, then re-runs it whenever a {@link Reschedule} function says to,
233
- * until it says stop (or it's aborted) the recurring sibling of
234
- * {@link ConcurrentRunner} / {@link SerialRunner}, and like them it's handed a
219
+ * Runs a task, then re-runs it whenever a {@link Reschedule} function says to, until it says stop (or it's aborted) —
220
+ * the recurring sibling of {@link ConcurrentRunner} / {@link SerialRunner}, and like them it's handed a
235
221
  * {@link TaskLike} to run.
236
222
  *
237
- * The runner has no notion of time: it just awaits whatever `reschedule`
238
- * returns (resolves `true` re-run; `false` stop). A `reschedule` is required;
239
- * pass {@link runOnce} for non-recurring, run-exactly-once work.
223
+ * The runner has no notion of time: it just awaits whatever `reschedule` returns (resolves `true` → re-run; `false` →
224
+ * stop). A `reschedule` is required; pass {@link runOnce} for non-recurring, run-exactly-once work.
240
225
  *
241
- * Single-slot, keyed by task **id**: there is always at most one identified
242
- * active task for re-running. Scheduling a task whose id matches the active one
243
- * is a no-op the existing recurrence keeps running (dedup by id). Scheduling a
244
- * task with a *different* id aborts the prior task's in-flight run and pending
245
- * reschedule, then takes over the slot (abort-and-replace) — the right shape
246
- * when there's one logical unit of recurring work (e.g. reloading the *selected*
226
+ * Single-slot, keyed by task **id**: there is always at most one identified active task for re-running. Scheduling a
227
+ * task whose id matches the active one is a no-op the existing recurrence keeps running (dedup by id). Scheduling a
228
+ * task with a _different_ id aborts the prior task's in-flight run and pending reschedule, then takes over the slot
229
+ * (abort-and-replace) the right shape when there's one logical unit of recurring work (e.g. reloading the _selected_
247
230
  * track's media playlist).
248
231
  *
249
- * Each re-run is a fresh `clone()` of the task (since `Task.run()` is memoized —
250
- * the same instance won't re-execute), carrying the same id so the slot's
251
- * identity is stable across cycles. The clone also carries the prior cycle's
252
- * value forward as `task.previous`. The run function should read any inputs that
253
- * change between cycles at call time rather than capturing them once.
232
+ * Each re-run is a fresh `clone()` of the task (since `Task.run()` is memoized — the same instance won't re-execute),
233
+ * carrying the same id so the slot's identity is stable across cycles. The clone also carries the prior cycle's value
234
+ * forward as `task.previous`. The run function should read any inputs that change between cycles at call time rather
235
+ * than capturing them once.
254
236
  *
255
- * The task is the sole cancellation channel: `abortAll()` aborts the active task,
256
- * which fires `task.signal` — cancelling both its in-flight run and any pending
257
- * reschedule delay waiting on that signal. An aborted (or stopped) recurrence
258
- * frees the slot, so a later schedule of the same id starts fresh.
237
+ * The task is the sole cancellation channel: `abortAll()` aborts the active task, which fires `task.signal` —
238
+ * cancelling both its in-flight run and any pending reschedule delay waiting on that signal. An aborted (or stopped)
239
+ * recurrence frees the slot, so a later schedule of the same id starts fresh.
259
240
  */
260
241
  var RecurringRunner = class {
261
242
  #reschedule;
@@ -265,25 +246,21 @@ var RecurringRunner = class {
265
246
  this.#reschedule = reschedule;
266
247
  }
267
248
  /**
268
- * Run `task` and recur per the `reschedule` verdict, as a single promise.
269
- * Resolves with the *final* cycle's value when the recurrence stops; **rejects**
270
- * if a run (or reschedule) genuinely fails the rejection propagates to the
271
- * caller, who owns error handling; the runner only frees its slot (no
272
- * swallowing). The runner's *own* cancellation (abort/supersede/destroy) is not
273
- * a failure, so an aborted recurrence settles quietly rather than rejecting —
249
+ * Run `task` and recur per the `reschedule` verdict, as a single promise. Resolves with the _final_ cycle's value
250
+ * when the recurrence stops; **rejects** if a run (or reschedule) genuinely fails — the rejection propagates to the
251
+ * caller, who owns error handling; the runner only frees its slot (no swallowing). The runner's _own_ cancellation
252
+ * (abort/supersede/destroy) is not a failure, so an aborted recurrence settles quietly rather than rejecting
274
253
  * callers don't have to `.catch` routine teardown.
275
254
  *
276
- * Each cycle runs the task and consults `reschedule` concurrently (so the delay
277
- * can be measured from the run's start); when both settle and this cycle still
278
- * owns the slot, a `true` verdict re-schedules a `clone()` whose promise is
279
- * *returned* so the recurrence is the method calling itself, threaded into one
280
- * promise, no separate loop. The clone shares the id, so the slot's identity is
281
- * stable across cycles; it's released just before the re-schedule so the call
282
- * advances rather than dedup-returning.
255
+ * Each cycle runs the task and consults `reschedule` concurrently (so the delay can be measured from the run's
256
+ * start); when both settle and this cycle still owns the slot, a `true` verdict re-schedules a `clone()` whose
257
+ * promise is _returned_ — so the recurrence is the method calling itself, threaded into one promise, no separate
258
+ * loop. The clone shares the id, so the slot's identity is stable across cycles; it's released just before the
259
+ * re-schedule so the call advances rather than dedup-returning.
283
260
  *
284
- * Note: because each cycle's promise adopts the next, the chain retains every
285
- * prior cycle for the life of the recurrence bounded for finite recurrences,
286
- * an unbounded (small per-cycle) cost for a long-lived one (e.g. live reload).
261
+ * Note: because each cycle's promise adopts the next, the chain retains every prior cycle for the life of the
262
+ * recurrence bounded for finite recurrences, an unbounded (small per-cycle) cost for a long-lived one (e.g. live
263
+ * reload).
287
264
  */
288
265
  schedule(task) {
289
266
  if (this.#destroyed) return Promise.resolve();
@@ -1 +1 @@
1
- {"version":3,"file":"task.js","names":["#runFn","#externalSignal","#abortController","#signal","#status","#value","#error","#previous","#promise","#execute","#pending","#destroyed","#settled","#resolveSettled","#chain","#current","#reschedule","#active","#cancel"],"sources":["../../../../src/core/tasks/task.ts"],"sourcesContent":["import { anyAbortSignal } from '@videojs/utils/events';\nimport { generateId } from '@videojs/utils/string';\n\n// =============================================================================\n// DeepReadonly\n// =============================================================================\n\n/** Recursively marks all properties as readonly. */\nexport type DeepReadonly<T> = T extends (infer U)[]\n ? ReadonlyArray<DeepReadonly<U>>\n : T extends object\n ? { readonly [K in keyof T]: DeepReadonly<T[K]> }\n : T;\n\n// =============================================================================\n// Task\n// =============================================================================\n\nexport type TaskStatus = 'pending' | 'running' | 'done' | 'error';\n\n/**\n * Configuration for a Task.\n */\nexport interface TaskConfig {\n /**\n * Identifier for this task.\n * - string: used as-is\n * - () => string: called once at construction time\n * - undefined: a unique ID is generated via generateId()\n */\n id?: string | (() => string);\n\n /**\n * Optional external AbortSignal to compose with the task's internal one.\n * The task's work is aborted when either the internal controller (via abort())\n * or this external signal fires — whichever comes first.\n */\n signal?: AbortSignal;\n}\n\n/**\n * Minimal contract for a schedulable unit of async work.\n */\nexport interface TaskLike<TValue = void, TError = unknown> {\n readonly id: string;\n readonly status: TaskStatus;\n readonly value: DeepReadonly<TValue> | undefined;\n readonly error: DeepReadonly<TError> | undefined;\n /**\n * The last successful value carried forward from the run this was `clone()`d\n * from — the prior cycle's result for a `RecurringRunner` (undefined for an\n * original, or until the lineage has produced a success).\n */\n readonly previous: DeepReadonly<TValue> | undefined;\n /**\n * The signal this task's work runs under (its own abort composed with any\n * external one). Aborting the task fires it — so a `reschedule` can wait on it\n * to have its delay cancelled when the recurrence is aborted.\n */\n readonly signal: AbortSignal;\n /** Run the work, memoized: repeated calls share one execution + result. */\n run(): Promise<TValue>;\n abort(): void;\n /** A fresh, structurally identical task (same work + id) in a pending state — for re-running. */\n clone(): TaskLike<TValue, TError>;\n}\n\n/**\n * Generic reusable task that wraps an async run function.\n *\n * Owns its own AbortController so it can always be aborted independently.\n * Optionally composes an external AbortSignal so that a parent's cancellation\n * propagates into the task's work without requiring the caller to track the\n * task separately.\n *\n * `run()` is memoized: the work runs at most once per instance, and every call\n * returns the same promise (so observers can `await run()` to read the result\n * without re-triggering the work). To re-run the *same* work, take a `clone()` —\n * a fresh instance with its own AbortController and a pending state.\n *\n * Ordering guarantee: `value` is written before `status` transitions to `'done'`;\n * `error` is written before `status` transitions to `'error'`. Any reader\n * observing `status === 'done'` is guaranteed `value` is already present.\n */\nexport class Task<TValue = void, TError = unknown> implements TaskLike<TValue, TError> {\n readonly id: string;\n readonly #runFn: (signal: AbortSignal) => Promise<TValue>;\n readonly #externalSignal: AbortSignal | undefined;\n readonly #abortController = new AbortController();\n readonly #signal: AbortSignal;\n\n #status: TaskStatus = 'pending';\n #value: TValue | undefined = undefined;\n #error: TError | undefined = undefined;\n #previous: TValue | undefined = undefined;\n #promise: Promise<TValue> | undefined = undefined;\n\n constructor(runFn: (signal: AbortSignal) => Promise<TValue>, config?: TaskConfig) {\n this.#runFn = runFn;\n const rawId = config?.id;\n this.id = typeof rawId === 'function' ? rawId() : (rawId ?? generateId());\n this.#externalSignal = config?.signal;\n this.#signal = config?.signal\n ? anyAbortSignal([this.#abortController.signal, config.signal])\n : this.#abortController.signal;\n }\n\n get status(): TaskStatus {\n return this.#status;\n }\n\n get value(): DeepReadonly<TValue> | undefined {\n return this.#value as DeepReadonly<TValue> | undefined;\n }\n\n get error(): DeepReadonly<TError> | undefined {\n return this.#error as DeepReadonly<TError> | undefined;\n }\n\n get previous(): DeepReadonly<TValue> | undefined {\n return this.#previous as DeepReadonly<TValue> | undefined;\n }\n\n get signal(): AbortSignal {\n return this.#signal;\n }\n\n run(): Promise<TValue> {\n // Memoized: run the work once, sharing the same promise across calls. The\n // memoized promise IS what callers await, so it's always handled (no orphan\n // `Promise.resolve/reject`); a sync-throwing `#runFn` is captured as a\n // rejection rather than re-run.\n this.#promise ??= this.#execute();\n return this.#promise;\n }\n\n async #execute(): Promise<TValue> {\n this.#status = 'running';\n try {\n const result = await this.#runFn(this.#signal);\n this.#value = result; // value before status — ordering guarantee\n this.#status = 'done';\n return result;\n } catch (e) {\n this.#error = e as TError; // error before status — ordering guarantee\n this.#status = 'error';\n throw e;\n }\n }\n\n abort(): void {\n this.#abortController.abort();\n }\n\n /**\n * A fresh task with the same work, id, and external signal, in a pending state\n * (its own AbortController, no memoized result) — so it can be run again. Used\n * to re-run structurally identical work (e.g. `RecurringRunner` reloads).\n *\n * The clone inherits this run's value as its `previous` (or this run's own\n * `previous` if it never produced one — e.g. it errored), so a recurrence's\n * `previous` always tracks the last *successful* value across the lineage with\n * no bookkeeping in the runner.\n */\n clone(): Task<TValue, TError> {\n const cloned = new Task<TValue, TError>(this.#runFn, { id: this.id, signal: this.#externalSignal });\n cloned.#previous = this.#value ?? this.#previous;\n return cloned;\n }\n}\n\n// =============================================================================\n// ConcurrentRunner\n// =============================================================================\n\n/**\n * Runs tasks concurrently, deduplicated by task id.\n *\n * If a task with a given id is already in flight, subsequent schedule() calls\n * for that id are silently ignored until the first completes. Tasks are stored\n * so abortAll() can cancel any in-flight work (e.g. on engine cleanup).\n */\nexport class ConcurrentRunner {\n readonly #pending = new Map<string, { task: TaskLike<unknown, unknown>; promise: Promise<unknown> }>();\n #settled: Promise<void> = Promise.resolve();\n #resolveSettled: (() => void) | null = null;\n #destroyed = false;\n\n schedule<TValue = void, TError = unknown>(task: TaskLike<TValue, TError>): Promise<TValue> {\n if (this.#destroyed) return Promise.resolve() as Promise<TValue>;\n const existing = this.#pending.get(task.id);\n if (existing) return existing.promise as Promise<TValue>;\n\n if (this.#pending.size === 0) {\n this.#settled = new Promise((resolve) => {\n this.#resolveSettled = resolve;\n });\n }\n\n const promise = task.run();\n // Suppress unhandled rejection for callers that ignore the return value.\n promise.catch(() => {});\n // Cleanup: update pending and resolve settled regardless of outcome.\n const cleanup = () => {\n this.#pending.delete(task.id);\n if (this.#pending.size === 0) {\n this.#resolveSettled?.();\n this.#resolveSettled = null;\n }\n };\n promise.then(cleanup, cleanup);\n\n this.#pending.set(task.id, { task: task as TaskLike<unknown, unknown>, promise: promise as Promise<unknown> });\n return promise;\n }\n\n /**\n * Registers a callback to fire when all currently in-flight tasks settle.\n * If the runner is already idle, the callback is never called. If abortAll()\n * is called before the batch settles, the callback is superseded and silently\n * dropped — no stale callbacks, no generation token required by the caller.\n */\n whenSettled(callback: () => void): void {\n if (this.#pending.size === 0) return;\n const captured = this.#settled;\n captured.then(\n () => {\n if (this.#settled !== captured) return;\n callback();\n },\n () => {}\n );\n }\n\n abortAll(): void {\n for (const { task } of this.#pending.values()) task.abort();\n this.#pending.clear();\n // Resolve the current settled promise so any .then() handlers are queued,\n // then replace the reference — whenSettled callbacks that captured the old\n // reference will see the identity mismatch and be dropped.\n this.#resolveSettled?.();\n this.#resolveSettled = null;\n this.#settled = Promise.resolve();\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.abortAll();\n }\n}\n\n// =============================================================================\n// SerialRunner\n// =============================================================================\n\n/**\n * Runs tasks one at a time in submission order.\n *\n * Each schedule() call returns a Promise that resolves or rejects with the\n * task's result when it is eventually executed. Tasks wait in queue until the\n * prior task completes.\n *\n * Serialization is achieved by chaining each task's run() onto the tail of a\n * shared promise chain — no explicit queue or drain loop needed.\n *\n * abortAll() aborts all pending (not yet started) tasks and the currently\n * in-flight task. Pending tasks still run briefly but receive an aborted\n * signal and are expected to exit early.\n */\nexport class SerialRunner {\n #chain: Promise<unknown> = Promise.resolve();\n readonly #pending = new Set<TaskLike<unknown, unknown>>();\n #current: TaskLike<unknown, unknown> | null = null;\n #destroyed = false;\n\n schedule<TValue = void, TError = unknown>(task: TaskLike<TValue, TError>): Promise<TValue> {\n if (this.#destroyed) return Promise.resolve() as Promise<TValue>;\n const t = task as TaskLike<unknown, unknown>;\n this.#pending.add(t);\n\n const result = this.#chain\n .then(() => {\n this.#pending.delete(t);\n this.#current = t;\n return task.run();\n })\n .finally(() => {\n this.#current = null;\n });\n\n // Advance the chain regardless of whether this task succeeds or fails.\n this.#chain = result.then(\n () => {},\n () => {}\n );\n\n return result as Promise<TValue>;\n }\n\n /**\n * A promise that resolves when all currently-scheduled tasks have settled.\n * Use the reference as a generation token: capture it after scheduling a\n * batch, then check identity in the resolution callback to detect whether\n * a subsequent abortAll() + new batch has superseded this one.\n */\n get settled(): Promise<void> {\n return this.#chain as Promise<void>;\n }\n\n /**\n * Registers a callback to fire when all currently-pending tasks settle.\n * If the runner is already idle (no pending or running tasks), the callback\n * is never called. If new tasks are scheduled before the current batch\n * settles, the callback is superseded and silently dropped — no stale\n * callbacks, no generation token required by the caller.\n */\n whenSettled(callback: () => void): void {\n if (this.#pending.size === 0 && this.#current === null) return;\n const currentChain = this.#chain;\n currentChain.then(\n () => {\n if (this.#chain !== currentChain) return;\n callback();\n },\n () => {}\n );\n }\n\n /** Aborts and clears queued tasks without touching the in-flight task. */\n abortPending(): void {\n for (const task of this.#pending) task.abort();\n this.#pending.clear();\n }\n\n abortAll(): void {\n this.abortPending();\n this.#current?.abort();\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.abortAll();\n }\n}\n\n// =============================================================================\n// RecurringRunner\n// =============================================================================\n\n/**\n * Decides whether — and *when* — a {@link RecurringRunner} re-runs its task.\n * Invoked **concurrently with the run** (so the inter-run interval can be\n * measured from when the run *started*, not when it finished) with the single\n * {@link TaskLike}, which carries everything a decision needs:\n * - `task.run()` — the in-flight run, observable via this memoized call (does\n * not re-trigger work), e.g. to read its result for a cadence/stop decision.\n * - `task.previous` — the prior successful run's value (`undefined` on the\n * first), for decisions that compare consecutive results.\n * - `task.signal` — aborts the wait (and the recurrence) when the task is.\n *\n * Resolves `true` to re-run (after whatever delay it owns) or `false` to stop.\n * The runner deals only in this awaitable verdict — *how* the delay is produced\n * (a timer, a frame, an event) and *when* it's measured from live entirely in\n * the reschedule function, so the runner itself knows nothing about time. See\n * `delayedReschedule` for the common timer-based, start-anchored implementation.\n */\nexport type Reschedule<TValue> = (task: TaskLike<TValue>) => PromiseLike<boolean>;\n\n/**\n * A {@link Reschedule} that never recurs — the task runs exactly once. Pass it to\n * a {@link RecurringRunner} for non-recurring, run-once work (e.g. resolving a\n * complete VoD playlist that can never go stale).\n */\nexport const runOnce: Reschedule<unknown> = () => Promise.resolve(false);\n\n/**\n * Runs a task, then re-runs it whenever a {@link Reschedule} function says to,\n * until it says stop (or it's aborted) — the recurring sibling of\n * {@link ConcurrentRunner} / {@link SerialRunner}, and like them it's handed a\n * {@link TaskLike} to run.\n *\n * The runner has no notion of time: it just awaits whatever `reschedule`\n * returns (resolves `true` → re-run; `false` → stop). A `reschedule` is required;\n * pass {@link runOnce} for non-recurring, run-exactly-once work.\n *\n * Single-slot, keyed by task **id**: there is always at most one identified\n * active task for re-running. Scheduling a task whose id matches the active one\n * is a no-op — the existing recurrence keeps running (dedup by id). Scheduling a\n * task with a *different* id aborts the prior task's in-flight run and pending\n * reschedule, then takes over the slot (abort-and-replace) — the right shape\n * when there's one logical unit of recurring work (e.g. reloading the *selected*\n * track's media playlist).\n *\n * Each re-run is a fresh `clone()` of the task (since `Task.run()` is memoized —\n * the same instance won't re-execute), carrying the same id so the slot's\n * identity is stable across cycles. The clone also carries the prior cycle's\n * value forward as `task.previous`. The run function should read any inputs that\n * change between cycles at call time rather than capturing them once.\n *\n * The task is the sole cancellation channel: `abortAll()` aborts the active task,\n * which fires `task.signal` — cancelling both its in-flight run and any pending\n * reschedule delay waiting on that signal. An aborted (or stopped) recurrence\n * frees the slot, so a later schedule of the same id starts fresh.\n */\nexport class RecurringRunner<TValue = unknown> {\n readonly #reschedule: Reschedule<TValue>;\n // The identified active task — the one being (re)run. Held across cycles\n // (including the inter-cycle wait); null once the recurrence stops/aborts. Also\n // serves as the ownership token: a cycle advances or frees the slot only while\n // `#active` still points at its own task (a supersede/abortAll swaps it).\n #active: TaskLike<TValue, unknown> | null = null;\n #destroyed = false;\n\n constructor(reschedule: Reschedule<TValue>) {\n this.#reschedule = reschedule;\n }\n\n /**\n * Run `task` and recur per the `reschedule` verdict, as a single promise.\n * Resolves with the *final* cycle's value when the recurrence stops; **rejects**\n * if a run (or reschedule) genuinely fails — the rejection propagates to the\n * caller, who owns error handling; the runner only frees its slot (no\n * swallowing). The runner's *own* cancellation (abort/supersede/destroy) is not\n * a failure, so an aborted recurrence settles quietly rather than rejecting —\n * callers don't have to `.catch` routine teardown.\n *\n * Each cycle runs the task and consults `reschedule` concurrently (so the delay\n * can be measured from the run's start); when both settle and this cycle still\n * owns the slot, a `true` verdict re-schedules a `clone()` whose promise is\n * *returned* — so the recurrence is the method calling itself, threaded into one\n * promise, no separate loop. The clone shares the id, so the slot's identity is\n * stable across cycles; it's released just before the re-schedule so the call\n * advances rather than dedup-returning.\n *\n * Note: because each cycle's promise adopts the next, the chain retains every\n * prior cycle for the life of the recurrence — bounded for finite recurrences,\n * an unbounded (small per-cycle) cost for a long-lived one (e.g. live reload).\n */\n schedule(task: TaskLike<TValue, unknown>): Promise<TValue> {\n if (this.#destroyed) return Promise.resolve() as Promise<TValue>;\n // Dedup by id: this id is already the active re-run target, so the existing\n // recurrence continues uninterrupted (don't restart it) — hand back its\n // in-flight run.\n if (this.#active?.id === task.id) return this.#active.run();\n // Different id supersedes: abort the prior recurrence, then take over.\n this.#cancel();\n this.#active = task;\n\n // Drive the run (in case `reschedule` doesn't observe it — e.g. `runOnce`)\n // and the verdict together; a rejected run rejects the whole cycle.\n return Promise.all([task.run(), this.#reschedule(task)]).then(\n ([value, again]) => {\n // Only act while we still own the slot — a supersede/abortAll swapped\n // `#active`, in which case this stale cycle does nothing.\n if (this.#active === task && again && !task.signal.aborted) {\n // Release first so the same-id clone advances (isn't dedup-returned),\n // then chain the next cycle into this promise.\n this.#active = null;\n return this.schedule(task.clone());\n }\n if (this.#active === task) this.#active = null; // natural stop / superseded\n return value;\n },\n (error) => {\n // The recurrence ended on a rejection; free the slot if we still own it.\n if (this.#active === task) this.#active = null;\n // The runner's own cancellation isn't a failure — settle quietly so\n // routine teardown (abort/supersede/destroy) needs no caller `.catch`.\n // A genuine run/reschedule failure propagates to the caller.\n if (task.signal.aborted) return undefined as TValue;\n throw error;\n }\n );\n }\n\n #cancel(): void {\n this.#active?.abort();\n this.#active = null;\n }\n\n abortAll(): void {\n this.#cancel();\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.abortAll();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"task.js","names":["#runFn","#externalSignal","#abortController","#signal","#status","#value","#error","#previous","#promise","#execute","#pending","#destroyed","#settled","#resolveSettled","#chain","#current","#reschedule","#active","#cancel"],"sources":["../../../../src/core/tasks/task.ts"],"sourcesContent":["import { anyAbortSignal } from '@videojs/utils/events';\nimport { generateId } from '@videojs/utils/string';\n\n// =============================================================================\n// DeepReadonly\n// =============================================================================\n\n/** Recursively marks all properties as readonly. */\nexport type DeepReadonly<T> = T extends (infer U)[]\n ? ReadonlyArray<DeepReadonly<U>>\n : T extends object\n ? { readonly [K in keyof T]: DeepReadonly<T[K]> }\n : T;\n\n// =============================================================================\n// Task\n// =============================================================================\n\nexport type TaskStatus = 'pending' | 'running' | 'done' | 'error';\n\n/** Configuration for a Task. */\nexport interface TaskConfig {\n /**\n * Identifier for this task. - string: used as-is - () => string: called once at construction time - undefined: a\n * unique ID is generated via generateId()\n */\n id?: string | (() => string);\n\n /**\n * Optional external AbortSignal to compose with the task's internal one. The task's work is aborted when either the\n * internal controller (via abort()) or this external signal fires — whichever comes first.\n */\n signal?: AbortSignal;\n}\n\n/** Minimal contract for a schedulable unit of async work. */\nexport interface TaskLike<TValue = void, TError = unknown> {\n readonly id: string;\n readonly status: TaskStatus;\n readonly value: DeepReadonly<TValue> | undefined;\n readonly error: DeepReadonly<TError> | undefined;\n /**\n * The last successful value carried forward from the run this was `clone()`d from — the prior cycle's result for a\n * `RecurringRunner` (undefined for an original, or until the lineage has produced a success).\n */\n readonly previous: DeepReadonly<TValue> | undefined;\n /**\n * The signal this task's work runs under (its own abort composed with any external one). Aborting the task fires it —\n * so a `reschedule` can wait on it to have its delay cancelled when the recurrence is aborted.\n */\n readonly signal: AbortSignal;\n /** Run the work, memoized: repeated calls share one execution + result. */\n run(): Promise<TValue>;\n abort(): void;\n /** A fresh, structurally identical task (same work + id) in a pending state — for re-running. */\n clone(): TaskLike<TValue, TError>;\n}\n\n/**\n * Generic reusable task that wraps an async run function.\n *\n * Owns its own AbortController so it can always be aborted independently. Optionally composes an external AbortSignal\n * so that a parent's cancellation propagates into the task's work without requiring the caller to track the task\n * separately.\n *\n * `run()` is memoized: the work runs at most once per instance, and every call returns the same promise (so observers\n * can `await run()` to read the result without re-triggering the work). To re-run the _same_ work, take a `clone()` — a\n * fresh instance with its own AbortController and a pending state.\n *\n * Ordering guarantee: `value` is written before `status` transitions to `'done'`; `error` is written before `status`\n * transitions to `'error'`. Any reader observing `status === 'done'` is guaranteed `value` is already present.\n */\nexport class Task<TValue = void, TError = unknown> implements TaskLike<TValue, TError> {\n readonly id: string;\n readonly #runFn: (signal: AbortSignal) => Promise<TValue>;\n readonly #externalSignal: AbortSignal | undefined;\n readonly #abortController = new AbortController();\n readonly #signal: AbortSignal;\n\n #status: TaskStatus = 'pending';\n #value: TValue | undefined = undefined;\n #error: TError | undefined = undefined;\n #previous: TValue | undefined = undefined;\n #promise: Promise<TValue> | undefined = undefined;\n\n constructor(runFn: (signal: AbortSignal) => Promise<TValue>, config?: TaskConfig) {\n this.#runFn = runFn;\n const rawId = config?.id;\n\n this.id = typeof rawId === 'function' ? rawId() : (rawId ?? generateId());\n this.#externalSignal = config?.signal;\n this.#signal = config?.signal\n ? anyAbortSignal([this.#abortController.signal, config.signal])\n : this.#abortController.signal;\n }\n\n get status(): TaskStatus {\n return this.#status;\n }\n\n get value(): DeepReadonly<TValue> | undefined {\n return this.#value as DeepReadonly<TValue> | undefined;\n }\n\n get error(): DeepReadonly<TError> | undefined {\n return this.#error as DeepReadonly<TError> | undefined;\n }\n\n get previous(): DeepReadonly<TValue> | undefined {\n return this.#previous as DeepReadonly<TValue> | undefined;\n }\n\n get signal(): AbortSignal {\n return this.#signal;\n }\n\n run(): Promise<TValue> {\n // Memoized: run the work once, sharing the same promise across calls. The\n // memoized promise IS what callers await, so it's always handled (no orphan\n // `Promise.resolve/reject`); a sync-throwing `#runFn` is captured as a\n // rejection rather than re-run.\n this.#promise ??= this.#execute();\n return this.#promise;\n }\n\n async #execute(): Promise<TValue> {\n this.#status = 'running';\n\n try {\n const result = await this.#runFn(this.#signal);\n\n this.#value = result; // value before status — ordering guarantee\n this.#status = 'done';\n return result;\n } catch (e) {\n this.#error = e as TError; // error before status — ordering guarantee\n this.#status = 'error';\n throw e;\n }\n }\n\n abort(): void {\n this.#abortController.abort();\n }\n\n /**\n * A fresh task with the same work, id, and external signal, in a pending state (its own AbortController, no memoized\n * result) — so it can be run again. Used to re-run structurally identical work (e.g. `RecurringRunner` reloads).\n *\n * The clone inherits this run's value as its `previous` (or this run's own `previous` if it never produced one — e.g.\n * it errored), so a recurrence's `previous` always tracks the last _successful_ value across the lineage with no\n * bookkeeping in the runner.\n */\n clone(): Task<TValue, TError> {\n const cloned = new Task<TValue, TError>(this.#runFn, { id: this.id, signal: this.#externalSignal });\n\n cloned.#previous = this.#value ?? this.#previous;\n return cloned;\n }\n}\n\n// =============================================================================\n// ConcurrentRunner\n// =============================================================================\n\n/**\n * Runs tasks concurrently, deduplicated by task id.\n *\n * If a task with a given id is already in flight, subsequent schedule() calls for that id are silently ignored until\n * the first completes. Tasks are stored so abortAll() can cancel any in-flight work (e.g. on engine cleanup).\n */\nexport class ConcurrentRunner {\n readonly #pending = new Map<string, { task: TaskLike<unknown, unknown>; promise: Promise<unknown> }>();\n #settled: Promise<void> = Promise.resolve();\n #resolveSettled: (() => void) | null = null;\n #destroyed = false;\n\n schedule<TValue = void, TError = unknown>(task: TaskLike<TValue, TError>): Promise<TValue> {\n if (this.#destroyed) return Promise.resolve() as Promise<TValue>;\n\n const existing = this.#pending.get(task.id);\n if (existing) return existing.promise as Promise<TValue>;\n\n if (this.#pending.size === 0) {\n this.#settled = new Promise((resolve) => {\n this.#resolveSettled = resolve;\n });\n }\n\n const promise = task.run();\n\n // Suppress unhandled rejection for callers that ignore the return value.\n promise.catch(() => {});\n // Cleanup: update pending and resolve settled regardless of outcome.\n const cleanup = () => {\n this.#pending.delete(task.id);\n\n if (this.#pending.size === 0) {\n this.#resolveSettled?.();\n this.#resolveSettled = null;\n }\n };\n\n promise.then(cleanup, cleanup);\n\n this.#pending.set(task.id, { task: task as TaskLike<unknown, unknown>, promise: promise as Promise<unknown> });\n return promise;\n }\n\n /**\n * Registers a callback to fire when all currently in-flight tasks settle. If the runner is already idle, the callback\n * is never called. If abortAll() is called before the batch settles, the callback is superseded and silently dropped\n * — no stale callbacks, no generation token required by the caller.\n */\n whenSettled(callback: () => void): void {\n if (this.#pending.size === 0) return;\n\n const captured = this.#settled;\n\n captured.then(\n () => {\n if (this.#settled !== captured) return;\n\n callback();\n },\n () => {}\n );\n }\n\n abortAll(): void {\n for (const { task } of this.#pending.values()) task.abort();\n\n this.#pending.clear();\n // Resolve the current settled promise so any .then() handlers are queued,\n // then replace the reference — whenSettled callbacks that captured the old\n // reference will see the identity mismatch and be dropped.\n this.#resolveSettled?.();\n this.#resolveSettled = null;\n this.#settled = Promise.resolve();\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.abortAll();\n }\n}\n\n// =============================================================================\n// SerialRunner\n// =============================================================================\n\n/**\n * Runs tasks one at a time in submission order.\n *\n * Each schedule() call returns a Promise that resolves or rejects with the task's result when it is eventually\n * executed. Tasks wait in queue until the prior task completes.\n *\n * Serialization is achieved by chaining each task's run() onto the tail of a shared promise chain — no explicit queue\n * or drain loop needed.\n *\n * AbortAll() aborts all pending (not yet started) tasks and the currently in-flight task. Pending tasks still run\n * briefly but receive an aborted signal and are expected to exit early.\n */\nexport class SerialRunner {\n #chain: Promise<unknown> = Promise.resolve();\n readonly #pending = new Set<TaskLike<unknown, unknown>>();\n #current: TaskLike<unknown, unknown> | null = null;\n #destroyed = false;\n\n schedule<TValue = void, TError = unknown>(task: TaskLike<TValue, TError>): Promise<TValue> {\n if (this.#destroyed) return Promise.resolve() as Promise<TValue>;\n\n const t = task as TaskLike<unknown, unknown>;\n\n this.#pending.add(t);\n\n const result = this.#chain\n .then(() => {\n this.#pending.delete(t);\n this.#current = t;\n return task.run();\n })\n .finally(() => {\n this.#current = null;\n });\n\n // Advance the chain regardless of whether this task succeeds or fails.\n this.#chain = result.then(\n () => {},\n () => {}\n );\n\n return result as Promise<TValue>;\n }\n\n /**\n * A promise that resolves when all currently-scheduled tasks have settled. Use the reference as a generation token:\n * capture it after scheduling a batch, then check identity in the resolution callback to detect whether a subsequent\n * abortAll() + new batch has superseded this one.\n */\n get settled(): Promise<void> {\n return this.#chain as Promise<void>;\n }\n\n /**\n * Registers a callback to fire when all currently-pending tasks settle. If the runner is already idle (no pending or\n * running tasks), the callback is never called. If new tasks are scheduled before the current batch settles, the\n * callback is superseded and silently dropped — no stale callbacks, no generation token required by the caller.\n */\n whenSettled(callback: () => void): void {\n if (this.#pending.size === 0 && this.#current === null) return;\n\n const currentChain = this.#chain;\n\n currentChain.then(\n () => {\n if (this.#chain !== currentChain) return;\n\n callback();\n },\n () => {}\n );\n }\n\n /** Aborts and clears queued tasks without touching the in-flight task. */\n abortPending(): void {\n for (const task of this.#pending) task.abort();\n\n this.#pending.clear();\n }\n\n abortAll(): void {\n this.abortPending();\n this.#current?.abort();\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.abortAll();\n }\n}\n\n// =============================================================================\n// RecurringRunner\n// =============================================================================\n\n/**\n * Decides whether — and _when_ — a {@link RecurringRunner} re-runs its task. Invoked **concurrently with the run** (so\n * the inter-run interval can be measured from when the run _started_, not when it finished) with the single\n * {@link TaskLike}, which carries everything a decision needs:\n *\n * - `task.run()` — the in-flight run, observable via this memoized call (does not re-trigger work), e.g. to read its\n * result for a cadence/stop decision.\n * - `task.previous` — the prior successful run's value (`undefined` on the first), for decisions that compare consecutive\n * results.\n * - `task.signal` — aborts the wait (and the recurrence) when the task is.\n *\n * Resolves `true` to re-run (after whatever delay it owns) or `false` to stop. The runner deals only in this awaitable\n * verdict — _how_ the delay is produced (a timer, a frame, an event) and _when_ it's measured from live entirely in the\n * reschedule function, so the runner itself knows nothing about time. See `delayedReschedule` for the common\n * timer-based, start-anchored implementation.\n */\nexport type Reschedule<TValue> = (task: TaskLike<TValue>) => PromiseLike<boolean>;\n\n/**\n * A {@link Reschedule} that never recurs — the task runs exactly once. Pass it to a {@link RecurringRunner} for\n * non-recurring, run-once work (e.g. resolving a complete VoD playlist that can never go stale).\n */\nexport const runOnce: Reschedule<unknown> = () => Promise.resolve(false);\n\n/**\n * Runs a task, then re-runs it whenever a {@link Reschedule} function says to, until it says stop (or it's aborted) —\n * the recurring sibling of {@link ConcurrentRunner} / {@link SerialRunner}, and like them it's handed a\n * {@link TaskLike} to run.\n *\n * The runner has no notion of time: it just awaits whatever `reschedule` returns (resolves `true` → re-run; `false` →\n * stop). A `reschedule` is required; pass {@link runOnce} for non-recurring, run-exactly-once work.\n *\n * Single-slot, keyed by task **id**: there is always at most one identified active task for re-running. Scheduling a\n * task whose id matches the active one is a no-op — the existing recurrence keeps running (dedup by id). Scheduling a\n * task with a _different_ id aborts the prior task's in-flight run and pending reschedule, then takes over the slot\n * (abort-and-replace) — the right shape when there's one logical unit of recurring work (e.g. reloading the _selected_\n * track's media playlist).\n *\n * Each re-run is a fresh `clone()` of the task (since `Task.run()` is memoized — the same instance won't re-execute),\n * carrying the same id so the slot's identity is stable across cycles. The clone also carries the prior cycle's value\n * forward as `task.previous`. The run function should read any inputs that change between cycles at call time rather\n * than capturing them once.\n *\n * The task is the sole cancellation channel: `abortAll()` aborts the active task, which fires `task.signal` —\n * cancelling both its in-flight run and any pending reschedule delay waiting on that signal. An aborted (or stopped)\n * recurrence frees the slot, so a later schedule of the same id starts fresh.\n */\nexport class RecurringRunner<TValue = unknown> {\n readonly #reschedule: Reschedule<TValue>;\n // The identified active task — the one being (re)run. Held across cycles\n // (including the inter-cycle wait); null once the recurrence stops/aborts. Also\n // serves as the ownership token: a cycle advances or frees the slot only while\n // `#active` still points at its own task (a supersede/abortAll swaps it).\n #active: TaskLike<TValue, unknown> | null = null;\n #destroyed = false;\n\n constructor(reschedule: Reschedule<TValue>) {\n this.#reschedule = reschedule;\n }\n\n /**\n * Run `task` and recur per the `reschedule` verdict, as a single promise. Resolves with the _final_ cycle's value\n * when the recurrence stops; **rejects** if a run (or reschedule) genuinely fails — the rejection propagates to the\n * caller, who owns error handling; the runner only frees its slot (no swallowing). The runner's _own_ cancellation\n * (abort/supersede/destroy) is not a failure, so an aborted recurrence settles quietly rather than rejecting —\n * callers don't have to `.catch` routine teardown.\n *\n * Each cycle runs the task and consults `reschedule` concurrently (so the delay can be measured from the run's\n * start); when both settle and this cycle still owns the slot, a `true` verdict re-schedules a `clone()` whose\n * promise is _returned_ — so the recurrence is the method calling itself, threaded into one promise, no separate\n * loop. The clone shares the id, so the slot's identity is stable across cycles; it's released just before the\n * re-schedule so the call advances rather than dedup-returning.\n *\n * Note: because each cycle's promise adopts the next, the chain retains every prior cycle for the life of the\n * recurrence — bounded for finite recurrences, an unbounded (small per-cycle) cost for a long-lived one (e.g. live\n * reload).\n */\n schedule(task: TaskLike<TValue, unknown>): Promise<TValue> {\n if (this.#destroyed) return Promise.resolve() as Promise<TValue>;\n\n // Dedup by id: this id is already the active re-run target, so the existing\n // recurrence continues uninterrupted (don't restart it) — hand back its\n // in-flight run.\n if (this.#active?.id === task.id) return this.#active.run();\n\n // Different id supersedes: abort the prior recurrence, then take over.\n this.#cancel();\n this.#active = task;\n\n // Drive the run (in case `reschedule` doesn't observe it — e.g. `runOnce`)\n // and the verdict together; a rejected run rejects the whole cycle.\n return Promise.all([task.run(), this.#reschedule(task)]).then(\n ([value, again]) => {\n // Only act while we still own the slot — a supersede/abortAll swapped\n // `#active`, in which case this stale cycle does nothing.\n if (this.#active === task && again && !task.signal.aborted) {\n // Release first so the same-id clone advances (isn't dedup-returned),\n // then chain the next cycle into this promise.\n this.#active = null;\n return this.schedule(task.clone());\n }\n\n if (this.#active === task) this.#active = null; // natural stop / superseded\n\n return value;\n },\n (error) => {\n // The recurrence ended on a rejection; free the slot if we still own it.\n if (this.#active === task) this.#active = null;\n\n // The runner's own cancellation isn't a failure — settle quietly so\n // routine teardown (abort/supersede/destroy) needs no caller `.catch`.\n // A genuine run/reschedule failure propagates to the caller.\n if (task.signal.aborted) return undefined as TValue;\n\n throw error;\n }\n );\n }\n\n #cancel(): void {\n this.#active?.abort();\n this.#active = null;\n }\n\n abortAll(): void {\n this.#cancel();\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.abortAll();\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  import { getMediaPlaylistMetadata } from "./media/types/index.js";
2
2
  import { SVTA_UNSUPPORTED_PLAYBACK_FEATURE, svtaCategory, svtaIndex } from "./media/errors.js";
3
3
  import { derivePerTypeStartMediaTime, deriveSharedMinStartMediaTime } from "./playback/behaviors/establish-start-media-time.js";
4
+ import { DEFAULT_PREFERRED_CODECS, preferCodecFamilies } from "./playback/primitives/selection-rules.js";
4
5
  import { preferHighestResolution, screenResolutionCap } from "./playback/behaviors/select-tracks.js";
6
+ import { stickToSelectedCodecs } from "./playback/behaviors/track-switching.js";
5
7
  import { createHlsVideoEngine } from "./playback/engines/hls/engine.js";
6
8
  import { createHlsAudioEngine } from "./playback/engines/hls/engine-audio-only.js";
7
9
  import { createBackgroundVideoEngine } from "./playback/engines/hls/engine-background-video.js";
8
- export { SVTA_UNSUPPORTED_PLAYBACK_FEATURE, createBackgroundVideoEngine, createHlsAudioEngine, createHlsVideoEngine, derivePerTypeStartMediaTime, deriveSharedMinStartMediaTime, getMediaPlaylistMetadata, preferHighestResolution, screenResolutionCap, svtaCategory, svtaIndex };
10
+ export { DEFAULT_PREFERRED_CODECS, SVTA_UNSUPPORTED_PLAYBACK_FEATURE, createBackgroundVideoEngine, createHlsAudioEngine, createHlsVideoEngine, derivePerTypeStartMediaTime, deriveSharedMinStartMediaTime, getMediaPlaylistMetadata, preferCodecFamilies, preferHighestResolution, screenResolutionCap, stickToSelectedCodecs, svtaCategory, svtaIndex };
@@ -10,9 +10,8 @@ import { createMachineReactor } from "./core/reactors/create-machine-reactor.js"
10
10
  /**
11
11
  * Stream Processing Framework (SPF) for Video.js 10
12
12
  *
13
- * The compositional primitives: createComposition, signals, tasks, actors,
14
- * reactors. Media-domain helpers and the HLS playback engine live behind
15
- * the `./dom` and `./hls` subpaths.
13
+ * The compositional primitives: createComposition, signals, tasks, actors, reactors. Media-domain helpers and the HLS
14
+ * playback engine live behind the `./dom` and `./hls` subpaths.
16
15
  *
17
16
  * @packageDocumentation
18
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["/**\n * Stream Processing Framework (SPF) for Video.js 10\n *\n * The compositional primitives: createComposition, signals, tasks, actors,\n * reactors. Media-domain helpers and the HLS playback engine live behind\n * the `./dom` and `./hls` subpaths.\n *\n * @packageDocumentation\n */\n\nexport const VERSION = '0.1.0';\n\n// =============================================================================\n// Composition\n// =============================================================================\n\nexport type {\n Behavior,\n BehaviorCleanup,\n BehaviorDeps,\n Composition,\n CompositionOptions,\n ContextSignals,\n InferBehaviorConfig,\n InferBehaviorContext,\n InferBehaviorState,\n ResolveBehaviorConfig,\n ResolveBehaviorContext,\n ResolveBehaviorState,\n StateSignals,\n} from './core/composition/create-composition';\nexport { createComposition, defineBehavior } from './core/composition/create-composition';\nexport type { ShareSignalsConfig } from './core/composition/share-signals';\nexport { makeShareSignals } from './core/composition/share-signals';\n\n// =============================================================================\n// Signals\n// =============================================================================\n\nexport { effect } from './core/signals/effect';\nexport type { Computed, ReadonlySignal, Signal, SignalOptions } from './core/signals/primitives';\nexport { computed, signal, snapshot, untrack, update } from './core/signals/primitives';\n\n// =============================================================================\n// Tasks\n// =============================================================================\n\nexport type { TaskConfig, TaskLike, TaskStatus } from './core/tasks/task';\nexport { ConcurrentRunner, SerialRunner, Task } from './core/tasks/task';\n\n// =============================================================================\n// Machine (shared by actors and reactors)\n// =============================================================================\n\nexport type { Machine, MachineSnapshot } from './core/machine';\n\n// =============================================================================\n// Actors\n// =============================================================================\n\nexport type { ActorSnapshot, CallbackActor, SignalActor } from './core/actors/actor';\nexport type {\n ActorDefinition,\n ActorStateDefinition,\n HandlerContext,\n MessageActor,\n RunnerLike,\n} from './core/actors/create-machine-actor';\nexport { createMachineActor } from './core/actors/create-machine-actor';\nexport type { TransitionActor } from './core/actors/create-transition-actor';\nexport { createTransitionActor } from './core/actors/create-transition-actor';\n\n// =============================================================================\n// Reactors\n// =============================================================================\n\nexport type {\n Reactor,\n ReactorDefinition,\n ReactorDeriveFn,\n ReactorEffectFn,\n ReactorStateDefinition,\n} from './core/reactors/create-machine-reactor';\nexport { createMachineReactor } from './core/reactors/create-machine-reactor';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAUA,MAAa,UAAU"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["/**\n * Stream Processing Framework (SPF) for Video.js 10\n *\n * The compositional primitives: createComposition, signals, tasks, actors, reactors. Media-domain helpers and the HLS\n * playback engine live behind the `./dom` and `./hls` subpaths.\n *\n * @packageDocumentation\n */\n\nexport const VERSION = '0.1.0';\n\n// =============================================================================\n// Composition\n// =============================================================================\n\nexport type {\n Behavior,\n BehaviorCleanup,\n BehaviorDeps,\n Composition,\n CompositionOptions,\n ContextSignals,\n InferBehaviorConfig,\n InferBehaviorContext,\n InferBehaviorState,\n ResolveBehaviorConfig,\n ResolveBehaviorContext,\n ResolveBehaviorState,\n StateSignals,\n} from './core/composition/create-composition';\nexport { createComposition, defineBehavior } from './core/composition/create-composition';\nexport type { ShareSignalsConfig } from './core/composition/share-signals';\nexport { makeShareSignals } from './core/composition/share-signals';\n\n// =============================================================================\n// Signals\n// =============================================================================\n\nexport { effect } from './core/signals/effect';\nexport type { Computed, ReadonlySignal, Signal, SignalOptions } from './core/signals/primitives';\nexport { computed, signal, snapshot, untrack, update } from './core/signals/primitives';\n\n// =============================================================================\n// Tasks\n// =============================================================================\n\nexport type { TaskConfig, TaskLike, TaskStatus } from './core/tasks/task';\nexport { ConcurrentRunner, SerialRunner, Task } from './core/tasks/task';\n\n// =============================================================================\n// Machine (shared by actors and reactors)\n// =============================================================================\n\nexport type { Machine, MachineSnapshot } from './core/machine';\n\n// =============================================================================\n// Actors\n// =============================================================================\n\nexport type { ActorSnapshot, CallbackActor, SignalActor } from './core/actors/actor';\nexport type {\n ActorDefinition,\n ActorStateDefinition,\n HandlerContext,\n MessageActor,\n RunnerLike,\n} from './core/actors/create-machine-actor';\nexport { createMachineActor } from './core/actors/create-machine-actor';\nexport type { TransitionActor } from './core/actors/create-transition-actor';\nexport { createTransitionActor } from './core/actors/create-transition-actor';\n\n// =============================================================================\n// Reactors\n// =============================================================================\n\nexport type {\n Reactor,\n ReactorDefinition,\n ReactorDeriveFn,\n ReactorEffectFn,\n ReactorStateDefinition,\n} from './core/reactors/create-machine-reactor';\nexport { createMachineReactor } from './core/reactors/create-machine-reactor';\n"],"mappings":";;;;;;;;;;;;;;;;;AASA,MAAa,UAAU"}
@@ -1,16 +1,12 @@
1
1
  //#region src/media/abr/quality-selection.ts
2
- /**
3
- * Default quality selection configuration.
4
- * Values match Shaka Player upgrade threshold (0.85 = 15% headroom).
5
- */
2
+ /** Default quality selection configuration. Values match Shaka Player upgrade threshold (0.85 = 15% headroom). */
6
3
  const DEFAULT_QUALITY_CONFIG = {
7
4
  safetyMargin: .85,
8
5
  upgradeMargin: 1.15
9
6
  };
10
7
  /**
11
- * Resolution as a total pixel count (`width × height`), the basis for
12
- * comparing two tracks at the same bitrate. Missing dimensions count as 0, so
13
- * tracks without resolution metadata (e.g. audio) area-compare equal.
8
+ * Resolution as a total pixel count (`width × height`), the basis for comparing two tracks at the same bitrate. Missing
9
+ * dimensions count as 0, so tracks without resolution metadata (e.g. audio) area-compare equal.
14
10
  */
15
11
  function resolutionArea(track) {
16
12
  return (track.width ?? 0) * (track.height ?? 0);