tempest-react-sdk 0.77.0 → 0.79.0

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 (1623) hide show
  1. package/README.md +6 -6
  2. package/bin/lib/alias/collect.mjs +20 -3
  3. package/bin/lib/alias/index.mjs +12 -1
  4. package/bin/lib/alias/index.test.mjs +24 -0
  5. package/bin/lib/css/analyze.test.mjs +21 -1
  6. package/bin/lib/css/collect.mjs +14 -0
  7. package/bin/lib/css/extract.mjs +63 -5
  8. package/bin/lib/css/extract.test.mjs +110 -1
  9. package/bin/lib/css/fix.e2e.test.mjs +50 -0
  10. package/bin/lib/css/index.mjs +6 -1
  11. package/bin/lib/fs/contain.mjs +50 -0
  12. package/bin/lib/icons/generate.mjs +28 -3
  13. package/bin/lib/icons/generate.test.mjs +57 -1
  14. package/bin/lib/openapi/escape.mjs +20 -6
  15. package/bin/lib/openapi/generate.encode.test.mjs +120 -0
  16. package/bin/lib/openapi/generate.hostile.test.mjs +38 -9
  17. package/bin/lib/openapi/generate.mjs +203 -64
  18. package/bin/lib/openapi/generate.pagination.test.mjs +3 -2
  19. package/bin/lib/openapi/generate.test.mjs +270 -3
  20. package/bin/lib/openapi/schema-to-zod.mjs +5 -3
  21. package/bin/tempest-gen.test.mjs +188 -0
  22. package/bin/tempest.mjs +120 -44
  23. package/dist/access/Can.cjs.map +1 -1
  24. package/dist/access/Can.js.map +1 -1
  25. package/dist/access/access-control-context.cjs.map +1 -1
  26. package/dist/access/access-control-context.js.map +1 -1
  27. package/dist/access/create-role-access-control.cjs.map +1 -1
  28. package/dist/access/create-role-access-control.js.map +1 -1
  29. package/dist/access/permissions-from-token.cjs.map +1 -1
  30. package/dist/access/permissions-from-token.js.map +1 -1
  31. package/dist/access/use-can.cjs.map +1 -1
  32. package/dist/access/use-can.js.map +1 -1
  33. package/dist/app/AppProviders.cjs.map +1 -1
  34. package/dist/app/AppProviders.js.map +1 -1
  35. package/dist/audio/audio-bus.cjs.map +1 -1
  36. package/dist/audio/audio-bus.js.map +1 -1
  37. package/dist/audio/audio-output.cjs.map +1 -1
  38. package/dist/audio/audio-output.js.map +1 -1
  39. package/dist/audio/audio-player.cjs.map +1 -1
  40. package/dist/audio/audio-player.js.map +1 -1
  41. package/dist/audio/audio-recorder.cjs.map +1 -1
  42. package/dist/audio/audio-recorder.js.map +1 -1
  43. package/dist/audio/duration.cjs.map +1 -1
  44. package/dist/audio/duration.js.map +1 -1
  45. package/dist/audio/level-meter.cjs.map +1 -1
  46. package/dist/audio/level-meter.js.map +1 -1
  47. package/dist/audio/media-access.cjs.map +1 -1
  48. package/dist/audio/media-access.js.map +1 -1
  49. package/dist/audio/noise-floor.cjs.map +1 -1
  50. package/dist/audio/noise-floor.js.map +1 -1
  51. package/dist/audio/sfx-pool.cjs.map +1 -1
  52. package/dist/audio/sfx-pool.js.map +1 -1
  53. package/dist/audio/use-audio-bus.cjs.map +1 -1
  54. package/dist/audio/use-audio-bus.js.map +1 -1
  55. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  56. package/dist/audio/use-audio-recorder.js.map +1 -1
  57. package/dist/audio/use-audio.cjs.map +1 -1
  58. package/dist/audio/use-audio.js.map +1 -1
  59. package/dist/audio/use-microphone.cjs +1 -1
  60. package/dist/audio/use-microphone.cjs.map +1 -1
  61. package/dist/audio/use-microphone.js +1 -5
  62. package/dist/audio/use-microphone.js.map +1 -1
  63. package/dist/audio/use-sfx-pool.cjs.map +1 -1
  64. package/dist/audio/use-sfx-pool.js.map +1 -1
  65. package/dist/audio/voice-activity.cjs.map +1 -1
  66. package/dist/audio/voice-activity.js.map +1 -1
  67. package/dist/audio/voice-chain-stages.cjs.map +1 -1
  68. package/dist/audio/voice-chain-stages.js.map +1 -1
  69. package/dist/audio/voice-chain.cjs.map +1 -1
  70. package/dist/audio/voice-chain.js.map +1 -1
  71. package/dist/audio/wav.cjs.map +1 -1
  72. package/dist/audio/wav.js.map +1 -1
  73. package/dist/auth/AuthGuard.cjs.map +1 -1
  74. package/dist/auth/AuthGuard.js.map +1 -1
  75. package/dist/auth/create-auth-store.cjs.map +1 -1
  76. package/dist/auth/create-auth-store.js.map +1 -1
  77. package/dist/auth/create-tempest-auth.cjs +1 -1
  78. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  79. package/dist/auth/create-tempest-auth.js +185 -114
  80. package/dist/auth/create-tempest-auth.js.map +1 -1
  81. package/dist/auth/jwt.cjs.map +1 -1
  82. package/dist/auth/jwt.js.map +1 -1
  83. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  84. package/dist/auth/lazy-with-retry.js.map +1 -1
  85. package/dist/auth/passkey.cjs.map +1 -1
  86. package/dist/auth/passkey.js.map +1 -1
  87. package/dist/auth/refresh-queue.cjs.map +1 -1
  88. package/dist/auth/refresh-queue.js.map +1 -1
  89. package/dist/auth/use-passkey.cjs +1 -1
  90. package/dist/auth/use-passkey.cjs.map +1 -1
  91. package/dist/auth/use-passkey.js +1 -1
  92. package/dist/auth/use-passkey.js.map +1 -1
  93. package/dist/br/BrazilMap.cjs.map +1 -1
  94. package/dist/br/BrazilMap.js.map +1 -1
  95. package/dist/br/BrazilMap.module.cjs.map +1 -1
  96. package/dist/br/BrazilMap.module.js.map +1 -1
  97. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  98. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  99. package/dist/br/BrazilStateMap.cjs.map +1 -1
  100. package/dist/br/BrazilStateMap.js.map +1 -1
  101. package/dist/br/MapLegend.cjs.map +1 -1
  102. package/dist/br/MapLegend.js.map +1 -1
  103. package/dist/br/MapLegend.module.cjs.map +1 -1
  104. package/dist/br/MapLegend.module.js.map +1 -1
  105. package/dist/br/MapMarkers.cjs.map +1 -1
  106. package/dist/br/MapMarkers.js.map +1 -1
  107. package/dist/br/MapTooltip.cjs.map +1 -1
  108. package/dist/br/MapTooltip.js.map +1 -1
  109. package/dist/br/MunicipalitySearch.cjs +1 -1
  110. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  111. package/dist/br/MunicipalitySearch.js +2 -5
  112. package/dist/br/MunicipalitySearch.js.map +1 -1
  113. package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
  114. package/dist/br/MunicipalitySearch.module.js.map +1 -1
  115. package/dist/br/PixQRCode.cjs.map +1 -1
  116. package/dist/br/PixQRCode.js.map +1 -1
  117. package/dist/br/PixQRCode.module.cjs.map +1 -1
  118. package/dist/br/PixQRCode.module.js.map +1 -1
  119. package/dist/br/boleto.cjs.map +1 -1
  120. package/dist/br/boleto.js.map +1 -1
  121. package/dist/br/br-geo.cjs.map +1 -1
  122. package/dist/br/br-geo.js.map +1 -1
  123. package/dist/br/data/br-centroids.cjs.map +1 -1
  124. package/dist/br/data/br-centroids.js.map +1 -1
  125. package/dist/br/data/br-locations.cjs.map +1 -1
  126. package/dist/br/data/br-locations.js.map +1 -1
  127. package/dist/br/data/br-uf-geo.cjs.map +1 -1
  128. package/dist/br/data/br-uf-geo.js.map +1 -1
  129. package/dist/br/data/mun/AC.cjs.map +1 -1
  130. package/dist/br/data/mun/AC.js.map +1 -1
  131. package/dist/br/data/mun/AL.cjs.map +1 -1
  132. package/dist/br/data/mun/AL.js.map +1 -1
  133. package/dist/br/data/mun/AM.cjs.map +1 -1
  134. package/dist/br/data/mun/AM.js.map +1 -1
  135. package/dist/br/data/mun/AP.cjs.map +1 -1
  136. package/dist/br/data/mun/AP.js.map +1 -1
  137. package/dist/br/data/mun/BA.cjs.map +1 -1
  138. package/dist/br/data/mun/BA.js.map +1 -1
  139. package/dist/br/data/mun/CE.cjs.map +1 -1
  140. package/dist/br/data/mun/CE.js.map +1 -1
  141. package/dist/br/data/mun/DF.cjs.map +1 -1
  142. package/dist/br/data/mun/DF.js.map +1 -1
  143. package/dist/br/data/mun/ES.cjs.map +1 -1
  144. package/dist/br/data/mun/ES.js.map +1 -1
  145. package/dist/br/data/mun/GO.cjs.map +1 -1
  146. package/dist/br/data/mun/GO.js.map +1 -1
  147. package/dist/br/data/mun/MA.cjs.map +1 -1
  148. package/dist/br/data/mun/MA.js.map +1 -1
  149. package/dist/br/data/mun/MG.cjs.map +1 -1
  150. package/dist/br/data/mun/MG.js.map +1 -1
  151. package/dist/br/data/mun/MS.cjs.map +1 -1
  152. package/dist/br/data/mun/MS.js.map +1 -1
  153. package/dist/br/data/mun/MT.cjs.map +1 -1
  154. package/dist/br/data/mun/MT.js.map +1 -1
  155. package/dist/br/data/mun/PA.cjs.map +1 -1
  156. package/dist/br/data/mun/PA.js.map +1 -1
  157. package/dist/br/data/mun/PB.cjs.map +1 -1
  158. package/dist/br/data/mun/PB.js.map +1 -1
  159. package/dist/br/data/mun/PE.cjs.map +1 -1
  160. package/dist/br/data/mun/PE.js.map +1 -1
  161. package/dist/br/data/mun/PI.cjs.map +1 -1
  162. package/dist/br/data/mun/PI.js.map +1 -1
  163. package/dist/br/data/mun/PR.cjs.map +1 -1
  164. package/dist/br/data/mun/PR.js.map +1 -1
  165. package/dist/br/data/mun/RJ.cjs.map +1 -1
  166. package/dist/br/data/mun/RJ.js.map +1 -1
  167. package/dist/br/data/mun/RN.cjs.map +1 -1
  168. package/dist/br/data/mun/RN.js.map +1 -1
  169. package/dist/br/data/mun/RO.cjs.map +1 -1
  170. package/dist/br/data/mun/RO.js.map +1 -1
  171. package/dist/br/data/mun/RR.cjs.map +1 -1
  172. package/dist/br/data/mun/RR.js.map +1 -1
  173. package/dist/br/data/mun/RS.cjs.map +1 -1
  174. package/dist/br/data/mun/RS.js.map +1 -1
  175. package/dist/br/data/mun/SC.cjs.map +1 -1
  176. package/dist/br/data/mun/SC.js.map +1 -1
  177. package/dist/br/data/mun/SE.cjs.map +1 -1
  178. package/dist/br/data/mun/SE.js.map +1 -1
  179. package/dist/br/data/mun/SP.cjs.map +1 -1
  180. package/dist/br/data/mun/SP.js.map +1 -1
  181. package/dist/br/data/mun/TO.cjs.map +1 -1
  182. package/dist/br/data/mun/TO.js.map +1 -1
  183. package/dist/br/geocode.cjs.map +1 -1
  184. package/dist/br/geocode.js.map +1 -1
  185. package/dist/br/holidays.cjs.map +1 -1
  186. package/dist/br/holidays.js.map +1 -1
  187. package/dist/br/locations.cjs.map +1 -1
  188. package/dist/br/locations.js.map +1 -1
  189. package/dist/br/nfe.cjs.map +1 -1
  190. package/dist/br/nfe.js.map +1 -1
  191. package/dist/br/pix.cjs +1 -1
  192. package/dist/br/pix.cjs.map +1 -1
  193. package/dist/br/pix.js +108 -71
  194. package/dist/br/pix.js.map +1 -1
  195. package/dist/br/regions.cjs.map +1 -1
  196. package/dist/br/regions.js.map +1 -1
  197. package/dist/br/scales.cjs.map +1 -1
  198. package/dist/br/scales.js.map +1 -1
  199. package/dist/br/state-geo.cjs.map +1 -1
  200. package/dist/br/state-geo.js.map +1 -1
  201. package/dist/br/svg-utils.cjs.map +1 -1
  202. package/dist/br/svg-utils.js.map +1 -1
  203. package/dist/br/use-map-hover.cjs.map +1 -1
  204. package/dist/br/use-map-hover.js.map +1 -1
  205. package/dist/br/use-map-zoom.cjs.map +1 -1
  206. package/dist/br/use-map-zoom.js.map +1 -1
  207. package/dist/br/whatsapp.cjs.map +1 -1
  208. package/dist/br/whatsapp.js.map +1 -1
  209. package/dist/br.cjs.map +1 -1
  210. package/dist/br.d.ts +16 -5
  211. package/dist/br.js.map +1 -1
  212. package/dist/capture/barcode.cjs.map +1 -1
  213. package/dist/capture/barcode.js.map +1 -1
  214. package/dist/capture/media-recorder.cjs.map +1 -1
  215. package/dist/capture/media-recorder.js.map +1 -1
  216. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  217. package/dist/capture/use-barcode-scanner.js.map +1 -1
  218. package/dist/capture/use-screen-capture.cjs +1 -1
  219. package/dist/capture/use-screen-capture.cjs.map +1 -1
  220. package/dist/capture/use-screen-capture.js +1 -7
  221. package/dist/capture/use-screen-capture.js.map +1 -1
  222. package/dist/capture/use-speech-recognition.cjs +1 -1
  223. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  224. package/dist/capture/use-speech-recognition.js +35 -36
  225. package/dist/capture/use-speech-recognition.js.map +1 -1
  226. package/dist/capture/use-torch.cjs.map +1 -1
  227. package/dist/capture/use-torch.js.map +1 -1
  228. package/dist/capture/use-video-recorder.cjs.map +1 -1
  229. package/dist/capture/use-video-recorder.js.map +1 -1
  230. package/dist/capture/video-recorder.cjs.map +1 -1
  231. package/dist/capture/video-recorder.js.map +1 -1
  232. package/dist/charts/AreaChart.cjs.map +1 -1
  233. package/dist/charts/AreaChart.js.map +1 -1
  234. package/dist/charts/BarChart.cjs.map +1 -1
  235. package/dist/charts/BarChart.js.map +1 -1
  236. package/dist/charts/LineChart.cjs.map +1 -1
  237. package/dist/charts/LineChart.js.map +1 -1
  238. package/dist/charts/PieChart.cjs.map +1 -1
  239. package/dist/charts/PieChart.js.map +1 -1
  240. package/dist/charts/RadarChart.cjs.map +1 -1
  241. package/dist/charts/RadarChart.js.map +1 -1
  242. package/dist/charts/palette.cjs.map +1 -1
  243. package/dist/charts/palette.js.map +1 -1
  244. package/dist/charts/scales.cjs.map +1 -1
  245. package/dist/charts/scales.js.map +1 -1
  246. package/dist/charts/types.cjs.map +1 -1
  247. package/dist/charts/types.js.map +1 -1
  248. package/dist/charts/use-chart-colors.cjs.map +1 -1
  249. package/dist/charts/use-chart-colors.js.map +1 -1
  250. package/dist/components/AIChat/AIChat.cjs +1 -1
  251. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  252. package/dist/components/AIChat/AIChat.js +1 -5
  253. package/dist/components/AIChat/AIChat.js.map +1 -1
  254. package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
  255. package/dist/components/AIChat/AIChat.module.js.map +1 -1
  256. package/dist/components/AIChat/AIChatComposer.cjs +1 -1
  257. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  258. package/dist/components/AIChat/AIChatComposer.js +1 -7
  259. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  260. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  261. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  262. package/dist/components/AIChat/ai-chat-turns.cjs.map +1 -1
  263. package/dist/components/AIChat/ai-chat-turns.js.map +1 -1
  264. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  265. package/dist/components/Accordion/Accordion.js.map +1 -1
  266. package/dist/components/Accordion/Accordion.module.cjs.map +1 -1
  267. package/dist/components/Accordion/Accordion.module.js.map +1 -1
  268. package/dist/components/Alert/Alert.cjs.map +1 -1
  269. package/dist/components/Alert/Alert.js.map +1 -1
  270. package/dist/components/Alert/Alert.module.cjs.map +1 -1
  271. package/dist/components/Alert/Alert.module.js.map +1 -1
  272. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  273. package/dist/components/AppBar/AppBar.js.map +1 -1
  274. package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
  275. package/dist/components/AppBar/AppBar.module.js.map +1 -1
  276. package/dist/components/AppBar/use-sticky-body-warning.cjs +1 -1
  277. package/dist/components/AppBar/use-sticky-body-warning.cjs.map +1 -1
  278. package/dist/components/AppBar/use-sticky-body-warning.js +1 -1
  279. package/dist/components/AppBar/use-sticky-body-warning.js.map +1 -1
  280. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  281. package/dist/components/AppShell/AppShell.js.map +1 -1
  282. package/dist/components/AppShell/AppShell.module.cjs.map +1 -1
  283. package/dist/components/AppShell/AppShell.module.js.map +1 -1
  284. package/dist/components/AspectRatio/AspectRatio.cjs.map +1 -1
  285. package/dist/components/AspectRatio/AspectRatio.js.map +1 -1
  286. package/dist/components/AspectRatio/AspectRatio.module.cjs.map +1 -1
  287. package/dist/components/AspectRatio/AspectRatio.module.js.map +1 -1
  288. package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
  289. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  290. package/dist/components/AudioPlayer/AudioPlayer.js +1 -7
  291. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  292. package/dist/components/AudioPlayer/AudioPlayer.module.cjs.map +1 -1
  293. package/dist/components/AudioPlayer/AudioPlayer.module.js.map +1 -1
  294. package/dist/components/AudioRecorder/AudioRecorder.cjs +1 -1
  295. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  296. package/dist/components/AudioRecorder/AudioRecorder.js +16 -21
  297. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  298. package/dist/components/AudioRecorder/AudioRecorder.module.cjs.map +1 -1
  299. package/dist/components/AudioRecorder/AudioRecorder.module.js.map +1 -1
  300. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  301. package/dist/components/Avatar/Avatar.js.map +1 -1
  302. package/dist/components/Avatar/Avatar.module.cjs.map +1 -1
  303. package/dist/components/Avatar/Avatar.module.js.map +1 -1
  304. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  305. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  306. package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -1
  307. package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -1
  308. package/dist/components/Badge/Badge.cjs.map +1 -1
  309. package/dist/components/Badge/Badge.js.map +1 -1
  310. package/dist/components/Badge/Badge.module.cjs.map +1 -1
  311. package/dist/components/Badge/Badge.module.js.map +1 -1
  312. package/dist/components/Banner/Banner.cjs.map +1 -1
  313. package/dist/components/Banner/Banner.js.map +1 -1
  314. package/dist/components/Banner/Banner.module.cjs.map +1 -1
  315. package/dist/components/Banner/Banner.module.js.map +1 -1
  316. package/dist/components/BarList/BarList.cjs.map +1 -1
  317. package/dist/components/BarList/BarList.js.map +1 -1
  318. package/dist/components/BarList/BarList.module.cjs.map +1 -1
  319. package/dist/components/BarList/BarList.module.js.map +1 -1
  320. package/dist/components/BarList/bar-list-model.cjs.map +1 -1
  321. package/dist/components/BarList/bar-list-model.js.map +1 -1
  322. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  323. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  324. package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs.map +1 -1
  325. package/dist/components/BarcodeScanner/BarcodeScanner.module.js.map +1 -1
  326. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  327. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  328. package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
  329. package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
  330. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  331. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  332. package/dist/components/BottomSheet/BottomSheet.module.cjs.map +1 -1
  333. package/dist/components/BottomSheet/BottomSheet.module.js.map +1 -1
  334. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  335. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  336. package/dist/components/Breadcrumbs/Breadcrumbs.module.cjs.map +1 -1
  337. package/dist/components/Breadcrumbs/Breadcrumbs.module.js.map +1 -1
  338. package/dist/components/Button/Button.cjs.map +1 -1
  339. package/dist/components/Button/Button.js.map +1 -1
  340. package/dist/components/Button/Button.module.cjs.map +1 -1
  341. package/dist/components/Button/Button.module.js.map +1 -1
  342. package/dist/components/Button/ButtonContent.cjs.map +1 -1
  343. package/dist/components/Button/ButtonContent.js.map +1 -1
  344. package/dist/components/Button/ButtonSlot.cjs.map +1 -1
  345. package/dist/components/Button/ButtonSlot.js.map +1 -1
  346. package/dist/components/Button/button-class.cjs.map +1 -1
  347. package/dist/components/Button/button-class.js.map +1 -1
  348. package/dist/components/Button/link-rel.cjs.map +1 -1
  349. package/dist/components/Button/link-rel.js.map +1 -1
  350. package/dist/components/Button/slot.cjs.map +1 -1
  351. package/dist/components/Button/slot.js.map +1 -1
  352. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  353. package/dist/components/Calendar/Calendar.js.map +1 -1
  354. package/dist/components/Calendar/Calendar.module.cjs.map +1 -1
  355. package/dist/components/Calendar/Calendar.module.js.map +1 -1
  356. package/dist/components/Card/Card.cjs.map +1 -1
  357. package/dist/components/Card/Card.js.map +1 -1
  358. package/dist/components/Card/Card.module.cjs.map +1 -1
  359. package/dist/components/Card/Card.module.js.map +1 -1
  360. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  361. package/dist/components/Carousel/Carousel.js.map +1 -1
  362. package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
  363. package/dist/components/Carousel/Carousel.module.js.map +1 -1
  364. package/dist/components/Center/Center.cjs.map +1 -1
  365. package/dist/components/Center/Center.js.map +1 -1
  366. package/dist/components/Center/Center.module.cjs.map +1 -1
  367. package/dist/components/Center/Center.module.js.map +1 -1
  368. package/dist/components/Chat/Chat.cjs.map +1 -1
  369. package/dist/components/Chat/Chat.js.map +1 -1
  370. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  371. package/dist/components/Chat/Chat.module.js.map +1 -1
  372. package/dist/components/Chat/ChatActionsMenu.cjs.map +1 -1
  373. package/dist/components/Chat/ChatActionsMenu.js.map +1 -1
  374. package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
  375. package/dist/components/Chat/ChatAttachments.js.map +1 -1
  376. package/dist/components/Chat/ChatBubble.cjs.map +1 -1
  377. package/dist/components/Chat/ChatBubble.js.map +1 -1
  378. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  379. package/dist/components/Chat/ChatComposer.js.map +1 -1
  380. package/dist/components/Chat/chat-groups.cjs +1 -1
  381. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  382. package/dist/components/Chat/chat-groups.js +2 -6
  383. package/dist/components/Chat/chat-groups.js.map +1 -1
  384. package/dist/components/Chat/chat-receipt.cjs.map +1 -1
  385. package/dist/components/Chat/chat-receipt.js.map +1 -1
  386. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  387. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  388. package/dist/components/Checkbox/Checkbox.module.cjs.map +1 -1
  389. package/dist/components/Checkbox/Checkbox.module.js.map +1 -1
  390. package/dist/components/ChipInput/ChipInput.cjs +1 -1
  391. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  392. package/dist/components/ChipInput/ChipInput.js +2 -12
  393. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  394. package/dist/components/ChipInput/ChipInput.module.cjs.map +1 -1
  395. package/dist/components/ChipInput/ChipInput.module.js.map +1 -1
  396. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  397. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  398. package/dist/components/CodeBlock/CodeBlock.cjs +1 -1
  399. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  400. package/dist/components/CodeBlock/CodeBlock.js +1 -1
  401. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  402. package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -1
  403. package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -1
  404. package/dist/components/CodeBlock/tokenize.cjs +1 -1
  405. package/dist/components/CodeBlock/tokenize.cjs.map +1 -1
  406. package/dist/components/CodeBlock/tokenize.js +54 -25
  407. package/dist/components/CodeBlock/tokenize.js.map +1 -1
  408. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  409. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  410. package/dist/components/Collapsible/Collapsible.module.cjs.map +1 -1
  411. package/dist/components/Collapsible/Collapsible.module.js.map +1 -1
  412. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  413. package/dist/components/Combobox/Combobox.js.map +1 -1
  414. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  415. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  416. package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -1
  417. package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -1
  418. package/dist/components/Command/Command.cjs +1 -1
  419. package/dist/components/Command/Command.cjs.map +1 -1
  420. package/dist/components/Command/Command.js +4 -11
  421. package/dist/components/Command/Command.js.map +1 -1
  422. package/dist/components/Command/Command.module.cjs.map +1 -1
  423. package/dist/components/Command/Command.module.js.map +1 -1
  424. package/dist/components/ConditionalWrapper/ConditionalWrapper.cjs.map +1 -1
  425. package/dist/components/ConditionalWrapper/ConditionalWrapper.js.map +1 -1
  426. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  427. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  428. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  429. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  430. package/dist/components/ContextMenu/ContextMenu.js +1 -1
  431. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  432. package/dist/components/ContextMenu/ContextMenu.module.cjs.map +1 -1
  433. package/dist/components/ContextMenu/ContextMenu.module.js.map +1 -1
  434. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  435. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  436. package/dist/components/CopyButton/CopyButton.module.cjs.map +1 -1
  437. package/dist/components/CopyButton/CopyButton.module.js.map +1 -1
  438. package/dist/components/DataList/DataList.cjs.map +1 -1
  439. package/dist/components/DataList/DataList.js.map +1 -1
  440. package/dist/components/DataList/DataList.module.cjs.map +1 -1
  441. package/dist/components/DataList/DataList.module.js.map +1 -1
  442. package/dist/components/DataTable/DataTable.cjs +1 -1
  443. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  444. package/dist/components/DataTable/DataTable.js +6 -14
  445. package/dist/components/DataTable/DataTable.js.map +1 -1
  446. package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
  447. package/dist/components/DataTable/DataTable.module.js.map +1 -1
  448. package/dist/components/DataTable/EditableCell.cjs +1 -1
  449. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  450. package/dist/components/DataTable/EditableCell.js +1 -9
  451. package/dist/components/DataTable/EditableCell.js.map +1 -1
  452. package/dist/components/DataTable/LoadingRows.cjs.map +1 -1
  453. package/dist/components/DataTable/LoadingRows.js.map +1 -1
  454. package/dist/components/DataTable/edit-labels.cjs.map +1 -1
  455. package/dist/components/DataTable/edit-labels.js.map +1 -1
  456. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  457. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  458. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  459. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  460. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  461. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  462. package/dist/components/DateRangePicker/DateRangePicker.module.cjs.map +1 -1
  463. package/dist/components/DateRangePicker/DateRangePicker.module.js.map +1 -1
  464. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  465. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  466. package/dist/components/DescriptionList/DescriptionList.module.cjs.map +1 -1
  467. package/dist/components/DescriptionList/DescriptionList.module.js.map +1 -1
  468. package/dist/components/Divider/Divider.cjs.map +1 -1
  469. package/dist/components/Divider/Divider.js.map +1 -1
  470. package/dist/components/Divider/Divider.module.cjs.map +1 -1
  471. package/dist/components/Divider/Divider.module.js.map +1 -1
  472. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  473. package/dist/components/Drawer/Drawer.js.map +1 -1
  474. package/dist/components/Drawer/Drawer.module.cjs.map +1 -1
  475. package/dist/components/Drawer/Drawer.module.js.map +1 -1
  476. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  477. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  478. package/dist/components/DropdownMenu/DropdownMenu.js +2 -14
  479. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  480. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  481. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  482. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  483. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  484. package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
  485. package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
  486. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  487. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  488. package/dist/components/EmptyState/EmptyState.module.cjs.map +1 -1
  489. package/dist/components/EmptyState/EmptyState.module.js.map +1 -1
  490. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  491. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  492. package/dist/components/ErrorState/ErrorState.module.cjs.map +1 -1
  493. package/dist/components/ErrorState/ErrorState.module.js.map +1 -1
  494. package/dist/components/ErrorText/ErrorText.cjs.map +1 -1
  495. package/dist/components/ErrorText/ErrorText.js.map +1 -1
  496. package/dist/components/ErrorText/ErrorText.module.cjs.map +1 -1
  497. package/dist/components/ErrorText/ErrorText.module.js.map +1 -1
  498. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  499. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  500. package/dist/components/FileUpload/FileUpload.js +7 -17
  501. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  502. package/dist/components/FileUpload/FileUpload.module.cjs.map +1 -1
  503. package/dist/components/FileUpload/FileUpload.module.js.map +1 -1
  504. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  505. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  506. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
  507. package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
  508. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  509. package/dist/components/FilterBar/filter-apply.js.map +1 -1
  510. package/dist/components/FilterBar/filter-model.cjs.map +1 -1
  511. package/dist/components/FilterBar/filter-model.js.map +1 -1
  512. package/dist/components/FilterBar/filter-query.cjs +1 -1
  513. package/dist/components/FilterBar/filter-query.cjs.map +1 -1
  514. package/dist/components/FilterBar/filter-query.js +2 -5
  515. package/dist/components/FilterBar/filter-query.js.map +1 -1
  516. package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -1
  517. package/dist/components/FilterPanel/FilterPanel.js.map +1 -1
  518. package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -1
  519. package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -1
  520. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  521. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  522. package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
  523. package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
  524. package/dist/components/For/For.cjs.map +1 -1
  525. package/dist/components/For/For.js.map +1 -1
  526. package/dist/components/Form/Form.cjs.map +1 -1
  527. package/dist/components/Form/Form.js.map +1 -1
  528. package/dist/components/Form/Form.module.cjs.map +1 -1
  529. package/dist/components/Form/Form.module.js.map +1 -1
  530. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  531. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  532. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  533. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  534. package/dist/components/Image/Image.cjs.map +1 -1
  535. package/dist/components/Image/Image.js.map +1 -1
  536. package/dist/components/Image/Image.module.cjs.map +1 -1
  537. package/dist/components/Image/Image.module.js.map +1 -1
  538. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  539. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  540. package/dist/components/ImageCropper/ImageCropper.js +4 -8
  541. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  542. package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
  543. package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
  544. package/dist/components/ImageCropper/crop-geometry.cjs.map +1 -1
  545. package/dist/components/ImageCropper/crop-geometry.js.map +1 -1
  546. package/dist/components/Input/Input.cjs.map +1 -1
  547. package/dist/components/Input/Input.js.map +1 -1
  548. package/dist/components/Input/Input.module.cjs.map +1 -1
  549. package/dist/components/Input/Input.module.js.map +1 -1
  550. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  551. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  552. package/dist/components/InstallBanner/InstallBanner.module.cjs.map +1 -1
  553. package/dist/components/InstallBanner/InstallBanner.module.js.map +1 -1
  554. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  555. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  556. package/dist/components/InstallButton/InstallButton.module.cjs.map +1 -1
  557. package/dist/components/InstallButton/InstallButton.module.js.map +1 -1
  558. package/dist/components/InstallButton/install-hints.cjs.map +1 -1
  559. package/dist/components/InstallButton/install-hints.js.map +1 -1
  560. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  561. package/dist/components/Kanban/Kanban.js.map +1 -1
  562. package/dist/components/Kanban/Kanban.module.cjs.map +1 -1
  563. package/dist/components/Kanban/Kanban.module.js.map +1 -1
  564. package/dist/components/Kbd/Kbd.cjs.map +1 -1
  565. package/dist/components/Kbd/Kbd.js.map +1 -1
  566. package/dist/components/Kbd/Kbd.module.cjs.map +1 -1
  567. package/dist/components/Kbd/Kbd.module.js.map +1 -1
  568. package/dist/components/Label/Label.cjs.map +1 -1
  569. package/dist/components/Label/Label.js.map +1 -1
  570. package/dist/components/Label/Label.module.cjs.map +1 -1
  571. package/dist/components/Label/Label.module.js.map +1 -1
  572. package/dist/components/Layout/Layout.cjs.map +1 -1
  573. package/dist/components/Layout/Layout.js.map +1 -1
  574. package/dist/components/Layout/Layout.module.cjs.map +1 -1
  575. package/dist/components/Layout/Layout.module.js.map +1 -1
  576. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  577. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  578. package/dist/components/Lightbox/Lightbox.js +1 -1
  579. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  580. package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -1
  581. package/dist/components/Lightbox/Lightbox.module.js.map +1 -1
  582. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  583. package/dist/components/ListTile/ListTile.js.map +1 -1
  584. package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
  585. package/dist/components/ListTile/ListTile.module.js.map +1 -1
  586. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  587. package/dist/components/Markdown/Markdown.js.map +1 -1
  588. package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
  589. package/dist/components/Markdown/Markdown.module.js.map +1 -1
  590. package/dist/components/Markdown/markdown-parse.cjs +6 -6
  591. package/dist/components/Markdown/markdown-parse.cjs.map +1 -1
  592. package/dist/components/Markdown/markdown-parse.js +94 -96
  593. package/dist/components/Markdown/markdown-parse.js.map +1 -1
  594. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  595. package/dist/components/Masonry/Masonry.js.map +1 -1
  596. package/dist/components/Masonry/Masonry.module.cjs.map +1 -1
  597. package/dist/components/Masonry/Masonry.module.js.map +1 -1
  598. package/dist/components/Masonry/masonry-layout.cjs.map +1 -1
  599. package/dist/components/Masonry/masonry-layout.js.map +1 -1
  600. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  601. package/dist/components/Menubar/Menubar.js.map +1 -1
  602. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  603. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  604. package/dist/components/Modal/Modal.cjs.map +1 -1
  605. package/dist/components/Modal/Modal.js.map +1 -1
  606. package/dist/components/Modal/Modal.module.cjs.map +1 -1
  607. package/dist/components/Modal/Modal.module.js.map +1 -1
  608. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  609. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  610. package/dist/components/ModalsManager/ModalsManager.module.cjs.map +1 -1
  611. package/dist/components/ModalsManager/ModalsManager.module.js.map +1 -1
  612. package/dist/components/Money/Money.cjs.map +1 -1
  613. package/dist/components/Money/Money.js.map +1 -1
  614. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  615. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  616. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  617. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  618. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  619. package/dist/components/NProgress/NProgress.js.map +1 -1
  620. package/dist/components/NProgress/NProgress.module.cjs.map +1 -1
  621. package/dist/components/NProgress/NProgress.module.js.map +1 -1
  622. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  623. package/dist/components/Navbar/Navbar.js.map +1 -1
  624. package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
  625. package/dist/components/Navbar/Navbar.module.js.map +1 -1
  626. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  627. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  628. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  629. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  630. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  631. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  632. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  633. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  634. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  635. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  636. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
  637. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
  638. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  639. package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -1
  640. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  641. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  642. package/dist/components/OfflineIndicator/OfflineIndicator.module.cjs.map +1 -1
  643. package/dist/components/OfflineIndicator/OfflineIndicator.module.js.map +1 -1
  644. package/dist/components/Page/Page.cjs.map +1 -1
  645. package/dist/components/Page/Page.js.map +1 -1
  646. package/dist/components/Page/Page.module.cjs.map +1 -1
  647. package/dist/components/Page/Page.module.js.map +1 -1
  648. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  649. package/dist/components/Pagination/Pagination.js.map +1 -1
  650. package/dist/components/Pagination/Pagination.module.cjs.map +1 -1
  651. package/dist/components/Pagination/Pagination.module.js.map +1 -1
  652. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  653. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  654. package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
  655. package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
  656. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  657. package/dist/components/PinInput/PinInput.js.map +1 -1
  658. package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
  659. package/dist/components/PinInput/PinInput.module.js.map +1 -1
  660. package/dist/components/Popover/Popover.cjs.map +1 -1
  661. package/dist/components/Popover/Popover.js.map +1 -1
  662. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  663. package/dist/components/Popover/Popover.module.js.map +1 -1
  664. package/dist/components/Portal/Portal.cjs.map +1 -1
  665. package/dist/components/Portal/Portal.js.map +1 -1
  666. package/dist/components/Portal/anchor-position.cjs.map +1 -1
  667. package/dist/components/Portal/anchor-position.js.map +1 -1
  668. package/dist/components/Portal/escape-layer.cjs.map +1 -1
  669. package/dist/components/Portal/escape-layer.js.map +1 -1
  670. package/dist/components/Portal/portal-host.cjs.map +1 -1
  671. package/dist/components/Portal/portal-host.js.map +1 -1
  672. package/dist/components/Portal/tab-bridge.cjs +1 -1
  673. package/dist/components/Portal/tab-bridge.cjs.map +1 -1
  674. package/dist/components/Portal/tab-bridge.js +1 -5
  675. package/dist/components/Portal/tab-bridge.js.map +1 -1
  676. package/dist/components/Progress/Progress.cjs.map +1 -1
  677. package/dist/components/Progress/Progress.js.map +1 -1
  678. package/dist/components/Progress/Progress.module.cjs.map +1 -1
  679. package/dist/components/Progress/Progress.module.js.map +1 -1
  680. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  681. package/dist/components/QRCode/QRCode.js.map +1 -1
  682. package/dist/components/QRCode/QRCode.module.cjs.map +1 -1
  683. package/dist/components/QRCode/QRCode.module.js.map +1 -1
  684. package/dist/components/QRCode/qr-encode.cjs +1 -1
  685. package/dist/components/QRCode/qr-encode.cjs.map +1 -1
  686. package/dist/components/QRCode/qr-encode.js +7 -13
  687. package/dist/components/QRCode/qr-encode.js.map +1 -1
  688. package/dist/components/QRCode/qr-tables.cjs.map +1 -1
  689. package/dist/components/QRCode/qr-tables.js.map +1 -1
  690. package/dist/components/Radio/Radio.cjs.map +1 -1
  691. package/dist/components/Radio/Radio.js.map +1 -1
  692. package/dist/components/Radio/Radio.module.cjs.map +1 -1
  693. package/dist/components/Radio/Radio.module.js.map +1 -1
  694. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  695. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  696. package/dist/components/RangeSlider/RangeSlider.module.cjs.map +1 -1
  697. package/dist/components/RangeSlider/RangeSlider.module.js.map +1 -1
  698. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  699. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  700. package/dist/components/RatingStars/RatingStars.module.cjs.map +1 -1
  701. package/dist/components/RatingStars/RatingStars.module.js.map +1 -1
  702. package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
  703. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  704. package/dist/components/RefreshIndicator/RefreshIndicator.js +10 -18
  705. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  706. package/dist/components/RefreshIndicator/RefreshIndicator.module.cjs.map +1 -1
  707. package/dist/components/RefreshIndicator/RefreshIndicator.module.js.map +1 -1
  708. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  709. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  710. package/dist/components/Resizable/Resizable.cjs +1 -1
  711. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  712. package/dist/components/Resizable/Resizable.js +1 -9
  713. package/dist/components/Resizable/Resizable.js.map +1 -1
  714. package/dist/components/Resizable/Resizable.module.cjs.map +1 -1
  715. package/dist/components/Resizable/Resizable.module.js.map +1 -1
  716. package/dist/components/Responsive/Responsive.cjs.map +1 -1
  717. package/dist/components/Responsive/Responsive.js.map +1 -1
  718. package/dist/components/Reveal/Reveal.cjs.map +1 -1
  719. package/dist/components/Reveal/Reveal.js.map +1 -1
  720. package/dist/components/Reveal/Reveal.module.cjs.map +1 -1
  721. package/dist/components/Reveal/Reveal.module.js.map +1 -1
  722. package/dist/components/Reveal/reveal-threshold.cjs.map +1 -1
  723. package/dist/components/Reveal/reveal-threshold.js.map +1 -1
  724. package/dist/components/SafeArea/SafeArea.cjs.map +1 -1
  725. package/dist/components/SafeArea/SafeArea.js.map +1 -1
  726. package/dist/components/SafeArea/SafeArea.module.cjs.map +1 -1
  727. package/dist/components/SafeArea/SafeArea.module.js.map +1 -1
  728. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  729. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  730. package/dist/components/Scheduler/Scheduler.module.cjs.map +1 -1
  731. package/dist/components/Scheduler/Scheduler.module.js.map +1 -1
  732. package/dist/components/Scheduler/scheduler-layout.cjs.map +1 -1
  733. package/dist/components/Scheduler/scheduler-layout.js.map +1 -1
  734. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  735. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  736. package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
  737. package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
  738. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  739. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  740. package/dist/components/SearchBar/SearchBar.module.cjs.map +1 -1
  741. package/dist/components/SearchBar/SearchBar.module.js.map +1 -1
  742. package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
  743. package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
  744. package/dist/components/SectionHeader/SectionHeader.module.cjs.map +1 -1
  745. package/dist/components/SectionHeader/SectionHeader.module.js.map +1 -1
  746. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  747. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  748. package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
  749. package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
  750. package/dist/components/Select/CaretIcon.cjs.map +1 -1
  751. package/dist/components/Select/CaretIcon.js.map +1 -1
  752. package/dist/components/Select/Select.cjs.map +1 -1
  753. package/dist/components/Select/Select.js.map +1 -1
  754. package/dist/components/Select/Select.module.cjs.map +1 -1
  755. package/dist/components/Select/Select.module.js.map +1 -1
  756. package/dist/components/Select/options.cjs.map +1 -1
  757. package/dist/components/Select/options.js.map +1 -1
  758. package/dist/components/Sidebar/Sidebar.cjs +1 -1
  759. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  760. package/dist/components/Sidebar/Sidebar.js +13 -23
  761. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  762. package/dist/components/Sidebar/Sidebar.module.cjs.map +1 -1
  763. package/dist/components/Sidebar/Sidebar.module.js.map +1 -1
  764. package/dist/components/Sidebar/SidebarEntry.cjs.map +1 -1
  765. package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
  766. package/dist/components/Sidebar/active-nav-key.cjs.map +1 -1
  767. package/dist/components/Sidebar/active-nav-key.js.map +1 -1
  768. package/dist/components/SignaturePad/SignaturePad.cjs +1 -1
  769. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  770. package/dist/components/SignaturePad/SignaturePad.js +1 -5
  771. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  772. package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -1
  773. package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -1
  774. package/dist/components/Skeleton/Skeleton.cjs.map +1 -1
  775. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  776. package/dist/components/Skeleton/Skeleton.module.cjs.map +1 -1
  777. package/dist/components/Skeleton/Skeleton.module.js.map +1 -1
  778. package/dist/components/Slider/Slider.cjs.map +1 -1
  779. package/dist/components/Slider/Slider.js.map +1 -1
  780. package/dist/components/Slider/Slider.module.cjs.map +1 -1
  781. package/dist/components/Slider/Slider.module.js.map +1 -1
  782. package/dist/components/Spacer/Spacer.cjs.map +1 -1
  783. package/dist/components/Spacer/Spacer.js.map +1 -1
  784. package/dist/components/Spacer/Spacer.module.cjs.map +1 -1
  785. package/dist/components/Spacer/Spacer.module.js.map +1 -1
  786. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  787. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  788. package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -1
  789. package/dist/components/Sparkline/Sparkline.module.js.map +1 -1
  790. package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -1
  791. package/dist/components/Sparkline/sparkline-geometry.js.map +1 -1
  792. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  793. package/dist/components/Spinner/Spinner.js.map +1 -1
  794. package/dist/components/Spinner/Spinner.module.cjs.map +1 -1
  795. package/dist/components/Spinner/Spinner.module.js.map +1 -1
  796. package/dist/components/Stat/Stat.cjs.map +1 -1
  797. package/dist/components/Stat/Stat.js.map +1 -1
  798. package/dist/components/Stat/Stat.module.cjs.map +1 -1
  799. package/dist/components/Stat/Stat.module.js.map +1 -1
  800. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  801. package/dist/components/Stepper/Stepper.js.map +1 -1
  802. package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
  803. package/dist/components/Stepper/Stepper.module.js.map +1 -1
  804. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  805. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  806. package/dist/components/StepperInput/StepperInput.module.cjs.map +1 -1
  807. package/dist/components/StepperInput/StepperInput.module.js.map +1 -1
  808. package/dist/components/Switch/Switch.cjs.map +1 -1
  809. package/dist/components/Switch/Switch.js.map +1 -1
  810. package/dist/components/Switch/Switch.module.cjs.map +1 -1
  811. package/dist/components/Switch/Switch.module.js.map +1 -1
  812. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  813. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  814. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.cjs.map +1 -1
  815. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.js.map +1 -1
  816. package/dist/components/Table/Table.cjs.map +1 -1
  817. package/dist/components/Table/Table.js.map +1 -1
  818. package/dist/components/Table/Table.module.cjs.map +1 -1
  819. package/dist/components/Table/Table.module.js.map +1 -1
  820. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  821. package/dist/components/Tabs/Tabs.js.map +1 -1
  822. package/dist/components/Tabs/Tabs.module.cjs.map +1 -1
  823. package/dist/components/Tabs/Tabs.module.js.map +1 -1
  824. package/dist/components/Tag/Tag.cjs.map +1 -1
  825. package/dist/components/Tag/Tag.js.map +1 -1
  826. package/dist/components/Tag/Tag.module.cjs.map +1 -1
  827. package/dist/components/Tag/Tag.module.js.map +1 -1
  828. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  829. package/dist/components/Textarea/Textarea.js.map +1 -1
  830. package/dist/components/Textarea/Textarea.module.cjs.map +1 -1
  831. package/dist/components/Textarea/Textarea.module.js.map +1 -1
  832. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  833. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  834. package/dist/components/TimePicker/TimePicker.module.cjs.map +1 -1
  835. package/dist/components/TimePicker/TimePicker.module.js.map +1 -1
  836. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  837. package/dist/components/Timeline/Timeline.js.map +1 -1
  838. package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
  839. package/dist/components/Timeline/Timeline.module.js.map +1 -1
  840. package/dist/components/Toast/Toast.module.cjs.map +1 -1
  841. package/dist/components/Toast/Toast.module.js.map +1 -1
  842. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  843. package/dist/components/Toast/ToastProvider.js.map +1 -1
  844. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  845. package/dist/components/Toggle/Toggle.js.map +1 -1
  846. package/dist/components/Toggle/Toggle.module.cjs.map +1 -1
  847. package/dist/components/Toggle/Toggle.module.js.map +1 -1
  848. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  849. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  850. package/dist/components/ToggleGroup/ToggleGroup.module.cjs.map +1 -1
  851. package/dist/components/ToggleGroup/ToggleGroup.module.js.map +1 -1
  852. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  853. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  854. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  855. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  856. package/dist/components/Tour/Tour.cjs +1 -1
  857. package/dist/components/Tour/Tour.cjs.map +1 -1
  858. package/dist/components/Tour/Tour.js +1 -5
  859. package/dist/components/Tour/Tour.js.map +1 -1
  860. package/dist/components/Tour/Tour.module.cjs.map +1 -1
  861. package/dist/components/Tour/Tour.module.js.map +1 -1
  862. package/dist/components/Tour/tour-position.cjs.map +1 -1
  863. package/dist/components/Tour/tour-position.js.map +1 -1
  864. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  865. package/dist/components/Transfer/Transfer.js.map +1 -1
  866. package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
  867. package/dist/components/Transfer/Transfer.module.js.map +1 -1
  868. package/dist/components/Transfer/transfer-state.cjs.map +1 -1
  869. package/dist/components/Transfer/transfer-state.js.map +1 -1
  870. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  871. package/dist/components/TreeView/TreeView.js.map +1 -1
  872. package/dist/components/TreeView/TreeView.module.cjs.map +1 -1
  873. package/dist/components/TreeView/TreeView.module.js.map +1 -1
  874. package/dist/components/TruncateText/TruncateText.cjs.map +1 -1
  875. package/dist/components/TruncateText/TruncateText.js.map +1 -1
  876. package/dist/components/TruncateText/TruncateText.module.cjs.map +1 -1
  877. package/dist/components/TruncateText/TruncateText.module.js.map +1 -1
  878. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  879. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  880. package/dist/components/UpdatePrompt/UpdatePrompt.module.cjs.map +1 -1
  881. package/dist/components/UpdatePrompt/UpdatePrompt.module.js.map +1 -1
  882. package/dist/components/VideoPlayer/VideoPlayer.cjs +1 -1
  883. package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -1
  884. package/dist/components/VideoPlayer/VideoPlayer.js +1 -7
  885. package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
  886. package/dist/components/VideoPlayer/VideoPlayer.module.cjs.map +1 -1
  887. package/dist/components/VideoPlayer/VideoPlayer.module.js.map +1 -1
  888. package/dist/components/VideoPlayer/playback-rates.cjs.map +1 -1
  889. package/dist/components/VideoPlayer/playback-rates.js.map +1 -1
  890. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  891. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  892. package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
  893. package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
  894. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  895. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  896. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
  897. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
  898. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  899. package/dist/components/VisuallyHidden/VisuallyHidden.js.map +1 -1
  900. package/dist/components/VisuallyHidden/VisuallyHidden.module.cjs.map +1 -1
  901. package/dist/components/VisuallyHidden/VisuallyHidden.module.js.map +1 -1
  902. package/dist/components/Wizard/Wizard.cjs +1 -1
  903. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  904. package/dist/components/Wizard/Wizard.js +4 -11
  905. package/dist/components/Wizard/Wizard.js.map +1 -1
  906. package/dist/components/Wizard/Wizard.module.cjs.map +1 -1
  907. package/dist/components/Wizard/Wizard.module.js.map +1 -1
  908. package/dist/data/create-data-provider.cjs.map +1 -1
  909. package/dist/data/create-data-provider.js.map +1 -1
  910. package/dist/data/data-provider-context.cjs.map +1 -1
  911. package/dist/data/data-provider-context.js.map +1 -1
  912. package/dist/data/use-resource.cjs.map +1 -1
  913. package/dist/data/use-resource.js.map +1 -1
  914. package/dist/editor/RichTextEditor.cjs.map +1 -1
  915. package/dist/editor/RichTextEditor.js.map +1 -1
  916. package/dist/editor/RichTextEditor.module.cjs.map +1 -1
  917. package/dist/editor/RichTextEditor.module.js.map +1 -1
  918. package/dist/editor.js +1 -2
  919. package/dist/error-boundary/ErrorBoundary.cjs.map +1 -1
  920. package/dist/error-boundary/ErrorBoundary.js.map +1 -1
  921. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  922. package/dist/error-boundary/use-error-handler.js.map +1 -1
  923. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  924. package/dist/feature-flags/FeatureFlagsProvider.js.map +1 -1
  925. package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
  926. package/dist/feature-flags/growthbook-adapter.js.map +1 -1
  927. package/dist/feature-flags/in-memory-adapter.cjs.map +1 -1
  928. package/dist/feature-flags/in-memory-adapter.js.map +1 -1
  929. package/dist/feature-flags/launchdarkly-adapter.cjs.map +1 -1
  930. package/dist/feature-flags/launchdarkly-adapter.js.map +1 -1
  931. package/dist/forms/FormField.cjs.map +1 -1
  932. package/dist/forms/FormField.js.map +1 -1
  933. package/dist/forms/br-validators.cjs.map +1 -1
  934. package/dist/forms/br-validators.js.map +1 -1
  935. package/dist/forms/masked-inputs.cjs.map +1 -1
  936. package/dist/forms/masked-inputs.js.map +1 -1
  937. package/dist/forms/use-viacep.cjs.map +1 -1
  938. package/dist/forms/use-viacep.js.map +1 -1
  939. package/dist/forms/use-zod-form.cjs.map +1 -1
  940. package/dist/forms/use-zod-form.js.map +1 -1
  941. package/dist/forms/validate-form.cjs.map +1 -1
  942. package/dist/forms/validate-form.js.map +1 -1
  943. package/dist/forms/zod-resolver.cjs.map +1 -1
  944. package/dist/forms/zod-resolver.js.map +1 -1
  945. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  946. package/dist/geo/TrajectoryMap.js.map +1 -1
  947. package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
  948. package/dist/geo/TrajectoryMap.module.js.map +1 -1
  949. package/dist/geo/bounds.cjs.map +1 -1
  950. package/dist/geo/bounds.js.map +1 -1
  951. package/dist/geo/create-position-tracker.cjs +1 -1
  952. package/dist/geo/create-position-tracker.cjs.map +1 -1
  953. package/dist/geo/create-position-tracker.js +1 -7
  954. package/dist/geo/create-position-tracker.js.map +1 -1
  955. package/dist/geo/distance.cjs.map +1 -1
  956. package/dist/geo/distance.js.map +1 -1
  957. package/dist/geo/estimate.cjs.map +1 -1
  958. package/dist/geo/estimate.js.map +1 -1
  959. package/dist/geo/leaflet-map.cjs.map +1 -1
  960. package/dist/geo/leaflet-map.js.map +1 -1
  961. package/dist/geo/projection.cjs.map +1 -1
  962. package/dist/geo/projection.js.map +1 -1
  963. package/dist/geo/routing.cjs.map +1 -1
  964. package/dist/geo/routing.js.map +1 -1
  965. package/dist/geo/types.cjs.map +1 -1
  966. package/dist/geo/types.js.map +1 -1
  967. package/dist/geo/use-position-tracker.cjs.map +1 -1
  968. package/dist/geo/use-position-tracker.js.map +1 -1
  969. package/dist/hooks/pwa-env.cjs.map +1 -1
  970. package/dist/hooks/pwa-env.js.map +1 -1
  971. package/dist/hooks/tab-sequence.cjs.map +1 -1
  972. package/dist/hooks/tab-sequence.js.map +1 -1
  973. package/dist/hooks/use-announce.cjs +1 -1
  974. package/dist/hooks/use-announce.cjs.map +1 -1
  975. package/dist/hooks/use-announce.js +2 -2
  976. package/dist/hooks/use-announce.js.map +1 -1
  977. package/dist/hooks/use-async.cjs.map +1 -1
  978. package/dist/hooks/use-async.js.map +1 -1
  979. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  980. package/dist/hooks/use-before-install-prompt.js.map +1 -1
  981. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  982. package/dist/hooks/use-breakpoint.js.map +1 -1
  983. package/dist/hooks/use-click-outside.cjs.map +1 -1
  984. package/dist/hooks/use-click-outside.js.map +1 -1
  985. package/dist/hooks/use-client-filter.cjs.map +1 -1
  986. package/dist/hooks/use-client-filter.js.map +1 -1
  987. package/dist/hooks/use-clipboard.cjs.map +1 -1
  988. package/dist/hooks/use-clipboard.js.map +1 -1
  989. package/dist/hooks/use-countdown.cjs.map +1 -1
  990. package/dist/hooks/use-countdown.js.map +1 -1
  991. package/dist/hooks/use-counter.cjs.map +1 -1
  992. package/dist/hooks/use-counter.js.map +1 -1
  993. package/dist/hooks/use-debounce.cjs.map +1 -1
  994. package/dist/hooks/use-debounce.js.map +1 -1
  995. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  996. package/dist/hooks/use-deep-memo.js.map +1 -1
  997. package/dist/hooks/use-disclosure.cjs.map +1 -1
  998. package/dist/hooks/use-disclosure.js.map +1 -1
  999. package/dist/hooks/use-document-title.cjs.map +1 -1
  1000. package/dist/hooks/use-document-title.js.map +1 -1
  1001. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  1002. package/dist/hooks/use-document-visibility.js.map +1 -1
  1003. package/dist/hooks/use-draft-filters.cjs.map +1 -1
  1004. package/dist/hooks/use-draft-filters.js.map +1 -1
  1005. package/dist/hooks/use-event-listener.cjs.map +1 -1
  1006. package/dist/hooks/use-event-listener.js.map +1 -1
  1007. package/dist/hooks/use-favicon.cjs.map +1 -1
  1008. package/dist/hooks/use-favicon.js.map +1 -1
  1009. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  1010. package/dist/hooks/use-focus-trap.js.map +1 -1
  1011. package/dist/hooks/use-fullscreen-element.cjs.map +1 -1
  1012. package/dist/hooks/use-fullscreen-element.js.map +1 -1
  1013. package/dist/hooks/use-fullscreen.cjs +1 -1
  1014. package/dist/hooks/use-fullscreen.cjs.map +1 -1
  1015. package/dist/hooks/use-fullscreen.js +7 -23
  1016. package/dist/hooks/use-fullscreen.js.map +1 -1
  1017. package/dist/hooks/use-geolocation.cjs.map +1 -1
  1018. package/dist/hooks/use-geolocation.js.map +1 -1
  1019. package/dist/hooks/use-hover.cjs.map +1 -1
  1020. package/dist/hooks/use-hover.js.map +1 -1
  1021. package/dist/hooks/use-idle.cjs.map +1 -1
  1022. package/dist/hooks/use-idle.js.map +1 -1
  1023. package/dist/hooks/use-install-prompt.cjs +1 -1
  1024. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  1025. package/dist/hooks/use-install-prompt.js +1 -1
  1026. package/dist/hooks/use-install-prompt.js.map +1 -1
  1027. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  1028. package/dist/hooks/use-intersection-observer.js.map +1 -1
  1029. package/dist/hooks/use-interval.cjs.map +1 -1
  1030. package/dist/hooks/use-interval.js.map +1 -1
  1031. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  1032. package/dist/hooks/use-is-first-render.js.map +1 -1
  1033. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  1034. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  1035. package/dist/hooks/use-latest-ref.cjs.map +1 -1
  1036. package/dist/hooks/use-latest-ref.js.map +1 -1
  1037. package/dist/hooks/use-list-state.cjs.map +1 -1
  1038. package/dist/hooks/use-list-state.js.map +1 -1
  1039. package/dist/hooks/use-local-storage.cjs +1 -1
  1040. package/dist/hooks/use-local-storage.cjs.map +1 -1
  1041. package/dist/hooks/use-local-storage.js +2 -5
  1042. package/dist/hooks/use-local-storage.js.map +1 -1
  1043. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  1044. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  1045. package/dist/hooks/use-long-press.cjs.map +1 -1
  1046. package/dist/hooks/use-long-press.js.map +1 -1
  1047. package/dist/hooks/use-map.cjs.map +1 -1
  1048. package/dist/hooks/use-map.js.map +1 -1
  1049. package/dist/hooks/use-media-devices.cjs.map +1 -1
  1050. package/dist/hooks/use-media-devices.js.map +1 -1
  1051. package/dist/hooks/use-media-permission.cjs +1 -1
  1052. package/dist/hooks/use-media-permission.cjs.map +1 -1
  1053. package/dist/hooks/use-media-permission.js +2 -5
  1054. package/dist/hooks/use-media-permission.js.map +1 -1
  1055. package/dist/hooks/use-media-query.cjs.map +1 -1
  1056. package/dist/hooks/use-media-query.js.map +1 -1
  1057. package/dist/hooks/use-object-url.cjs.map +1 -1
  1058. package/dist/hooks/use-object-url.js.map +1 -1
  1059. package/dist/hooks/use-online.cjs.map +1 -1
  1060. package/dist/hooks/use-online.js.map +1 -1
  1061. package/dist/hooks/use-pagination.cjs.map +1 -1
  1062. package/dist/hooks/use-pagination.js.map +1 -1
  1063. package/dist/hooks/use-previous.cjs.map +1 -1
  1064. package/dist/hooks/use-previous.js.map +1 -1
  1065. package/dist/hooks/use-push-to-talk.cjs.map +1 -1
  1066. package/dist/hooks/use-push-to-talk.js.map +1 -1
  1067. package/dist/hooks/use-queue.cjs.map +1 -1
  1068. package/dist/hooks/use-queue.js.map +1 -1
  1069. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  1070. package/dist/hooks/use-resize-observer.js.map +1 -1
  1071. package/dist/hooks/use-scroll-lock.cjs.map +1 -1
  1072. package/dist/hooks/use-scroll-lock.js.map +1 -1
  1073. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  1074. package/dist/hooks/use-scroll-overflow.js.map +1 -1
  1075. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  1076. package/dist/hooks/use-service-worker-update.js.map +1 -1
  1077. package/dist/hooks/use-set.cjs.map +1 -1
  1078. package/dist/hooks/use-set.js.map +1 -1
  1079. package/dist/hooks/use-sortable.cjs.map +1 -1
  1080. package/dist/hooks/use-sortable.js.map +1 -1
  1081. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  1082. package/dist/hooks/use-stable-callback.js.map +1 -1
  1083. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  1084. package/dist/hooks/use-storage-estimate.js.map +1 -1
  1085. package/dist/hooks/use-throttle.cjs.map +1 -1
  1086. package/dist/hooks/use-throttle.js.map +1 -1
  1087. package/dist/hooks/use-timeout.cjs.map +1 -1
  1088. package/dist/hooks/use-timeout.js.map +1 -1
  1089. package/dist/hooks/use-toggle.cjs.map +1 -1
  1090. package/dist/hooks/use-toggle.js.map +1 -1
  1091. package/dist/hooks/use-typewriter.cjs.map +1 -1
  1092. package/dist/hooks/use-typewriter.js.map +1 -1
  1093. package/dist/hooks/use-window-size.cjs.map +1 -1
  1094. package/dist/hooks/use-window-size.js.map +1 -1
  1095. package/dist/http/api-client.cjs.map +1 -1
  1096. package/dist/http/api-client.js.map +1 -1
  1097. package/dist/http/build-url.cjs.map +1 -1
  1098. package/dist/http/build-url.js.map +1 -1
  1099. package/dist/http/credential-scope.cjs.map +1 -1
  1100. package/dist/http/credential-scope.js.map +1 -1
  1101. package/dist/http/csrf.cjs.map +1 -1
  1102. package/dist/http/csrf.js.map +1 -1
  1103. package/dist/http/decode-response.cjs.map +1 -1
  1104. package/dist/http/decode-response.js.map +1 -1
  1105. package/dist/http/describe-api-error.cjs.map +1 -1
  1106. package/dist/http/describe-api-error.js.map +1 -1
  1107. package/dist/http/errors.cjs.map +1 -1
  1108. package/dist/http/errors.js.map +1 -1
  1109. package/dist/http/idempotency.cjs.map +1 -1
  1110. package/dist/http/idempotency.js.map +1 -1
  1111. package/dist/http/parse-response.cjs.map +1 -1
  1112. package/dist/http/parse-response.js.map +1 -1
  1113. package/dist/http/resumable-upload.cjs +1 -1
  1114. package/dist/http/resumable-upload.cjs.map +1 -1
  1115. package/dist/http/resumable-upload.js +141 -105
  1116. package/dist/http/resumable-upload.js.map +1 -1
  1117. package/dist/http/retry.cjs +1 -1
  1118. package/dist/http/retry.cjs.map +1 -1
  1119. package/dist/http/retry.js +5 -6
  1120. package/dist/http/retry.js.map +1 -1
  1121. package/dist/http/timeout.cjs.map +1 -1
  1122. package/dist/http/timeout.js.map +1 -1
  1123. package/dist/http/upload-with-progress.cjs +1 -1
  1124. package/dist/http/upload-with-progress.cjs.map +1 -1
  1125. package/dist/http/upload-with-progress.js +2 -7
  1126. package/dist/http/upload-with-progress.js.map +1 -1
  1127. package/dist/http/use-describe-api-error.cjs.map +1 -1
  1128. package/dist/http/use-describe-api-error.js.map +1 -1
  1129. package/dist/http/use-poll.cjs +1 -1
  1130. package/dist/http/use-poll.cjs.map +1 -1
  1131. package/dist/http/use-poll.js +2 -5
  1132. package/dist/http/use-poll.js.map +1 -1
  1133. package/dist/i18n/I18nProvider.cjs.map +1 -1
  1134. package/dist/i18n/I18nProvider.js.map +1 -1
  1135. package/dist/i18n/create-i18n.cjs.map +1 -1
  1136. package/dist/i18n/create-i18n.js.map +1 -1
  1137. package/dist/icons/Icon.cjs.map +1 -1
  1138. package/dist/icons/Icon.js.map +1 -1
  1139. package/dist/icons/IconPicker.cjs.map +1 -1
  1140. package/dist/icons/IconPicker.js.map +1 -1
  1141. package/dist/icons/IconPicker.module.cjs.map +1 -1
  1142. package/dist/icons/IconPicker.module.js.map +1 -1
  1143. package/dist/icons/IconProvider.cjs.map +1 -1
  1144. package/dist/icons/IconProvider.js.map +1 -1
  1145. package/dist/icons/alias.cjs.map +1 -1
  1146. package/dist/icons/alias.js.map +1 -1
  1147. package/dist/icons/generated/aliases.cjs.map +1 -1
  1148. package/dist/icons/generated/aliases.js.map +1 -1
  1149. package/dist/icons/generated/icon-names.cjs.map +1 -1
  1150. package/dist/icons/generated/icon-names.js.map +1 -1
  1151. package/dist/icons/generated/loaders.cjs.map +1 -1
  1152. package/dist/icons/generated/loaders.js.map +1 -1
  1153. package/dist/icons/generated/shard-00.cjs.map +1 -1
  1154. package/dist/icons/generated/shard-00.js.map +1 -1
  1155. package/dist/icons/generated/shard-01.cjs.map +1 -1
  1156. package/dist/icons/generated/shard-01.js.map +1 -1
  1157. package/dist/icons/generated/shard-02.cjs.map +1 -1
  1158. package/dist/icons/generated/shard-02.js.map +1 -1
  1159. package/dist/icons/generated/shard-03.cjs.map +1 -1
  1160. package/dist/icons/generated/shard-03.js.map +1 -1
  1161. package/dist/icons/generated/shard-04.cjs.map +1 -1
  1162. package/dist/icons/generated/shard-04.js.map +1 -1
  1163. package/dist/icons/generated/shard-05.cjs.map +1 -1
  1164. package/dist/icons/generated/shard-05.js.map +1 -1
  1165. package/dist/icons/generated/shard-06.cjs.map +1 -1
  1166. package/dist/icons/generated/shard-06.js.map +1 -1
  1167. package/dist/icons/generated/shard-07.cjs.map +1 -1
  1168. package/dist/icons/generated/shard-07.js.map +1 -1
  1169. package/dist/icons/generated/shard-08.cjs.map +1 -1
  1170. package/dist/icons/generated/shard-08.js.map +1 -1
  1171. package/dist/icons/generated/shard-09.cjs.map +1 -1
  1172. package/dist/icons/generated/shard-09.js.map +1 -1
  1173. package/dist/icons/generated/shard-10.cjs.map +1 -1
  1174. package/dist/icons/generated/shard-10.js.map +1 -1
  1175. package/dist/icons/generated/shard-11.cjs.map +1 -1
  1176. package/dist/icons/generated/shard-11.js.map +1 -1
  1177. package/dist/icons/generated/shard-12.cjs.map +1 -1
  1178. package/dist/icons/generated/shard-12.js.map +1 -1
  1179. package/dist/icons/generated/shard-13.cjs.map +1 -1
  1180. package/dist/icons/generated/shard-13.js.map +1 -1
  1181. package/dist/icons/generated/shard-14.cjs.map +1 -1
  1182. package/dist/icons/generated/shard-14.js.map +1 -1
  1183. package/dist/icons/generated/shard-15.cjs.map +1 -1
  1184. package/dist/icons/generated/shard-15.js.map +1 -1
  1185. package/dist/icons/generated/shard-16.cjs.map +1 -1
  1186. package/dist/icons/generated/shard-16.js.map +1 -1
  1187. package/dist/icons/generated/shard-17.cjs.map +1 -1
  1188. package/dist/icons/generated/shard-17.js.map +1 -1
  1189. package/dist/icons/generated/shard-18.cjs.map +1 -1
  1190. package/dist/icons/generated/shard-18.js.map +1 -1
  1191. package/dist/icons/generated/shard-19.cjs.map +1 -1
  1192. package/dist/icons/generated/shard-19.js.map +1 -1
  1193. package/dist/icons/generated/shard-20.cjs.map +1 -1
  1194. package/dist/icons/generated/shard-20.js.map +1 -1
  1195. package/dist/icons/generated/shard-21.cjs.map +1 -1
  1196. package/dist/icons/generated/shard-21.js.map +1 -1
  1197. package/dist/icons/generated/shard-22.cjs.map +1 -1
  1198. package/dist/icons/generated/shard-22.js.map +1 -1
  1199. package/dist/icons/generated/shard-23.cjs.map +1 -1
  1200. package/dist/icons/generated/shard-23.js.map +1 -1
  1201. package/dist/icons/generated/shard-24.cjs.map +1 -1
  1202. package/dist/icons/generated/shard-24.js.map +1 -1
  1203. package/dist/icons/generated/shard-25.cjs.map +1 -1
  1204. package/dist/icons/generated/shard-25.js.map +1 -1
  1205. package/dist/icons/generated/shard-26.cjs.map +1 -1
  1206. package/dist/icons/generated/shard-26.js.map +1 -1
  1207. package/dist/icons/generated/shard-27.cjs.map +1 -1
  1208. package/dist/icons/generated/shard-27.js.map +1 -1
  1209. package/dist/icons/generated/shard-28.cjs.map +1 -1
  1210. package/dist/icons/generated/shard-28.js.map +1 -1
  1211. package/dist/icons/generated/shard-29.cjs.map +1 -1
  1212. package/dist/icons/generated/shard-29.js.map +1 -1
  1213. package/dist/icons/generated/shard-30.cjs.map +1 -1
  1214. package/dist/icons/generated/shard-30.js.map +1 -1
  1215. package/dist/icons/generated/shard-31.cjs.map +1 -1
  1216. package/dist/icons/generated/shard-31.js.map +1 -1
  1217. package/dist/icons/generated/shard-32.cjs.map +1 -1
  1218. package/dist/icons/generated/shard-32.js.map +1 -1
  1219. package/dist/icons/generated/shard-33.cjs.map +1 -1
  1220. package/dist/icons/generated/shard-33.js.map +1 -1
  1221. package/dist/icons/generated/shard-34.cjs.map +1 -1
  1222. package/dist/icons/generated/shard-34.js.map +1 -1
  1223. package/dist/icons/generated/shard-35.cjs.map +1 -1
  1224. package/dist/icons/generated/shard-35.js.map +1 -1
  1225. package/dist/icons/generated/shard-36.cjs.map +1 -1
  1226. package/dist/icons/generated/shard-36.js.map +1 -1
  1227. package/dist/icons/generated/shard-37.cjs.map +1 -1
  1228. package/dist/icons/generated/shard-37.js.map +1 -1
  1229. package/dist/icons/generated/shard-38.cjs.map +1 -1
  1230. package/dist/icons/generated/shard-38.js.map +1 -1
  1231. package/dist/icons/generated/shard-39.cjs.map +1 -1
  1232. package/dist/icons/generated/shard-39.js.map +1 -1
  1233. package/dist/icons/generated/shard-40.cjs.map +1 -1
  1234. package/dist/icons/generated/shard-40.js.map +1 -1
  1235. package/dist/icons/generated/shard-41.cjs.map +1 -1
  1236. package/dist/icons/generated/shard-41.js.map +1 -1
  1237. package/dist/icons/generated/shard-42.cjs.map +1 -1
  1238. package/dist/icons/generated/shard-42.js.map +1 -1
  1239. package/dist/icons/generated/shard-43.cjs.map +1 -1
  1240. package/dist/icons/generated/shard-43.js.map +1 -1
  1241. package/dist/icons/generated/shard-44.cjs.map +1 -1
  1242. package/dist/icons/generated/shard-44.js.map +1 -1
  1243. package/dist/icons/generated/shard-45.cjs.map +1 -1
  1244. package/dist/icons/generated/shard-45.js.map +1 -1
  1245. package/dist/icons/icon-context.cjs.map +1 -1
  1246. package/dist/icons/icon-context.js.map +1 -1
  1247. package/dist/icons/is-icon-name.cjs.map +1 -1
  1248. package/dist/icons/is-icon-name.js.map +1 -1
  1249. package/dist/icons/material-symbols.cjs.map +1 -1
  1250. package/dist/icons/material-symbols.js.map +1 -1
  1251. package/dist/icons/normalize-icon-name.cjs.map +1 -1
  1252. package/dist/icons/normalize-icon-name.js.map +1 -1
  1253. package/dist/icons/shard-cache.cjs +1 -1
  1254. package/dist/icons/shard-cache.cjs.map +1 -1
  1255. package/dist/icons/shard-cache.js +2 -5
  1256. package/dist/icons/shard-cache.js.map +1 -1
  1257. package/dist/icons/use-icon.cjs.map +1 -1
  1258. package/dist/icons/use-icon.js.map +1 -1
  1259. package/dist/icons/validate-icon-name.cjs.map +1 -1
  1260. package/dist/icons/validate-icon-name.js.map +1 -1
  1261. package/dist/icons-virtual.cjs.map +1 -1
  1262. package/dist/icons-virtual.js.map +1 -1
  1263. package/dist/imaging/canvas.cjs.map +1 -1
  1264. package/dist/imaging/canvas.js.map +1 -1
  1265. package/dist/imaging/compress.cjs.map +1 -1
  1266. package/dist/imaging/compress.js.map +1 -1
  1267. package/dist/imaging/decode.cjs.map +1 -1
  1268. package/dist/imaging/decode.js.map +1 -1
  1269. package/dist/imaging/encode.cjs.map +1 -1
  1270. package/dist/imaging/encode.js.map +1 -1
  1271. package/dist/imaging/exceptions.cjs.map +1 -1
  1272. package/dist/imaging/exceptions.js.map +1 -1
  1273. package/dist/imaging/frame.cjs.map +1 -1
  1274. package/dist/imaging/frame.js.map +1 -1
  1275. package/dist/imaging/thumbnails.cjs.map +1 -1
  1276. package/dist/imaging/thumbnails.js.map +1 -1
  1277. package/dist/imaging/transform.cjs.map +1 -1
  1278. package/dist/imaging/transform.js.map +1 -1
  1279. package/dist/imaging/use-image-processing.cjs.map +1 -1
  1280. package/dist/imaging/use-image-processing.js.map +1 -1
  1281. package/dist/logger/logger.cjs.map +1 -1
  1282. package/dist/logger/logger.js.map +1 -1
  1283. package/dist/neural.cjs.map +1 -1
  1284. package/dist/neural.js.map +1 -1
  1285. package/dist/oauth/GoogleSignIn.cjs +1 -1
  1286. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  1287. package/dist/oauth/GoogleSignIn.js +6 -9
  1288. package/dist/oauth/GoogleSignIn.js.map +1 -1
  1289. package/dist/oauth/callback.cjs.map +1 -1
  1290. package/dist/oauth/callback.js.map +1 -1
  1291. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  1292. package/dist/oauth/use-oauth-callback.js.map +1 -1
  1293. package/dist/offline/conflict.cjs.map +1 -1
  1294. package/dist/offline/conflict.js.map +1 -1
  1295. package/dist/offline/create-offline-database.cjs.map +1 -1
  1296. package/dist/offline/create-offline-database.js.map +1 -1
  1297. package/dist/offline/create-offline-store.cjs +1 -1
  1298. package/dist/offline/create-offline-store.cjs.map +1 -1
  1299. package/dist/offline/create-offline-store.js +1 -5
  1300. package/dist/offline/create-offline-store.js.map +1 -1
  1301. package/dist/offline/create-offline-sync.cjs +1 -1
  1302. package/dist/offline/create-offline-sync.cjs.map +1 -1
  1303. package/dist/offline/create-offline-sync.js +9 -14
  1304. package/dist/offline/create-offline-sync.js.map +1 -1
  1305. package/dist/offline/use-offline-sync.cjs.map +1 -1
  1306. package/dist/offline/use-offline-sync.js.map +1 -1
  1307. package/dist/perf/cache-size.cjs.map +1 -1
  1308. package/dist/perf/cache-size.js.map +1 -1
  1309. package/dist/perf/device.cjs.map +1 -1
  1310. package/dist/perf/device.js.map +1 -1
  1311. package/dist/perf/format.cjs.map +1 -1
  1312. package/dist/perf/format.js.map +1 -1
  1313. package/dist/perf/profiler.cjs.map +1 -1
  1314. package/dist/perf/profiler.js.map +1 -1
  1315. package/dist/push/use-push-subscription.cjs.map +1 -1
  1316. package/dist/push/use-push-subscription.js.map +1 -1
  1317. package/dist/push/utils.cjs.map +1 -1
  1318. package/dist/push/utils.js.map +1 -1
  1319. package/dist/push/web-push-client.cjs.map +1 -1
  1320. package/dist/push/web-push-client.js.map +1 -1
  1321. package/dist/query/QueryProvider.cjs.map +1 -1
  1322. package/dist/query/QueryProvider.js.map +1 -1
  1323. package/dist/query/constants.cjs.map +1 -1
  1324. package/dist/query/constants.js.map +1 -1
  1325. package/dist/query/create-query-keys.cjs.map +1 -1
  1326. package/dist/query/create-query-keys.js.map +1 -1
  1327. package/dist/query/foreign-client-warning.cjs.map +1 -1
  1328. package/dist/query/foreign-client-warning.js.map +1 -1
  1329. package/dist/query/offline-persistence.cjs +1 -1
  1330. package/dist/query/offline-persistence.cjs.map +1 -1
  1331. package/dist/query/offline-persistence.js +2 -10
  1332. package/dist/query/offline-persistence.js.map +1 -1
  1333. package/dist/query/optimistic.cjs.map +1 -1
  1334. package/dist/query/optimistic.js.map +1 -1
  1335. package/dist/query/pagination.cjs.map +1 -1
  1336. package/dist/query/pagination.js.map +1 -1
  1337. package/dist/query/retry-policy.cjs.map +1 -1
  1338. package/dist/query/retry-policy.js.map +1 -1
  1339. package/dist/query/use-cursor-query.cjs.map +1 -1
  1340. package/dist/query/use-cursor-query.js.map +1 -1
  1341. package/dist/query/use-offline-mutation.cjs.map +1 -1
  1342. package/dist/query/use-offline-mutation.js.map +1 -1
  1343. package/dist/query/use-paginated-query.cjs.map +1 -1
  1344. package/dist/query/use-paginated-query.js.map +1 -1
  1345. package/dist/router/AppRouter.cjs.map +1 -1
  1346. package/dist/router/AppRouter.js.map +1 -1
  1347. package/dist/router/RouteGuard.cjs.map +1 -1
  1348. package/dist/router/RouteGuard.js.map +1 -1
  1349. package/dist/router/index.js +2 -2
  1350. package/dist/share/share-or-download.cjs.map +1 -1
  1351. package/dist/share/share-or-download.js.map +1 -1
  1352. package/dist/share/share.cjs.map +1 -1
  1353. package/dist/share/share.js.map +1 -1
  1354. package/dist/sse/create-event-stream.cjs.map +1 -1
  1355. package/dist/sse/create-event-stream.js.map +1 -1
  1356. package/dist/sse/use-event-stream.cjs.map +1 -1
  1357. package/dist/sse/use-event-stream.js.map +1 -1
  1358. package/dist/store/create-selectors.cjs.map +1 -1
  1359. package/dist/store/create-selectors.js.map +1 -1
  1360. package/dist/store/create-store.cjs.map +1 -1
  1361. package/dist/store/create-store.js.map +1 -1
  1362. package/dist/sw/background-sync.cjs +1 -1
  1363. package/dist/sw/background-sync.cjs.map +1 -1
  1364. package/dist/sw/background-sync.js +32 -31
  1365. package/dist/sw/background-sync.js.map +1 -1
  1366. package/dist/sw/cache-inspect.cjs.map +1 -1
  1367. package/dist/sw/cache-inspect.js.map +1 -1
  1368. package/dist/sw/cache.cjs +1 -1
  1369. package/dist/sw/cache.cjs.map +1 -1
  1370. package/dist/sw/cache.js +2 -6
  1371. package/dist/sw/cache.js.map +1 -1
  1372. package/dist/sw/create-push-handler.cjs.map +1 -1
  1373. package/dist/sw/create-push-handler.js.map +1 -1
  1374. package/dist/sw/credential-headers.cjs.map +1 -1
  1375. package/dist/sw/credential-headers.js.map +1 -1
  1376. package/dist/sw/periodic-sync.cjs.map +1 -1
  1377. package/dist/sw/periodic-sync.js.map +1 -1
  1378. package/dist/sw/register-service-worker.cjs.map +1 -1
  1379. package/dist/sw/register-service-worker.js.map +1 -1
  1380. package/dist/sw/session-data.cjs.map +1 -1
  1381. package/dist/sw/session-data.js.map +1 -1
  1382. package/dist/sw.d.ts +46 -8
  1383. package/dist/tabular/assets.cjs.map +1 -1
  1384. package/dist/tabular/assets.js.map +1 -1
  1385. package/dist/tabular/cache.cjs.map +1 -1
  1386. package/dist/tabular/cache.js.map +1 -1
  1387. package/dist/tabular/compact.cjs.map +1 -1
  1388. package/dist/tabular/compact.js.map +1 -1
  1389. package/dist/tabular/exceptions.cjs.map +1 -1
  1390. package/dist/tabular/exceptions.js.map +1 -1
  1391. package/dist/tabular/manifest.cjs.map +1 -1
  1392. package/dist/tabular/manifest.js.map +1 -1
  1393. package/dist/tabular/predictor.cjs.map +1 -1
  1394. package/dist/tabular/predictor.js.map +1 -1
  1395. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  1396. package/dist/tabular/use-tabular-predictor.js.map +1 -1
  1397. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  1398. package/dist/telemetry/TelemetryProvider.js.map +1 -1
  1399. package/dist/telemetry/app-error-adapter.cjs.map +1 -1
  1400. package/dist/telemetry/app-error-adapter.js.map +1 -1
  1401. package/dist/telemetry/app-error-queue.cjs.map +1 -1
  1402. package/dist/telemetry/app-error-queue.js.map +1 -1
  1403. package/dist/telemetry/app-error-reporter.cjs +1 -1
  1404. package/dist/telemetry/app-error-reporter.cjs.map +1 -1
  1405. package/dist/telemetry/app-error-reporter.js +1 -1
  1406. package/dist/telemetry/app-error-reporter.js.map +1 -1
  1407. package/dist/telemetry/app-error-schema.cjs.map +1 -1
  1408. package/dist/telemetry/app-error-schema.js.map +1 -1
  1409. package/dist/telemetry/app-error-transport.cjs.map +1 -1
  1410. package/dist/telemetry/app-error-transport.js.map +1 -1
  1411. package/dist/telemetry/console-adapter.cjs.map +1 -1
  1412. package/dist/telemetry/console-adapter.js.map +1 -1
  1413. package/dist/telemetry/describe-app-error.cjs.map +1 -1
  1414. package/dist/telemetry/describe-app-error.js.map +1 -1
  1415. package/dist/telemetry/posthog-adapter.cjs +1 -1
  1416. package/dist/telemetry/posthog-adapter.cjs.map +1 -1
  1417. package/dist/telemetry/posthog-adapter.js +1 -5
  1418. package/dist/telemetry/posthog-adapter.js.map +1 -1
  1419. package/dist/telemetry/sentry-adapter.cjs.map +1 -1
  1420. package/dist/telemetry/sentry-adapter.js.map +1 -1
  1421. package/dist/tempest-react-sdk.cjs +1 -1
  1422. package/dist/tempest-react-sdk.d.ts +448 -15
  1423. package/dist/tempest-react-sdk.js +119 -119
  1424. package/dist/testing/create-mock-handlers.cjs.map +1 -1
  1425. package/dist/testing/create-mock-handlers.js.map +1 -1
  1426. package/dist/testing.js +1 -2
  1427. package/dist/theme/ThemeProvider.cjs.map +1 -1
  1428. package/dist/theme/ThemeProvider.js.map +1 -1
  1429. package/dist/theme/apply-theme.cjs.map +1 -1
  1430. package/dist/theme/apply-theme.js.map +1 -1
  1431. package/dist/theme/color.cjs.map +1 -1
  1432. package/dist/theme/color.js.map +1 -1
  1433. package/dist/theme/create-theme.cjs.map +1 -1
  1434. package/dist/theme/create-theme.js.map +1 -1
  1435. package/dist/theme/data-viz-ramps.cjs.map +1 -1
  1436. package/dist/theme/data-viz-ramps.js.map +1 -1
  1437. package/dist/theme/initial-theme.cjs.map +1 -1
  1438. package/dist/theme/initial-theme.js.map +1 -1
  1439. package/dist/theme/inverse-render.cjs.map +1 -1
  1440. package/dist/theme/inverse-render.js.map +1 -1
  1441. package/dist/theme/inverse-restore.cjs.map +1 -1
  1442. package/dist/theme/inverse-restore.js.map +1 -1
  1443. package/dist/theme/inverse-surface.cjs.map +1 -1
  1444. package/dist/theme/inverse-surface.js.map +1 -1
  1445. package/dist/theme/status-tokens.cjs.map +1 -1
  1446. package/dist/theme/status-tokens.js.map +1 -1
  1447. package/dist/theme/theme-presets.cjs.map +1 -1
  1448. package/dist/theme/theme-presets.js.map +1 -1
  1449. package/dist/utils/absent.cjs.map +1 -1
  1450. package/dist/utils/absent.js.map +1 -1
  1451. package/dist/utils/arrays.cjs.map +1 -1
  1452. package/dist/utils/arrays.js.map +1 -1
  1453. package/dist/utils/base64.cjs.map +1 -1
  1454. package/dist/utils/base64.js.map +1 -1
  1455. package/dist/utils/cn.cjs.map +1 -1
  1456. package/dist/utils/cn.js.map +1 -1
  1457. package/dist/utils/compare-values.cjs.map +1 -1
  1458. package/dist/utils/compare-values.js.map +1 -1
  1459. package/dist/utils/compressed-storage.cjs.map +1 -1
  1460. package/dist/utils/compressed-storage.js.map +1 -1
  1461. package/dist/utils/csv.cjs +3 -3
  1462. package/dist/utils/csv.cjs.map +1 -1
  1463. package/dist/utils/csv.js +11 -10
  1464. package/dist/utils/csv.js.map +1 -1
  1465. package/dist/utils/dev-mode.cjs.map +1 -1
  1466. package/dist/utils/dev-mode.js.map +1 -1
  1467. package/dist/utils/duplicate-instance.cjs.map +1 -1
  1468. package/dist/utils/duplicate-instance.js.map +1 -1
  1469. package/dist/utils/format.cjs.map +1 -1
  1470. package/dist/utils/format.js.map +1 -1
  1471. package/dist/utils/functions.cjs +1 -1
  1472. package/dist/utils/functions.cjs.map +1 -1
  1473. package/dist/utils/functions.js +1 -1
  1474. package/dist/utils/functions.js.map +1 -1
  1475. package/dist/utils/guards.cjs.map +1 -1
  1476. package/dist/utils/guards.js.map +1 -1
  1477. package/dist/utils/ids.cjs.map +1 -1
  1478. package/dist/utils/ids.js.map +1 -1
  1479. package/dist/utils/intl-cache.cjs.map +1 -1
  1480. package/dist/utils/intl-cache.js.map +1 -1
  1481. package/dist/utils/json-frame.cjs.map +1 -1
  1482. package/dist/utils/json-frame.js.map +1 -1
  1483. package/dist/utils/numbers.cjs.map +1 -1
  1484. package/dist/utils/numbers.js.map +1 -1
  1485. package/dist/utils/objects.cjs.map +1 -1
  1486. package/dist/utils/objects.js.map +1 -1
  1487. package/dist/{telemetry/app-error-owner.cjs → utils/owner-fingerprint.cjs} +2 -2
  1488. package/dist/utils/owner-fingerprint.cjs.map +1 -0
  1489. package/dist/{telemetry/app-error-owner.js → utils/owner-fingerprint.js} +3 -3
  1490. package/dist/utils/owner-fingerprint.js.map +1 -0
  1491. package/dist/utils/promises.cjs.map +1 -1
  1492. package/dist/utils/promises.js.map +1 -1
  1493. package/dist/utils/relative-time.cjs.map +1 -1
  1494. package/dist/utils/relative-time.js.map +1 -1
  1495. package/dist/utils/safe-url.cjs.map +1 -1
  1496. package/dist/utils/safe-url.js.map +1 -1
  1497. package/dist/utils/schema-like.cjs.map +1 -1
  1498. package/dist/utils/schema-like.js.map +1 -1
  1499. package/dist/utils/storage.cjs +1 -1
  1500. package/dist/utils/storage.cjs.map +1 -1
  1501. package/dist/utils/storage.js +2 -2
  1502. package/dist/utils/storage.js.map +1 -1
  1503. package/dist/utils/strings.cjs.map +1 -1
  1504. package/dist/utils/strings.js.map +1 -1
  1505. package/dist/utils/xlsx.cjs.map +1 -1
  1506. package/dist/utils/xlsx.js.map +1 -1
  1507. package/dist/vision/core/canvas.cjs.map +1 -1
  1508. package/dist/vision/core/canvas.js.map +1 -1
  1509. package/dist/vision/core/dtypes.cjs.map +1 -1
  1510. package/dist/vision/core/dtypes.js.map +1 -1
  1511. package/dist/vision/core/exceptions.cjs.map +1 -1
  1512. package/dist/vision/core/exceptions.js.map +1 -1
  1513. package/dist/vision/core/graph.cjs.map +1 -1
  1514. package/dist/vision/core/graph.js.map +1 -1
  1515. package/dist/vision/core/metadata.cjs +1 -1
  1516. package/dist/vision/core/metadata.cjs.map +1 -1
  1517. package/dist/vision/core/metadata.js +9 -26
  1518. package/dist/vision/core/metadata.js.map +1 -1
  1519. package/dist/vision/core/providers.cjs.map +1 -1
  1520. package/dist/vision/core/providers.js.map +1 -1
  1521. package/dist/vision/core/session.cjs.map +1 -1
  1522. package/dist/vision/core/session.js.map +1 -1
  1523. package/dist/vision/core/timing.cjs.map +1 -1
  1524. package/dist/vision/core/timing.js.map +1 -1
  1525. package/dist/vision/fusion.cjs.map +1 -1
  1526. package/dist/vision/fusion.js.map +1 -1
  1527. package/dist/vision/index.cjs.map +1 -1
  1528. package/dist/vision/index.js.map +1 -1
  1529. package/dist/vision/io/image.cjs.map +1 -1
  1530. package/dist/vision/io/image.js.map +1 -1
  1531. package/dist/vision/labels.cjs.map +1 -1
  1532. package/dist/vision/labels.js.map +1 -1
  1533. package/dist/vision/luminance.cjs.map +1 -1
  1534. package/dist/vision/luminance.js.map +1 -1
  1535. package/dist/vision/normalization.cjs.map +1 -1
  1536. package/dist/vision/normalization.js.map +1 -1
  1537. package/dist/vision/postprocess/classification.cjs.map +1 -1
  1538. package/dist/vision/postprocess/classification.js.map +1 -1
  1539. package/dist/vision/postprocess/detection.cjs.map +1 -1
  1540. package/dist/vision/postprocess/detection.js.map +1 -1
  1541. package/dist/vision/postprocess/segmentation.cjs.map +1 -1
  1542. package/dist/vision/postprocess/segmentation.js.map +1 -1
  1543. package/dist/vision/preprocess/image.cjs.map +1 -1
  1544. package/dist/vision/preprocess/image.js.map +1 -1
  1545. package/dist/vision/preprocess/pipeline.cjs.map +1 -1
  1546. package/dist/vision/preprocess/pipeline.js.map +1 -1
  1547. package/dist/vision/results.cjs.map +1 -1
  1548. package/dist/vision/results.js.map +1 -1
  1549. package/dist/vision/tasks/base.cjs.map +1 -1
  1550. package/dist/vision/tasks/base.js.map +1 -1
  1551. package/dist/vision/tasks/classifier.cjs.map +1 -1
  1552. package/dist/vision/tasks/classifier.js.map +1 -1
  1553. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  1554. package/dist/vision/tasks/detectClassify.js.map +1 -1
  1555. package/dist/vision/tasks/detector.cjs.map +1 -1
  1556. package/dist/vision/tasks/detector.js.map +1 -1
  1557. package/dist/vision/tasks/segmenter.cjs.map +1 -1
  1558. package/dist/vision/tasks/segmenter.js.map +1 -1
  1559. package/dist/vision/types.cjs.map +1 -1
  1560. package/dist/vision/types.js.map +1 -1
  1561. package/dist/vision/use-camera-stream.cjs +1 -1
  1562. package/dist/vision/use-camera-stream.cjs.map +1 -1
  1563. package/dist/vision/use-camera-stream.js +3 -9
  1564. package/dist/vision/use-camera-stream.js.map +1 -1
  1565. package/dist/vision/use-live-luminance.cjs +1 -1
  1566. package/dist/vision/use-live-luminance.cjs.map +1 -1
  1567. package/dist/vision/use-live-luminance.js +1 -5
  1568. package/dist/vision/use-live-luminance.js.map +1 -1
  1569. package/dist/vite/base-url.cjs.map +1 -1
  1570. package/dist/vite/base-url.js.map +1 -1
  1571. package/dist/vite/create-vite-config.cjs.map +1 -1
  1572. package/dist/vite/create-vite-config.js.map +1 -1
  1573. package/dist/vite/narrow-tokens.cjs.map +1 -1
  1574. package/dist/vite/narrow-tokens.js.map +1 -1
  1575. package/dist/vite/tempest-csp.cjs +2 -2
  1576. package/dist/vite/tempest-csp.cjs.map +1 -1
  1577. package/dist/vite/tempest-csp.js +69 -66
  1578. package/dist/vite/tempest-csp.js.map +1 -1
  1579. package/dist/vite/tempest-icons.cjs.map +1 -1
  1580. package/dist/vite/tempest-icons.js.map +1 -1
  1581. package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
  1582. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  1583. package/dist/vite/tempest-pwa-dev-sw.js +9 -16
  1584. package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
  1585. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  1586. package/dist/vite/tempest-pwa-icons.js.map +1 -1
  1587. package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
  1588. package/dist/vite/tempest-pwa-manifest.js.map +1 -1
  1589. package/dist/vite/tempest-styles.cjs.map +1 -1
  1590. package/dist/vite/tempest-styles.js.map +1 -1
  1591. package/dist/vite/tempest-vitest.cjs.map +1 -1
  1592. package/dist/vite/tempest-vitest.js.map +1 -1
  1593. package/dist/vite.d.ts +5 -3
  1594. package/dist/webrtc/link-stats.cjs.map +1 -1
  1595. package/dist/webrtc/link-stats.js.map +1 -1
  1596. package/dist/webrtc/mesh-quality.cjs.map +1 -1
  1597. package/dist/webrtc/mesh-quality.js.map +1 -1
  1598. package/dist/webrtc/opus-sdp.cjs.map +1 -1
  1599. package/dist/webrtc/opus-sdp.js.map +1 -1
  1600. package/dist/webrtc/peer-link.cjs +1 -1
  1601. package/dist/webrtc/peer-link.cjs.map +1 -1
  1602. package/dist/webrtc/peer-link.js +2 -5
  1603. package/dist/webrtc/peer-link.js.map +1 -1
  1604. package/dist/webrtc/peer-mesh.cjs +1 -1
  1605. package/dist/webrtc/peer-mesh.cjs.map +1 -1
  1606. package/dist/webrtc/peer-mesh.js +8 -24
  1607. package/dist/webrtc/peer-mesh.js.map +1 -1
  1608. package/dist/webrtc/sender-bitrate.cjs.map +1 -1
  1609. package/dist/webrtc/sender-bitrate.js.map +1 -1
  1610. package/dist/webrtc/use-link-stats.cjs.map +1 -1
  1611. package/dist/webrtc/use-link-stats.js.map +1 -1
  1612. package/dist/ws/create-web-socket.cjs +1 -1
  1613. package/dist/ws/create-web-socket.cjs.map +1 -1
  1614. package/dist/ws/create-web-socket.js +4 -22
  1615. package/dist/ws/create-web-socket.js.map +1 -1
  1616. package/dist/ws/resilience.cjs.map +1 -1
  1617. package/dist/ws/resilience.js.map +1 -1
  1618. package/dist/ws/use-web-socket.cjs.map +1 -1
  1619. package/dist/ws/use-web-socket.js.map +1 -1
  1620. package/package.json +9 -6
  1621. package/template/package.json +1 -1
  1622. package/dist/telemetry/app-error-owner.cjs.map +0 -1
  1623. package/dist/telemetry/app-error-owner.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"opus-sdp.cjs","names":[],"sources":["../../src/webrtc/opus-sdp.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — parsing a session description, merging one\n * `fmtp` line and inserting a missing one are the same pass over the same\n * grammar; split apart, each half is a parser of half an SDP.\n */\n\n/** What an Opus `fmtp` line can be asked to carry. Every field is optional. */\nexport interface OpusProfile {\n /**\n * Ceiling the encoder is asked to respect, in bits per second.\n *\n * This describes what we want **to receive**. To cap what we *send*, use\n * `setSenderBitrate` — in a mesh that is the one that matters, because the\n * uplink carries one copy per participant.\n */\n maxAverageBitrate?: number;\n /** Highest sample rate worth decoding, in Hz. `48000` for full band. */\n maxPlaybackRate?: number;\n /**\n * Two channels instead of one.\n *\n * Sets `stereo` **and** `sprop-stereo`, which point in opposite directions:\n * `stereo=1` asks the *remote* to send two channels, `sprop-stereo=1`\n * announces that *we* will. Setting only one leaves the link asymmetric,\n * which is the recurring reason \"I asked for stereo and got mono\".\n */\n stereo?: boolean;\n /**\n * In-band forward error correction (`useinbandfec`).\n *\n * Rebuilds a lost packet from the next one, which keeps speech intelligible\n * on a lossy link — and smears music, since it spends bitrate on redundancy\n * instead of detail.\n */\n fec?: boolean;\n /**\n * Discontinuous transmission (`usedtx`): stop sending during silence.\n *\n * Saves uplink in a mesh, at the cost of clipping the first instant after a\n * pause. Wrong for music and for a shared screen, where the quiet passages\n * are content.\n */\n dtx?: boolean;\n /** Constant bitrate (`cbr`). Off by default, as Opus intends. */\n cbr?: boolean;\n /**\n * Any other `fmtp` key, merged verbatim.\n *\n * The escape hatch for a parameter this type does not model. Values are\n * written as given; a key with an empty string is emitted as a bare flag.\n */\n extra?: Record<string, string>;\n}\n\n/**\n * Profiles to apply, keyed by audio m-line index (`0`, `1`, …) or by `mid`.\n *\n * Position and `mid` can be mixed in one object. A key that matches nothing is\n * ignored rather than an error — an SDP is negotiated, and a slot that was not\n * offered this time is normal.\n */\nexport type OpusProfileMap = Record<string | number, OpusProfile>;\n\n/** Keys that identify a bare {@link OpusProfile} rather than a map of them. */\nconst PROFILE_KEYS: ReadonlySet<string> = new Set([\n \"maxAverageBitrate\",\n \"maxPlaybackRate\",\n \"stereo\",\n \"fec\",\n \"dtx\",\n \"cbr\",\n \"extra\",\n]);\n\n/**\n * Whether the caller passed one profile for every audio m-line, or a map.\n *\n * An empty object is read as a profile, which makes `tuneOpus(sdp, {})` a no-op\n * instead of a silent surprise.\n */\nfunction isSingleProfile(value: OpusProfile | OpusProfileMap): value is OpusProfile {\n const keys = Object.keys(value);\n return keys.length === 0 || keys.some((key) => PROFILE_KEYS.has(key));\n}\n\n/** The `fmtp` parameters a profile asks for, in the order Opus documents them. */\nfunction fmtpParams(profile: OpusProfile): Record<string, string> {\n const params: Record<string, string> = {};\n if (profile.maxAverageBitrate !== undefined) {\n params.maxaveragebitrate = String(profile.maxAverageBitrate);\n }\n if (profile.maxPlaybackRate !== undefined) {\n params.maxplaybackrate = String(profile.maxPlaybackRate);\n }\n if (profile.stereo !== undefined) {\n params.stereo = profile.stereo ? \"1\" : \"0\";\n params[\"sprop-stereo\"] = profile.stereo ? \"1\" : \"0\";\n }\n if (profile.fec !== undefined) params.useinbandfec = profile.fec ? \"1\" : \"0\";\n if (profile.dtx !== undefined) params.usedtx = profile.dtx ? \"1\" : \"0\";\n if (profile.cbr !== undefined) params.cbr = profile.cbr ? \"1\" : \"0\";\n return { ...params, ...profile.extra };\n}\n\n/**\n * Merge parameters into an existing `fmtp` payload, key by key.\n *\n * Replacing the whole line is the obvious move and it is wrong: the browser\n * emits `minptime=10;useinbandfec=1` on its own, and overwriting drops the\n * `minptime` — a packetization decision nobody meant to change.\n */\nfunction mergeFmtp(existing: string, params: Record<string, string>): string {\n const merged = new Map<string, string>();\n for (const entry of existing.split(\";\")) {\n const trimmed = entry.trim();\n if (!trimmed) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq < 0) merged.set(trimmed, \"\");\n else merged.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));\n }\n for (const [key, value] of Object.entries(params)) merged.set(key, value);\n return [...merged.entries()]\n .map(([key, value]) => (value === \"\" ? key : `${key}=${value}`))\n .join(\";\");\n}\n\n/** Payload types this media block maps to Opus. There can be more than one. */\nfunction opusPayloads(block: readonly string[]): string[] {\n const payloads: string[] = [];\n for (const line of block) {\n const match = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (match) payloads.push(match[1]);\n }\n return payloads;\n}\n\n/** The block's `mid`, when it declares one. */\nfunction blockMid(block: readonly string[]): string | null {\n for (const line of block) {\n const match = /^a=mid:(.+)$/.exec(line);\n if (match) return match[1].trim();\n }\n return null;\n}\n\n/**\n * Rewrite one media block's Opus `fmtp` lines to carry a profile.\n *\n * A payload type with no `fmtp` of its own gets one inserted right after its\n * `rtpmap`, because \"the parameter is missing\" and \"the parameter is empty\" are\n * the same request from the caller's side.\n */\nfunction tuneBlock(block: readonly string[], profile: OpusProfile): string[] {\n const params = fmtpParams(profile);\n const payloads = opusPayloads(block);\n if (payloads.length === 0 || Object.keys(params).length === 0) return [...block];\n\n const out: string[] = [];\n for (const line of block) {\n const fmtp = /^a=fmtp:(\\d+)\\s+(.*)$/.exec(line);\n if (fmtp && payloads.includes(fmtp[1])) {\n out.push(`a=fmtp:${fmtp[1]} ${mergeFmtp(fmtp[2], params)}`);\n continue;\n }\n out.push(line);\n\n const rtpmap = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (rtpmap && !block.some((other) => other.startsWith(`a=fmtp:${rtpmap[1]} `))) {\n out.push(`a=fmtp:${rtpmap[1]} ${mergeFmtp(\"\", params)}`);\n }\n }\n return out;\n}\n\n/** Split a session description into its session part plus one block per m-line. */\nfunction mediaBlocks(sdp: string): string[][] {\n const blocks: string[][] = [];\n let current: string[] = [];\n for (const line of sdp.split(/\\r\\n|\\n/)) {\n if (line.startsWith(\"m=\") && current.length > 0) {\n blocks.push(current);\n current = [];\n }\n current.push(line);\n }\n if (current.length > 0) blocks.push(current);\n return blocks;\n}\n\n/**\n * Apply Opus profiles to the audio m-lines of a session description.\n *\n * Audio over WebRTC is mono and narrow by default, and the only place that is\n * corrected is the SDP — which is why shared-screen audio famously sounds like a\n * telephone: music and video inherit the speech profile (mono, ~32 kbps, FEC on,\n * DTX gating the quiet passages) and no high-level API lets you change it.\n *\n * Deliberately **without** built-in presets: which values to use is the\n * consumer's call — voice in a mesh does not want what system audio wants — and\n * a preset table is the kind of thing that has no business inside a dependency.\n * What lives here is the parsing, merging and insertion, which is where the long\n * tail is. Getting any of it wrong degrades silently: nobody sees an exception,\n * the audio is just worse.\n *\n * @param sdp - The description from `createOffer` or `createAnswer`.\n * @param profiles - One {@link OpusProfile} for every audio m-line, or an\n * {@link OpusProfileMap} keyed by audio m-line index or by `mid`.\n * @returns The rewritten SDP, with CRLF line endings as RFC 4566 requires.\n * Untouched when there is no Opus, when no profile matches, or when a profile\n * asks for nothing.\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, {\n * 0: { maxAverageBitrate: 48_000, stereo: false, fec: true, dtx: true },\n * 1: { maxAverageBitrate: 192_000, stereo: true, fec: false, dtx: false },\n * });\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, { stereo: true, dtx: false });\n */\nexport function tuneOpus(sdp: string, profiles: OpusProfile | OpusProfileMap): string {\n const single = isSingleProfile(profiles) ? profiles : null;\n const map = single ? null : (profiles as OpusProfileMap);\n\n let audioIndex = 0;\n const tuned = mediaBlocks(sdp).map((block) => {\n if (!block[0]?.startsWith(\"m=audio\")) return block;\n\n const index = audioIndex;\n audioIndex += 1;\n if (single) return tuneBlock(block, single);\n\n const mid = blockMid(block);\n const profile = map?.[index] ?? (mid !== null ? map?.[mid] : undefined);\n return profile ? tuneBlock(block, profile) : block;\n });\n\n return tuned.flat().join(\"\\r\\n\");\n}\n\n/** Which description a peer connection actually accepted. */\nexport type TunedDescriptionResult = \"tuned\" | \"original\";\n\n/**\n * Set a local description, falling back to the untouched one if it is refused.\n *\n * Chrome has been tightening what `setLocalDescription` accepts from edited SDP,\n * and there is no way to know in advance. Without a fallback the call dies\n * instead of merely losing the profile — which is the wrong trade by a wide\n * margin: worse audio beats no audio.\n *\n * @param connection - The peer connection.\n * @param description - The description from `createOffer` / `createAnswer`.\n * @param profiles - Passed straight to {@link tuneOpus}.\n * @returns `\"tuned\"` when the rewritten SDP was accepted, `\"original\"` when the\n * fallback was used — worth reporting, because it means the profile silently\n * did not apply.\n * @throws Whatever `setLocalDescription` throws for the original description: at\n * that point the failure is not about the rewrite and the caller has to know.\n *\n * @example\n * const applied = await setTunedLocalDescription(pc, await pc.createOffer(), profiles);\n * if (applied === \"original\") logger.warn(\"opus profile refused by the browser\");\n */\nexport async function setTunedLocalDescription(\n connection: RTCPeerConnection,\n description: RTCSessionDescriptionInit,\n profiles: OpusProfile | OpusProfileMap,\n): Promise<TunedDescriptionResult> {\n if (description.sdp) {\n const sdp = tuneOpus(description.sdp, profiles);\n if (sdp !== description.sdp) {\n try {\n await connection.setLocalDescription({ ...description, sdp });\n return \"tuned\";\n } catch {\n /* the browser refused the edit; the untouched offer still works */\n }\n }\n }\n await connection.setLocalDescription(description);\n return \"original\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"opus-sdp.cjs","names":["PROFILE_KEYS","isSingleProfile","keys","value","key","fmtpParams","params","profile","mergeFmtp","merged","entry","existing","trimmed","eq","opusPayloads","payloads","line","block","match","blockMid","tuneBlock","out","fmtp","rtpmap","other","mediaBlocks","blocks","current","sdp","tuneOpus","single","profiles","map","audioIndex","index","mid","setTunedLocalDescription","description","connection"],"sources":["../../src/webrtc/opus-sdp.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — parsing a session description, merging one\n * `fmtp` line and inserting a missing one are the same pass over the same\n * grammar; split apart, each half is a parser of half an SDP.\n */\n\n/** What an Opus `fmtp` line can be asked to carry. Every field is optional. */\nexport interface OpusProfile {\n /**\n * Ceiling the encoder is asked to respect, in bits per second.\n *\n * This describes what we want **to receive**. To cap what we *send*, use\n * `setSenderBitrate` — in a mesh that is the one that matters, because the\n * uplink carries one copy per participant.\n */\n maxAverageBitrate?: number;\n /** Highest sample rate worth decoding, in Hz. `48000` for full band. */\n maxPlaybackRate?: number;\n /**\n * Two channels instead of one.\n *\n * Sets `stereo` **and** `sprop-stereo`, which point in opposite directions:\n * `stereo=1` asks the *remote* to send two channels, `sprop-stereo=1`\n * announces that *we* will. Setting only one leaves the link asymmetric,\n * which is the recurring reason \"I asked for stereo and got mono\".\n */\n stereo?: boolean;\n /**\n * In-band forward error correction (`useinbandfec`).\n *\n * Rebuilds a lost packet from the next one, which keeps speech intelligible\n * on a lossy link — and smears music, since it spends bitrate on redundancy\n * instead of detail.\n */\n fec?: boolean;\n /**\n * Discontinuous transmission (`usedtx`): stop sending during silence.\n *\n * Saves uplink in a mesh, at the cost of clipping the first instant after a\n * pause. Wrong for music and for a shared screen, where the quiet passages\n * are content.\n */\n dtx?: boolean;\n /** Constant bitrate (`cbr`). Off by default, as Opus intends. */\n cbr?: boolean;\n /**\n * Any other `fmtp` key, merged verbatim.\n *\n * The escape hatch for a parameter this type does not model. Values are\n * written as given; a key with an empty string is emitted as a bare flag.\n */\n extra?: Record<string, string>;\n}\n\n/**\n * Profiles to apply, keyed by audio m-line index (`0`, `1`, …) or by `mid`.\n *\n * Position and `mid` can be mixed in one object. A key that matches nothing is\n * ignored rather than an error — an SDP is negotiated, and a slot that was not\n * offered this time is normal.\n */\nexport type OpusProfileMap = Record<string | number, OpusProfile>;\n\n/** Keys that identify a bare {@link OpusProfile} rather than a map of them. */\nconst PROFILE_KEYS: ReadonlySet<string> = new Set([\n \"maxAverageBitrate\",\n \"maxPlaybackRate\",\n \"stereo\",\n \"fec\",\n \"dtx\",\n \"cbr\",\n \"extra\",\n]);\n\n/**\n * Whether the caller passed one profile for every audio m-line, or a map.\n *\n * An empty object is read as a profile, which makes `tuneOpus(sdp, {})` a no-op\n * instead of a silent surprise.\n */\nfunction isSingleProfile(value: OpusProfile | OpusProfileMap): value is OpusProfile {\n const keys = Object.keys(value);\n return keys.length === 0 || keys.some((key) => PROFILE_KEYS.has(key));\n}\n\n/** The `fmtp` parameters a profile asks for, in the order Opus documents them. */\nfunction fmtpParams(profile: OpusProfile): Record<string, string> {\n const params: Record<string, string> = {};\n if (profile.maxAverageBitrate !== undefined) {\n params.maxaveragebitrate = String(profile.maxAverageBitrate);\n }\n if (profile.maxPlaybackRate !== undefined) {\n params.maxplaybackrate = String(profile.maxPlaybackRate);\n }\n if (profile.stereo !== undefined) {\n params.stereo = profile.stereo ? \"1\" : \"0\";\n params[\"sprop-stereo\"] = profile.stereo ? \"1\" : \"0\";\n }\n if (profile.fec !== undefined) params.useinbandfec = profile.fec ? \"1\" : \"0\";\n if (profile.dtx !== undefined) params.usedtx = profile.dtx ? \"1\" : \"0\";\n if (profile.cbr !== undefined) params.cbr = profile.cbr ? \"1\" : \"0\";\n return { ...params, ...profile.extra };\n}\n\n/**\n * Merge parameters into an existing `fmtp` payload, key by key.\n *\n * Replacing the whole line is the obvious move and it is wrong: the browser\n * emits `minptime=10;useinbandfec=1` on its own, and overwriting drops the\n * `minptime` — a packetization decision nobody meant to change.\n */\nfunction mergeFmtp(existing: string, params: Record<string, string>): string {\n const merged = new Map<string, string>();\n for (const entry of existing.split(\";\")) {\n const trimmed = entry.trim();\n if (!trimmed) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq < 0) merged.set(trimmed, \"\");\n else merged.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));\n }\n for (const [key, value] of Object.entries(params)) merged.set(key, value);\n return [...merged.entries()]\n .map(([key, value]) => (value === \"\" ? key : `${key}=${value}`))\n .join(\";\");\n}\n\n/** Payload types this media block maps to Opus. There can be more than one. */\nfunction opusPayloads(block: readonly string[]): string[] {\n const payloads: string[] = [];\n for (const line of block) {\n const match = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (match) payloads.push(match[1]);\n }\n return payloads;\n}\n\n/** The block's `mid`, when it declares one. */\nfunction blockMid(block: readonly string[]): string | null {\n for (const line of block) {\n const match = /^a=mid:(.+)$/.exec(line);\n if (match) return match[1].trim();\n }\n return null;\n}\n\n/**\n * Rewrite one media block's Opus `fmtp` lines to carry a profile.\n *\n * A payload type with no `fmtp` of its own gets one inserted right after its\n * `rtpmap`, because \"the parameter is missing\" and \"the parameter is empty\" are\n * the same request from the caller's side.\n */\nfunction tuneBlock(block: readonly string[], profile: OpusProfile): string[] {\n const params = fmtpParams(profile);\n const payloads = opusPayloads(block);\n if (payloads.length === 0 || Object.keys(params).length === 0) return [...block];\n\n const out: string[] = [];\n for (const line of block) {\n const fmtp = /^a=fmtp:(\\d+)\\s+(.*)$/.exec(line);\n if (fmtp && payloads.includes(fmtp[1])) {\n out.push(`a=fmtp:${fmtp[1]} ${mergeFmtp(fmtp[2], params)}`);\n continue;\n }\n out.push(line);\n\n const rtpmap = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (rtpmap && !block.some((other) => other.startsWith(`a=fmtp:${rtpmap[1]} `))) {\n out.push(`a=fmtp:${rtpmap[1]} ${mergeFmtp(\"\", params)}`);\n }\n }\n return out;\n}\n\n/** Split a session description into its session part plus one block per m-line. */\nfunction mediaBlocks(sdp: string): string[][] {\n const blocks: string[][] = [];\n let current: string[] = [];\n for (const line of sdp.split(/\\r\\n|\\n/)) {\n if (line.startsWith(\"m=\") && current.length > 0) {\n blocks.push(current);\n current = [];\n }\n current.push(line);\n }\n if (current.length > 0) blocks.push(current);\n return blocks;\n}\n\n/**\n * Apply Opus profiles to the audio m-lines of a session description.\n *\n * Audio over WebRTC is mono and narrow by default, and the only place that is\n * corrected is the SDP — which is why shared-screen audio famously sounds like a\n * telephone: music and video inherit the speech profile (mono, ~32 kbps, FEC on,\n * DTX gating the quiet passages) and no high-level API lets you change it.\n *\n * Deliberately **without** built-in presets: which values to use is the\n * consumer's call — voice in a mesh does not want what system audio wants — and\n * a preset table is the kind of thing that has no business inside a dependency.\n * What lives here is the parsing, merging and insertion, which is where the long\n * tail is. Getting any of it wrong degrades silently: nobody sees an exception,\n * the audio is just worse.\n *\n * @param sdp - The description from `createOffer` or `createAnswer`.\n * @param profiles - One {@link OpusProfile} for every audio m-line, or an\n * {@link OpusProfileMap} keyed by audio m-line index or by `mid`.\n * @returns The rewritten SDP, with CRLF line endings as RFC 4566 requires.\n * Untouched when there is no Opus, when no profile matches, or when a profile\n * asks for nothing.\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, {\n * 0: { maxAverageBitrate: 48_000, stereo: false, fec: true, dtx: true },\n * 1: { maxAverageBitrate: 192_000, stereo: true, fec: false, dtx: false },\n * });\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, { stereo: true, dtx: false });\n */\nexport function tuneOpus(sdp: string, profiles: OpusProfile | OpusProfileMap): string {\n const single = isSingleProfile(profiles) ? profiles : null;\n const map = single ? null : (profiles as OpusProfileMap);\n\n let audioIndex = 0;\n const tuned = mediaBlocks(sdp).map((block) => {\n if (!block[0]?.startsWith(\"m=audio\")) return block;\n\n const index = audioIndex;\n audioIndex += 1;\n if (single) return tuneBlock(block, single);\n\n const mid = blockMid(block);\n const profile = map?.[index] ?? (mid !== null ? map?.[mid] : undefined);\n return profile ? tuneBlock(block, profile) : block;\n });\n\n return tuned.flat().join(\"\\r\\n\");\n}\n\n/** Which description a peer connection actually accepted. */\nexport type TunedDescriptionResult = \"tuned\" | \"original\";\n\n/**\n * Set a local description, falling back to the untouched one if it is refused.\n *\n * Chrome has been tightening what `setLocalDescription` accepts from edited SDP,\n * and there is no way to know in advance. Without a fallback the call dies\n * instead of merely losing the profile — which is the wrong trade by a wide\n * margin: worse audio beats no audio.\n *\n * @param connection - The peer connection.\n * @param description - The description from `createOffer` / `createAnswer`.\n * @param profiles - Passed straight to {@link tuneOpus}.\n * @returns `\"tuned\"` when the rewritten SDP was accepted, `\"original\"` when the\n * fallback was used — worth reporting, because it means the profile silently\n * did not apply.\n * @throws Whatever `setLocalDescription` throws for the original description: at\n * that point the failure is not about the rewrite and the caller has to know.\n *\n * @example\n * const applied = await setTunedLocalDescription(pc, await pc.createOffer(), profiles);\n * if (applied === \"original\") logger.warn(\"opus profile refused by the browser\");\n */\nexport async function setTunedLocalDescription(\n connection: RTCPeerConnection,\n description: RTCSessionDescriptionInit,\n profiles: OpusProfile | OpusProfileMap,\n): Promise<TunedDescriptionResult> {\n if (description.sdp) {\n const sdp = tuneOpus(description.sdp, profiles);\n if (sdp !== description.sdp) {\n try {\n await connection.setLocalDescription({ ...description, sdp });\n return \"tuned\";\n } catch {\n /* the browser refused the edit; the untouched offer still works */\n }\n }\n }\n await connection.setLocalDescription(description);\n return \"original\";\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"opus-sdp.js","names":[],"sources":["../../src/webrtc/opus-sdp.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — parsing a session description, merging one\n * `fmtp` line and inserting a missing one are the same pass over the same\n * grammar; split apart, each half is a parser of half an SDP.\n */\n\n/** What an Opus `fmtp` line can be asked to carry. Every field is optional. */\nexport interface OpusProfile {\n /**\n * Ceiling the encoder is asked to respect, in bits per second.\n *\n * This describes what we want **to receive**. To cap what we *send*, use\n * `setSenderBitrate` — in a mesh that is the one that matters, because the\n * uplink carries one copy per participant.\n */\n maxAverageBitrate?: number;\n /** Highest sample rate worth decoding, in Hz. `48000` for full band. */\n maxPlaybackRate?: number;\n /**\n * Two channels instead of one.\n *\n * Sets `stereo` **and** `sprop-stereo`, which point in opposite directions:\n * `stereo=1` asks the *remote* to send two channels, `sprop-stereo=1`\n * announces that *we* will. Setting only one leaves the link asymmetric,\n * which is the recurring reason \"I asked for stereo and got mono\".\n */\n stereo?: boolean;\n /**\n * In-band forward error correction (`useinbandfec`).\n *\n * Rebuilds a lost packet from the next one, which keeps speech intelligible\n * on a lossy link — and smears music, since it spends bitrate on redundancy\n * instead of detail.\n */\n fec?: boolean;\n /**\n * Discontinuous transmission (`usedtx`): stop sending during silence.\n *\n * Saves uplink in a mesh, at the cost of clipping the first instant after a\n * pause. Wrong for music and for a shared screen, where the quiet passages\n * are content.\n */\n dtx?: boolean;\n /** Constant bitrate (`cbr`). Off by default, as Opus intends. */\n cbr?: boolean;\n /**\n * Any other `fmtp` key, merged verbatim.\n *\n * The escape hatch for a parameter this type does not model. Values are\n * written as given; a key with an empty string is emitted as a bare flag.\n */\n extra?: Record<string, string>;\n}\n\n/**\n * Profiles to apply, keyed by audio m-line index (`0`, `1`, …) or by `mid`.\n *\n * Position and `mid` can be mixed in one object. A key that matches nothing is\n * ignored rather than an error — an SDP is negotiated, and a slot that was not\n * offered this time is normal.\n */\nexport type OpusProfileMap = Record<string | number, OpusProfile>;\n\n/** Keys that identify a bare {@link OpusProfile} rather than a map of them. */\nconst PROFILE_KEYS: ReadonlySet<string> = new Set([\n \"maxAverageBitrate\",\n \"maxPlaybackRate\",\n \"stereo\",\n \"fec\",\n \"dtx\",\n \"cbr\",\n \"extra\",\n]);\n\n/**\n * Whether the caller passed one profile for every audio m-line, or a map.\n *\n * An empty object is read as a profile, which makes `tuneOpus(sdp, {})` a no-op\n * instead of a silent surprise.\n */\nfunction isSingleProfile(value: OpusProfile | OpusProfileMap): value is OpusProfile {\n const keys = Object.keys(value);\n return keys.length === 0 || keys.some((key) => PROFILE_KEYS.has(key));\n}\n\n/** The `fmtp` parameters a profile asks for, in the order Opus documents them. */\nfunction fmtpParams(profile: OpusProfile): Record<string, string> {\n const params: Record<string, string> = {};\n if (profile.maxAverageBitrate !== undefined) {\n params.maxaveragebitrate = String(profile.maxAverageBitrate);\n }\n if (profile.maxPlaybackRate !== undefined) {\n params.maxplaybackrate = String(profile.maxPlaybackRate);\n }\n if (profile.stereo !== undefined) {\n params.stereo = profile.stereo ? \"1\" : \"0\";\n params[\"sprop-stereo\"] = profile.stereo ? \"1\" : \"0\";\n }\n if (profile.fec !== undefined) params.useinbandfec = profile.fec ? \"1\" : \"0\";\n if (profile.dtx !== undefined) params.usedtx = profile.dtx ? \"1\" : \"0\";\n if (profile.cbr !== undefined) params.cbr = profile.cbr ? \"1\" : \"0\";\n return { ...params, ...profile.extra };\n}\n\n/**\n * Merge parameters into an existing `fmtp` payload, key by key.\n *\n * Replacing the whole line is the obvious move and it is wrong: the browser\n * emits `minptime=10;useinbandfec=1` on its own, and overwriting drops the\n * `minptime` — a packetization decision nobody meant to change.\n */\nfunction mergeFmtp(existing: string, params: Record<string, string>): string {\n const merged = new Map<string, string>();\n for (const entry of existing.split(\";\")) {\n const trimmed = entry.trim();\n if (!trimmed) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq < 0) merged.set(trimmed, \"\");\n else merged.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));\n }\n for (const [key, value] of Object.entries(params)) merged.set(key, value);\n return [...merged.entries()]\n .map(([key, value]) => (value === \"\" ? key : `${key}=${value}`))\n .join(\";\");\n}\n\n/** Payload types this media block maps to Opus. There can be more than one. */\nfunction opusPayloads(block: readonly string[]): string[] {\n const payloads: string[] = [];\n for (const line of block) {\n const match = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (match) payloads.push(match[1]);\n }\n return payloads;\n}\n\n/** The block's `mid`, when it declares one. */\nfunction blockMid(block: readonly string[]): string | null {\n for (const line of block) {\n const match = /^a=mid:(.+)$/.exec(line);\n if (match) return match[1].trim();\n }\n return null;\n}\n\n/**\n * Rewrite one media block's Opus `fmtp` lines to carry a profile.\n *\n * A payload type with no `fmtp` of its own gets one inserted right after its\n * `rtpmap`, because \"the parameter is missing\" and \"the parameter is empty\" are\n * the same request from the caller's side.\n */\nfunction tuneBlock(block: readonly string[], profile: OpusProfile): string[] {\n const params = fmtpParams(profile);\n const payloads = opusPayloads(block);\n if (payloads.length === 0 || Object.keys(params).length === 0) return [...block];\n\n const out: string[] = [];\n for (const line of block) {\n const fmtp = /^a=fmtp:(\\d+)\\s+(.*)$/.exec(line);\n if (fmtp && payloads.includes(fmtp[1])) {\n out.push(`a=fmtp:${fmtp[1]} ${mergeFmtp(fmtp[2], params)}`);\n continue;\n }\n out.push(line);\n\n const rtpmap = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (rtpmap && !block.some((other) => other.startsWith(`a=fmtp:${rtpmap[1]} `))) {\n out.push(`a=fmtp:${rtpmap[1]} ${mergeFmtp(\"\", params)}`);\n }\n }\n return out;\n}\n\n/** Split a session description into its session part plus one block per m-line. */\nfunction mediaBlocks(sdp: string): string[][] {\n const blocks: string[][] = [];\n let current: string[] = [];\n for (const line of sdp.split(/\\r\\n|\\n/)) {\n if (line.startsWith(\"m=\") && current.length > 0) {\n blocks.push(current);\n current = [];\n }\n current.push(line);\n }\n if (current.length > 0) blocks.push(current);\n return blocks;\n}\n\n/**\n * Apply Opus profiles to the audio m-lines of a session description.\n *\n * Audio over WebRTC is mono and narrow by default, and the only place that is\n * corrected is the SDP — which is why shared-screen audio famously sounds like a\n * telephone: music and video inherit the speech profile (mono, ~32 kbps, FEC on,\n * DTX gating the quiet passages) and no high-level API lets you change it.\n *\n * Deliberately **without** built-in presets: which values to use is the\n * consumer's call — voice in a mesh does not want what system audio wants — and\n * a preset table is the kind of thing that has no business inside a dependency.\n * What lives here is the parsing, merging and insertion, which is where the long\n * tail is. Getting any of it wrong degrades silently: nobody sees an exception,\n * the audio is just worse.\n *\n * @param sdp - The description from `createOffer` or `createAnswer`.\n * @param profiles - One {@link OpusProfile} for every audio m-line, or an\n * {@link OpusProfileMap} keyed by audio m-line index or by `mid`.\n * @returns The rewritten SDP, with CRLF line endings as RFC 4566 requires.\n * Untouched when there is no Opus, when no profile matches, or when a profile\n * asks for nothing.\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, {\n * 0: { maxAverageBitrate: 48_000, stereo: false, fec: true, dtx: true },\n * 1: { maxAverageBitrate: 192_000, stereo: true, fec: false, dtx: false },\n * });\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, { stereo: true, dtx: false });\n */\nexport function tuneOpus(sdp: string, profiles: OpusProfile | OpusProfileMap): string {\n const single = isSingleProfile(profiles) ? profiles : null;\n const map = single ? null : (profiles as OpusProfileMap);\n\n let audioIndex = 0;\n const tuned = mediaBlocks(sdp).map((block) => {\n if (!block[0]?.startsWith(\"m=audio\")) return block;\n\n const index = audioIndex;\n audioIndex += 1;\n if (single) return tuneBlock(block, single);\n\n const mid = blockMid(block);\n const profile = map?.[index] ?? (mid !== null ? map?.[mid] : undefined);\n return profile ? tuneBlock(block, profile) : block;\n });\n\n return tuned.flat().join(\"\\r\\n\");\n}\n\n/** Which description a peer connection actually accepted. */\nexport type TunedDescriptionResult = \"tuned\" | \"original\";\n\n/**\n * Set a local description, falling back to the untouched one if it is refused.\n *\n * Chrome has been tightening what `setLocalDescription` accepts from edited SDP,\n * and there is no way to know in advance. Without a fallback the call dies\n * instead of merely losing the profile — which is the wrong trade by a wide\n * margin: worse audio beats no audio.\n *\n * @param connection - The peer connection.\n * @param description - The description from `createOffer` / `createAnswer`.\n * @param profiles - Passed straight to {@link tuneOpus}.\n * @returns `\"tuned\"` when the rewritten SDP was accepted, `\"original\"` when the\n * fallback was used — worth reporting, because it means the profile silently\n * did not apply.\n * @throws Whatever `setLocalDescription` throws for the original description: at\n * that point the failure is not about the rewrite and the caller has to know.\n *\n * @example\n * const applied = await setTunedLocalDescription(pc, await pc.createOffer(), profiles);\n * if (applied === \"original\") logger.warn(\"opus profile refused by the browser\");\n */\nexport async function setTunedLocalDescription(\n connection: RTCPeerConnection,\n description: RTCSessionDescriptionInit,\n profiles: OpusProfile | OpusProfileMap,\n): Promise<TunedDescriptionResult> {\n if (description.sdp) {\n const sdp = tuneOpus(description.sdp, profiles);\n if (sdp !== description.sdp) {\n try {\n await connection.setLocalDescription({ ...description, sdp });\n return \"tuned\";\n } catch {\n /* the browser refused the edit; the untouched offer still works */\n }\n }\n }\n await connection.setLocalDescription(description);\n return \"original\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"opus-sdp.js","names":["PROFILE_KEYS","isSingleProfile","keys","value","key","fmtpParams","params","profile","mergeFmtp","merged","entry","existing","trimmed","eq","opusPayloads","payloads","line","block","match","blockMid","tuneBlock","out","fmtp","rtpmap","other","mediaBlocks","blocks","current","sdp","tuneOpus","single","profiles","map","audioIndex","index","mid","setTunedLocalDescription","description","connection"],"sources":["../../src/webrtc/opus-sdp.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — parsing a session description, merging one\n * `fmtp` line and inserting a missing one are the same pass over the same\n * grammar; split apart, each half is a parser of half an SDP.\n */\n\n/** What an Opus `fmtp` line can be asked to carry. Every field is optional. */\nexport interface OpusProfile {\n /**\n * Ceiling the encoder is asked to respect, in bits per second.\n *\n * This describes what we want **to receive**. To cap what we *send*, use\n * `setSenderBitrate` — in a mesh that is the one that matters, because the\n * uplink carries one copy per participant.\n */\n maxAverageBitrate?: number;\n /** Highest sample rate worth decoding, in Hz. `48000` for full band. */\n maxPlaybackRate?: number;\n /**\n * Two channels instead of one.\n *\n * Sets `stereo` **and** `sprop-stereo`, which point in opposite directions:\n * `stereo=1` asks the *remote* to send two channels, `sprop-stereo=1`\n * announces that *we* will. Setting only one leaves the link asymmetric,\n * which is the recurring reason \"I asked for stereo and got mono\".\n */\n stereo?: boolean;\n /**\n * In-band forward error correction (`useinbandfec`).\n *\n * Rebuilds a lost packet from the next one, which keeps speech intelligible\n * on a lossy link — and smears music, since it spends bitrate on redundancy\n * instead of detail.\n */\n fec?: boolean;\n /**\n * Discontinuous transmission (`usedtx`): stop sending during silence.\n *\n * Saves uplink in a mesh, at the cost of clipping the first instant after a\n * pause. Wrong for music and for a shared screen, where the quiet passages\n * are content.\n */\n dtx?: boolean;\n /** Constant bitrate (`cbr`). Off by default, as Opus intends. */\n cbr?: boolean;\n /**\n * Any other `fmtp` key, merged verbatim.\n *\n * The escape hatch for a parameter this type does not model. Values are\n * written as given; a key with an empty string is emitted as a bare flag.\n */\n extra?: Record<string, string>;\n}\n\n/**\n * Profiles to apply, keyed by audio m-line index (`0`, `1`, …) or by `mid`.\n *\n * Position and `mid` can be mixed in one object. A key that matches nothing is\n * ignored rather than an error — an SDP is negotiated, and a slot that was not\n * offered this time is normal.\n */\nexport type OpusProfileMap = Record<string | number, OpusProfile>;\n\n/** Keys that identify a bare {@link OpusProfile} rather than a map of them. */\nconst PROFILE_KEYS: ReadonlySet<string> = new Set([\n \"maxAverageBitrate\",\n \"maxPlaybackRate\",\n \"stereo\",\n \"fec\",\n \"dtx\",\n \"cbr\",\n \"extra\",\n]);\n\n/**\n * Whether the caller passed one profile for every audio m-line, or a map.\n *\n * An empty object is read as a profile, which makes `tuneOpus(sdp, {})` a no-op\n * instead of a silent surprise.\n */\nfunction isSingleProfile(value: OpusProfile | OpusProfileMap): value is OpusProfile {\n const keys = Object.keys(value);\n return keys.length === 0 || keys.some((key) => PROFILE_KEYS.has(key));\n}\n\n/** The `fmtp` parameters a profile asks for, in the order Opus documents them. */\nfunction fmtpParams(profile: OpusProfile): Record<string, string> {\n const params: Record<string, string> = {};\n if (profile.maxAverageBitrate !== undefined) {\n params.maxaveragebitrate = String(profile.maxAverageBitrate);\n }\n if (profile.maxPlaybackRate !== undefined) {\n params.maxplaybackrate = String(profile.maxPlaybackRate);\n }\n if (profile.stereo !== undefined) {\n params.stereo = profile.stereo ? \"1\" : \"0\";\n params[\"sprop-stereo\"] = profile.stereo ? \"1\" : \"0\";\n }\n if (profile.fec !== undefined) params.useinbandfec = profile.fec ? \"1\" : \"0\";\n if (profile.dtx !== undefined) params.usedtx = profile.dtx ? \"1\" : \"0\";\n if (profile.cbr !== undefined) params.cbr = profile.cbr ? \"1\" : \"0\";\n return { ...params, ...profile.extra };\n}\n\n/**\n * Merge parameters into an existing `fmtp` payload, key by key.\n *\n * Replacing the whole line is the obvious move and it is wrong: the browser\n * emits `minptime=10;useinbandfec=1` on its own, and overwriting drops the\n * `minptime` — a packetization decision nobody meant to change.\n */\nfunction mergeFmtp(existing: string, params: Record<string, string>): string {\n const merged = new Map<string, string>();\n for (const entry of existing.split(\";\")) {\n const trimmed = entry.trim();\n if (!trimmed) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq < 0) merged.set(trimmed, \"\");\n else merged.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));\n }\n for (const [key, value] of Object.entries(params)) merged.set(key, value);\n return [...merged.entries()]\n .map(([key, value]) => (value === \"\" ? key : `${key}=${value}`))\n .join(\";\");\n}\n\n/** Payload types this media block maps to Opus. There can be more than one. */\nfunction opusPayloads(block: readonly string[]): string[] {\n const payloads: string[] = [];\n for (const line of block) {\n const match = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (match) payloads.push(match[1]);\n }\n return payloads;\n}\n\n/** The block's `mid`, when it declares one. */\nfunction blockMid(block: readonly string[]): string | null {\n for (const line of block) {\n const match = /^a=mid:(.+)$/.exec(line);\n if (match) return match[1].trim();\n }\n return null;\n}\n\n/**\n * Rewrite one media block's Opus `fmtp` lines to carry a profile.\n *\n * A payload type with no `fmtp` of its own gets one inserted right after its\n * `rtpmap`, because \"the parameter is missing\" and \"the parameter is empty\" are\n * the same request from the caller's side.\n */\nfunction tuneBlock(block: readonly string[], profile: OpusProfile): string[] {\n const params = fmtpParams(profile);\n const payloads = opusPayloads(block);\n if (payloads.length === 0 || Object.keys(params).length === 0) return [...block];\n\n const out: string[] = [];\n for (const line of block) {\n const fmtp = /^a=fmtp:(\\d+)\\s+(.*)$/.exec(line);\n if (fmtp && payloads.includes(fmtp[1])) {\n out.push(`a=fmtp:${fmtp[1]} ${mergeFmtp(fmtp[2], params)}`);\n continue;\n }\n out.push(line);\n\n const rtpmap = /^a=rtpmap:(\\d+)\\s+opus\\/48000/i.exec(line);\n if (rtpmap && !block.some((other) => other.startsWith(`a=fmtp:${rtpmap[1]} `))) {\n out.push(`a=fmtp:${rtpmap[1]} ${mergeFmtp(\"\", params)}`);\n }\n }\n return out;\n}\n\n/** Split a session description into its session part plus one block per m-line. */\nfunction mediaBlocks(sdp: string): string[][] {\n const blocks: string[][] = [];\n let current: string[] = [];\n for (const line of sdp.split(/\\r\\n|\\n/)) {\n if (line.startsWith(\"m=\") && current.length > 0) {\n blocks.push(current);\n current = [];\n }\n current.push(line);\n }\n if (current.length > 0) blocks.push(current);\n return blocks;\n}\n\n/**\n * Apply Opus profiles to the audio m-lines of a session description.\n *\n * Audio over WebRTC is mono and narrow by default, and the only place that is\n * corrected is the SDP — which is why shared-screen audio famously sounds like a\n * telephone: music and video inherit the speech profile (mono, ~32 kbps, FEC on,\n * DTX gating the quiet passages) and no high-level API lets you change it.\n *\n * Deliberately **without** built-in presets: which values to use is the\n * consumer's call — voice in a mesh does not want what system audio wants — and\n * a preset table is the kind of thing that has no business inside a dependency.\n * What lives here is the parsing, merging and insertion, which is where the long\n * tail is. Getting any of it wrong degrades silently: nobody sees an exception,\n * the audio is just worse.\n *\n * @param sdp - The description from `createOffer` or `createAnswer`.\n * @param profiles - One {@link OpusProfile} for every audio m-line, or an\n * {@link OpusProfileMap} keyed by audio m-line index or by `mid`.\n * @returns The rewritten SDP, with CRLF line endings as RFC 4566 requires.\n * Untouched when there is no Opus, when no profile matches, or when a profile\n * asks for nothing.\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, {\n * 0: { maxAverageBitrate: 48_000, stereo: false, fec: true, dtx: true },\n * 1: { maxAverageBitrate: 192_000, stereo: true, fec: false, dtx: false },\n * });\n *\n * @example\n * const tuned = tuneOpus(offer.sdp, { stereo: true, dtx: false });\n */\nexport function tuneOpus(sdp: string, profiles: OpusProfile | OpusProfileMap): string {\n const single = isSingleProfile(profiles) ? profiles : null;\n const map = single ? null : (profiles as OpusProfileMap);\n\n let audioIndex = 0;\n const tuned = mediaBlocks(sdp).map((block) => {\n if (!block[0]?.startsWith(\"m=audio\")) return block;\n\n const index = audioIndex;\n audioIndex += 1;\n if (single) return tuneBlock(block, single);\n\n const mid = blockMid(block);\n const profile = map?.[index] ?? (mid !== null ? map?.[mid] : undefined);\n return profile ? tuneBlock(block, profile) : block;\n });\n\n return tuned.flat().join(\"\\r\\n\");\n}\n\n/** Which description a peer connection actually accepted. */\nexport type TunedDescriptionResult = \"tuned\" | \"original\";\n\n/**\n * Set a local description, falling back to the untouched one if it is refused.\n *\n * Chrome has been tightening what `setLocalDescription` accepts from edited SDP,\n * and there is no way to know in advance. Without a fallback the call dies\n * instead of merely losing the profile — which is the wrong trade by a wide\n * margin: worse audio beats no audio.\n *\n * @param connection - The peer connection.\n * @param description - The description from `createOffer` / `createAnswer`.\n * @param profiles - Passed straight to {@link tuneOpus}.\n * @returns `\"tuned\"` when the rewritten SDP was accepted, `\"original\"` when the\n * fallback was used — worth reporting, because it means the profile silently\n * did not apply.\n * @throws Whatever `setLocalDescription` throws for the original description: at\n * that point the failure is not about the rewrite and the caller has to know.\n *\n * @example\n * const applied = await setTunedLocalDescription(pc, await pc.createOffer(), profiles);\n * if (applied === \"original\") logger.warn(\"opus profile refused by the browser\");\n */\nexport async function setTunedLocalDescription(\n connection: RTCPeerConnection,\n description: RTCSessionDescriptionInit,\n profiles: OpusProfile | OpusProfileMap,\n): Promise<TunedDescriptionResult> {\n if (description.sdp) {\n const sdp = tuneOpus(description.sdp, profiles);\n if (sdp !== description.sdp) {\n try {\n await connection.setLocalDescription({ ...description, sdp });\n return \"tuned\";\n } catch {\n /* the browser refused the edit; the untouched offer still works */\n }\n }\n }\n await connection.setLocalDescription(description);\n return \"original\";\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- function e(e){return new RTCPeerConnection({iceServers:e,bundlePolicy:`max-bundle`,rtcpMuxPolicy:`require`})}function t(e,t,n){let r=Number(e.mid);if(e.mid!==null&&Number.isInteger(r)&&n[r])return n[r];let i=t.transceivers.indexOf(e);return i>=0?n[i]??null:null}async function n(e){let t=e.pendingCandidates.splice(0,e.pendingCandidates.length);for(let n of t)try{await e.pc.addIceCandidate(n)}catch{}}async function r(e,t){if(!e.remoteReady){e.pendingCandidates.push(t);return}try{await e.pc.addIceCandidate(t)}catch{}}function i(e){e.transceivers=e.pc.getTransceivers().filter(e=>e.mid!==null).sort((e,t)=>Number(e.mid)-Number(t.mid));for(let t of e.transceivers)t.direction!==`sendrecv`&&(t.direction=`sendrecv`)}exports.acceptCandidate=r,exports.adoptTransceivers=i,exports.createPeerConnection=e,exports.drainCandidates=n,exports.slotOf=t;
1
+ function e(e){return new RTCPeerConnection({iceServers:e,bundlePolicy:`max-bundle`,rtcpMuxPolicy:`require`})}function t(e,t,n){let r=Number(e.mid);if(e.mid!==null&&Number.isInteger(r)&&n[r])return n[r];let i=t.transceivers.indexOf(e);return i>=0?n[i]??null:null}async function n(e){let t=e.pendingCandidates.splice(0,e.pendingCandidates.length);for(let n of t)try{await e.pc.addIceCandidate(n)}catch{}}async function r(e,t){if(!e.remoteReady)e.pendingCandidates.push(t);else try{await e.pc.addIceCandidate(t)}catch{}}function i(e){e.transceivers=e.pc.getTransceivers().filter(e=>e.mid!==null).sort((e,t)=>Number(e.mid)-Number(t.mid));for(let t of e.transceivers)t.direction!==`sendrecv`&&(t.direction=`sendrecv`)}exports.acceptCandidate=r,exports.adoptTransceivers=i,exports.createPeerConnection=e,exports.drainCandidates=n,exports.slotOf=t;
2
2
  //# sourceMappingURL=peer-link.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"peer-link.cjs","names":[],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":"AAwBA,SAAgB,EAAqB,EAA+C,CAChF,OAAO,IAAI,kBAAkB,CACzB,aACA,aAAc,aACd,cAAe,SACnB,CAAC,CACL,CAoBA,SAAgB,EACZ,EACA,EACA,EACe,CACf,IAAM,EAAU,OAAO,EAAY,GAAG,EACtC,GAAI,EAAY,MAAQ,MAAQ,OAAO,UAAU,CAAO,GAAK,EAAM,GAC/D,OAAO,EAAM,GAEjB,IAAM,EAAQ,EAAK,aAAa,QAAQ,CAAW,EACnD,OAAO,GAAS,EAAK,EAAM,IAAU,KAAQ,IACjD,CAYA,eAAsB,EAAgB,EAA+B,CACjE,IAAM,EAAS,EAAK,kBAAkB,OAAO,EAAG,EAAK,kBAAkB,MAAM,EAC7E,IAAK,IAAM,KAAa,EACpB,GAAI,CACA,MAAM,EAAK,GAAG,gBAAgB,CAAS,CAC3C,MAAQ,CAER,CAER,CAQA,eAAsB,EAAgB,EAAgB,EAA0C,CAC5F,GAAI,CAAC,EAAK,YAAa,CACnB,EAAK,kBAAkB,KAAK,CAAI,EAChC,MACJ,CACA,GAAI,CACA,MAAM,EAAK,GAAG,gBAAgB,CAAI,CACtC,MAAQ,CAER,CACJ,CAiBA,SAAgB,EAAkB,EAAsB,CACpD,EAAK,aAAe,EAAK,GACpB,gBAAgB,CAAC,CACjB,OAAQ,GAAgB,EAAY,MAAQ,IAAI,CAAC,CACjD,MAAM,EAAG,IAAM,OAAO,EAAE,GAAG,EAAI,OAAO,EAAE,GAAG,CAAC,EACjD,IAAK,IAAM,KAAe,EAAK,aACvB,EAAY,YAAc,aAAY,EAAY,UAAY,WAE1E"}
1
+ {"version":3,"file":"peer-link.cjs","names":["createPeerConnection","slotOf","ordinal","transceiver","slots","index","link","drainCandidates","queued","candidate","acceptCandidate","init","adoptTransceivers","a","b"],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":"AAwBA,SAAgBA,EAAqB,EAA+C,CAChF,OAAO,IAAI,kBAAkB,CACzB,aACA,aAAc,aACd,cAAe,SACnB,CAAC,CACL,CAoBA,SAAgBC,EACZ,EACA,EACA,EACe,CACf,IAAMC,EAAU,OAAOC,EAAY,GAAG,EACtC,GAAIA,EAAY,MAAQ,MAAQ,OAAO,UAAUD,CAAO,GAAKE,EAAMF,GAC/D,OAAOE,EAAMF,GAEjB,IAAMG,EAAQC,EAAK,aAAa,QAAQH,CAAW,EACnD,OAAOE,GAAS,EAAKD,EAAMC,IAAU,KAAQ,IACjD,CAYA,eAAsBE,EAAgB,EAA+B,CACjE,IAAMC,EAASF,EAAK,kBAAkB,OAAO,EAAGA,EAAK,kBAAkB,MAAM,EAC7E,IAAK,IAAMG,KAAaD,EACpB,GAAI,CACA,MAAMF,EAAK,GAAG,gBAAgBG,CAAS,CAC3C,MAAQ,CAER,CAER,CAQA,eAAsBC,EAAgB,EAAgB,EAA0C,CAC5F,GAAI,CAACJ,EAAK,YACNA,EAAK,kBAAkB,KAAKK,CAAI,OAGpC,GAAI,CACA,MAAML,EAAK,GAAG,gBAAgBK,CAAI,CACtC,MAAQ,CAER,CACJ,CAiBA,SAAgBC,EAAkB,EAAsB,CACpD,EAAK,aAAeN,EAAK,GACpB,gBAAgB,CAAC,CACjB,OAAQ,GAAgBH,EAAY,MAAQ,IAAI,CAAC,CACjD,MAAM,EAAG,IAAM,OAAOU,EAAE,GAAG,EAAI,OAAOC,EAAE,GAAG,CAAC,EACjD,IAAK,IAAMX,KAAeG,EAAK,aACvBH,EAAY,YAAc,aAAY,EAAY,UAAY,WAE1E,C"}
@@ -19,11 +19,8 @@ async function n(e) {
19
19
  } catch {}
20
20
  }
21
21
  async function r(e, t) {
22
- if (!e.remoteReady) {
23
- e.pendingCandidates.push(t);
24
- return;
25
- }
26
- try {
22
+ if (!e.remoteReady) e.pendingCandidates.push(t);
23
+ else try {
27
24
  await e.pc.addIceCandidate(t);
28
25
  } catch {}
29
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"peer-link.js","names":[],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":";AAwBA,SAAgB,EAAqB,GAA+C;CAChF,OAAO,IAAI,kBAAkB;EACzB;EACA,cAAc;EACd,eAAe;CACnB,CAAC;AACL;AAoBA,SAAgB,EACZ,GACA,GACA,GACe;CACf,IAAM,IAAU,OAAO,EAAY,GAAG;CACtC,IAAI,EAAY,QAAQ,QAAQ,OAAO,UAAU,CAAO,KAAK,EAAM,IAC/D,OAAO,EAAM;CAEjB,IAAM,IAAQ,EAAK,aAAa,QAAQ,CAAW;CACnD,OAAO,KAAS,IAAK,EAAM,MAAU,OAAQ;AACjD;AAYA,eAAsB,EAAgB,GAA+B;CACjE,IAAM,IAAS,EAAK,kBAAkB,OAAO,GAAG,EAAK,kBAAkB,MAAM;CAC7E,KAAK,IAAM,KAAa,GACpB,IAAI;EACA,MAAM,EAAK,GAAG,gBAAgB,CAAS;CAC3C,QAAQ,CAER;AAER;AAQA,eAAsB,EAAgB,GAAgB,GAA0C;CAC5F,IAAI,CAAC,EAAK,aAAa;EACnB,EAAK,kBAAkB,KAAK,CAAI;EAChC;CACJ;CACA,IAAI;EACA,MAAM,EAAK,GAAG,gBAAgB,CAAI;CACtC,QAAQ,CAER;AACJ;AAiBA,SAAgB,EAAkB,GAAsB;CACpD,EAAK,eAAe,EAAK,GACpB,gBAAgB,CAAC,CACjB,QAAQ,MAAgB,EAAY,QAAQ,IAAI,CAAC,CACjD,MAAM,GAAG,MAAM,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,CAAC;CACjD,KAAK,IAAM,KAAe,EAAK,cAC3B,AAAI,EAAY,cAAc,eAAY,EAAY,YAAY;AAE1E"}
1
+ {"version":3,"file":"peer-link.js","names":["createPeerConnection","slotOf","ordinal","transceiver","slots","index","link","drainCandidates","queued","candidate","acceptCandidate","init","adoptTransceivers","a","b"],"sources":["../../src/webrtc/peer-link.ts"],"sourcesContent":["import type { MeshSlot } from \"./mesh-types\";\n\n/** One remote peer's connection and everything the mesh tracks about it. */\nexport interface PeerLink {\n peerId: string;\n pc: RTCPeerConnection;\n /**\n * Transceivers in slot order.\n *\n * Held explicitly rather than re-read from `getTransceivers()` so slot\n * lookup stays O(1) and cannot drift if a browser reorders.\n */\n transceivers: RTCRtpTransceiver[];\n /** Candidates that arrived before the remote description they belong to. */\n pendingCandidates: RTCIceCandidateInit[];\n /** Whether `setRemoteDescription` has landed, which gates the queue. */\n remoteReady: boolean;\n /** Whether an offer is in flight, so a re-entrant call does not stack one. */\n makingOffer: boolean;\n /** Whether this side offers. Exactly one side of a link does. */\n isOfferer: boolean;\n}\n\n/** Open a connection with the policies a mesh needs. */\nexport function createPeerConnection(iceServers: RTCIceServer[]): RTCPeerConnection {\n return new RTCPeerConnection({\n iceServers,\n bundlePolicy: \"max-bundle\",\n rtcpMuxPolicy: \"require\",\n });\n}\n\n/**\n * Resolve which slot a transceiver carries.\n *\n * The offerer allocates the m-lines in slot order, so a transceiver's `mid` is\n * its ordinal and both ends read the same one. That makes `mid` the slot's wire\n * identity, and the **only** identifier correct on both sides of a link.\n *\n * Position in the link's own array is a fallback for a `mid` that is not a plain\n * ordinal, and never the primary: a browser answering an offer appends the\n * negotiated transceivers *after* any it already held, so positional lookup\n * silently resolves to the wrong slot — the camera arriving in the screen tile —\n * or to none at all, dropping the track.\n *\n * @param transceiver - The transceiver a track arrived on.\n * @param link - The link it belongs to.\n * @param slots - The mesh's slot list.\n * @returns The slot, or `null` when neither route names one.\n */\nexport function slotOf(\n transceiver: RTCRtpTransceiver,\n link: PeerLink,\n slots: readonly MeshSlot[],\n): MeshSlot | null {\n const ordinal = Number(transceiver.mid);\n if (transceiver.mid !== null && Number.isInteger(ordinal) && slots[ordinal]) {\n return slots[ordinal];\n }\n const index = link.transceivers.indexOf(transceiver);\n return index >= 0 ? (slots[index] ?? null) : null;\n}\n\n/**\n * Feed a link every candidate that arrived before its remote description.\n *\n * `addIceCandidate` throws while `remoteDescription` is `null`, and candidates\n * routinely beat the offer or answer they belong to. Without the queue the\n * connection loses them and sits in `checking` until it times out — a failure\n * with no error anywhere.\n *\n * @param link - The link whose queue is drained.\n */\nexport async function drainCandidates(link: PeerLink): Promise<void> {\n const queued = link.pendingCandidates.splice(0, link.pendingCandidates.length);\n for (const candidate of queued) {\n try {\n await link.pc.addIceCandidate(candidate);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n }\n}\n\n/**\n * Hand a candidate to the connection, or park it until the description lands.\n *\n * @param link - The link the candidate belongs to.\n * @param init - The candidate, already in `RTCIceCandidateInit` shape.\n */\nexport async function acceptCandidate(link: PeerLink, init: RTCIceCandidateInit): Promise<void> {\n if (!link.remoteReady) {\n link.pendingCandidates.push(init);\n return;\n }\n try {\n await link.pc.addIceCandidate(init);\n } catch {\n /* a candidate the browser rejects is not fatal to the connection */\n }\n}\n\n/**\n * Adopt the transceivers a remote offer created, in `mid` order.\n *\n * The answering side allocates **nothing** up front, and that is the whole\n * subtlety: applying a remote offer creates one transceiver per m-line, in\n * m-line order, and browsers do not reuse transceivers the answerer made\n * beforehand. Pre-allocating leaves dead, never-negotiated transceivers sitting\n * in front of the live ones, which is how slot lookup ends up pointing at the\n * wrong media or at nothing.\n *\n * Each adopted transceiver is switched to `sendrecv` so this side may publish on\n * it too; without that a peer that answered could hear but never be heard.\n *\n * @param link - The link that just applied a remote offer.\n */\nexport function adoptTransceivers(link: PeerLink): void {\n link.transceivers = link.pc\n .getTransceivers()\n .filter((transceiver) => transceiver.mid !== null)\n .sort((a, b) => Number(a.mid) - Number(b.mid));\n for (const transceiver of link.transceivers) {\n if (transceiver.direction !== \"sendrecv\") transceiver.direction = \"sendrecv\";\n }\n}\n"],"mappings":";AAwBA,SAAgBA,EAAqB,GAA+C;CAChF,OAAO,IAAI,kBAAkB;EACzB;EACA,cAAc;EACd,eAAe;CACnB,CAAC;AACL;AAoBA,SAAgBC,EACZ,GACA,GACA,GACe;CACf,IAAMC,IAAU,OAAOC,EAAY,GAAG;CACtC,IAAIA,EAAY,QAAQ,QAAQ,OAAO,UAAUD,CAAO,KAAKE,EAAMF,IAC/D,OAAOE,EAAMF;CAEjB,IAAMG,IAAQC,EAAK,aAAa,QAAQH,CAAW;CACnD,OAAOE,KAAS,IAAKD,EAAMC,MAAU,OAAQ;AACjD;AAYA,eAAsBE,EAAgB,GAA+B;CACjE,IAAMC,IAASF,EAAK,kBAAkB,OAAO,GAAGA,EAAK,kBAAkB,MAAM;CAC7E,KAAK,IAAMG,KAAaD,GACpB,IAAI;EACA,MAAMF,EAAK,GAAG,gBAAgBG,CAAS;CAC3C,QAAQ,CAER;AAER;AAQA,eAAsBC,EAAgB,GAAgB,GAA0C;CAC5F,IAAI,CAACJ,EAAK,aACN,EAAK,kBAAkB,KAAKK,CAAI;MAGpC,IAAI;EACA,MAAML,EAAK,GAAG,gBAAgBK,CAAI;CACtC,QAAQ,CAER;AACJ;AAiBA,SAAgBC,EAAkB,GAAsB;CACpD,EAAK,eAAeN,EAAK,GACpB,gBAAgB,CAAC,CACjB,QAAQ,MAAgBH,EAAY,QAAQ,IAAI,CAAC,CACjD,MAAM,GAAG,MAAM,OAAOU,EAAE,GAAG,IAAI,OAAOC,EAAE,GAAG,CAAC;CACjD,KAAK,IAAMX,KAAeG,EAAK,cAC3B,AAAIH,EAAY,cAAc,eAAY,EAAY,YAAY;AAE1E"}
@@ -1,2 +1,2 @@
1
- const e=require("./link-stats.cjs"),t=require("./mesh-quality.cjs"),n=require("./peer-link.cjs");var r=Symbol(`gone`);function i(i){let{slots:a,send:o}=i,s=new Map,c=new Map,l=new Map,u=new Map,d=i.iceServers??[],f=i.setLocalDescription??((e,t)=>e.setLocalDescription(t)),p=i.quality??{},m=!1,h=new Map,g=null,_=()=>Object.fromEntries(a.map(e=>[e.name,null])),v=()=>{i.onPeers?.([...c.values()].map(e=>({...e})))},y=e=>!m&&s.get(e.peerId)===e,b=async(e,t)=>{try{let n=await t;return y(e)?n:r}catch(t){if(!y(e))return r;throw t}},x=async t=>{if(m)return;let n=!1;for(let r of[...s.values()]){if(r.pc.connectionState!==`connected`)continue;let i=h.get(r.peerId);i===void 0&&(i=e.createLinkStatsSampler(t.kind===void 0?{}:{kind:t.kind}),h.set(r.peerId,i));let a;try{a=await i.sample(r.pc)}catch{continue}let o=c.get(r.peerId);y(r)&&o!==void 0&&(o.stats=a,n=!0,t.onStats?.(r.peerId,a))}n&&v()},S=()=>{let e=i.stats;if(e===void 0)return;let t=!m&&s.size>0;if(t&&g===null){g=setInterval(()=>void x(e),e.intervalMs??2e3);return}!t&&g!==null&&(clearInterval(g),g=null)},C=()=>{if(m)return;let e=[...s.values()].map(e=>e.pc.connectionState);e.some(e=>e===`connected`)?i.onState?.(`connected`):e.length>0?i.onState?.(`connecting`,`negotiating`):i.onState?.(`connected`,`alone`)},w=async e=>{if(m)return;p=e;let n=t.scaleForRoom(e,s.size),r=t.resolveDegradation(e,n);for(let e of s.values())await t.applyQualityToLink(e.transceivers,a,n,r)},T=async e=>{if(!e.makingOffer){e.makingOffer=!0;try{let t=await e.pc.createOffer();if(!y(e))return;if(!t.sdp){i.onNotice?.(`empty_local_offer_sdp`);return}if(await f(e.pc,t),!y(e))return;o({type:`offer`,to:e.peerId,sdp:e.pc.localDescription?.sdp??t.sdp})}catch{y(e)&&i.onNotice?.(`offer_failed`)}finally{e.makingOffer=!1}}},E=e=>e.streams?.[0]||(typeof MediaStream>`u`?null:new MediaStream([e.track])),D=(e,t)=>{let r=n.slotOf(t.transceiver,e,a),i=c.get(e.peerId);r&&i&&(i.streams={...i.streams,[r.name]:E(t)},t.track.onended=()=>{let t=c.get(e.peerId);t&&(t.streams={...t.streams,[r.name]:null},v())},v())},O=(e,t)=>{let n=(u.get(e)??Promise.resolve()).then(t);return u.set(e,n),n},k=async(e,t,n)=>{let r=e.transceivers[n];if(r&&y(e))try{await r.sender.replaceTrack(l.get(t)??null)}catch{return}},A=e=>Promise.all(a.map((t,n)=>O(t.name,()=>k(e,t.name,n)))),j=e=>{if(m)return;let t=s.get(e);t&&(t.pc.close(),s.delete(e)),c.delete(e),h.delete(e),w(p),S(),v(),C()},M=async(e,{offerer:t})=>{if(m||s.has(e))return;let r=n.createPeerConnection(d),i=[];if(t)try{i=a.map(e=>r.addTransceiver(e.kind,{direction:`sendrecv`}))}catch(e){throw r.close(),e}let l={peerId:e,pc:r,transceivers:i,pendingCandidates:[],remoteReady:!1,makingOffer:!1,isOfferer:t};s.set(e,l),c.set(e,{peerId:e,connection:r.connectionState,streams:c.get(e)?.streams??_()}),!(t&&(await A(l),!y(l)))&&(r.onicecandidate=t=>{o({type:`ice`,to:e,candidate:t.candidate?.candidate??null,sdpMid:t.candidate?.sdpMid??null,sdpMLineIndex:t.candidate?.sdpMLineIndex??null})},r.ontrack=e=>D(l,e),r.onconnectionstatechange=()=>{if(!y(l))return;let t=c.get(e);if(t&&(t.connection=r.connectionState),r.connectionState===`failed`||r.connectionState===`closed`){j(e);return}v(),C()},r.onnegotiationneeded=()=>{l.isOfferer&&T(l)},S(),v(),C(),t&&await T(l))},N=async(e,t)=>{s.has(e)||await M(e,{offerer:!1});let a=s.get(e);if(!a||!y(a)||await b(a,a.pc.setRemoteDescription({type:`offer`,sdp:t}))===r||(a.remoteReady=!0,await n.drainCandidates(a),a.isOfferer||(n.adoptTransceivers(a),await A(a)),!y(a)))return;let c=await b(a,a.pc.createAnswer());if(c!==r){if(!c.sdp){i.onNotice?.(`empty_local_answer_sdp`);return}await b(a,f(a.pc,c))!==r&&(o({type:`answer`,to:e,sdp:a.pc.localDescription?.sdp??c.sdp}),await w(p))}};return i.onState?.(`connecting`,`signaling`),{addPeer:M,removePeer:j,accept:async e=>{if(m)return;if(e.type===`offer`){await N(e.from,e.sdp);return}let t=s.get(e.from);if(t){if(e.type===`answer`){let i=t.pc.setRemoteDescription({type:`answer`,sdp:e.sdp});if(await b(t,i)===r)return;t.remoteReady=!0,await n.drainCandidates(t),await w(p);return}e.candidate!==null&&await n.acceptCandidate(t,{candidate:e.candidate,sdpMid:e.sdpMid??void 0,sdpMLineIndex:e.sdpMLineIndex??void 0})}},setLocalTrack:async(e,t)=>{if(m)return;l.set(e,t);let n=a.findIndex(t=>t.name===e);n<0||(await O(e,async()=>{for(let t of[...s.values()])await k(t,e,n)}),await w(p))},applyQuality:w,setIceServers:e=>{d=e},stop:()=>{if(!m){m=!0;for(let e of s.values())e.pc.close();s.clear(),c.clear(),h.clear(),l.clear(),S(),v(),i.onState?.(`closed`)}},getConnection:e=>s.get(e)?.pc??null,get peers(){return[...c.values()].map(e=>({...e}))}}}exports.createPeerMesh=i;
1
+ const e=require("./link-stats.cjs"),t=require("./mesh-quality.cjs"),n=require("./peer-link.cjs");var r=Symbol(`gone`);function i(i){let{slots:a,send:o}=i,s=new Map,c=new Map,l=new Map,u=new Map,d=i.iceServers??[],f=i.setLocalDescription??((e,t)=>e.setLocalDescription(t)),p=i.quality??{},m=!1,h=new Map,g=null,_=()=>Object.fromEntries(a.map(e=>[e.name,null])),v=()=>{i.onPeers?.([...c.values()].map(e=>({...e})))},y=e=>!m&&s.get(e.peerId)===e,b=async(e,t)=>{try{let n=await t;return y(e)?n:r}catch(t){if(!y(e))return r;throw t}},x=async t=>{if(m)return;let n=!1;for(let r of[...s.values()]){if(r.pc.connectionState!==`connected`)continue;let i=h.get(r.peerId);i===void 0&&(i=e.createLinkStatsSampler(t.kind===void 0?{}:{kind:t.kind}),h.set(r.peerId,i));let a;try{a=await i.sample(r.pc)}catch{continue}let o=c.get(r.peerId);y(r)&&o!==void 0&&(o.stats=a,n=!0,t.onStats?.(r.peerId,a))}n&&v()},S=()=>{let e=i.stats;if(e===void 0)return;let t=!m&&s.size>0;t&&g===null?g=setInterval(()=>void x(e),e.intervalMs??2e3):!t&&g!==null&&(clearInterval(g),g=null)},C=()=>{if(m)return;let e=[...s.values()].map(e=>e.pc.connectionState);e.some(e=>e===`connected`)?i.onState?.(`connected`):e.length>0?i.onState?.(`connecting`,`negotiating`):i.onState?.(`connected`,`alone`)},w=async e=>{if(m)return;p=e;let n=t.scaleForRoom(e,s.size),r=t.resolveDegradation(e,n);for(let e of s.values())await t.applyQualityToLink(e.transceivers,a,n,r)},T=async e=>{if(!e.makingOffer){e.makingOffer=!0;try{let t=await e.pc.createOffer();if(!y(e))return;if(!t.sdp){i.onNotice?.(`empty_local_offer_sdp`);return}if(await f(e.pc,t),!y(e))return;o({type:`offer`,to:e.peerId,sdp:e.pc.localDescription?.sdp??t.sdp})}catch{y(e)&&i.onNotice?.(`offer_failed`)}finally{e.makingOffer=!1}}},E=e=>e.streams?.[0]||(typeof MediaStream>`u`?null:new MediaStream([e.track])),D=(e,t)=>{let r=n.slotOf(t.transceiver,e,a),i=c.get(e.peerId);r&&i&&(i.streams={...i.streams,[r.name]:E(t)},t.track.onended=()=>{let t=c.get(e.peerId);t&&(t.streams={...t.streams,[r.name]:null},v())},v())},O=(e,t)=>{let n=(u.get(e)??Promise.resolve()).then(t);return u.set(e,n),n},k=async(e,t,n)=>{let r=e.transceivers[n];if(r&&y(e))try{await r.sender.replaceTrack(l.get(t)??null)}catch{return}},A=e=>Promise.all(a.map((t,n)=>O(t.name,()=>k(e,t.name,n)))),j=e=>{if(m)return;let t=s.get(e);t&&(t.pc.close(),s.delete(e)),c.delete(e),h.delete(e),w(p),S(),v(),C()},M=async(e,{offerer:t})=>{if(m||s.has(e))return;let r=n.createPeerConnection(d),i=[];if(t)try{i=a.map(e=>r.addTransceiver(e.kind,{direction:`sendrecv`}))}catch(e){throw r.close(),e}let l={peerId:e,pc:r,transceivers:i,pendingCandidates:[],remoteReady:!1,makingOffer:!1,isOfferer:t};s.set(e,l),c.set(e,{peerId:e,connection:r.connectionState,streams:c.get(e)?.streams??_()}),!(t&&(await A(l),!y(l)))&&(r.onicecandidate=t=>{o({type:`ice`,to:e,candidate:t.candidate?.candidate??null,sdpMid:t.candidate?.sdpMid??null,sdpMLineIndex:t.candidate?.sdpMLineIndex??null})},r.ontrack=e=>D(l,e),r.onconnectionstatechange=()=>{if(!y(l))return;let t=c.get(e);t&&(t.connection=r.connectionState),r.connectionState===`failed`||r.connectionState===`closed`?j(e):(v(),C())},r.onnegotiationneeded=()=>{l.isOfferer&&T(l)},S(),v(),C(),t&&await T(l))},N=async(e,t)=>{s.has(e)||await M(e,{offerer:!1});let a=s.get(e);if(!a||!y(a)||await b(a,a.pc.setRemoteDescription({type:`offer`,sdp:t}))===r||(a.remoteReady=!0,await n.drainCandidates(a),a.isOfferer||(n.adoptTransceivers(a),await A(a)),!y(a)))return;let c=await b(a,a.pc.createAnswer());c!==r&&(c.sdp?await b(a,f(a.pc,c))!==r&&(o({type:`answer`,to:e,sdp:a.pc.localDescription?.sdp??c.sdp}),await w(p)):i.onNotice?.(`empty_local_answer_sdp`))};return i.onState?.(`connecting`,`signaling`),{addPeer:M,removePeer:j,accept:async e=>{if(m)return;if(e.type===`offer`){await N(e.from,e.sdp);return}let t=s.get(e.from);if(t){if(e.type===`answer`){let i=t.pc.setRemoteDescription({type:`answer`,sdp:e.sdp});if(await b(t,i)===r)return;t.remoteReady=!0,await n.drainCandidates(t),await w(p)}else e.candidate!==null&&await n.acceptCandidate(t,{candidate:e.candidate,sdpMid:e.sdpMid??void 0,sdpMLineIndex:e.sdpMLineIndex??void 0})}},setLocalTrack:async(e,t)=>{if(m)return;l.set(e,t);let n=a.findIndex(t=>t.name===e);n<0||(await O(e,async()=>{for(let t of[...s.values()])await k(t,e,n)}),await w(p))},applyQuality:w,setIceServers:e=>{d=e},stop:()=>{if(!m){m=!0;for(let e of s.values())e.pc.close();s.clear(),c.clear(),h.clear(),l.clear(),S(),v(),i.onState?.(`closed`)}},getConnection:e=>s.get(e)?.pc??null,get peers(){return[...c.values()].map(e=>({...e}))}}}exports.createPeerMesh=i;
2
2
  //# sourceMappingURL=peer-mesh.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"peer-mesh.cjs","names":[],"sources":["../../src/webrtc/peer-mesh.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the mesh is one object's lifetime: a link's\n * transceivers, the offer it owes, the tracks published on it and the share of\n * the uplink it costs all change together, and every method here reads or writes\n * the same two maps. The pieces that *could* stand alone already do —\n * `peer-link.ts` for the per-connection mechanics and `mesh-quality.ts` for the\n * division — and what is left is the coordination between them.\n */\nimport { applyQualityToLink, resolveDegradation, scaleForRoom } from \"./mesh-quality\";\nimport {\n acceptCandidate,\n adoptTransceivers,\n createPeerConnection,\n drainCandidates,\n slotOf,\n type PeerLink,\n} from \"./peer-link\";\nimport { createLinkStatsSampler, type LinkStats, type LinkStatsSampler } from \"./link-stats\";\nimport type {\n MeshMessage,\n MeshPeer,\n MeshQuality,\n MeshStatsOptions,\n PeerMeshOptions,\n} from \"./mesh-types\";\n\n/** What {@link createPeerMesh}'s negotiation steps return once their link is gone. */\nconst GONE = Symbol(\"gone\");\n\n/** A running mesh. */\nexport interface PeerMesh {\n /**\n * Open a link to a peer.\n *\n * `offerer` decides which side sends the offer, and exactly one side of each\n * link must say `true`. Drive it from the arrival order your server already\n * imposes — the peer that joined **later** offers, the one already in the\n * room answers. That avoids glare by construction, without the rollback\n * dance of perfect negotiation and without depending on a browser\n * implementing argument-less `setLocalDescription`.\n */\n addPeer: (peerId: string, options: { offerer: boolean }) => Promise<void>;\n /** Close one link and give its share of the uplink back to the others. */\n removePeer: (peerId: string) => void;\n /** Feed the mesh an `offer`, `answer` or `ice` message from `from`. */\n accept: (message: MeshMessage & { from: string }) => Promise<void>;\n /**\n * Publish or retract one slot across every live link.\n *\n * `null` retracts: the sender keeps its negotiated transceiver and stops\n * producing, which is what mutes a microphone without disturbing the other\n * slots or the connection. Nothing renegotiates — the m-lines were allocated\n * before any track existed, which is what makes a mesh survive toggling: a\n * renegotiation per toggle is N-1 simultaneous offer/answer rounds every time\n * somebody unmutes.\n */\n setLocalTrack: (slot: string, track: MediaStreamTrack | null) => Promise<void>;\n /** Apply encoder limits, divided by the current size of the room. */\n applyQuality: (quality: MeshQuality) => Promise<void>;\n /** Replace the ICE servers used for links opened from now on. */\n setIceServers: (servers: RTCIceServer[]) => void;\n /**\n * Close every link, forget the local tracks and report `closed` — for good.\n *\n * Stopping is terminal. The signalling socket usually outlives the call, so\n * an offer still in flight from a former participant, or from anyone the\n * server relays to this user, keeps reaching {@link PeerMesh.accept} after\n * the hang-up. A stopped mesh drops it: no connection is opened, nothing is\n * answered and no track is published, so a call that reports `closed` never\n * sends the microphone or camera again. The same holds for `addPeer`,\n * `setLocalTrack` and `applyQuality`, and for every negotiation that was\n * already awaiting the browser when `stop()` ran. Calling it twice is a\n * no-op.\n *\n * The tracks themselves are not stopped: they belong to the caller, who may\n * still be showing them in a preview or reusing them on the next call. To\n * join again, create a new mesh.\n */\n stop: () => void;\n /** The peers as the mesh currently sees them. */\n readonly peers: MeshPeer[];\n /**\n * The connection carrying one peer's link, or `null`.\n *\n * The escape hatch for everything this mesh does not model. `getStats()`,\n * `getSenders()`, an `RTCDataChannel`, an encoding tweak the `quality`\n * shape has no field for — all of it lives on the connection, and a mesh\n * that keeps it private turns adopting the mesh into losing a feature.\n *\n * {@link MeshPeer.connection} is the *state*, which is what a view needs;\n * this is the object, which is what a measurement needs. For the common\n * case of measuring, {@link PeerMeshOptions.stats} spares you the loop —\n * including the one-sampler-per-connection rule that a hand-rolled version\n * gets wrong.\n *\n * @param peerId - The id the peer was added under.\n * @returns The connection, or `null` when there is no link for that id.\n */\n getConnection: (peerId: string) => RTCPeerConnection | null;\n}\n\n/**\n * One `RTCPeerConnection` per peer, with the slots negotiated up front.\n *\n * The signalling protocol stays yours: this produces and accepts three message\n * shapes (`offer`, `answer`, `ice`) and leaves delivery, room membership and\n * identity to your server. What it owns is the part that is the same in every\n * mesh and wrong in most of them — see {@link PeerMesh} for the traps each\n * method exists to avoid.\n *\n * @param options - See {@link PeerMeshOptions}.\n * @returns The mesh.\n *\n * @example\n * const mesh = createPeerMesh({\n * slots: [\n * { name: \"mic\", kind: \"audio\" },\n * { name: \"cam\", kind: \"video\" },\n * ],\n * send: (message) => socket.send(message),\n * onPeers: setPeers,\n * });\n * socket.onMessage = (message) => void mesh.accept(message);\n * await mesh.addPeer(\"peer-2\", { offerer: true });\n * await mesh.setLocalTrack(\"mic\", micTrack);\n */\nexport function createPeerMesh(options: PeerMeshOptions): PeerMesh {\n const { slots, send } = options;\n const links = new Map<string, PeerLink>();\n const peers = new Map<string, MeshPeer>();\n const localTracks = new Map<string, MediaStreamTrack | null>();\n const slotWrites = new Map<string, Promise<void>>();\n let iceServers = options.iceServers ?? [];\n const describe =\n options.setLocalDescription ??\n ((connection: RTCPeerConnection, description: RTCSessionDescriptionInit) =>\n connection.setLocalDescription(description));\n let quality: MeshQuality = options.quality ?? {};\n let stopped = false;\n const samplers = new Map<string, LinkStatsSampler>();\n let statsTimer: ReturnType<typeof setInterval> | null = null;\n\n const emptyStreams = (): Record<string, MediaStream | null> =>\n Object.fromEntries(slots.map((slot) => [slot.name, null]));\n\n const emitPeers = (): void => {\n options.onPeers?.([...peers.values()].map((peer) => ({ ...peer })));\n };\n\n /**\n * Whether a link is still the one the mesh holds for its peer.\n *\n * Every negotiation step awaits the browser, and `stop()` or `removePeer()`\n * can close the link inside any of those awaits. A continuation that does\n * not re-check keeps negotiating on a closed connection — which a browser\n * answers with `InvalidStateError` — or, worse, signals an answer for a call\n * that already hung up.\n *\n * @param link - The link a continuation is about to touch.\n * @returns `false` once the mesh stopped or the link was removed or replaced.\n */\n const isLive = (link: PeerLink): boolean => !stopped && links.get(link.peerId) === link;\n\n /**\n * Await one negotiation step, and tell the caller whether to go on.\n *\n * A browser settles a call that `close()` ran under in one of two ways:\n * it rejects with `InvalidStateError`, or — what Chromium was measured\n * doing — it never settles at all. The second needs nothing here; the\n * first would surface as a rejected `accept()`, which the documented\n * `void mesh.accept(message)` wiring turns into an unhandled rejection\n * for a call that already hung up. So a rejection on a link that is no\n * longer live is swallowed, and one on a live link is rethrown untouched.\n *\n * @param link - The link the step negotiates on.\n * @param step - The pending browser call.\n * @returns The step's value, or {@link GONE} when the link stopped being live.\n */\n const whileLive = async <T>(link: PeerLink, step: Promise<T>): Promise<T | typeof GONE> => {\n try {\n const value = await step;\n return isLive(link) ? value : GONE;\n } catch (error) {\n if (!isLive(link)) return GONE;\n throw error;\n }\n };\n\n /**\n * Sample every connected link once.\n *\n * Only `connected` links are asked. A link still gathering candidates has\n * no traffic to measure, and asking anyway spends a `getStats()` round trip\n * to learn that — per link, on every tick.\n *\n * `settings` arrives as an argument rather than being read from `options`\n * here: the timer is only ever armed past the check that they exist, so\n * reading them again would add a branch that nothing can reach.\n *\n * Each link is sampled on its own: a `getStats()` that rejects — a link\n * closing under the call does that — skips that link for this tick and\n * leaves the others measured. Across the await the link is re-checked by\n * identity, not by id: a peer removed and re-added under the same id holds\n * a new connection, and the old one's sample must not land on it.\n *\n * @param settings - The measuring options, already known to be present.\n */\n const sampleLinks = async (settings: MeshStatsOptions): Promise<void> => {\n if (stopped) return;\n let changed = false;\n\n for (const link of [...links.values()]) {\n if (link.pc.connectionState !== \"connected\") continue;\n let sampler = samplers.get(link.peerId);\n if (sampler === undefined) {\n sampler = createLinkStatsSampler(\n settings.kind === undefined ? {} : { kind: settings.kind },\n );\n samplers.set(link.peerId, sampler);\n }\n let stats: LinkStats;\n try {\n stats = await sampler.sample(link.pc);\n } catch {\n continue;\n }\n const peer = peers.get(link.peerId);\n if (!isLive(link) || peer === undefined) continue;\n peer.stats = stats;\n changed = true;\n settings.onStats?.(link.peerId, stats);\n }\n\n if (changed) emitPeers();\n };\n\n /**\n * Keep the timer alive exactly while there is something to measure.\n *\n * One timer for the whole mesh, not one per peer — and none at all in an\n * empty room, which is where a call sits for as long as the first person is\n * early.\n */\n const syncStatsTimer = (): void => {\n const settings = options.stats;\n if (settings === undefined) return;\n const wanted = !stopped && links.size > 0;\n if (wanted && statsTimer === null) {\n statsTimer = setInterval(() => void sampleLinks(settings), settings.intervalMs ?? 2000);\n return;\n }\n if (!wanted && statsTimer !== null) {\n clearInterval(statsTimer);\n statsTimer = null;\n }\n };\n\n /**\n * Collapse the per-link states into the one badge a call shows.\n *\n * No links at all is `connected`, not a failure: it means nobody else is in\n * the room yet, which is a legitimate state a call sits in for as long as the\n * first person is early.\n */\n const refreshState = (): void => {\n if (stopped) return;\n const states = [...links.values()].map((link) => link.pc.connectionState);\n if (states.some((state) => state === \"connected\")) options.onState?.(\"connected\");\n else if (states.length > 0) options.onState?.(\"connecting\", \"negotiating\");\n else options.onState?.(\"connected\", \"alone\");\n };\n\n const applyQuality = async (next: MeshQuality): Promise<void> => {\n if (stopped) return;\n quality = next;\n const effective = scaleForRoom(next, links.size);\n const degradation = resolveDegradation(next, effective);\n for (const link of links.values()) {\n await applyQualityToLink(link.transceivers, slots, effective, degradation);\n }\n };\n\n const makeOffer = async (link: PeerLink): Promise<void> => {\n if (link.makingOffer) return;\n link.makingOffer = true;\n try {\n const offer = await link.pc.createOffer();\n if (!isLive(link)) return;\n if (!offer.sdp) {\n options.onNotice?.(\"empty_local_offer_sdp\");\n return;\n }\n await describe(link.pc, offer);\n if (!isLive(link)) return;\n send({\n type: \"offer\",\n to: link.peerId,\n sdp: link.pc.localDescription?.sdp ?? offer.sdp,\n });\n } catch {\n if (isLive(link)) options.onNotice?.(\"offer_failed\");\n } finally {\n link.makingOffer = false;\n }\n };\n\n /**\n * Wrap an inbound track in the stream the caller renders.\n *\n * The event's own stream is preferred: it is the one the sending side\n * grouped the track into, so a caller that reads `stream.id` sees what the\n * peer published rather than a wrapper invented here. Browsers only fill it\n * when the offer named a stream, hence the fallback — and the guard after\n * that is for a runtime with no `MediaStream` at all, where routing still\n * has to not throw.\n */\n const streamFor = (event: RTCTrackEvent): MediaStream | null => {\n const provided = event.streams?.[0];\n if (provided) return provided;\n return typeof MediaStream === \"undefined\" ? null : new MediaStream([event.track]);\n };\n\n const attachRemoteTrack = (link: PeerLink, event: RTCTrackEvent): void => {\n const slot = slotOf(event.transceiver, link, slots);\n const peer = peers.get(link.peerId);\n if (!slot || !peer) return;\n\n peer.streams = { ...peer.streams, [slot.name]: streamFor(event) };\n event.track.onended = (): void => {\n const current = peers.get(link.peerId);\n if (!current) return;\n current.streams = { ...current.streams, [slot.name]: null };\n emitPeers();\n };\n emitPeers();\n };\n\n /**\n * Queue one write behind every earlier write to the same slot.\n *\n * Every write that puts a local track on a sender goes through here — the\n * fan-out of `setLocalTrack` and the first write onto a link that just\n * got its transceivers alike. Two writes to one slot therefore never run\n * at once, and a write queued later always finishes later.\n *\n * @param slot - The slot name.\n * @param write - The write to run once the earlier ones have finished.\n * @returns The queued write.\n */\n const enqueueWrite = (slot: string, write: () => Promise<void>): Promise<void> => {\n const queued = (slotWrites.get(slot) ?? Promise.resolve()).then(write);\n slotWrites.set(slot, queued);\n return queued;\n };\n\n /**\n * Put a slot's current track on one link's sender.\n *\n * The track is read when the write runs, not when it was queued, so the\n * last `setLocalTrack` wins whichever write lands last. A refusal\n * belongs to a link that is tearing down, whose state handler removes it,\n * so it is not an error here.\n *\n * @param link - The link to write onto.\n * @param slot - The slot name.\n * @param index - The slot's position in `slots`, which is its transceiver.\n */\n const writeSlot = async (link: PeerLink, slot: string, index: number): Promise<void> => {\n const transceiver = link.transceivers[index];\n if (!transceiver || !isLive(link)) return;\n try {\n await transceiver.sender.replaceTrack(localTracks.get(slot) ?? null);\n } catch {\n return;\n }\n };\n\n /**\n * Publish every held local track onto a link whose transceivers now exist.\n *\n * Up front for the offerer, after the offer lands for the answerer, so a\n * microphone that was already live when the peer joined starts flowing\n * without waiting for a toggle. Each slot's write joins that slot's queue,\n * so a mute issued while it is in flight still has the last word.\n *\n * @param link - The link to publish onto.\n */\n const attachLocalTracks = (link: PeerLink): Promise<unknown> =>\n Promise.all(\n slots.map((slot, index) =>\n enqueueWrite(slot.name, () => writeSlot(link, slot.name, index)),\n ),\n );\n\n const removePeer = (peerId: string): void => {\n if (stopped) return;\n const link = links.get(peerId);\n if (link) {\n link.pc.close();\n links.delete(peerId);\n }\n peers.delete(peerId);\n samplers.delete(peerId);\n void applyQuality(quality);\n syncStatsTimer();\n emitPeers();\n refreshState();\n };\n\n const addPeer = async (peerId: string, { offerer }: { offerer: boolean }): Promise<void> => {\n if (stopped || links.has(peerId)) return;\n\n const pc = createPeerConnection(iceServers);\n let transceivers: RTCRtpTransceiver[] = [];\n if (offerer) {\n try {\n transceivers = slots.map((slot) =>\n pc.addTransceiver(slot.kind, { direction: \"sendrecv\" }),\n );\n } catch (error) {\n pc.close();\n throw error;\n }\n }\n const link: PeerLink = {\n peerId,\n pc,\n transceivers,\n pendingCandidates: [],\n remoteReady: false,\n makingOffer: false,\n isOfferer: offerer,\n };\n links.set(peerId, link);\n peers.set(peerId, {\n peerId,\n connection: pc.connectionState,\n streams: peers.get(peerId)?.streams ?? emptyStreams(),\n });\n\n if (offerer) {\n await attachLocalTracks(link);\n if (!isLive(link)) return;\n }\n\n pc.onicecandidate = (event): void => {\n send({\n type: \"ice\",\n to: peerId,\n candidate: event.candidate?.candidate ?? null,\n sdpMid: event.candidate?.sdpMid ?? null,\n sdpMLineIndex: event.candidate?.sdpMLineIndex ?? null,\n });\n };\n\n pc.ontrack = (event): void => attachRemoteTrack(link, event);\n\n pc.onconnectionstatechange = (): void => {\n if (!isLive(link)) return;\n const peer = peers.get(peerId);\n if (peer) peer.connection = pc.connectionState;\n if (pc.connectionState === \"failed\" || pc.connectionState === \"closed\") {\n removePeer(peerId);\n return;\n }\n emitPeers();\n refreshState();\n };\n\n pc.onnegotiationneeded = (): void => {\n if (link.isOfferer) void makeOffer(link);\n };\n\n syncStatsTimer();\n emitPeers();\n refreshState();\n if (offerer) await makeOffer(link);\n };\n\n const acceptOffer = async (from: string, sdp: string): Promise<void> => {\n if (!links.has(from)) await addPeer(from, { offerer: false });\n const link = links.get(from);\n if (!link || !isLive(link)) return;\n\n if (\n (await whileLive(link, link.pc.setRemoteDescription({ type: \"offer\", sdp }))) === GONE\n ) {\n return;\n }\n link.remoteReady = true;\n await drainCandidates(link);\n\n if (!link.isOfferer) {\n adoptTransceivers(link);\n await attachLocalTracks(link);\n }\n if (!isLive(link)) return;\n\n const answer = await whileLive(link, link.pc.createAnswer());\n if (answer === GONE) return;\n if (!answer.sdp) {\n options.onNotice?.(\"empty_local_answer_sdp\");\n return;\n }\n if ((await whileLive(link, describe(link.pc, answer))) === GONE) return;\n send({ type: \"answer\", to: from, sdp: link.pc.localDescription?.sdp ?? answer.sdp });\n await applyQuality(quality);\n };\n\n const accept = async (message: MeshMessage & { from: string }): Promise<void> => {\n if (stopped) return;\n if (message.type === \"offer\") {\n await acceptOffer(message.from, message.sdp);\n return;\n }\n\n const link = links.get(message.from);\n if (!link) return;\n\n if (message.type === \"answer\") {\n const applied = link.pc.setRemoteDescription({ type: \"answer\", sdp: message.sdp });\n if ((await whileLive(link, applied)) === GONE) return;\n link.remoteReady = true;\n await drainCandidates(link);\n await applyQuality(quality);\n return;\n }\n\n if (message.candidate === null) return;\n await acceptCandidate(link, {\n candidate: message.candidate,\n sdpMid: message.sdpMid ?? undefined,\n sdpMLineIndex: message.sdpMLineIndex ?? undefined,\n });\n };\n\n /**\n * Publish or retract one slot, one write at a time per slot.\n *\n * Writes to a slot are chained, and each publishes whatever the slot holds\n * when it runs. Without the chain, an unmute whose `replaceTrack` is still\n * in flight could finish after the mute that followed it, leaving the\n * sender on the microphone while the mesh believes the slot is empty.\n */\n const setLocalTrack = async (slot: string, track: MediaStreamTrack | null): Promise<void> => {\n if (stopped) return;\n localTracks.set(slot, track);\n const index = slots.findIndex((entry) => entry.name === slot);\n if (index < 0) return;\n\n await enqueueWrite(slot, async () => {\n for (const link of [...links.values()]) await writeSlot(link, slot, index);\n });\n await applyQuality(quality);\n };\n\n const stop = (): void => {\n if (stopped) return;\n stopped = true;\n for (const link of links.values()) link.pc.close();\n links.clear();\n peers.clear();\n samplers.clear();\n localTracks.clear();\n syncStatsTimer();\n emitPeers();\n options.onState?.(\"closed\");\n };\n\n options.onState?.(\"connecting\", \"signaling\");\n\n return {\n addPeer,\n removePeer,\n accept,\n setLocalTrack,\n applyQuality,\n setIceServers: (servers): void => {\n iceServers = servers;\n },\n stop,\n getConnection: (peerId: string): RTCPeerConnection | null => links.get(peerId)?.pc ?? null,\n get peers(): MeshPeer[] {\n return [...peers.values()].map((peer) => ({ ...peer }));\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"peer-mesh.cjs","names":["createLinkStatsSampler","scaleForRoom","resolveDegradation","applyQualityToLink","slotOf","createPeerConnection","drainCandidates","acceptCandidate","require_link_stats","require_mesh_quality","require_peer_link","GONE","createPeerMesh","options","links","peers","localTracks","slotWrites","iceServers","describe","connection","description","quality","stopped","samplers","statsTimer","emptyStreams","slots","slot","emitPeers","peer","isLive","link","whileLive","value","step","error","sampleLinks","changed","sampler","settings","stats","syncStatsTimer","wanted","refreshState","states","state","applyQuality","next","effective","degradation","makeOffer","offer","send","streamFor","event","attachRemoteTrack","current","enqueueWrite","queued","write","writeSlot","transceiver","index","attachLocalTracks","removePeer","peerId","addPeer","pc","transceivers","offerer","acceptOffer","from","answer","message","applied","track","entry","servers"],"sources":["../../src/webrtc/peer-mesh.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — the mesh is one object's lifetime: a link's\n * transceivers, the offer it owes, the tracks published on it and the share of\n * the uplink it costs all change together, and every method here reads or writes\n * the same two maps. The pieces that *could* stand alone already do —\n * `peer-link.ts` for the per-connection mechanics and `mesh-quality.ts` for the\n * division — and what is left is the coordination between them.\n */\nimport { applyQualityToLink, resolveDegradation, scaleForRoom } from \"./mesh-quality\";\nimport {\n acceptCandidate,\n adoptTransceivers,\n createPeerConnection,\n drainCandidates,\n slotOf,\n type PeerLink,\n} from \"./peer-link\";\nimport { createLinkStatsSampler, type LinkStats, type LinkStatsSampler } from \"./link-stats\";\nimport type {\n MeshMessage,\n MeshPeer,\n MeshQuality,\n MeshStatsOptions,\n PeerMeshOptions,\n} from \"./mesh-types\";\n\n/** What {@link createPeerMesh}'s negotiation steps return once their link is gone. */\nconst GONE = Symbol(\"gone\");\n\n/** A running mesh. */\nexport interface PeerMesh {\n /**\n * Open a link to a peer.\n *\n * `offerer` decides which side sends the offer, and exactly one side of each\n * link must say `true`. Drive it from the arrival order your server already\n * imposes — the peer that joined **later** offers, the one already in the\n * room answers. That avoids glare by construction, without the rollback\n * dance of perfect negotiation and without depending on a browser\n * implementing argument-less `setLocalDescription`.\n */\n addPeer: (peerId: string, options: { offerer: boolean }) => Promise<void>;\n /** Close one link and give its share of the uplink back to the others. */\n removePeer: (peerId: string) => void;\n /** Feed the mesh an `offer`, `answer` or `ice` message from `from`. */\n accept: (message: MeshMessage & { from: string }) => Promise<void>;\n /**\n * Publish or retract one slot across every live link.\n *\n * `null` retracts: the sender keeps its negotiated transceiver and stops\n * producing, which is what mutes a microphone without disturbing the other\n * slots or the connection. Nothing renegotiates — the m-lines were allocated\n * before any track existed, which is what makes a mesh survive toggling: a\n * renegotiation per toggle is N-1 simultaneous offer/answer rounds every time\n * somebody unmutes.\n */\n setLocalTrack: (slot: string, track: MediaStreamTrack | null) => Promise<void>;\n /** Apply encoder limits, divided by the current size of the room. */\n applyQuality: (quality: MeshQuality) => Promise<void>;\n /** Replace the ICE servers used for links opened from now on. */\n setIceServers: (servers: RTCIceServer[]) => void;\n /**\n * Close every link, forget the local tracks and report `closed` — for good.\n *\n * Stopping is terminal. The signalling socket usually outlives the call, so\n * an offer still in flight from a former participant, or from anyone the\n * server relays to this user, keeps reaching {@link PeerMesh.accept} after\n * the hang-up. A stopped mesh drops it: no connection is opened, nothing is\n * answered and no track is published, so a call that reports `closed` never\n * sends the microphone or camera again. The same holds for `addPeer`,\n * `setLocalTrack` and `applyQuality`, and for every negotiation that was\n * already awaiting the browser when `stop()` ran. Calling it twice is a\n * no-op.\n *\n * The tracks themselves are not stopped: they belong to the caller, who may\n * still be showing them in a preview or reusing them on the next call. To\n * join again, create a new mesh.\n */\n stop: () => void;\n /** The peers as the mesh currently sees them. */\n readonly peers: MeshPeer[];\n /**\n * The connection carrying one peer's link, or `null`.\n *\n * The escape hatch for everything this mesh does not model. `getStats()`,\n * `getSenders()`, an `RTCDataChannel`, an encoding tweak the `quality`\n * shape has no field for — all of it lives on the connection, and a mesh\n * that keeps it private turns adopting the mesh into losing a feature.\n *\n * {@link MeshPeer.connection} is the *state*, which is what a view needs;\n * this is the object, which is what a measurement needs. For the common\n * case of measuring, {@link PeerMeshOptions.stats} spares you the loop —\n * including the one-sampler-per-connection rule that a hand-rolled version\n * gets wrong.\n *\n * @param peerId - The id the peer was added under.\n * @returns The connection, or `null` when there is no link for that id.\n */\n getConnection: (peerId: string) => RTCPeerConnection | null;\n}\n\n/**\n * One `RTCPeerConnection` per peer, with the slots negotiated up front.\n *\n * The signalling protocol stays yours: this produces and accepts three message\n * shapes (`offer`, `answer`, `ice`) and leaves delivery, room membership and\n * identity to your server. What it owns is the part that is the same in every\n * mesh and wrong in most of them — see {@link PeerMesh} for the traps each\n * method exists to avoid.\n *\n * @param options - See {@link PeerMeshOptions}.\n * @returns The mesh.\n *\n * @example\n * const mesh = createPeerMesh({\n * slots: [\n * { name: \"mic\", kind: \"audio\" },\n * { name: \"cam\", kind: \"video\" },\n * ],\n * send: (message) => socket.send(message),\n * onPeers: setPeers,\n * });\n * socket.onMessage = (message) => void mesh.accept(message);\n * await mesh.addPeer(\"peer-2\", { offerer: true });\n * await mesh.setLocalTrack(\"mic\", micTrack);\n */\nexport function createPeerMesh(options: PeerMeshOptions): PeerMesh {\n const { slots, send } = options;\n const links = new Map<string, PeerLink>();\n const peers = new Map<string, MeshPeer>();\n const localTracks = new Map<string, MediaStreamTrack | null>();\n const slotWrites = new Map<string, Promise<void>>();\n let iceServers = options.iceServers ?? [];\n const describe =\n options.setLocalDescription ??\n ((connection: RTCPeerConnection, description: RTCSessionDescriptionInit) =>\n connection.setLocalDescription(description));\n let quality: MeshQuality = options.quality ?? {};\n let stopped = false;\n const samplers = new Map<string, LinkStatsSampler>();\n let statsTimer: ReturnType<typeof setInterval> | null = null;\n\n const emptyStreams = (): Record<string, MediaStream | null> =>\n Object.fromEntries(slots.map((slot) => [slot.name, null]));\n\n const emitPeers = (): void => {\n options.onPeers?.([...peers.values()].map((peer) => ({ ...peer })));\n };\n\n /**\n * Whether a link is still the one the mesh holds for its peer.\n *\n * Every negotiation step awaits the browser, and `stop()` or `removePeer()`\n * can close the link inside any of those awaits. A continuation that does\n * not re-check keeps negotiating on a closed connection — which a browser\n * answers with `InvalidStateError` — or, worse, signals an answer for a call\n * that already hung up.\n *\n * @param link - The link a continuation is about to touch.\n * @returns `false` once the mesh stopped or the link was removed or replaced.\n */\n const isLive = (link: PeerLink): boolean => !stopped && links.get(link.peerId) === link;\n\n /**\n * Await one negotiation step, and tell the caller whether to go on.\n *\n * A browser settles a call that `close()` ran under in one of two ways:\n * it rejects with `InvalidStateError`, or — what Chromium was measured\n * doing — it never settles at all. The second needs nothing here; the\n * first would surface as a rejected `accept()`, which the documented\n * `void mesh.accept(message)` wiring turns into an unhandled rejection\n * for a call that already hung up. So a rejection on a link that is no\n * longer live is swallowed, and one on a live link is rethrown untouched.\n *\n * @param link - The link the step negotiates on.\n * @param step - The pending browser call.\n * @returns The step's value, or {@link GONE} when the link stopped being live.\n */\n const whileLive = async <T>(link: PeerLink, step: Promise<T>): Promise<T | typeof GONE> => {\n try {\n const value = await step;\n return isLive(link) ? value : GONE;\n } catch (error) {\n if (!isLive(link)) return GONE;\n throw error;\n }\n };\n\n /**\n * Sample every connected link once.\n *\n * Only `connected` links are asked. A link still gathering candidates has\n * no traffic to measure, and asking anyway spends a `getStats()` round trip\n * to learn that — per link, on every tick.\n *\n * `settings` arrives as an argument rather than being read from `options`\n * here: the timer is only ever armed past the check that they exist, so\n * reading them again would add a branch that nothing can reach.\n *\n * Each link is sampled on its own: a `getStats()` that rejects — a link\n * closing under the call does that — skips that link for this tick and\n * leaves the others measured. Across the await the link is re-checked by\n * identity, not by id: a peer removed and re-added under the same id holds\n * a new connection, and the old one's sample must not land on it.\n *\n * @param settings - The measuring options, already known to be present.\n */\n const sampleLinks = async (settings: MeshStatsOptions): Promise<void> => {\n if (stopped) return;\n let changed = false;\n\n for (const link of [...links.values()]) {\n if (link.pc.connectionState !== \"connected\") continue;\n let sampler = samplers.get(link.peerId);\n if (sampler === undefined) {\n sampler = createLinkStatsSampler(\n settings.kind === undefined ? {} : { kind: settings.kind },\n );\n samplers.set(link.peerId, sampler);\n }\n let stats: LinkStats;\n try {\n stats = await sampler.sample(link.pc);\n } catch {\n continue;\n }\n const peer = peers.get(link.peerId);\n if (!isLive(link) || peer === undefined) continue;\n peer.stats = stats;\n changed = true;\n settings.onStats?.(link.peerId, stats);\n }\n\n if (changed) emitPeers();\n };\n\n /**\n * Keep the timer alive exactly while there is something to measure.\n *\n * One timer for the whole mesh, not one per peer — and none at all in an\n * empty room, which is where a call sits for as long as the first person is\n * early.\n */\n const syncStatsTimer = (): void => {\n const settings = options.stats;\n if (settings === undefined) return;\n const wanted = !stopped && links.size > 0;\n if (wanted && statsTimer === null) {\n statsTimer = setInterval(() => void sampleLinks(settings), settings.intervalMs ?? 2000);\n return;\n }\n if (!wanted && statsTimer !== null) {\n clearInterval(statsTimer);\n statsTimer = null;\n }\n };\n\n /**\n * Collapse the per-link states into the one badge a call shows.\n *\n * No links at all is `connected`, not a failure: it means nobody else is in\n * the room yet, which is a legitimate state a call sits in for as long as the\n * first person is early.\n */\n const refreshState = (): void => {\n if (stopped) return;\n const states = [...links.values()].map((link) => link.pc.connectionState);\n if (states.some((state) => state === \"connected\")) options.onState?.(\"connected\");\n else if (states.length > 0) options.onState?.(\"connecting\", \"negotiating\");\n else options.onState?.(\"connected\", \"alone\");\n };\n\n const applyQuality = async (next: MeshQuality): Promise<void> => {\n if (stopped) return;\n quality = next;\n const effective = scaleForRoom(next, links.size);\n const degradation = resolveDegradation(next, effective);\n for (const link of links.values()) {\n await applyQualityToLink(link.transceivers, slots, effective, degradation);\n }\n };\n\n const makeOffer = async (link: PeerLink): Promise<void> => {\n if (link.makingOffer) return;\n link.makingOffer = true;\n try {\n const offer = await link.pc.createOffer();\n if (!isLive(link)) return;\n if (!offer.sdp) {\n options.onNotice?.(\"empty_local_offer_sdp\");\n return;\n }\n await describe(link.pc, offer);\n if (!isLive(link)) return;\n send({\n type: \"offer\",\n to: link.peerId,\n sdp: link.pc.localDescription?.sdp ?? offer.sdp,\n });\n } catch {\n if (isLive(link)) options.onNotice?.(\"offer_failed\");\n } finally {\n link.makingOffer = false;\n }\n };\n\n /**\n * Wrap an inbound track in the stream the caller renders.\n *\n * The event's own stream is preferred: it is the one the sending side\n * grouped the track into, so a caller that reads `stream.id` sees what the\n * peer published rather than a wrapper invented here. Browsers only fill it\n * when the offer named a stream, hence the fallback — and the guard after\n * that is for a runtime with no `MediaStream` at all, where routing still\n * has to not throw.\n */\n const streamFor = (event: RTCTrackEvent): MediaStream | null => {\n const provided = event.streams?.[0];\n if (provided) return provided;\n return typeof MediaStream === \"undefined\" ? null : new MediaStream([event.track]);\n };\n\n const attachRemoteTrack = (link: PeerLink, event: RTCTrackEvent): void => {\n const slot = slotOf(event.transceiver, link, slots);\n const peer = peers.get(link.peerId);\n if (!slot || !peer) return;\n\n peer.streams = { ...peer.streams, [slot.name]: streamFor(event) };\n event.track.onended = (): void => {\n const current = peers.get(link.peerId);\n if (!current) return;\n current.streams = { ...current.streams, [slot.name]: null };\n emitPeers();\n };\n emitPeers();\n };\n\n /**\n * Queue one write behind every earlier write to the same slot.\n *\n * Every write that puts a local track on a sender goes through here — the\n * fan-out of `setLocalTrack` and the first write onto a link that just\n * got its transceivers alike. Two writes to one slot therefore never run\n * at once, and a write queued later always finishes later.\n *\n * @param slot - The slot name.\n * @param write - The write to run once the earlier ones have finished.\n * @returns The queued write.\n */\n const enqueueWrite = (slot: string, write: () => Promise<void>): Promise<void> => {\n const queued = (slotWrites.get(slot) ?? Promise.resolve()).then(write);\n slotWrites.set(slot, queued);\n return queued;\n };\n\n /**\n * Put a slot's current track on one link's sender.\n *\n * The track is read when the write runs, not when it was queued, so the\n * last `setLocalTrack` wins whichever write lands last. A refusal\n * belongs to a link that is tearing down, whose state handler removes it,\n * so it is not an error here.\n *\n * @param link - The link to write onto.\n * @param slot - The slot name.\n * @param index - The slot's position in `slots`, which is its transceiver.\n */\n const writeSlot = async (link: PeerLink, slot: string, index: number): Promise<void> => {\n const transceiver = link.transceivers[index];\n if (!transceiver || !isLive(link)) return;\n try {\n await transceiver.sender.replaceTrack(localTracks.get(slot) ?? null);\n } catch {\n return;\n }\n };\n\n /**\n * Publish every held local track onto a link whose transceivers now exist.\n *\n * Up front for the offerer, after the offer lands for the answerer, so a\n * microphone that was already live when the peer joined starts flowing\n * without waiting for a toggle. Each slot's write joins that slot's queue,\n * so a mute issued while it is in flight still has the last word.\n *\n * @param link - The link to publish onto.\n */\n const attachLocalTracks = (link: PeerLink): Promise<unknown> =>\n Promise.all(\n slots.map((slot, index) =>\n enqueueWrite(slot.name, () => writeSlot(link, slot.name, index)),\n ),\n );\n\n const removePeer = (peerId: string): void => {\n if (stopped) return;\n const link = links.get(peerId);\n if (link) {\n link.pc.close();\n links.delete(peerId);\n }\n peers.delete(peerId);\n samplers.delete(peerId);\n void applyQuality(quality);\n syncStatsTimer();\n emitPeers();\n refreshState();\n };\n\n const addPeer = async (peerId: string, { offerer }: { offerer: boolean }): Promise<void> => {\n if (stopped || links.has(peerId)) return;\n\n const pc = createPeerConnection(iceServers);\n let transceivers: RTCRtpTransceiver[] = [];\n if (offerer) {\n try {\n transceivers = slots.map((slot) =>\n pc.addTransceiver(slot.kind, { direction: \"sendrecv\" }),\n );\n } catch (error) {\n pc.close();\n throw error;\n }\n }\n const link: PeerLink = {\n peerId,\n pc,\n transceivers,\n pendingCandidates: [],\n remoteReady: false,\n makingOffer: false,\n isOfferer: offerer,\n };\n links.set(peerId, link);\n peers.set(peerId, {\n peerId,\n connection: pc.connectionState,\n streams: peers.get(peerId)?.streams ?? emptyStreams(),\n });\n\n if (offerer) {\n await attachLocalTracks(link);\n if (!isLive(link)) return;\n }\n\n pc.onicecandidate = (event): void => {\n send({\n type: \"ice\",\n to: peerId,\n candidate: event.candidate?.candidate ?? null,\n sdpMid: event.candidate?.sdpMid ?? null,\n sdpMLineIndex: event.candidate?.sdpMLineIndex ?? null,\n });\n };\n\n pc.ontrack = (event): void => attachRemoteTrack(link, event);\n\n pc.onconnectionstatechange = (): void => {\n if (!isLive(link)) return;\n const peer = peers.get(peerId);\n if (peer) peer.connection = pc.connectionState;\n if (pc.connectionState === \"failed\" || pc.connectionState === \"closed\") {\n removePeer(peerId);\n return;\n }\n emitPeers();\n refreshState();\n };\n\n pc.onnegotiationneeded = (): void => {\n if (link.isOfferer) void makeOffer(link);\n };\n\n syncStatsTimer();\n emitPeers();\n refreshState();\n if (offerer) await makeOffer(link);\n };\n\n const acceptOffer = async (from: string, sdp: string): Promise<void> => {\n if (!links.has(from)) await addPeer(from, { offerer: false });\n const link = links.get(from);\n if (!link || !isLive(link)) return;\n\n if (\n (await whileLive(link, link.pc.setRemoteDescription({ type: \"offer\", sdp }))) === GONE\n ) {\n return;\n }\n link.remoteReady = true;\n await drainCandidates(link);\n\n if (!link.isOfferer) {\n adoptTransceivers(link);\n await attachLocalTracks(link);\n }\n if (!isLive(link)) return;\n\n const answer = await whileLive(link, link.pc.createAnswer());\n if (answer === GONE) return;\n if (!answer.sdp) {\n options.onNotice?.(\"empty_local_answer_sdp\");\n return;\n }\n if ((await whileLive(link, describe(link.pc, answer))) === GONE) return;\n send({ type: \"answer\", to: from, sdp: link.pc.localDescription?.sdp ?? answer.sdp });\n await applyQuality(quality);\n };\n\n const accept = async (message: MeshMessage & { from: string }): Promise<void> => {\n if (stopped) return;\n if (message.type === \"offer\") {\n await acceptOffer(message.from, message.sdp);\n return;\n }\n\n const link = links.get(message.from);\n if (!link) return;\n\n if (message.type === \"answer\") {\n const applied = link.pc.setRemoteDescription({ type: \"answer\", sdp: message.sdp });\n if ((await whileLive(link, applied)) === GONE) return;\n link.remoteReady = true;\n await drainCandidates(link);\n await applyQuality(quality);\n return;\n }\n\n if (message.candidate === null) return;\n await acceptCandidate(link, {\n candidate: message.candidate,\n sdpMid: message.sdpMid ?? undefined,\n sdpMLineIndex: message.sdpMLineIndex ?? undefined,\n });\n };\n\n /**\n * Publish or retract one slot, one write at a time per slot.\n *\n * Writes to a slot are chained, and each publishes whatever the slot holds\n * when it runs. Without the chain, an unmute whose `replaceTrack` is still\n * in flight could finish after the mute that followed it, leaving the\n * sender on the microphone while the mesh believes the slot is empty.\n */\n const setLocalTrack = async (slot: string, track: MediaStreamTrack | null): Promise<void> => {\n if (stopped) return;\n localTracks.set(slot, track);\n const index = slots.findIndex((entry) => entry.name === slot);\n if (index < 0) return;\n\n await enqueueWrite(slot, async () => {\n for (const link of [...links.values()]) await writeSlot(link, slot, index);\n });\n await applyQuality(quality);\n };\n\n const stop = (): void => {\n if (stopped) return;\n stopped = true;\n for (const link of links.values()) link.pc.close();\n links.clear();\n peers.clear();\n samplers.clear();\n localTracks.clear();\n syncStatsTimer();\n emitPeers();\n options.onState?.(\"closed\");\n };\n\n options.onState?.(\"connecting\", \"signaling\");\n\n return {\n addPeer,\n removePeer,\n accept,\n setLocalTrack,\n applyQuality,\n setIceServers: (servers): void => {\n iceServers = servers;\n },\n stop,\n getConnection: (peerId: string): RTCPeerConnection | null => links.get(peerId)?.pc ?? null,\n get peers(): MeshPeer[] {\n return [...peers.values()].map((peer) => ({ ...peer }));\n },\n };\n}\n"],"mappings":"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"}
@@ -35,11 +35,7 @@ function u(u) {
35
35
  let e = u.stats;
36
36
  if (e === void 0) return;
37
37
  let t = !b && p.size > 0;
38
- if (t && S === null) {
39
- S = setInterval(() => void D(e), e.intervalMs ?? 2e3);
40
- return;
41
- }
42
- !t && S !== null && (clearInterval(S), S = null);
38
+ t && S === null ? S = setInterval(() => void D(e), e.intervalMs ?? 2e3) : !t && S !== null && (clearInterval(S), S = null);
43
39
  }, k = () => {
44
40
  if (b) return;
45
41
  let e = [...p.values()].map((e) => e.pc.connectionState);
@@ -129,11 +125,7 @@ function u(u) {
129
125
  }, n.ontrack = (e) => N(i, e), n.onconnectionstatechange = () => {
130
126
  if (!T(i)) return;
131
127
  let t = m.get(e);
132
- if (t && (t.connection = n.connectionState), n.connectionState === "failed" || n.connectionState === "closed") {
133
- L(e);
134
- return;
135
- }
136
- w(), k();
128
+ t && (t.connection = n.connectionState), n.connectionState === "failed" || n.connectionState === "closed" ? L(e) : (w(), k());
137
129
  }, n.onnegotiationneeded = () => {
138
130
  i.isOfferer && j(i);
139
131
  }, O(), w(), k(), t && await j(i));
@@ -145,17 +137,11 @@ function u(u) {
145
137
  sdp: t
146
138
  })) === l || (n.remoteReady = !0, await s(n), n.isOfferer || (a(n), await I(n)), !T(n))) return;
147
139
  let r = await E(n, n.pc.createAnswer());
148
- if (r !== l) {
149
- if (!r.sdp) {
150
- u.onNotice?.("empty_local_answer_sdp");
151
- return;
152
- }
153
- await E(n, v(n.pc, r)) !== l && (f({
154
- type: "answer",
155
- to: e,
156
- sdp: n.pc.localDescription?.sdp ?? r.sdp
157
- }), await A(y));
158
- }
140
+ r !== l && (r.sdp ? await E(n, v(n.pc, r)) !== l && (f({
141
+ type: "answer",
142
+ to: e,
143
+ sdp: n.pc.localDescription?.sdp ?? r.sdp
144
+ }), await A(y)) : u.onNotice?.("empty_local_answer_sdp"));
159
145
  };
160
146
  return u.onState?.("connecting", "signaling"), {
161
147
  addPeer: R,
@@ -175,9 +161,7 @@ function u(u) {
175
161
  });
176
162
  if (await E(t, n) === l) return;
177
163
  t.remoteReady = !0, await s(t), await A(y);
178
- return;
179
- }
180
- e.candidate !== null && await i(t, {
164
+ } else e.candidate !== null && await i(t, {
181
165
  candidate: e.candidate,
182
166
  sdpMid: e.sdpMid ?? void 0,
183
167
  sdpMLineIndex: e.sdpMLineIndex ?? void 0