@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
@@ -1,10 +1,8 @@
1
1
  import { ReadonlySignal, Signal } from "../signals/primitives.js";
2
2
  //#region src/core/composition/create-composition.d.ts
3
3
  /**
4
- * Cleanup returned by a behavior. Behaviors may return:
5
- * - `void` / `undefined` — no cleanup needed
6
- * - A function — called on destroy (may return a Promise)
7
- * - An object with `destroy()` — called on destroy (may return a Promise)
4
+ * Cleanup returned by a behavior. Behaviors may return: - `void` / `undefined` — no cleanup needed - A function —
5
+ * called on destroy (may return a Promise) - An object with `destroy()` — called on destroy (may return a Promise)
8
6
  */
9
7
  type BehaviorCleanup = void | (() => void | Promise<void>) | {
10
8
  destroy(): void | Promise<void>;
@@ -12,46 +10,40 @@ type BehaviorCleanup = void | (() => void | Promise<void>) | {
12
10
  /**
13
11
  * A signal map keyed by the fields of `S`. Each field is a writable signal.
14
12
  *
15
- * Optional fields on `S` map to required signal slots whose value type
16
- * includes `undefined`, ensuring every key has a signal even when the
17
- * underlying value is absent.
13
+ * Optional fields on `S` map to required signal slots whose value type includes `undefined`, ensuring every key has a
14
+ * signal even when the underlying value is absent.
18
15
  *
19
16
  * Used in two roles:
20
- * - Engine-side **construction**: `Composition<S, C>` exposes its public
21
- * surface as `StateSignals<S>` (everything writable) so external code
22
- * can read or write any slot.
23
- * - Behavior **input convenience**: a behavior that writes to every slot
24
- * can type its setup state param as `StateSignals<{ ... }>` rather than
25
- * spelling out per-slot `Signal<T>` types.
26
17
  *
27
- * Behaviors that mix read-only and writable slots type the setup param
28
- * directly as a slot map (`{ x: Signal<T>; y: ReadonlySignal<U> }`)
29
- * instead of going through `StateSignals<>`.
18
+ * - Engine-side **construction**: `Composition<S, C>` exposes its public surface as `StateSignals<S>` (everything
19
+ * writable) so external code can read or write any slot.
20
+ * - Behavior **input convenience**: a behavior that writes to every slot can type its setup state param as
21
+ * `StateSignals<{ ... }>` rather than spelling out per-slot `Signal<T>` types.
22
+ *
23
+ * Behaviors that mix read-only and writable slots type the setup param directly as a slot map (`{ x: Signal<T>; y:
24
+ * ReadonlySignal<U> }`) instead of going through `StateSignals<>`.
30
25
  */
31
26
  type StateSignals<S extends object> = { [K in keyof S]-?: Signal<S[K]>; };
32
27
  /**
33
- * A signal map keyed by the fields of `C`. Each field is a writable signal
34
- * for a platform object or actor reference. Same dual role as
35
- * `StateSignals<S>` — see its docblock.
28
+ * A signal map keyed by the fields of `C`. Each field is a writable signal for a platform object or actor reference.
29
+ * Same dual role as `StateSignals<S>` see its docblock.
36
30
  */
37
31
  type ContextSignals<C extends object> = { [K in keyof C]-?: Signal<C[K]>; };
38
32
  /**
39
- * Slot-map shape — a record where each value is at least a `ReadonlySignal`.
40
- * `Signal<T>` is structurally a subtype of `ReadonlySignal<T>` (it adds
41
- * `.set()`), so a writable slot satisfies this bound too.
33
+ * Slot-map shape — a record where each value is at least a `ReadonlySignal`. `Signal<T>` is structurally a subtype of
34
+ * `ReadonlySignal<T>` (it adds `.set()`), so a writable slot satisfies this bound too.
42
35
  *
43
- * This is the bound used for behavior `state` / `context` slot maps. It
44
- * lets a single behavior declare a *heterogeneous* slot map where some
45
- * slots are `Signal<T>` (writable) and others are `ReadonlySignal<T>`
46
- * (read-only) — making read/write intent explicit at the call site and
47
- * giving body-level enforcement (TS rejects `.set()` on a read-only slot).
36
+ * This is the bound used for behavior `state` / `context` slot maps. It lets a single behavior declare a
37
+ * _heterogeneous_ slot map where some slots are `Signal<T>` (writable) and others are `ReadonlySignal<T>` (read-only) —
38
+ * making read/write intent explicit at the call site and giving body-level enforcement (TS rejects `.set()` on a
39
+ * read-only slot).
48
40
  */
49
41
  type AnySlotMap = Record<PropertyKey, ReadonlySignal<unknown>>;
50
42
  /**
51
43
  * The deps object passed to each behavior by the composition.
52
44
  *
53
- * - `state` — slot map for state fields (reactive data). Per-slot read/
54
- * write intent expressed via `Signal<T>` vs `ReadonlySignal<T>`.
45
+ * - `state` — slot map for state fields (reactive data). Per-slot read/ write intent expressed via `Signal<T>` vs
46
+ * `ReadonlySignal<T>`.
55
47
  * - `context` — slot map for platform objects and actor references.
56
48
  * - `config` — static configuration, passed once at composition creation.
57
49
  */
@@ -61,21 +53,16 @@ interface BehaviorDeps<StateMap extends AnySlotMap, ContextMap extends AnySlotMa
61
53
  config: Cfg;
62
54
  }
63
55
  /**
64
- * A behavior announces the state and context keys it needs alongside a
65
- * `setup` function that receives deps (state, context, config) and
66
- * returns an optional cleanup handle.
56
+ * A behavior announces the state and context keys it needs alongside a `setup` function that receives deps (state,
57
+ * context, config) and returns an optional cleanup handle.
67
58
  *
68
- * The `stateKeys` / `contextKeys` declarations are the runtime expression
69
- * of the behavior's contract the caller (e.g. `createComposition`) uses
70
- * them to know which signals to provide. The setup parameter type
71
- * declares the *slot map* (per-slot `Signal<T>` vs `ReadonlySignal<T>`);
72
- * together they form a complete contract.
59
+ * The `stateKeys` / `contextKeys` declarations are the runtime expression of the behavior's contract — the caller (e.g.
60
+ * `createComposition`) uses them to know which signals to provide. The setup parameter type declares the _slot map_
61
+ * (per-slot `Signal<T>` vs `ReadonlySignal<T>`); together they form a complete contract.
73
62
  *
74
- * Manual `Behavior<>` literals (e.g. engine wrappers that forward keys
75
- * from a wrapped behavior, or pass-through behaviors like `shareSignals`)
76
- * opt out of exhaustiveness the type alias is permissive (subset).
77
- * Source behaviors should use `defineBehavior` to get exhaustiveness
78
- * enforcement at the call site.
63
+ * Manual `Behavior<>` literals (e.g. engine wrappers that forward keys from a wrapped behavior, or pass-through
64
+ * behaviors like `shareSignals`) opt out of exhaustiveness the type alias is permissive (subset). Source behaviors
65
+ * should use `defineBehavior` to get exhaustiveness enforcement at the call site.
79
66
  */
80
67
  interface Behavior<StateMap extends AnySlotMap = Empty, ContextMap extends AnySlotMap = Empty, Cfg extends object = Empty> {
81
68
  /** State keys this behavior reads/writes. Subset of `keyof StateMap`. */
@@ -97,18 +84,16 @@ type DepsOf<B> = B extends {
97
84
  /**
98
85
  * Empty-object fallback used when a behavior omits state, context, or config.
99
86
  *
100
- * Using `{}` rather than `object` is deliberate — `object & {x: T}` collapses
101
- * to `{x: never}` under TS's union-to-intersection conversion in some inference
102
- * contexts (likely a TS quirk around the `object` upper bound), whereas
103
- * `{} & {x: T}` simplifies cleanly to `{x: T}`.
87
+ * Using `{}` rather than `object` is deliberate — `object & {x: T}` collapses to `{x: never}` under TS's
88
+ * union-to-intersection conversion in some inference contexts (likely a TS quirk around the `object` upper bound),
89
+ * whereas `{} & {x: T}` simplifies cleanly to `{x: T}`.
104
90
  */
105
91
  type Empty = {};
106
92
  /**
107
93
  * Unwrap a signal map back to its state/context shape.
108
94
  *
109
- * Inferring through `{ get(): infer V }` rather than `Signal<infer V>`
110
- * sidesteps `Signal`'s nominal/invariance behaviour the conditional
111
- * matches structurally on the read side, and `V` is inferred covariantly.
95
+ * Inferring through `{ get(): infer V }` rather than `Signal<infer V>` sidesteps `Signal`'s nominal/invariance
96
+ * behaviour the conditional matches structurally on the read side, and `V` is inferred covariantly.
112
97
  */
113
98
  type UnwrapSignals<M> = M extends object ? { [K in keyof M]: M[K] extends {
114
99
  get(): infer V;
@@ -128,16 +113,14 @@ type InferBehaviorConfig<F> = DepsOf<F> extends {
128
113
  /**
129
114
  * Recursively intersect a per-behavior projection across the tuple.
130
115
  *
131
- * Iterating over the tuple directly avoids `UnionToIntersection`'s
132
- * function-contravariance trick, which produces unstable intersections
133
- * (collapsing concrete fields to `never` or unrelated types) when one of the
134
- * union members is the empty `{}` fallback.
116
+ * Iterating over the tuple directly avoids `UnionToIntersection`'s function-contravariance trick, which produces
117
+ * unstable intersections (collapsing concrete fields to `never` or unrelated types) when one of the union members is
118
+ * the empty `{}` fallback.
135
119
  */
136
120
  type IntersectBehaviors<Behaviors extends readonly AnyBehavior[], Project extends object> = Behaviors extends readonly [infer First extends AnyBehavior, ...infer Rest extends readonly AnyBehavior[]] ? Apply<Project, First> & IntersectBehaviors<Rest, Project> : Empty;
137
121
  /**
138
- * Apply a projection (one of the marker types below) to a single behavior.
139
- * Encoded as a discriminated dispatch so the recursion above can stay generic
140
- * and we don't have to write three near-identical recursive types.
122
+ * Apply a projection (one of the marker types below) to a single behavior. Encoded as a discriminated dispatch so the
123
+ * recursion above can stay generic and we don't have to write three near-identical recursive types.
141
124
  */
142
125
  type Apply<Project extends object, F> = Project extends {
143
126
  kind: 'state';
@@ -162,29 +145,25 @@ type ResolveBehaviorContext<Behaviors extends readonly AnyBehavior[]> = Intersec
162
145
  /** Resolve the combined config shape from an array of behaviors (intersection of all requirements). */
163
146
  type ResolveBehaviorConfig<Behaviors extends readonly AnyBehavior[]> = IntersectBehaviors<Behaviors, ConfigProjection> extends (infer R extends object) ? R : Empty;
164
147
  /**
165
- * True if any property in `T` collapsed to `undefined` or `never` — indicating
166
- * a type conflict from intersecting incompatible behavior requirements.
148
+ * True if any property in `T` collapsed to `undefined` or `never` — indicating a type conflict from intersecting
149
+ * incompatible behavior requirements.
167
150
  *
168
151
  * - Required conflicts: `{ v: number } & { v: string }` → `{ v: never }` — caught via `[never] extends [undefined]`
169
152
  * - Optional conflicts: `{ v?: number } & { v?: string }` → `{ v?: undefined }` — caught directly
170
153
  */
171
154
  type HasConflict<T extends object> = true extends { [K in keyof T]: [T[K]] extends [undefined] ? true : never; }[keyof T] ? true : false;
172
155
  /**
173
- * Validate that a behavior composition has no type conflicts.
174
- * Returns the behaviors tuple if valid, or an error message type if conflicts are detected.
156
+ * Validate that a behavior composition has no type conflicts. Returns the behaviors tuple if valid, or an error message
157
+ * type if conflicts are detected.
175
158
  *
176
- * State, context, and config are all checked the same way — by intersecting
177
- * each behavior's requirement and looking for collapsed fields. The
178
- * intersection-based check applies the same rule to context as to state, so
179
- * two behaviors that disagree on a context field's type (e.g. `Surface` vs
180
- * `VideoSurface`) surface a conflict at compose time. The prior subtype-based
181
- * approach for owners is gone — the unified rule is simpler and catches the
182
- * cases where two behaviors silently agreed on a wider supertype.
159
+ * State, context, and config are all checked the same way — by intersecting each behavior's requirement and looking for
160
+ * collapsed fields. The intersection-based check applies the same rule to context as to state, so two behaviors that
161
+ * disagree on a context field's type (e.g. `Surface` vs `VideoSurface`) surface a conflict at compose time. The prior
162
+ * subtype-based approach for owners is gone the unified rule is simpler and catches the cases where two behaviors
163
+ * silently agreed on a wider supertype.
183
164
  */
184
165
  type ValidateComposition<Behaviors extends readonly AnyBehavior[]> = HasConflict<ResolveBehaviorState<Behaviors>> extends true ? 'Error: behaviors have conflicting state types' : HasConflict<ResolveBehaviorContext<Behaviors>> extends true ? 'Error: behaviors have conflicting context types' : HasConflict<ResolveBehaviorConfig<Behaviors>> extends true ? 'Error: behaviors have conflicting config types' : [...Behaviors];
185
- /**
186
- * A composition of behaviors with shared state and context signal maps.
187
- */
166
+ /** A composition of behaviors with shared state and context signal maps. */
188
167
  interface Composition<S extends object, C extends object> {
189
168
  state: StateSignals<S>;
190
169
  context: ContextSignals<C>;
@@ -193,10 +172,8 @@ interface Composition<S extends object, C extends object> {
193
172
  /**
194
173
  * Options for `createComposition`.
195
174
  *
196
- * Composition derives the state and context signal maps from each
197
- * behavior's declared `stateKeys` / `contextKeys`; `initialState` and
198
- * `initialContext` seed those signals at creation time. Any unseeded
199
- * signal starts as `undefined`.
175
+ * Composition derives the state and context signal maps from each behavior's declared `stateKeys` / `contextKeys`;
176
+ * `initialState` and `initialContext` seed those signals at creation time. Any unseeded signal starts as `undefined`.
200
177
  */
201
178
  interface CompositionOptions<S extends object, C extends object, Cfg extends object> {
202
179
  /** Static configuration passed to every behavior. */
@@ -210,48 +187,39 @@ declare function createComposition<const Behaviors extends readonly AnyBehavior[
210
187
  /**
211
188
  * Compose-time exhaustiveness check.
212
189
  *
213
- * Adds a phantom error tag to the parameter shape when `Keys` does not
214
- * cover every key in `Slot`. The user's value won't satisfy the phantom
215
- * field requirement, so TS surfaces the failure at the call site with a
216
- * descriptive message. When exhaustive, the tag is `Empty` and adds no
217
- * constraint.
190
+ * Adds a phantom error tag to the parameter shape when `Keys` does not cover every key in `Slot`. The user's value
191
+ * won't satisfy the phantom field requirement, so TS surfaces the failure at the call site with a descriptive message.
192
+ * When exhaustive, the tag is `Empty` and adds no constraint.
218
193
  */
219
194
  type ExhaustiveKeys<Keys extends readonly PropertyKey[], Slot extends object, Name extends string> = [keyof Slot] extends [Keys[number]] ? Empty : { [K in `Error: ${Name}Keys must list every key in the typed slice`]: Exclude<keyof Slot, Keys[number]>; };
220
195
  /**
221
- * Typed factory for behaviors that enforces single-behavior key/param
222
- * consistency: declared `stateKeys` must equal `keyof S` (where `S` is
223
- * inferred from the setup's `state` parameter type), and same for
224
- * `contextKeys` / `C`.
196
+ * Typed factory for behaviors that enforces single-behavior key/param consistency: declared `stateKeys` must equal
197
+ * `keyof S` (where `S` is inferred from the setup's `state` parameter type), and same for `contextKeys` / `C`.
225
198
  *
226
- * The `const` modifier on `SK` / `CK` captures literal tuples so e.g.
227
- * `stateKeys: ['preload']` infers as `readonly ['preload']`, no `as
228
- * const` needed at the call site.
199
+ * The `const` modifier on `SK` / `CK` captures literal tuples so e.g. `stateKeys: ['preload']` infers as `readonly
200
+ * ['preload']`, no `as const` needed at the call site.
229
201
  *
230
- * Cross-behavior consistency at `createComposition` is unchanged — the
231
- * existing `IntersectBehaviors` machinery still runs over each
232
- * behavior's setup param type.
202
+ * Cross-behavior consistency at `createComposition` is unchanged — the existing `IntersectBehaviors` machinery still
203
+ * runs over each behavior's setup param type.
233
204
  *
234
205
  * @example
235
- * ```ts
236
- * export const syncPreload = defineBehavior({
206
+ * ```ts
207
+ * export const syncPreload = defineBehavior({
237
208
  * stateKeys: ['preload'],
238
209
  * contextKeys: ['mediaElement'],
239
210
  * setup: ({ state, context }: {
240
- * state: StateSignals<{ preload?: 'auto' | 'metadata' | 'none' }>;
241
- * context: ContextSignals<{ mediaElement?: HTMLMediaElement | undefined }>;
211
+ * state: StateSignals<{ preload?: 'auto' | 'metadata' | 'none' }>;
212
+ * context: ContextSignals<{ mediaElement?: HTMLMediaElement | undefined }>;
242
213
  * }) => { ... },
243
- * });
244
- * ```
214
+ * });
215
+ * ```;
245
216
  */
246
217
  /**
247
- * Deps shape for a behavior whose deps slot is empty (no keys). When a
248
- * slot is empty, the corresponding deps field is optional callers
249
- * (typically tests) can omit it, and it defaults to `{}` at runtime via
250
- * `createComposition`.
218
+ * Deps shape for a behavior whose deps slot is empty (no keys). When a slot is empty, the corresponding deps field is
219
+ * optional callers (typically tests) can omit it, and it defaults to `{}` at runtime via `createComposition`.
251
220
  *
252
- * When a slot has at least one key, the behavior reads `state.foo` /
253
- * `context.bar` / `config.baz` and we need the field to be required so
254
- * the access is type-safe.
221
+ * When a slot has at least one key, the behavior reads `state.foo` / `context.bar` / `config.baz` and we need the field
222
+ * to be required so the access is type-safe.
255
223
  */
256
224
  type RequireIfNonEmpty<Key extends string, T extends object> = keyof T extends never ? { [K in Key]?: T; } : { [K in Key]: T; };
257
225
  type DepsForCfg<StateMap extends AnySlotMap, ContextMap extends AnySlotMap, Cfg extends object> = RequireIfNonEmpty<'state', StateMap> & RequireIfNonEmpty<'context', ContextMap> & RequireIfNonEmpty<'config', Cfg>;
@@ -1 +1 @@
1
- {"version":3,"file":"create-composition.d.ts","names":[],"sources":["../../../../src/core/composition/create-composition.ts"],"mappings":";;;;;;;;KAQY,uCAAuC;EAAmB,kBAAkB;;;;;;;;;;;;;;;;;;;;;KAqB5E,aAAa,uBAAuB,WAAW,MAAM,OAAO,EAAE;;;;;;KAO9D,eAAe,uBAAuB,WAAW,MAAM,OAAO,EAAE;;;;;;;;;;;;KAahE,aAAa,OAAO,aAAa;;;;;;;;;UAU5B,aAAa,iBAAiB,YAAY,mBAAmB,YAAY;EACxF,OAAO;EACP,SAAS;EACT,QAAQ;;;;;;;;;;;;;;;;;;;UAoBO,SACf,iBAAiB,aAAa,OAC9B,mBAAmB,aAAa,OAChC,qBAAqB;;EAGrB,2BAA2B;;EAE3B,6BAA6B;EAC7B,QAAQ,MAAM,aAAa,UAAU,YAAY,SAAS;;;KAQvD;EACH,oBAAoB;EACpB,sBAAsB;EACtB,QAAQ,cAAc;;;KAInB,OAAO,KAAK;EAAY,QAAQ,YAAY,MAAM;IAAwB;;;;;;;;;KAW1E;;;;;;;;KASA,cAAc,KAAK,sBAAsB,WAAW,IAAI,EAAE;EAAa,aAAa;IAAM,eAAc;;KAGjG,mBAAmB,KAAK,OAAO;EAAa,aAAa;IAAM,cAAc,KAAK;;KAGlF,qBAAqB,KAAK,OAAO;EAAa,eAAe;IAAM,cAAc,KAAK;;KAGtF,oBAAoB,KAAK,OAAO;EAAa,cAAc;IAAqB,IAAI;;;;;;;;;KAU3F,mBAAmB,2BAA2B,eAAe,0BAA0B,kCACpF,cAAc,sBACX,sBAAsB,iBAE7B,MAAM,SAAS,SAAS,mBAAmB,MAAM,WACjD;;;;;;KAOC,MAAM,wBAAwB,KAAK;EAAkB;IACtD,mBAAmB,KACnB;EAAkB;IAChB,qBAAqB,KACrB;EAAkB;IAChB,oBAAoB;KAGvB;EAAoB;;KACpB;EAAsB;;KACtB;EAAqB;;;KAGd,qBAAqB,2BAA2B,iBAC1D,mBAAmB,WAAW,gCAA+B,oBAAmB,IAAI;;KAG1E,uBAAuB,2BAA2B,iBAC5D,mBAAmB,WAAW,kCAAiC,oBAAmB,IAAI;;KAG5E,sBAAsB,2BAA2B,iBAC3D,mBAAmB,WAAW,iCAAgC,oBAAmB,IAAI;;;;;;;;KASlF,YAAY,oCACd,WAAW,KAAK,EAAE,gDACb;;;;;;;;;;;;;KAoBH,oBAAoB,2BAA2B,iBAClD,YAAY,qBAAqB,6EAE7B,YAAY,uBAAuB,+EAEjC,YAAY,sBAAsB,kFAE5B;;;;UASG,YAAY,kBAAkB;EAC7C,OAAO,aAAa;EACpB,SAAS,eAAe;EACxB,WAAW;;;;;;;;;;UAWI,mBAAmB,kBAAkB,kBAAkB;;EAEtE,SAAS;;EAET,eAAe,QAAQ;;EAEvB,iBAAiB,QAAQ;;iBA2DX,wBAAwB,2BAA2B,eACjE,WAAW,oBAAoB,YAC/B,UAAU,mBACR,qBAAqB,YACrB,uBAAuB,YACvB,sBAAsB,cAEvB,YAAY,qBAAqB,YAAY,uBAAuB;;;;;;;;;;KA8DlE,eAAe,sBAAsB,eAAe,qBAAqB,8BACtE,eACG,gBACP,WACG,eAAe,oDAAoD,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsCzF,kBAAkB,oBAAoB,0BAA0B,qBAC9D,KAAK,OAAO,UACZ,KAAK,MAAM;KAEb,WAAW,iBAAiB,YAAY,mBAAmB,YAAY,sBAAsB,2BAEhG,YAEA,6BAA6B,cAC7B,4BAA4B;iBAEd,eACd,iBAAiB,aAAa,OAC9B,mBAAmB,aAAa,OAChC,qBAAqB,aACf,2BAA2B,iCAC3B,2BAA2B,6BACjC,UAAU,kBAAkB,iBAE5B;EACE,WAAW;EACX,aAAa;EACb,QAAQ;IAAQ,OAAO;IAAU,SAAS;IAAY,QAAQ;QAAU;IACtE,eAAe,IAAI,qBACrB,eAAe,IAAI;EAErB,WAAW;EACX,aAAa;EACb,QAAQ,MAAM,WAAW,UAAU,YAAY,SAAS"}
1
+ {"version":3,"file":"create-composition.d.ts","names":[],"sources":["../../../../src/core/composition/create-composition.ts"],"mappings":";;;;;;KAMY,uCAAuC;EAAmB,kBAAkB;;;;;;;;;;;;;;;;;;KAkB5E,aAAa,uBAAuB,WAAW,MAAM,OAAO,EAAE;;;;;KAM9D,eAAe,uBAAuB,WAAW,MAAM,OAAO,EAAE;;;;;;;;;;KAWhE,aAAa,OAAO,aAAa;;;;;;;;;UAU5B,aAAa,iBAAiB,YAAY,mBAAmB,YAAY;EACxF,OAAO;EACP,SAAS;EACT,QAAQ;;;;;;;;;;;;;;UAeO,SACf,iBAAiB,aAAa,OAC9B,mBAAmB,aAAa,OAChC,qBAAqB;;EAGrB,2BAA2B;;EAE3B,6BAA6B;EAC7B,QAAQ,MAAM,aAAa,UAAU,YAAY,SAAS;;;KAQvD;EACH,oBAAoB;EACpB,sBAAsB;EACtB,QAAQ,cAAc;;;KAInB,OAAO,KAAK;EAAY,QAAQ,YAAY,MAAM;IAAwB;;;;;;;;KAW1E;;;;;;;KAQA,cAAc,KAAK,sBAAsB,WAAW,IAAI,EAAE;EAAa,aAAa;IAAM,eAAc;;KAGjG,mBAAmB,KAAK,OAAO;EAAa,aAAa;IAAM,cAAc,KAAK;;KAGlF,qBAAqB,KAAK,OAAO;EAAa,eAAe;IAAM,cAAc,KAAK;;KAGtF,oBAAoB,KAAK,OAAO;EAAa,cAAc;IAAqB,IAAI;;;;;;;;KAS3F,mBAAmB,2BAA2B,eAAe,0BAA0B,kCACpF,cAAc,sBACX,sBAAsB,iBAE7B,MAAM,SAAS,SAAS,mBAAmB,MAAM,WACjD;;;;;KAMC,MAAM,wBAAwB,KAAK;EAAkB;IACtD,mBAAmB,KACnB;EAAkB;IAChB,qBAAqB,KACrB;EAAkB;IAChB,oBAAoB;KAGvB;EAAoB;;KACpB;EAAsB;;KACtB;EAAqB;;;KAGd,qBAAqB,2BAA2B,iBAC1D,mBAAmB,WAAW,gCAA+B,oBAAmB,IAAI;;KAG1E,uBAAuB,2BAA2B,iBAC5D,mBAAmB,WAAW,kCAAiC,oBAAmB,IAAI;;KAG5E,sBAAsB,2BAA2B,iBAC3D,mBAAmB,WAAW,iCAAgC,oBAAmB,IAAI;;;;;;;;KASlF,YAAY,oCACd,WAAW,KAAK,EAAE,gDACb;;;;;;;;;;;KAkBH,oBAAoB,2BAA2B,iBAClD,YAAY,qBAAqB,6EAE7B,YAAY,uBAAuB,+EAEjC,YAAY,sBAAsB,kFAE5B;;UAOG,YAAY,kBAAkB;EAC7C,OAAO,aAAa;EACpB,SAAS,eAAe;EACxB,WAAW;;;;;;;;UASI,mBAAmB,kBAAkB,kBAAkB;;EAEtE,SAAS;;EAET,eAAe,QAAQ;;EAEvB,iBAAiB,QAAQ;;iBAyDX,wBAAwB,2BAA2B,eACjE,WAAW,oBAAoB,YAC/B,UAAU,mBACR,qBAAqB,YACrB,uBAAuB,YACvB,sBAAsB,cAEvB,YAAY,qBAAqB,YAAY,uBAAuB;;;;;;;;KAiElE,eAAe,sBAAsB,eAAe,qBAAqB,8BACtE,eACG,gBACP,WACG,eAAe,oDAAoD,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+BzF,kBAAkB,oBAAoB,0BAA0B,qBAC9D,KAAK,OAAO,UACZ,KAAK,MAAM;KAEb,WAAW,iBAAiB,YAAY,mBAAmB,YAAY,sBAAsB,2BAEhG,YAEA,6BAA6B,cAC7B,4BAA4B;iBAEd,eACd,iBAAiB,aAAa,OAC9B,mBAAmB,aAAa,OAChC,qBAAqB,aACf,2BAA2B,iCAC3B,2BAA2B,6BACjC,UAAU,kBAAkB,iBAE5B;EACE,WAAW;EACX,aAAa;EACb,QAAQ;IAAQ,OAAO;IAAU,SAAS;IAAY,QAAQ;QAAU;IACtE,eAAe,IAAI,qBACrB,eAAe,IAAI;EAErB,WAAW;EACX,aAAa;EACb,QAAQ,MAAM,WAAW,UAAU,YAAY,SAAS"}
@@ -3,47 +3,44 @@ import { signal } from "../signals/primitives.js";
3
3
  /**
4
4
  * Create a composition from a set of behaviors.
5
5
  *
6
- * Composition unions the behaviors' declared `stateKeys` / `contextKeys`
7
- * to know which signals to create. Each signal is seeded from
8
- * `initialState` / `initialContext` when supplied, defaulting to
9
- * `undefined`. Behaviors are responsible for writing their own slots
10
- * once their preconditions are met.
6
+ * Composition unions the behaviors' declared `stateKeys` / `contextKeys` to know which signals to create. Each signal
7
+ * is seeded from `initialState` / `initialContext` when supplied, defaulting to `undefined`. Behaviors are responsible
8
+ * for writing their own slots once their preconditions are met.
11
9
  *
12
- * Cross-behavior type conflicts (e.g. two behaviors disagreeing on a
13
- * field's type) surface as a compose-time type error via
14
- * `ValidateComposition`.
10
+ * Cross-behavior type conflicts (e.g. two behaviors disagreeing on a field's type) surface as a compose-time type error
11
+ * via `ValidateComposition`.
15
12
  *
16
13
  * @example
17
- * ```ts
18
- * const composition = createComposition([resolvePresentation, switchVideoTrack], {
14
+ * ```ts
15
+ * const composition = createComposition([resolvePresentation, switchVideoTrack], {
19
16
  * config: { parsePresentation: parseMultivariantPlaylist, initialBandwidth: 2_000_000 },
20
17
  * initialState: { bandwidthState: { fastEstimate: 0, ... } },
21
- * });
22
- * ```
18
+ * });
19
+ * ```;
23
20
  */
24
21
  /**
25
- * Create a typed signal map for a given set of keys, seeded from an
26
- * optional partial initial value.
22
+ * Create a typed signal map for a given set of keys, seeded from an optional partial initial value.
27
23
  *
28
- * Pipeline: `Set` dedupes the iterable (insertion order preserved, so
29
- * first occurrence wins) `Object.fromEntries` materializes one
30
- * `signal()` per unique key, seeded from `initial[key]` or `undefined`.
24
+ * Pipeline: `Set` dedupes the iterable (insertion order preserved, so first occurrence wins) → `Object.fromEntries`
25
+ * materializes one `signal()` per unique key, seeded from `initial[key]` or `undefined`.
31
26
  *
32
- * Per-key value types live in TypeScript only — at runtime every signal
33
- * is `Signal<unknown>`. The boundary cast at the return narrows the wide
34
- * `Record<PropertyKey, Signal<unknown>>` shape to the caller's expected
35
- * per-key types from `S`.
27
+ * Per-key value types live in TypeScript only — at runtime every signal is `Signal<unknown>`. The boundary cast at the
28
+ * return narrows the wide `Record<PropertyKey, Signal<unknown>>` shape to the caller's expected per-key types from
29
+ * `S`.
36
30
  *
37
- * Used by `createComposition` to derive engine state/context maps from
38
- * the union of behaviors' declared `stateKeys` / `contextKeys`.
31
+ * Used by `createComposition` to derive engine state/context maps from the union of behaviors' declared `stateKeys` /
32
+ * `contextKeys`.
39
33
  *
40
34
  * @example
41
- * ```ts
42
- * interface State { count?: number; label?: string }
43
- * const state = buildSignalMap<State>(['count', 'label'], { count: 5 });
44
- * state.count.get(); // 5
45
- * state.label.get(); // undefined
46
- * ```
35
+ * ```ts
36
+ * interface State {
37
+ * count?: number;
38
+ * label?: string;
39
+ * }
40
+ * const state = buildSignalMap<State>(['count', 'label'], { count: 5 });
41
+ * state.count.get(); // 5
42
+ * state.label.get(); // undefined
43
+ * ```;
47
44
  */
48
45
  function buildSignalMap(keys, initial) {
49
46
  const init = initial;
@@ -1 +1 @@
1
- {"version":3,"file":"create-composition.js","names":[],"sources":["../../../../src/core/composition/create-composition.ts"],"sourcesContent":["import { type ReadonlySignal, type Signal, signal } from '../signals/primitives';\n\n/**\n * Cleanup returned by a behavior. Behaviors may return:\n * - `void` / `undefined` — no cleanup needed\n * - A function — called on destroy (may return a Promise)\n * - An object with `destroy()` — called on destroy (may return a Promise)\n */\nexport type BehaviorCleanup = void | (() => void | Promise<void>) | { destroy(): void | Promise<void> };\n\n/**\n * A signal map keyed by the fields of `S`. Each field is a writable signal.\n *\n * Optional fields on `S` map to required signal slots whose value type\n * includes `undefined`, ensuring every key has a signal even when the\n * underlying value is absent.\n *\n * Used in two roles:\n * - Engine-side **construction**: `Composition<S, C>` exposes its public\n * surface as `StateSignals<S>` (everything writable) so external code\n * can read or write any slot.\n * - Behavior **input convenience**: a behavior that writes to every slot\n * can type its setup state param as `StateSignals<{ ... }>` rather than\n * spelling out per-slot `Signal<T>` types.\n *\n * Behaviors that mix read-only and writable slots type the setup param\n * directly as a slot map (`{ x: Signal<T>; y: ReadonlySignal<U> }`)\n * instead of going through `StateSignals<>`.\n */\nexport type StateSignals<S extends object> = { [K in keyof S]-?: Signal<S[K]> };\n\n/**\n * A signal map keyed by the fields of `C`. Each field is a writable signal\n * for a platform object or actor reference. Same dual role as\n * `StateSignals<S>` — see its docblock.\n */\nexport type ContextSignals<C extends object> = { [K in keyof C]-?: Signal<C[K]> };\n\n/**\n * Slot-map shape — a record where each value is at least a `ReadonlySignal`.\n * `Signal<T>` is structurally a subtype of `ReadonlySignal<T>` (it adds\n * `.set()`), so a writable slot satisfies this bound too.\n *\n * This is the bound used for behavior `state` / `context` slot maps. It\n * lets a single behavior declare a *heterogeneous* slot map where some\n * slots are `Signal<T>` (writable) and others are `ReadonlySignal<T>`\n * (read-only) — making read/write intent explicit at the call site and\n * giving body-level enforcement (TS rejects `.set()` on a read-only slot).\n */\nexport type AnySlotMap = Record<PropertyKey, ReadonlySignal<unknown>>;\n\n/**\n * The deps object passed to each behavior by the composition.\n *\n * - `state` — slot map for state fields (reactive data). Per-slot read/\n * write intent expressed via `Signal<T>` vs `ReadonlySignal<T>`.\n * - `context` — slot map for platform objects and actor references.\n * - `config` — static configuration, passed once at composition creation.\n */\nexport interface BehaviorDeps<StateMap extends AnySlotMap, ContextMap extends AnySlotMap, Cfg extends object> {\n state: StateMap;\n context: ContextMap;\n config: Cfg;\n}\n\n/**\n * A behavior announces the state and context keys it needs alongside a\n * `setup` function that receives deps (state, context, config) and\n * returns an optional cleanup handle.\n *\n * The `stateKeys` / `contextKeys` declarations are the runtime expression\n * of the behavior's contract — the caller (e.g. `createComposition`) uses\n * them to know which signals to provide. The setup parameter type\n * declares the *slot map* (per-slot `Signal<T>` vs `ReadonlySignal<T>`);\n * together they form a complete contract.\n *\n * Manual `Behavior<>` literals (e.g. engine wrappers that forward keys\n * from a wrapped behavior, or pass-through behaviors like `shareSignals`)\n * opt out of exhaustiveness — the type alias is permissive (subset).\n * Source behaviors should use `defineBehavior` to get exhaustiveness\n * enforcement at the call site.\n */\nexport interface Behavior<\n StateMap extends AnySlotMap = Empty,\n ContextMap extends AnySlotMap = Empty,\n Cfg extends object = Empty,\n> {\n /** State keys this behavior reads/writes. Subset of `keyof StateMap`. */\n stateKeys: readonly (keyof StateMap)[];\n /** Context keys this behavior reads/writes. Subset of `keyof ContextMap`. */\n contextKeys: readonly (keyof ContextMap)[];\n setup: (deps: BehaviorDeps<StateMap, ContextMap, Cfg>) => BehaviorCleanup;\n}\n\n// =============================================================================\n// Behavior type inference\n// =============================================================================\n\n/** A behavior with an unconstrained setup — used as a generic bound. */\ntype AnyBehavior = {\n stateKeys: readonly PropertyKey[];\n contextKeys: readonly PropertyKey[];\n setup: (deps: any) => BehaviorCleanup;\n};\n\n/** Extract the deps type from a behavior's setup function. */\ntype DepsOf<B> = B extends { setup: (deps: infer D, ...args: any[]) => any } ? D : never;\n\n/**\n * Empty-object fallback used when a behavior omits state, context, or config.\n *\n * Using `{}` rather than `object` is deliberate — `object & {x: T}` collapses\n * to `{x: never}` under TS's union-to-intersection conversion in some inference\n * contexts (likely a TS quirk around the `object` upper bound), whereas\n * `{} & {x: T}` simplifies cleanly to `{x: T}`.\n */\n// biome-ignore lint/complexity/noBannedTypes: see comment above\ntype Empty = {};\n\n/**\n * Unwrap a signal map back to its state/context shape.\n *\n * Inferring through `{ get(): infer V }` rather than `Signal<infer V>`\n * sidesteps `Signal`'s nominal/invariance behaviour — the conditional\n * matches structurally on the read side, and `V` is inferred covariantly.\n */\ntype UnwrapSignals<M> = M extends object ? { [K in keyof M]: M[K] extends { get(): infer V } ? V : never } : Empty;\n\n/** Infer the state shape a behavior requires from its deps parameter. */\nexport type InferBehaviorState<F> = DepsOf<F> extends { state: infer M } ? UnwrapSignals<M> : Empty;\n\n/** Infer the context shape a behavior requires from its deps parameter. */\nexport type InferBehaviorContext<F> = DepsOf<F> extends { context: infer M } ? UnwrapSignals<M> : Empty;\n\n/** Infer the config shape a behavior requires from its deps parameter. */\nexport type InferBehaviorConfig<F> = DepsOf<F> extends { config: infer C extends object } ? C : Empty;\n\n/**\n * Recursively intersect a per-behavior projection across the tuple.\n *\n * Iterating over the tuple directly avoids `UnionToIntersection`'s\n * function-contravariance trick, which produces unstable intersections\n * (collapsing concrete fields to `never` or unrelated types) when one of the\n * union members is the empty `{}` fallback.\n */\ntype IntersectBehaviors<Behaviors extends readonly AnyBehavior[], Project extends object> = Behaviors extends readonly [\n infer First extends AnyBehavior,\n ...infer Rest extends readonly AnyBehavior[],\n]\n ? Apply<Project, First> & IntersectBehaviors<Rest, Project>\n : Empty;\n\n/**\n * Apply a projection (one of the marker types below) to a single behavior.\n * Encoded as a discriminated dispatch so the recursion above can stay generic\n * and we don't have to write three near-identical recursive types.\n */\ntype Apply<Project extends object, F> = Project extends { kind: 'state' }\n ? InferBehaviorState<F>\n : Project extends { kind: 'context' }\n ? InferBehaviorContext<F>\n : Project extends { kind: 'config' }\n ? InferBehaviorConfig<F>\n : never;\n\ntype StateProjection = { kind: 'state' };\ntype ContextProjection = { kind: 'context' };\ntype ConfigProjection = { kind: 'config' };\n\n/** Resolve the combined state shape from an array of behaviors (intersection of all requirements). */\nexport type ResolveBehaviorState<Behaviors extends readonly AnyBehavior[]> =\n IntersectBehaviors<Behaviors, StateProjection> extends infer R extends object ? R : Empty;\n\n/** Resolve the combined context shape from an array of behaviors (intersection of all requirements). */\nexport type ResolveBehaviorContext<Behaviors extends readonly AnyBehavior[]> =\n IntersectBehaviors<Behaviors, ContextProjection> extends infer R extends object ? R : Empty;\n\n/** Resolve the combined config shape from an array of behaviors (intersection of all requirements). */\nexport type ResolveBehaviorConfig<Behaviors extends readonly AnyBehavior[]> =\n IntersectBehaviors<Behaviors, ConfigProjection> extends infer R extends object ? R : Empty;\n\n/**\n * True if any property in `T` collapsed to `undefined` or `never` — indicating\n * a type conflict from intersecting incompatible behavior requirements.\n *\n * - Required conflicts: `{ v: number } & { v: string }` → `{ v: never }` — caught via `[never] extends [undefined]`\n * - Optional conflicts: `{ v?: number } & { v?: string }` → `{ v?: undefined }` — caught directly\n */\ntype HasConflict<T extends object> = true extends {\n [K in keyof T]: [T[K]] extends [undefined] ? true : never;\n}[keyof T]\n ? true\n : false;\n\n// =============================================================================\n// Composition validation\n// =============================================================================\n\n/**\n * Validate that a behavior composition has no type conflicts.\n * Returns the behaviors tuple if valid, or an error message type if conflicts are detected.\n *\n * State, context, and config are all checked the same way — by intersecting\n * each behavior's requirement and looking for collapsed fields. The\n * intersection-based check applies the same rule to context as to state, so\n * two behaviors that disagree on a context field's type (e.g. `Surface` vs\n * `VideoSurface`) surface a conflict at compose time. The prior subtype-based\n * approach for owners is gone — the unified rule is simpler and catches the\n * cases where two behaviors silently agreed on a wider supertype.\n */\ntype ValidateComposition<Behaviors extends readonly AnyBehavior[]> =\n HasConflict<ResolveBehaviorState<Behaviors>> extends true\n ? 'Error: behaviors have conflicting state types'\n : HasConflict<ResolveBehaviorContext<Behaviors>> extends true\n ? 'Error: behaviors have conflicting context types'\n : HasConflict<ResolveBehaviorConfig<Behaviors>> extends true\n ? 'Error: behaviors have conflicting config types'\n : [...Behaviors];\n\n// =============================================================================\n// Composition\n// =============================================================================\n\n/**\n * A composition of behaviors with shared state and context signal maps.\n */\nexport interface Composition<S extends object, C extends object> {\n state: StateSignals<S>;\n context: ContextSignals<C>;\n destroy(): Promise<void>;\n}\n\n/**\n * Options for `createComposition`.\n *\n * Composition derives the state and context signal maps from each\n * behavior's declared `stateKeys` / `contextKeys`; `initialState` and\n * `initialContext` seed those signals at creation time. Any unseeded\n * signal starts as `undefined`.\n */\nexport interface CompositionOptions<S extends object, C extends object, Cfg extends object> {\n /** Static configuration passed to every behavior. */\n config?: Cfg;\n /** Initial values for state signals — any subset of `keyof S`. */\n initialState?: Partial<S>;\n /** Initial values for context signals — any subset of `keyof C`. */\n initialContext?: Partial<C>;\n}\n\n/**\n * Create a composition from a set of behaviors.\n *\n * Composition unions the behaviors' declared `stateKeys` / `contextKeys`\n * to know which signals to create. Each signal is seeded from\n * `initialState` / `initialContext` when supplied, defaulting to\n * `undefined`. Behaviors are responsible for writing their own slots\n * once their preconditions are met.\n *\n * Cross-behavior type conflicts (e.g. two behaviors disagreeing on a\n * field's type) surface as a compose-time type error via\n * `ValidateComposition`.\n *\n * @example\n * ```ts\n * const composition = createComposition([resolvePresentation, switchVideoTrack], {\n * config: { parsePresentation: parseMultivariantPlaylist, initialBandwidth: 2_000_000 },\n * initialState: { bandwidthState: { fastEstimate: 0, ... } },\n * });\n * ```\n */\n/**\n * Create a typed signal map for a given set of keys, seeded from an\n * optional partial initial value.\n *\n * Pipeline: `Set` dedupes the iterable (insertion order preserved, so\n * first occurrence wins) → `Object.fromEntries` materializes one\n * `signal()` per unique key, seeded from `initial[key]` or `undefined`.\n *\n * Per-key value types live in TypeScript only — at runtime every signal\n * is `Signal<unknown>`. The boundary cast at the return narrows the wide\n * `Record<PropertyKey, Signal<unknown>>` shape to the caller's expected\n * per-key types from `S`.\n *\n * Used by `createComposition` to derive engine state/context maps from\n * the union of behaviors' declared `stateKeys` / `contextKeys`.\n *\n * @example\n * ```ts\n * interface State { count?: number; label?: string }\n * const state = buildSignalMap<State>(['count', 'label'], { count: 5 });\n * state.count.get(); // 5\n * state.label.get(); // undefined\n * ```\n */\nexport function buildSignalMap<S extends object>(\n keys: Iterable<PropertyKey>,\n initial: Partial<S>\n): { [K in keyof S]-?: Signal<S[K]> } {\n const init = initial as Record<PropertyKey, unknown>;\n const uniqueKeys = new Set(keys);\n return Object.fromEntries([...uniqueKeys].map((key) => [key, signal(init[key])])) as {\n [K in keyof S]-?: Signal<S[K]>;\n };\n}\n\nexport function createComposition<const Behaviors extends readonly AnyBehavior[]>(\n behaviors: ValidateComposition<Behaviors>,\n options?: CompositionOptions<\n ResolveBehaviorState<Behaviors>,\n ResolveBehaviorContext<Behaviors>,\n ResolveBehaviorConfig<Behaviors>\n >\n): Composition<ResolveBehaviorState<Behaviors>, ResolveBehaviorContext<Behaviors>> {\n type S = ResolveBehaviorState<Behaviors>;\n type C = ResolveBehaviorContext<Behaviors>;\n type Cfg = ResolveBehaviorConfig<Behaviors>;\n\n // ValidateComposition<Behaviors> is `[...Behaviors]` on success, an error\n // string on conflict. The function body only runs when the call typechecks\n // (i.e. the success case), so iterating as the behavior tuple is sound.\n const validBehaviors = behaviors as unknown as readonly AnyBehavior[];\n\n const state = buildSignalMap<S>(\n validBehaviors.flatMap((b) => b.stateKeys),\n options?.initialState ?? {}\n );\n const context = buildSignalMap<C>(\n validBehaviors.flatMap((b) => b.contextKeys),\n options?.initialContext ?? {}\n );\n\n const deps: BehaviorDeps<StateSignals<S>, ContextSignals<C>, Cfg> = {\n state,\n context,\n config: (options?.config ?? {}) as Cfg,\n };\n const cleanups = validBehaviors.map((behavior) => behavior.setup(deps));\n\n return {\n state,\n context,\n async destroy() {\n const results: (void | Promise<void>)[] = [];\n for (const cleanup of cleanups) {\n if (cleanup == null) continue;\n if (typeof cleanup === 'function') {\n results.push(cleanup());\n } else if ('destroy' in cleanup) {\n results.push(cleanup.destroy());\n }\n }\n await Promise.all(results);\n // Reset every signal to undefined as a final cleanup, matching the\n // prior post-destroy `owners.set({})` semantics. A later stage will\n // move per-signal cleanup into the behaviors that own the writes.\n for (const sig of Object.values(state) as Signal<unknown>[]) sig.set(undefined);\n for (const sig of Object.values(context) as Signal<unknown>[]) sig.set(undefined);\n },\n };\n}\n\n// =============================================================================\n// defineBehavior — typed factory with key/param consistency enforcement\n// =============================================================================\n\n/**\n * Compose-time exhaustiveness check.\n *\n * Adds a phantom error tag to the parameter shape when `Keys` does not\n * cover every key in `Slot`. The user's value won't satisfy the phantom\n * field requirement, so TS surfaces the failure at the call site with a\n * descriptive message. When exhaustive, the tag is `Empty` and adds no\n * constraint.\n */\ntype ExhaustiveKeys<Keys extends readonly PropertyKey[], Slot extends object, Name extends string> = [\n keyof Slot,\n] extends [Keys[number]]\n ? Empty\n : { [K in `Error: ${Name}Keys must list every key in the typed slice`]: Exclude<keyof Slot, Keys[number]> };\n\n/**\n * Typed factory for behaviors that enforces single-behavior key/param\n * consistency: declared `stateKeys` must equal `keyof S` (where `S` is\n * inferred from the setup's `state` parameter type), and same for\n * `contextKeys` / `C`.\n *\n * The `const` modifier on `SK` / `CK` captures literal tuples so e.g.\n * `stateKeys: ['preload']` infers as `readonly ['preload']`, no `as\n * const` needed at the call site.\n *\n * Cross-behavior consistency at `createComposition` is unchanged — the\n * existing `IntersectBehaviors` machinery still runs over each\n * behavior's setup param type.\n *\n * @example\n * ```ts\n * export const syncPreload = defineBehavior({\n * stateKeys: ['preload'],\n * contextKeys: ['mediaElement'],\n * setup: ({ state, context }: {\n * state: StateSignals<{ preload?: 'auto' | 'metadata' | 'none' }>;\n * context: ContextSignals<{ mediaElement?: HTMLMediaElement | undefined }>;\n * }) => { ... },\n * });\n * ```\n */\n/**\n * Deps shape for a behavior whose deps slot is empty (no keys). When a\n * slot is empty, the corresponding deps field is optional — callers\n * (typically tests) can omit it, and it defaults to `{}` at runtime via\n * `createComposition`.\n *\n * When a slot has at least one key, the behavior reads `state.foo` /\n * `context.bar` / `config.baz` and we need the field to be required so\n * the access is type-safe.\n */\ntype RequireIfNonEmpty<Key extends string, T extends object> = keyof T extends never\n ? { [K in Key]?: T }\n : { [K in Key]: T };\n\ntype DepsForCfg<StateMap extends AnySlotMap, ContextMap extends AnySlotMap, Cfg extends object> = RequireIfNonEmpty<\n 'state',\n StateMap\n> &\n RequireIfNonEmpty<'context', ContextMap> &\n RequireIfNonEmpty<'config', Cfg>;\n\nexport function defineBehavior<\n StateMap extends AnySlotMap = Empty,\n ContextMap extends AnySlotMap = Empty,\n Cfg extends object = Empty,\n const SK extends readonly (keyof StateMap)[] = readonly [],\n const CK extends readonly (keyof ContextMap)[] = readonly [],\n R extends BehaviorCleanup = BehaviorCleanup,\n>(\n behavior: {\n stateKeys: SK;\n contextKeys: CK;\n setup: (deps: { state: StateMap; context: ContextMap; config: Cfg }) => R;\n } & ExhaustiveKeys<SK, StateMap, 'state'> &\n ExhaustiveKeys<CK, ContextMap, 'context'>\n): {\n stateKeys: SK;\n contextKeys: CK;\n setup: (deps: DepsForCfg<StateMap, ContextMap, Cfg>) => R;\n} {\n // The runtime shape is identical; the cast bridges TS's view of the\n // parameter (config required) to the return view (config optional when\n // Cfg has no keys).\n return behavior as unknown as {\n stateKeys: SK;\n contextKeys: CK;\n setup: (deps: DepsForCfg<StateMap, ContextMap, Cfg>) => R;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsSA,SAAgB,eACd,MACA,SACoC;CACpC,MAAM,OAAO;CACb,MAAM,aAAa,IAAI,IAAI,IAAI;CAC/B,OAAO,OAAO,YAAY,CAAC,GAAG,UAAU,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC;AAGlF;AAEA,SAAgB,kBACd,WACA,SAKiF;CAQjF,MAAM,iBAAiB;CAEvB,MAAM,QAAQ,eACZ,eAAe,SAAS,MAAM,EAAE,SAAS,GACzC,SAAS,gBAAgB,CAAC,CAC5B;CACA,MAAM,UAAU,eACd,eAAe,SAAS,MAAM,EAAE,WAAW,GAC3C,SAAS,kBAAkB,CAAC,CAC9B;CAEA,MAAM,OAA8D;EAClE;EACA;EACA,QAAS,SAAS,UAAU,CAAC;CAC/B;CACA,MAAM,WAAW,eAAe,KAAK,aAAa,SAAS,MAAM,IAAI,CAAC;CAEtE,OAAO;EACL;EACA;EACA,MAAM,UAAU;GACd,MAAM,UAAoC,CAAC;GAC3C,KAAK,MAAM,WAAW,UAAU;IAC9B,IAAI,WAAW,MAAM;IACrB,IAAI,OAAO,YAAY,YACrB,QAAQ,KAAK,QAAQ,CAAC;SACjB,IAAI,aAAa,SACtB,QAAQ,KAAK,QAAQ,QAAQ,CAAC;GAElC;GACA,MAAM,QAAQ,IAAI,OAAO;GAIzB,KAAK,MAAM,OAAO,OAAO,OAAO,KAAK,GAAwB,IAAI,IAAI,KAAA,CAAS;GAC9E,KAAK,MAAM,OAAO,OAAO,OAAO,OAAO,GAAwB,IAAI,IAAI,KAAA,CAAS;EAClF;CACF;AACF;AAoEA,SAAgB,eAQd,UAUA;CAIA,OAAO;AAKT"}
1
+ {"version":3,"file":"create-composition.js","names":[],"sources":["../../../../src/core/composition/create-composition.ts"],"sourcesContent":["import { type ReadonlySignal, type Signal, signal } from '../signals/primitives';\n\n/**\n * Cleanup returned by a behavior. Behaviors may return: - `void` / `undefined` — no cleanup needed - A function —\n * called on destroy (may return a Promise) - An object with `destroy()` — called on destroy (may return a Promise)\n */\nexport type BehaviorCleanup = void | (() => void | Promise<void>) | { destroy(): void | Promise<void> };\n\n/**\n * A signal map keyed by the fields of `S`. Each field is a writable signal.\n *\n * Optional fields on `S` map to required signal slots whose value type includes `undefined`, ensuring every key has a\n * signal even when the underlying value is absent.\n *\n * Used in two roles:\n *\n * - Engine-side **construction**: `Composition<S, C>` exposes its public surface as `StateSignals<S>` (everything\n * writable) so external code can read or write any slot.\n * - Behavior **input convenience**: a behavior that writes to every slot can type its setup state param as\n * `StateSignals<{ ... }>` rather than spelling out per-slot `Signal<T>` types.\n *\n * Behaviors that mix read-only and writable slots type the setup param directly as a slot map (`{ x: Signal<T>; y:\n * ReadonlySignal<U> }`) instead of going through `StateSignals<>`.\n */\nexport type StateSignals<S extends object> = { [K in keyof S]-?: Signal<S[K]> };\n\n/**\n * A signal map keyed by the fields of `C`. Each field is a writable signal for a platform object or actor reference.\n * Same dual role as `StateSignals<S>` — see its docblock.\n */\nexport type ContextSignals<C extends object> = { [K in keyof C]-?: Signal<C[K]> };\n\n/**\n * Slot-map shape — a record where each value is at least a `ReadonlySignal`. `Signal<T>` is structurally a subtype of\n * `ReadonlySignal<T>` (it adds `.set()`), so a writable slot satisfies this bound too.\n *\n * This is the bound used for behavior `state` / `context` slot maps. It lets a single behavior declare a\n * _heterogeneous_ slot map where some slots are `Signal<T>` (writable) and others are `ReadonlySignal<T>` (read-only) —\n * making read/write intent explicit at the call site and giving body-level enforcement (TS rejects `.set()` on a\n * read-only slot).\n */\nexport type AnySlotMap = Record<PropertyKey, ReadonlySignal<unknown>>;\n\n/**\n * The deps object passed to each behavior by the composition.\n *\n * - `state` — slot map for state fields (reactive data). Per-slot read/ write intent expressed via `Signal<T>` vs\n * `ReadonlySignal<T>`.\n * - `context` — slot map for platform objects and actor references.\n * - `config` — static configuration, passed once at composition creation.\n */\nexport interface BehaviorDeps<StateMap extends AnySlotMap, ContextMap extends AnySlotMap, Cfg extends object> {\n state: StateMap;\n context: ContextMap;\n config: Cfg;\n}\n\n/**\n * A behavior announces the state and context keys it needs alongside a `setup` function that receives deps (state,\n * context, config) and returns an optional cleanup handle.\n *\n * The `stateKeys` / `contextKeys` declarations are the runtime expression of the behavior's contract — the caller (e.g.\n * `createComposition`) uses them to know which signals to provide. The setup parameter type declares the _slot map_\n * (per-slot `Signal<T>` vs `ReadonlySignal<T>`); together they form a complete contract.\n *\n * Manual `Behavior<>` literals (e.g. engine wrappers that forward keys from a wrapped behavior, or pass-through\n * behaviors like `shareSignals`) opt out of exhaustiveness — the type alias is permissive (subset). Source behaviors\n * should use `defineBehavior` to get exhaustiveness enforcement at the call site.\n */\nexport interface Behavior<\n StateMap extends AnySlotMap = Empty,\n ContextMap extends AnySlotMap = Empty,\n Cfg extends object = Empty,\n> {\n /** State keys this behavior reads/writes. Subset of `keyof StateMap`. */\n stateKeys: readonly (keyof StateMap)[];\n /** Context keys this behavior reads/writes. Subset of `keyof ContextMap`. */\n contextKeys: readonly (keyof ContextMap)[];\n setup: (deps: BehaviorDeps<StateMap, ContextMap, Cfg>) => BehaviorCleanup;\n}\n\n// =============================================================================\n// Behavior type inference\n// =============================================================================\n\n/** A behavior with an unconstrained setup — used as a generic bound. */\ntype AnyBehavior = {\n stateKeys: readonly PropertyKey[];\n contextKeys: readonly PropertyKey[];\n setup: (deps: any) => BehaviorCleanup;\n};\n\n/** Extract the deps type from a behavior's setup function. */\ntype DepsOf<B> = B extends { setup: (deps: infer D, ...args: any[]) => any } ? D : never;\n\n/**\n * Empty-object fallback used when a behavior omits state, context, or config.\n *\n * Using `{}` rather than `object` is deliberate — `object & {x: T}` collapses to `{x: never}` under TS's\n * union-to-intersection conversion in some inference contexts (likely a TS quirk around the `object` upper bound),\n * whereas `{} & {x: T}` simplifies cleanly to `{x: T}`.\n */\n// see comment above\n// oxlint-disable-next-line typescript/no-empty-object-type\ntype Empty = {};\n\n/**\n * Unwrap a signal map back to its state/context shape.\n *\n * Inferring through `{ get(): infer V }` rather than `Signal<infer V>` sidesteps `Signal`'s nominal/invariance\n * behaviour — the conditional matches structurally on the read side, and `V` is inferred covariantly.\n */\ntype UnwrapSignals<M> = M extends object ? { [K in keyof M]: M[K] extends { get(): infer V } ? V : never } : Empty;\n\n/** Infer the state shape a behavior requires from its deps parameter. */\nexport type InferBehaviorState<F> = DepsOf<F> extends { state: infer M } ? UnwrapSignals<M> : Empty;\n\n/** Infer the context shape a behavior requires from its deps parameter. */\nexport type InferBehaviorContext<F> = DepsOf<F> extends { context: infer M } ? UnwrapSignals<M> : Empty;\n\n/** Infer the config shape a behavior requires from its deps parameter. */\nexport type InferBehaviorConfig<F> = DepsOf<F> extends { config: infer C extends object } ? C : Empty;\n\n/**\n * Recursively intersect a per-behavior projection across the tuple.\n *\n * Iterating over the tuple directly avoids `UnionToIntersection`'s function-contravariance trick, which produces\n * unstable intersections (collapsing concrete fields to `never` or unrelated types) when one of the union members is\n * the empty `{}` fallback.\n */\ntype IntersectBehaviors<Behaviors extends readonly AnyBehavior[], Project extends object> = Behaviors extends readonly [\n infer First extends AnyBehavior,\n ...infer Rest extends readonly AnyBehavior[],\n]\n ? Apply<Project, First> & IntersectBehaviors<Rest, Project>\n : Empty;\n\n/**\n * Apply a projection (one of the marker types below) to a single behavior. Encoded as a discriminated dispatch so the\n * recursion above can stay generic and we don't have to write three near-identical recursive types.\n */\ntype Apply<Project extends object, F> = Project extends { kind: 'state' }\n ? InferBehaviorState<F>\n : Project extends { kind: 'context' }\n ? InferBehaviorContext<F>\n : Project extends { kind: 'config' }\n ? InferBehaviorConfig<F>\n : never;\n\ntype StateProjection = { kind: 'state' };\ntype ContextProjection = { kind: 'context' };\ntype ConfigProjection = { kind: 'config' };\n\n/** Resolve the combined state shape from an array of behaviors (intersection of all requirements). */\nexport type ResolveBehaviorState<Behaviors extends readonly AnyBehavior[]> =\n IntersectBehaviors<Behaviors, StateProjection> extends infer R extends object ? R : Empty;\n\n/** Resolve the combined context shape from an array of behaviors (intersection of all requirements). */\nexport type ResolveBehaviorContext<Behaviors extends readonly AnyBehavior[]> =\n IntersectBehaviors<Behaviors, ContextProjection> extends infer R extends object ? R : Empty;\n\n/** Resolve the combined config shape from an array of behaviors (intersection of all requirements). */\nexport type ResolveBehaviorConfig<Behaviors extends readonly AnyBehavior[]> =\n IntersectBehaviors<Behaviors, ConfigProjection> extends infer R extends object ? R : Empty;\n\n/**\n * True if any property in `T` collapsed to `undefined` or `never` — indicating a type conflict from intersecting\n * incompatible behavior requirements.\n *\n * - Required conflicts: `{ v: number } & { v: string }` → `{ v: never }` — caught via `[never] extends [undefined]`\n * - Optional conflicts: `{ v?: number } & { v?: string }` → `{ v?: undefined }` — caught directly\n */\ntype HasConflict<T extends object> = true extends {\n [K in keyof T]: [T[K]] extends [undefined] ? true : never;\n}[keyof T]\n ? true\n : false;\n\n// =============================================================================\n// Composition validation\n// =============================================================================\n\n/**\n * Validate that a behavior composition has no type conflicts. Returns the behaviors tuple if valid, or an error message\n * type if conflicts are detected.\n *\n * State, context, and config are all checked the same way — by intersecting each behavior's requirement and looking for\n * collapsed fields. The intersection-based check applies the same rule to context as to state, so two behaviors that\n * disagree on a context field's type (e.g. `Surface` vs `VideoSurface`) surface a conflict at compose time. The prior\n * subtype-based approach for owners is gone — the unified rule is simpler and catches the cases where two behaviors\n * silently agreed on a wider supertype.\n */\ntype ValidateComposition<Behaviors extends readonly AnyBehavior[]> =\n HasConflict<ResolveBehaviorState<Behaviors>> extends true\n ? 'Error: behaviors have conflicting state types'\n : HasConflict<ResolveBehaviorContext<Behaviors>> extends true\n ? 'Error: behaviors have conflicting context types'\n : HasConflict<ResolveBehaviorConfig<Behaviors>> extends true\n ? 'Error: behaviors have conflicting config types'\n : [...Behaviors];\n\n// =============================================================================\n// Composition\n// =============================================================================\n\n/** A composition of behaviors with shared state and context signal maps. */\nexport interface Composition<S extends object, C extends object> {\n state: StateSignals<S>;\n context: ContextSignals<C>;\n destroy(): Promise<void>;\n}\n\n/**\n * Options for `createComposition`.\n *\n * Composition derives the state and context signal maps from each behavior's declared `stateKeys` / `contextKeys`;\n * `initialState` and `initialContext` seed those signals at creation time. Any unseeded signal starts as `undefined`.\n */\nexport interface CompositionOptions<S extends object, C extends object, Cfg extends object> {\n /** Static configuration passed to every behavior. */\n config?: Cfg;\n /** Initial values for state signals — any subset of `keyof S`. */\n initialState?: Partial<S>;\n /** Initial values for context signals — any subset of `keyof C`. */\n initialContext?: Partial<C>;\n}\n\n/**\n * Create a composition from a set of behaviors.\n *\n * Composition unions the behaviors' declared `stateKeys` / `contextKeys` to know which signals to create. Each signal\n * is seeded from `initialState` / `initialContext` when supplied, defaulting to `undefined`. Behaviors are responsible\n * for writing their own slots once their preconditions are met.\n *\n * Cross-behavior type conflicts (e.g. two behaviors disagreeing on a field's type) surface as a compose-time type error\n * via `ValidateComposition`.\n *\n * @example\n * ```ts\n * const composition = createComposition([resolvePresentation, switchVideoTrack], {\n * config: { parsePresentation: parseMultivariantPlaylist, initialBandwidth: 2_000_000 },\n * initialState: { bandwidthState: { fastEstimate: 0, ... } },\n * });\n * ```;\n */\n/**\n * Create a typed signal map for a given set of keys, seeded from an optional partial initial value.\n *\n * Pipeline: `Set` dedupes the iterable (insertion order preserved, so first occurrence wins) → `Object.fromEntries`\n * materializes one `signal()` per unique key, seeded from `initial[key]` or `undefined`.\n *\n * Per-key value types live in TypeScript only — at runtime every signal is `Signal<unknown>`. The boundary cast at the\n * return narrows the wide `Record<PropertyKey, Signal<unknown>>` shape to the caller's expected per-key types from\n * `S`.\n *\n * Used by `createComposition` to derive engine state/context maps from the union of behaviors' declared `stateKeys` /\n * `contextKeys`.\n *\n * @example\n * ```ts\n * interface State {\n * count?: number;\n * label?: string;\n * }\n * const state = buildSignalMap<State>(['count', 'label'], { count: 5 });\n * state.count.get(); // 5\n * state.label.get(); // undefined\n * ```;\n */\nexport function buildSignalMap<S extends object>(\n keys: Iterable<PropertyKey>,\n initial: Partial<S>\n): { [K in keyof S]-?: Signal<S[K]> } {\n const init = initial as Record<PropertyKey, unknown>;\n const uniqueKeys = new Set(keys);\n\n return Object.fromEntries([...uniqueKeys].map((key) => [key, signal(init[key])])) as {\n [K in keyof S]-?: Signal<S[K]>;\n };\n}\n\nexport function createComposition<const Behaviors extends readonly AnyBehavior[]>(\n behaviors: ValidateComposition<Behaviors>,\n options?: CompositionOptions<\n ResolveBehaviorState<Behaviors>,\n ResolveBehaviorContext<Behaviors>,\n ResolveBehaviorConfig<Behaviors>\n >\n): Composition<ResolveBehaviorState<Behaviors>, ResolveBehaviorContext<Behaviors>> {\n type S = ResolveBehaviorState<Behaviors>;\n type C = ResolveBehaviorContext<Behaviors>;\n type Cfg = ResolveBehaviorConfig<Behaviors>;\n\n // ValidateComposition<Behaviors> is `[...Behaviors]` on success, an error\n // string on conflict. The function body only runs when the call typechecks\n // (i.e. the success case), so iterating as the behavior tuple is sound.\n const validBehaviors = behaviors as unknown as readonly AnyBehavior[];\n\n const state = buildSignalMap<S>(\n validBehaviors.flatMap((b) => b.stateKeys),\n options?.initialState ?? {}\n );\n const context = buildSignalMap<C>(\n validBehaviors.flatMap((b) => b.contextKeys),\n options?.initialContext ?? {}\n );\n\n const deps: BehaviorDeps<StateSignals<S>, ContextSignals<C>, Cfg> = {\n state,\n context,\n config: (options?.config ?? {}) as Cfg,\n };\n const cleanups = validBehaviors.map((behavior) => behavior.setup(deps));\n\n return {\n state,\n context,\n async destroy() {\n const results: (void | Promise<void>)[] = [];\n\n for (const cleanup of cleanups) {\n if (cleanup == null) continue;\n\n if (typeof cleanup === 'function') {\n results.push(cleanup());\n } else if ('destroy' in cleanup) {\n results.push(cleanup.destroy());\n }\n }\n\n await Promise.all(results);\n\n // Reset every signal to undefined as a final cleanup, matching the\n // prior post-destroy `owners.set({})` semantics. A later stage will\n // move per-signal cleanup into the behaviors that own the writes.\n for (const sig of Object.values(state) as Signal<unknown>[]) sig.set(undefined);\n\n for (const sig of Object.values(context) as Signal<unknown>[]) sig.set(undefined);\n },\n };\n}\n\n// =============================================================================\n// defineBehavior — typed factory with key/param consistency enforcement\n// =============================================================================\n\n/**\n * Compose-time exhaustiveness check.\n *\n * Adds a phantom error tag to the parameter shape when `Keys` does not cover every key in `Slot`. The user's value\n * won't satisfy the phantom field requirement, so TS surfaces the failure at the call site with a descriptive message.\n * When exhaustive, the tag is `Empty` and adds no constraint.\n */\ntype ExhaustiveKeys<Keys extends readonly PropertyKey[], Slot extends object, Name extends string> = [\n keyof Slot,\n] extends [Keys[number]]\n ? Empty\n : { [K in `Error: ${Name}Keys must list every key in the typed slice`]: Exclude<keyof Slot, Keys[number]> };\n\n/**\n * Typed factory for behaviors that enforces single-behavior key/param consistency: declared `stateKeys` must equal\n * `keyof S` (where `S` is inferred from the setup's `state` parameter type), and same for `contextKeys` / `C`.\n *\n * The `const` modifier on `SK` / `CK` captures literal tuples so e.g. `stateKeys: ['preload']` infers as `readonly\n * ['preload']`, no `as const` needed at the call site.\n *\n * Cross-behavior consistency at `createComposition` is unchanged — the existing `IntersectBehaviors` machinery still\n * runs over each behavior's setup param type.\n *\n * @example\n * ```ts\n * export const syncPreload = defineBehavior({\n * stateKeys: ['preload'],\n * contextKeys: ['mediaElement'],\n * setup: ({ state, context }: {\n * state: StateSignals<{ preload?: 'auto' | 'metadata' | 'none' }>;\n * context: ContextSignals<{ mediaElement?: HTMLMediaElement | undefined }>;\n * }) => { ... },\n * });\n * ```;\n */\n/**\n * Deps shape for a behavior whose deps slot is empty (no keys). When a slot is empty, the corresponding deps field is\n * optional — callers (typically tests) can omit it, and it defaults to `{}` at runtime via `createComposition`.\n *\n * When a slot has at least one key, the behavior reads `state.foo` / `context.bar` / `config.baz` and we need the field\n * to be required so the access is type-safe.\n */\ntype RequireIfNonEmpty<Key extends string, T extends object> = keyof T extends never\n ? { [K in Key]?: T }\n : { [K in Key]: T };\n\ntype DepsForCfg<StateMap extends AnySlotMap, ContextMap extends AnySlotMap, Cfg extends object> = RequireIfNonEmpty<\n 'state',\n StateMap\n> &\n RequireIfNonEmpty<'context', ContextMap> &\n RequireIfNonEmpty<'config', Cfg>;\n\nexport function defineBehavior<\n StateMap extends AnySlotMap = Empty,\n ContextMap extends AnySlotMap = Empty,\n Cfg extends object = Empty,\n const SK extends readonly (keyof StateMap)[] = readonly [],\n const CK extends readonly (keyof ContextMap)[] = readonly [],\n R extends BehaviorCleanup = BehaviorCleanup,\n>(\n behavior: {\n stateKeys: SK;\n contextKeys: CK;\n setup: (deps: { state: StateMap; context: ContextMap; config: Cfg }) => R;\n } & ExhaustiveKeys<SK, StateMap, 'state'> &\n ExhaustiveKeys<CK, ContextMap, 'context'>\n): {\n stateKeys: SK;\n contextKeys: CK;\n setup: (deps: DepsForCfg<StateMap, ContextMap, Cfg>) => R;\n} {\n // The runtime shape is identical; the cast bridges TS's view of the\n // parameter (config required) to the return view (config optional when\n // Cfg has no keys).\n return behavior as unknown as {\n stateKeys: SK;\n contextKeys: CK;\n setup: (deps: DepsForCfg<StateMap, ContextMap, Cfg>) => R;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6QA,SAAgB,eACd,MACA,SACoC;CACpC,MAAM,OAAO;CACb,MAAM,aAAa,IAAI,IAAI,IAAI;CAE/B,OAAO,OAAO,YAAY,CAAC,GAAG,UAAU,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC;AAGlF;AAEA,SAAgB,kBACd,WACA,SAKiF;CAQjF,MAAM,iBAAiB;CAEvB,MAAM,QAAQ,eACZ,eAAe,SAAS,MAAM,EAAE,SAAS,GACzC,SAAS,gBAAgB,CAAC,CAC5B;CACA,MAAM,UAAU,eACd,eAAe,SAAS,MAAM,EAAE,WAAW,GAC3C,SAAS,kBAAkB,CAAC,CAC9B;CAEA,MAAM,OAA8D;EAClE;EACA;EACA,QAAS,SAAS,UAAU,CAAC;CAC/B;CACA,MAAM,WAAW,eAAe,KAAK,aAAa,SAAS,MAAM,IAAI,CAAC;CAEtE,OAAO;EACL;EACA;EACA,MAAM,UAAU;GACd,MAAM,UAAoC,CAAC;GAE3C,KAAK,MAAM,WAAW,UAAU;IAC9B,IAAI,WAAW,MAAM;IAErB,IAAI,OAAO,YAAY,YACrB,QAAQ,KAAK,QAAQ,CAAC;SACjB,IAAI,aAAa,SACtB,QAAQ,KAAK,QAAQ,QAAQ,CAAC;GAElC;GAEA,MAAM,QAAQ,IAAI,OAAO;GAKzB,KAAK,MAAM,OAAO,OAAO,OAAO,KAAK,GAAwB,IAAI,IAAI,KAAA,CAAS;GAE9E,KAAK,MAAM,OAAO,OAAO,OAAO,OAAO,GAAwB,IAAI,IAAI,KAAA,CAAS;EAClF;CACF;AACF;AA2DA,SAAgB,eAQd,UAUA;CAIA,OAAO;AAKT"}
@@ -3,14 +3,12 @@ import { Behavior, ContextSignals, StateSignals } from "./create-composition.js"
3
3
  /**
4
4
  * Config consumed by the `shareSignals` behavior.
5
5
  *
6
- * The callback fires once during composition setup with the composition's
7
- * state and context signal refs. Capture them to drive the composition
8
- * externally (writes) or observe its state (reads).
6
+ * The callback fires once during composition setup with the composition's state and context signal refs. Capture them
7
+ * to drive the composition externally (writes) or observe its state (reads).
9
8
  *
10
- * The callback runs while other behaviors are still in their setup phase —
11
- * for the typical "capture refs, use later" pattern this is fine (signal
12
- * refs are stable identities), but reading inside the callback may yield
13
- * only initial-seed values rather than what later behaviors write.
9
+ * The callback runs while other behaviors are still in their setup phase — for the typical "capture refs, use later"
10
+ * pattern this is fine (signal refs are stable identities), but reading inside the callback may yield only initial-seed
11
+ * values rather than what later behaviors write.
14
12
  */
15
13
  interface ShareSignalsConfig<S extends object, C extends object> {
16
14
  onSignalsReady?: (signals: {
@@ -19,26 +17,21 @@ interface ShareSignalsConfig<S extends object, C extends object> {
19
17
  }) => void;
20
18
  }
21
19
  /**
22
- * Behavior factory that hands the composition's signal refs to a
23
- * consumer-supplied callback (`config.onSignalsReady`) at setup time.
20
+ * Behavior factory that hands the composition's signal refs to a consumer-supplied callback (`config.onSignalsReady`)
21
+ * at setup time.
24
22
  *
25
- * Generic over `S` and `C` — the caller instantiates with their own
26
- * state/context types, and the callback's parameter shape is fully
27
- * type-driven from those. Suitable for both reads and writes (per-slot
28
- * intent can be expressed by typing captured refs as `Signal<T>` or
29
- * `ReadonlySignal<T>` at the call site).
23
+ * Generic over `S` and `C` — the caller instantiates with their own state/context types, and the callback's parameter
24
+ * shape is fully type-driven from those. Suitable for both reads and writes (per-slot intent can be expressed by typing
25
+ * captured refs as `Signal<T>` or `ReadonlySignal<T>` at the call site).
30
26
  *
31
- * By default declares no keys; the composition's state/context maps come from
32
- * other behaviors. Pass `inputStateKeys` / `inputContextKeys` to *materialize*
33
- * consumer-input slots that no other behavior produces a slot the consumer
34
- * writes (e.g. `userAudioTrackSelection`) but only a rule reads. shareSignals
35
- * is the consumer boundary, so it's the natural place to bring those slots into
36
- * existence; readers then treat them as optional.
27
+ * By default declares no keys; the composition's state/context maps come from other behaviors. Pass `inputStateKeys` /
28
+ * `inputContextKeys` to _materialize_ consumer-input slots that no other behavior produces a slot the consumer writes
29
+ * (e.g. `userAudioTrackSelection`) but only a rule reads. shareSignals is the consumer boundary, so it's the natural
30
+ * place to bring those slots into existence; readers then treat them as optional.
37
31
  *
38
- * Uses a `Behavior<>` literal (not `defineBehavior`) so its (possibly empty,
39
- * possibly partial) key arrays don't trip the exhaustiveness check the
40
- * setup-param state/context shapes describe what the callback receives (the
41
- * full `S` / `C`), not the subset this behavior materializes.
32
+ * Uses a `Behavior<>` literal (not `defineBehavior`) so its (possibly empty, possibly partial) key arrays don't trip
33
+ * the exhaustiveness check the setup-param state/context shapes describe what the callback receives (the full `S` /
34
+ * `C`), not the subset this behavior materializes.
42
35
  */
43
36
  declare function makeShareSignals<S extends object, C extends object>(inputStateKeys?: readonly (keyof S)[], inputContextKeys?: readonly (keyof C)[]): Behavior<StateSignals<S>, ContextSignals<C>, ShareSignalsConfig<S, C>>;
44
37
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"share-signals.d.ts","names":[],"sources":["../../../../src/core/composition/share-signals.ts"],"mappings":";;;;;;;;;;;;;;UAciB,mBAAmB,kBAAkB;EACpD,kBAAkB;IAAW,OAAO,aAAa;IAAI,SAAS,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;iBAyB/D,iBAAiB,kBAAkB,kBACjD,iCAAgC,MAChC,mCAAkC,OACjC,SAAS,aAAa,IAAI,eAAe,IAAI,mBAAmB,GAAG"}
1
+ {"version":3,"file":"share-signals.d.ts","names":[],"sources":["../../../../src/core/composition/share-signals.ts"],"mappings":";;;;;;;;;;;;UAYiB,mBAAmB,kBAAkB;EACpD,kBAAkB;IAAW,OAAO,aAAa;IAAI,SAAS,eAAe;;;;;;;;;;;;;;;;;;;;iBAoB/D,iBAAiB,kBAAkB,kBACjD,iCAAgC,MAChC,mCAAkC,OACjC,SAAS,aAAa,IAAI,eAAe,IAAI,mBAAmB,GAAG"}
@@ -1,25 +1,20 @@
1
1
  //#region src/core/composition/share-signals.ts
2
2
  /**
3
- * Behavior factory that hands the composition's signal refs to a
4
- * consumer-supplied callback (`config.onSignalsReady`) at setup time.
3
+ * Behavior factory that hands the composition's signal refs to a consumer-supplied callback (`config.onSignalsReady`)
4
+ * at setup time.
5
5
  *
6
- * Generic over `S` and `C` — the caller instantiates with their own
7
- * state/context types, and the callback's parameter shape is fully
8
- * type-driven from those. Suitable for both reads and writes (per-slot
9
- * intent can be expressed by typing captured refs as `Signal<T>` or
10
- * `ReadonlySignal<T>` at the call site).
6
+ * Generic over `S` and `C` — the caller instantiates with their own state/context types, and the callback's parameter
7
+ * shape is fully type-driven from those. Suitable for both reads and writes (per-slot intent can be expressed by typing
8
+ * captured refs as `Signal<T>` or `ReadonlySignal<T>` at the call site).
11
9
  *
12
- * By default declares no keys; the composition's state/context maps come from
13
- * other behaviors. Pass `inputStateKeys` / `inputContextKeys` to *materialize*
14
- * consumer-input slots that no other behavior produces a slot the consumer
15
- * writes (e.g. `userAudioTrackSelection`) but only a rule reads. shareSignals
16
- * is the consumer boundary, so it's the natural place to bring those slots into
17
- * existence; readers then treat them as optional.
10
+ * By default declares no keys; the composition's state/context maps come from other behaviors. Pass `inputStateKeys` /
11
+ * `inputContextKeys` to _materialize_ consumer-input slots that no other behavior produces a slot the consumer writes
12
+ * (e.g. `userAudioTrackSelection`) but only a rule reads. shareSignals is the consumer boundary, so it's the natural
13
+ * place to bring those slots into existence; readers then treat them as optional.
18
14
  *
19
- * Uses a `Behavior<>` literal (not `defineBehavior`) so its (possibly empty,
20
- * possibly partial) key arrays don't trip the exhaustiveness check the
21
- * setup-param state/context shapes describe what the callback receives (the
22
- * full `S` / `C`), not the subset this behavior materializes.
15
+ * Uses a `Behavior<>` literal (not `defineBehavior`) so its (possibly empty, possibly partial) key arrays don't trip
16
+ * the exhaustiveness check the setup-param state/context shapes describe what the callback receives (the full `S` /
17
+ * `C`), not the subset this behavior materializes.
23
18
  */
24
19
  function makeShareSignals(inputStateKeys = [], inputContextKeys = []) {
25
20
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"share-signals.js","names":[],"sources":["../../../../src/core/composition/share-signals.ts"],"sourcesContent":["import type { Behavior, ContextSignals, StateSignals } from './create-composition';\n\n/**\n * Config consumed by the `shareSignals` behavior.\n *\n * The callback fires once during composition setup with the composition's\n * state and context signal refs. Capture them to drive the composition\n * externally (writes) or observe its state (reads).\n *\n * The callback runs while other behaviors are still in their setup phase —\n * for the typical \"capture refs, use later\" pattern this is fine (signal\n * refs are stable identities), but reading inside the callback may yield\n * only initial-seed values rather than what later behaviors write.\n */\nexport interface ShareSignalsConfig<S extends object, C extends object> {\n onSignalsReady?: (signals: { state: StateSignals<S>; context: ContextSignals<C> }) => void;\n}\n\n/**\n * Behavior factory that hands the composition's signal refs to a\n * consumer-supplied callback (`config.onSignalsReady`) at setup time.\n *\n * Generic over `S` and `C` — the caller instantiates with their own\n * state/context types, and the callback's parameter shape is fully\n * type-driven from those. Suitable for both reads and writes (per-slot\n * intent can be expressed by typing captured refs as `Signal<T>` or\n * `ReadonlySignal<T>` at the call site).\n *\n * By default declares no keys; the composition's state/context maps come from\n * other behaviors. Pass `inputStateKeys` / `inputContextKeys` to *materialize*\n * consumer-input slots that no other behavior produces — a slot the consumer\n * writes (e.g. `userAudioTrackSelection`) but only a rule reads. shareSignals\n * is the consumer boundary, so it's the natural place to bring those slots into\n * existence; readers then treat them as optional.\n *\n * Uses a `Behavior<>` literal (not `defineBehavior`) so its (possibly empty,\n * possibly partial) key arrays don't trip the exhaustiveness check — the\n * setup-param state/context shapes describe what the callback receives (the\n * full `S` / `C`), not the subset this behavior materializes.\n */\nexport function makeShareSignals<S extends object, C extends object>(\n inputStateKeys: readonly (keyof S)[] = [],\n inputContextKeys: readonly (keyof C)[] = []\n): Behavior<StateSignals<S>, ContextSignals<C>, ShareSignalsConfig<S, C>> {\n return {\n stateKeys: inputStateKeys,\n contextKeys: inputContextKeys,\n setup: ({ state, context, config }) => {\n config.onSignalsReady?.({ state, context });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwCA,SAAgB,iBACd,iBAAuC,CAAC,GACxC,mBAAyC,CAAC,GAC8B;CACxE,OAAO;EACL,WAAW;EACX,aAAa;EACb,QAAQ,EAAE,OAAO,SAAS,aAAa;GACrC,OAAO,iBAAiB;IAAE;IAAO;GAAQ,CAAC;EAC5C;CACF;AACF"}
1
+ {"version":3,"file":"share-signals.js","names":[],"sources":["../../../../src/core/composition/share-signals.ts"],"sourcesContent":["import type { Behavior, ContextSignals, StateSignals } from './create-composition';\n\n/**\n * Config consumed by the `shareSignals` behavior.\n *\n * The callback fires once during composition setup with the composition's state and context signal refs. Capture them\n * to drive the composition externally (writes) or observe its state (reads).\n *\n * The callback runs while other behaviors are still in their setup phase for the typical \"capture refs, use later\"\n * pattern this is fine (signal refs are stable identities), but reading inside the callback may yield only initial-seed\n * values rather than what later behaviors write.\n */\nexport interface ShareSignalsConfig<S extends object, C extends object> {\n onSignalsReady?: (signals: { state: StateSignals<S>; context: ContextSignals<C> }) => void;\n}\n\n/**\n * Behavior factory that hands the composition's signal refs to a consumer-supplied callback (`config.onSignalsReady`)\n * at setup time.\n *\n * Generic over `S` and `C` — the caller instantiates with their own state/context types, and the callback's parameter\n * shape is fully type-driven from those. Suitable for both reads and writes (per-slot intent can be expressed by typing\n * captured refs as `Signal<T>` or `ReadonlySignal<T>` at the call site).\n *\n * By default declares no keys; the composition's state/context maps come from other behaviors. Pass `inputStateKeys` /\n * `inputContextKeys` to _materialize_ consumer-input slots that no other behavior produces — a slot the consumer writes\n * (e.g. `userAudioTrackSelection`) but only a rule reads. shareSignals is the consumer boundary, so it's the natural\n * place to bring those slots into existence; readers then treat them as optional.\n *\n * Uses a `Behavior<>` literal (not `defineBehavior`) so its (possibly empty, possibly partial) key arrays don't trip\n * the exhaustiveness check — the setup-param state/context shapes describe what the callback receives (the full `S` /\n * `C`), not the subset this behavior materializes.\n */\nexport function makeShareSignals<S extends object, C extends object>(\n inputStateKeys: readonly (keyof S)[] = [],\n inputContextKeys: readonly (keyof C)[] = []\n): Behavior<StateSignals<S>, ContextSignals<C>, ShareSignalsConfig<S, C>> {\n return {\n stateKeys: inputStateKeys,\n contextKeys: inputContextKeys,\n setup: ({ state, context, config }) => {\n config.onSignalsReady?.({ state, context });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiCA,SAAgB,iBACd,iBAAuC,CAAC,GACxC,mBAAyC,CAAC,GAC8B;CACxE,OAAO;EACL,WAAW;EACX,aAAa;EACb,QAAQ,EAAE,OAAO,SAAS,aAAa;GACrC,OAAO,iBAAiB;IAAE;IAAO;GAAQ,CAAC;EAC5C;CACF;AACF"}