@q9labsai/chalk-react-native 4.1.17 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/README.md +134 -29
  2. package/android/build.gradle +35 -0
  3. package/android/compatibility/ModuleApiCompatibility.java +215 -0
  4. package/android/src/main/AndroidManifest.xml +2 -1
  5. package/android/src/main/java/ai/q9labs/chalk/reactnative/ChalkSpaceForegroundService.java +105 -31
  6. package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/ChalkAndroidConnectionServicePackage.kt +2 -0
  7. package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/ChalkAudioRouteModule.kt +137 -0
  8. package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/ChalkCallServiceModule.kt +32 -0
  9. package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/CommunicationDeviceListener.kt +23 -0
  10. package/android/src/test/kotlin/ai/q9labs/chalk/compatibility/UnsafeSignatures.kt +29 -0
  11. package/dist/android/call-service.d.ts +4 -0
  12. package/dist/android/call-service.d.ts.map +1 -0
  13. package/dist/avatar/FaceAvatar.d.ts +19 -0
  14. package/dist/avatar/FaceAvatar.d.ts.map +1 -0
  15. package/dist/avatar/tile-avatar-size.d.ts +3 -0
  16. package/dist/avatar/tile-avatar-size.d.ts.map +1 -0
  17. package/dist/chunk-GYVZSOGQ.js +30 -0
  18. package/dist/chunk-IHE6EA3T.js +25 -0
  19. package/dist/chunk-OIBT2FNM.js +1479 -0
  20. package/dist/client.d.ts +1 -5
  21. package/dist/client.d.ts.map +1 -1
  22. package/dist/client.js +185 -2
  23. package/dist/components/EmbeddedWhiteboard.d.ts.map +1 -1
  24. package/dist/components/native-media-visibility.d.ts +3 -2
  25. package/dist/components/native-media-visibility.d.ts.map +1 -1
  26. package/dist/components/useAndroidCallService.d.ts +8 -0
  27. package/dist/components/useAndroidCallService.d.ts.map +1 -0
  28. package/dist/dev.d.ts +10 -0
  29. package/dist/dev.d.ts.map +1 -0
  30. package/dist/dev.js +10 -0
  31. package/dist/dock/Dock.d.ts +23 -0
  32. package/dist/dock/Dock.d.ts.map +1 -0
  33. package/dist/dock/LeaveMenu.d.ts +12 -0
  34. package/dist/dock/LeaveMenu.d.ts.map +1 -0
  35. package/dist/dock/MoreSheet.d.ts +17 -0
  36. package/dist/dock/MoreSheet.d.ts.map +1 -0
  37. package/dist/dock/ReactionBurst.d.ts +8 -0
  38. package/dist/dock/ReactionBurst.d.ts.map +1 -0
  39. package/dist/dock/RoutePicker.d.ts +16 -0
  40. package/dist/dock/RoutePicker.d.ts.map +1 -0
  41. package/dist/dock/audio-route.d.ts +25 -0
  42. package/dist/dock/audio-route.d.ts.map +1 -0
  43. package/dist/error-YOPTEH5N.wav +0 -0
  44. package/dist/frame/CallFrame.d.ts +17 -0
  45. package/dist/frame/CallFrame.d.ts.map +1 -0
  46. package/dist/frame/Chalk.d.ts +40 -0
  47. package/dist/frame/Chalk.d.ts.map +1 -0
  48. package/dist/frame/back-handler.d.ts +6 -0
  49. package/dist/frame/back-handler.d.ts.map +1 -0
  50. package/dist/frame/dev-scenario.d.ts +28 -0
  51. package/dist/frame/dev-scenario.d.ts.map +1 -0
  52. package/dist/frame/device-layout.d.ts +16 -0
  53. package/dist/frame/device-layout.d.ts.map +1 -0
  54. package/dist/frame/measurement.d.ts +28 -0
  55. package/dist/frame/measurement.d.ts.map +1 -0
  56. package/dist/frame/portal.d.ts +24 -0
  57. package/dist/frame/portal.d.ts.map +1 -0
  58. package/dist/frame/preferences.d.ts +21 -0
  59. package/dist/frame/preferences.d.ts.map +1 -0
  60. package/dist/frame/regions.d.ts +25 -0
  61. package/dist/frame/regions.d.ts.map +1 -0
  62. package/dist/hand-DFWVXPH2.wav +0 -0
  63. package/dist/haptics/haptics.d.ts +12 -0
  64. package/dist/haptics/haptics.d.ts.map +1 -0
  65. package/dist/header/CallDetailsSheet.d.ts +18 -0
  66. package/dist/header/CallDetailsSheet.d.ts.map +1 -0
  67. package/dist/header/Header.d.ts +17 -0
  68. package/dist/header/Header.d.ts.map +1 -0
  69. package/dist/header/QrCode.d.ts +6 -0
  70. package/dist/header/QrCode.d.ts.map +1 -0
  71. package/dist/icons/Icon.d.ts +12 -0
  72. package/dist/icons/Icon.d.ts.map +1 -0
  73. package/dist/icons/icon-element.d.ts +24 -0
  74. package/dist/icons/icon-element.d.ts.map +1 -0
  75. package/dist/icons/icon-paths.d.ts +530 -0
  76. package/dist/icons/icon-paths.d.ts.map +1 -0
  77. package/dist/index.d.ts +6 -9
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +2956 -38
  80. package/dist/join-Z6RL5AHE.wav +0 -0
  81. package/dist/knock-4VBQSHK4.wav +0 -0
  82. package/dist/leave-MQLZOWQD.wav +0 -0
  83. package/dist/limbo/Limbo.d.ts +25 -0
  84. package/dist/limbo/Limbo.d.ts.map +1 -0
  85. package/dist/limbo/Veil.d.ts +10 -0
  86. package/dist/limbo/Veil.d.ts.map +1 -0
  87. package/dist/media/native-capture-error.d.ts +7 -0
  88. package/dist/media/native-capture-error.d.ts.map +1 -0
  89. package/dist/message-6Y6WJGTB.wav +0 -0
  90. package/dist/motion/MovingFrame.d.ts +36 -0
  91. package/dist/motion/MovingFrame.d.ts.map +1 -0
  92. package/dist/motion/motion.d.ts +82 -0
  93. package/dist/motion/motion.d.ts.map +1 -0
  94. package/dist/motion/presence.d.ts +6 -0
  95. package/dist/motion/presence.d.ts.map +1 -0
  96. package/dist/motion/press.d.ts +15 -0
  97. package/dist/motion/press.d.ts.map +1 -0
  98. package/dist/mute-H5SJFXVI.wav +0 -0
  99. package/dist/primitives/BottomSheet.d.ts +36 -0
  100. package/dist/primitives/BottomSheet.d.ts.map +1 -0
  101. package/dist/primitives/ChalkText.d.ts +13 -0
  102. package/dist/primitives/ChalkText.d.ts.map +1 -0
  103. package/dist/primitives/CopyButton.d.ts +11 -0
  104. package/dist/primitives/CopyButton.d.ts.map +1 -0
  105. package/dist/primitives/IconButton.d.ts +26 -0
  106. package/dist/primitives/IconButton.d.ts.map +1 -0
  107. package/dist/primitives/Menu.d.ts +39 -0
  108. package/dist/primitives/Menu.d.ts.map +1 -0
  109. package/dist/primitives/NameTag.d.ts +19 -0
  110. package/dist/primitives/NameTag.d.ts.map +1 -0
  111. package/dist/primitives/PillButton.d.ts +19 -0
  112. package/dist/primitives/PillButton.d.ts.map +1 -0
  113. package/dist/primitives/SegmentedControl.d.ts +17 -0
  114. package/dist/primitives/SegmentedControl.d.ts.map +1 -0
  115. package/dist/primitives/SheetGroup.d.ts +24 -0
  116. package/dist/primitives/SheetGroup.d.ts.map +1 -0
  117. package/dist/primitives/Switch.d.ts +9 -0
  118. package/dist/primitives/Switch.d.ts.map +1 -0
  119. package/dist/primitives/TileShell.d.ts +18 -0
  120. package/dist/primitives/TileShell.d.ts.map +1 -0
  121. package/dist/primitives/announce.d.ts +3 -0
  122. package/dist/primitives/announce.d.ts.map +1 -0
  123. package/dist/primitives/menu-placement.d.ts +32 -0
  124. package/dist/primitives/menu-placement.d.ts.map +1 -0
  125. package/dist/primitives/toast/Toast.d.ts +8 -0
  126. package/dist/primitives/toast/Toast.d.ts.map +1 -0
  127. package/dist/primitives/toast/ToastStack.d.ts +18 -0
  128. package/dist/primitives/toast/ToastStack.d.ts.map +1 -0
  129. package/dist/primitives/toast/toast-store.d.ts +39 -0
  130. package/dist/primitives/toast/toast-store.d.ts.map +1 -0
  131. package/dist/recording-Q4GB77Y4.wav +0 -0
  132. package/dist/sheets/people-chat/ChatNotices.d.ts +14 -0
  133. package/dist/sheets/people-chat/ChatNotices.d.ts.map +1 -0
  134. package/dist/sheets/people-chat/ChatTab.d.ts +6 -0
  135. package/dist/sheets/people-chat/ChatTab.d.ts.map +1 -0
  136. package/dist/sheets/people-chat/Composer.d.ts +7 -0
  137. package/dist/sheets/people-chat/Composer.d.ts.map +1 -0
  138. package/dist/sheets/people-chat/PeopleChatSheet.d.ts +17 -0
  139. package/dist/sheets/people-chat/PeopleChatSheet.d.ts.map +1 -0
  140. package/dist/sheets/people-chat/PeopleTab.d.ts +3 -0
  141. package/dist/sheets/people-chat/PeopleTab.d.ts.map +1 -0
  142. package/dist/sheets/people-chat/PhotoViewer.d.ts +19 -0
  143. package/dist/sheets/people-chat/PhotoViewer.d.ts.map +1 -0
  144. package/dist/sheets/people-chat/TextField.d.ts +4 -0
  145. package/dist/sheets/people-chat/TextField.d.ts.map +1 -0
  146. package/dist/sheets/people-chat/attachments.d.ts +33 -0
  147. package/dist/sheets/people-chat/attachments.d.ts.map +1 -0
  148. package/dist/sheets/people-chat/chat-model.d.ts +64 -0
  149. package/dist/sheets/people-chat/chat-model.d.ts.map +1 -0
  150. package/dist/sheets/people-chat/people-model.d.ts +43 -0
  151. package/dist/sheets/people-chat/people-model.d.ts.map +1 -0
  152. package/dist/sounds/sounds.d.ts +33 -0
  153. package/dist/sounds/sounds.d.ts.map +1 -0
  154. package/dist/space-client/create-native-space-client.d.ts +0 -4
  155. package/dist/space-client/create-native-space-client.d.ts.map +1 -1
  156. package/dist/space-client/random-uuid.d.ts +7 -0
  157. package/dist/space-client/random-uuid.d.ts.map +1 -0
  158. package/dist/stage/ContentTile.d.ts +18 -0
  159. package/dist/stage/ContentTile.d.ts.map +1 -0
  160. package/dist/stage/ParticipantTile.d.ts +18 -0
  161. package/dist/stage/ParticipantTile.d.ts.map +1 -0
  162. package/dist/stage/Stage.d.ts +14 -0
  163. package/dist/stage/Stage.d.ts.map +1 -0
  164. package/dist/stage/TileSheet.d.ts +12 -0
  165. package/dist/stage/TileSheet.d.ts.map +1 -0
  166. package/dist/stage/camera.d.ts +7 -0
  167. package/dist/stage/camera.d.ts.map +1 -0
  168. package/dist/stage/layout.d.ts +57 -0
  169. package/dist/stage/layout.d.ts.map +1 -0
  170. package/dist/stage/space-selector.d.ts +10 -0
  171. package/dist/stage/space-selector.d.ts.map +1 -0
  172. package/dist/stage/stage-view.d.ts +23 -0
  173. package/dist/stage/stage-view.d.ts.map +1 -0
  174. package/dist/status/CallOverlays.d.ts +17 -0
  175. package/dist/status/CallOverlays.d.ts.map +1 -0
  176. package/dist/status/ChalkArrival.d.ts +24 -0
  177. package/dist/status/ChalkArrival.d.ts.map +1 -0
  178. package/dist/status/StatusPage.d.ts +14 -0
  179. package/dist/status/StatusPage.d.ts.map +1 -0
  180. package/dist/status/call-screen.d.ts +20 -0
  181. package/dist/status/call-screen.d.ts.map +1 -0
  182. package/dist/test-VD2KAM4D.wav +0 -0
  183. package/dist/theme/theme.d.ts +15 -0
  184. package/dist/theme/theme.d.ts.map +1 -0
  185. package/dist/theme/tokens.d.ts +248 -0
  186. package/dist/theme/tokens.d.ts.map +1 -0
  187. package/dist/toasts/CallEventToasts.d.ts +21 -0
  188. package/dist/toasts/CallEventToasts.d.ts.map +1 -0
  189. package/dist/toasts/notices.d.ts +34 -0
  190. package/dist/toasts/notices.d.ts.map +1 -0
  191. package/dist/ui/ChalkUI.d.ts +12 -0
  192. package/dist/ui/ChalkUI.d.ts.map +1 -0
  193. package/dist/ui.d.ts +25 -0
  194. package/dist/ui.d.ts.map +1 -0
  195. package/dist/ui.js +77 -0
  196. package/dist/unmute-2XR2LICU.wav +0 -0
  197. package/embedded/chalk-whiteboard/asset-manifest.json +2 -2
  198. package/embedded/chalk-whiteboard/renderer.js +510 -510
  199. package/ios/ChalkAudioRouteModule.swift +93 -0
  200. package/ios/ChalkAudioRouteModuleBridge.m +9 -0
  201. package/package.json +46 -76
  202. package/src/android/call-service.ts +19 -0
  203. package/src/avatar/FaceAvatar.tsx +145 -0
  204. package/src/avatar/tile-avatar-size.ts +4 -0
  205. package/src/client.ts +1 -5
  206. package/src/components/EmbeddedWhiteboard.tsx +14 -71
  207. package/src/components/native-media-visibility.ts +1 -2
  208. package/src/components/useAndroidCallService.ts +41 -0
  209. package/src/dev.ts +9 -0
  210. package/src/dock/Dock.tsx +95 -0
  211. package/src/dock/LeaveMenu.tsx +21 -0
  212. package/src/dock/MoreSheet.tsx +233 -0
  213. package/src/dock/ReactionBurst.tsx +55 -0
  214. package/src/dock/RoutePicker.tsx +42 -0
  215. package/src/dock/audio-route.ts +69 -0
  216. package/src/frame/CallFrame.tsx +209 -0
  217. package/src/frame/Chalk.tsx +83 -0
  218. package/src/frame/back-handler.ts +19 -0
  219. package/src/frame/dev-scenario.ts +48 -0
  220. package/src/frame/device-layout.tsx +31 -0
  221. package/src/frame/measurement.ts +44 -0
  222. package/src/frame/portal.tsx +107 -0
  223. package/src/frame/preferences.tsx +48 -0
  224. package/src/frame/regions.test.ts +38 -0
  225. package/src/frame/regions.ts +60 -0
  226. package/src/haptics/haptics.ts +19 -0
  227. package/src/header/CallDetailsSheet.tsx +139 -0
  228. package/src/header/Header.tsx +107 -0
  229. package/src/header/QrCode.tsx +34 -0
  230. package/src/icons/Icon.tsx +35 -0
  231. package/src/icons/icon-element.ts +11 -0
  232. package/src/icons/icon-paths.ts +199 -0
  233. package/src/index.ts +6 -9
  234. package/src/limbo/Limbo.tsx +159 -0
  235. package/src/limbo/Veil.tsx +36 -0
  236. package/src/media/native-capture-error.test.ts +19 -0
  237. package/src/media/native-capture-error.ts +13 -0
  238. package/src/motion/MovingFrame.tsx +101 -0
  239. package/src/motion/motion.ts +33 -0
  240. package/src/motion/presence.ts +20 -0
  241. package/src/motion/press.ts +35 -0
  242. package/src/primitives/BottomSheet.tsx +211 -0
  243. package/src/primitives/ChalkText.tsx +23 -0
  244. package/src/primitives/CopyButton.tsx +78 -0
  245. package/src/primitives/IconButton.tsx +90 -0
  246. package/src/primitives/Menu.tsx +212 -0
  247. package/src/primitives/NameTag.tsx +68 -0
  248. package/src/primitives/PillButton.tsx +56 -0
  249. package/src/primitives/SegmentedControl.tsx +55 -0
  250. package/src/primitives/SheetGroup.tsx +72 -0
  251. package/src/primitives/Switch.tsx +39 -0
  252. package/src/primitives/TileShell.tsx +53 -0
  253. package/src/primitives/announce.ts +7 -0
  254. package/src/primitives/menu-placement.test.ts +50 -0
  255. package/src/primitives/menu-placement.ts +43 -0
  256. package/src/primitives/toast/Toast.tsx +50 -0
  257. package/src/primitives/toast/ToastStack.tsx +89 -0
  258. package/src/primitives/toast/toast-store.ts +86 -0
  259. package/src/sheets/people-chat/ChatNotices.tsx +69 -0
  260. package/src/sheets/people-chat/ChatTab.tsx +186 -0
  261. package/src/sheets/people-chat/Composer.tsx +182 -0
  262. package/src/sheets/people-chat/PeopleChatSheet.tsx +100 -0
  263. package/src/sheets/people-chat/PeopleTab.tsx +326 -0
  264. package/src/sheets/people-chat/PhotoViewer.tsx +132 -0
  265. package/src/sheets/people-chat/TextField.tsx +14 -0
  266. package/src/sheets/people-chat/attachments.tsx +183 -0
  267. package/src/sheets/people-chat/chat-model.ts +157 -0
  268. package/src/sheets/people-chat/people-chat-model.test.ts +98 -0
  269. package/src/sheets/people-chat/people-model.ts +68 -0
  270. package/src/sounds/assets/error.wav +0 -0
  271. package/src/sounds/assets/hand.wav +0 -0
  272. package/src/sounds/assets/join.wav +0 -0
  273. package/src/sounds/assets/knock.wav +0 -0
  274. package/src/sounds/assets/leave.wav +0 -0
  275. package/src/sounds/assets/message.wav +0 -0
  276. package/src/sounds/assets/mute.wav +0 -0
  277. package/src/sounds/assets/recording.wav +0 -0
  278. package/src/sounds/assets/test.wav +0 -0
  279. package/src/sounds/assets/unmute.wav +0 -0
  280. package/src/sounds/assets.d.ts +5 -0
  281. package/src/sounds/sounds.ts +50 -0
  282. package/src/space-client/create-native-space-client.ts +20 -181
  283. package/src/space-client/random-uuid.ts +17 -0
  284. package/src/space-client/whiteboard-watchdog.test.ts +23 -0
  285. package/src/stage/ContentTile.tsx +100 -0
  286. package/src/stage/ParticipantTile.tsx +140 -0
  287. package/src/stage/Stage.tsx +152 -0
  288. package/src/stage/TileSheet.tsx +116 -0
  289. package/src/stage/camera.ts +20 -0
  290. package/src/stage/layout.test.ts +77 -0
  291. package/src/stage/layout.ts +226 -0
  292. package/src/stage/space-selector.ts +31 -0
  293. package/src/stage/stage-view.tsx +68 -0
  294. package/src/status/CallOverlays.tsx +47 -0
  295. package/src/status/ChalkArrival.tsx +53 -0
  296. package/src/status/StatusPage.tsx +123 -0
  297. package/src/status/call-screen.test.ts +42 -0
  298. package/src/status/call-screen.ts +29 -0
  299. package/src/theme/theme.tsx +28 -0
  300. package/src/theme/tokens.ts +247 -0
  301. package/src/toasts/CallEventToasts.tsx +192 -0
  302. package/src/toasts/notices.test.ts +92 -0
  303. package/src/toasts/notices.ts +62 -0
  304. package/src/ui/ChalkUI.tsx +49 -0
  305. package/src/ui.ts +24 -0
  306. package/dist/android.d.ts +0 -2
  307. package/dist/android.d.ts.map +0 -1
  308. package/dist/android.js +0 -62
  309. package/dist/chunk-2OS7SSXE.js +0 -552
  310. package/dist/chunk-5DQ4KBRH.js +0 -690
  311. package/dist/chunk-ITLUHTVS.js +0 -5271
  312. package/dist/chunk-JB4LNWVP.js +0 -247
  313. package/dist/components/Chalk.d.ts +0 -79
  314. package/dist/components/Chalk.d.ts.map +0 -1
  315. package/dist/components/ChatMessageList.d.ts +0 -11
  316. package/dist/components/ChatMessageList.d.ts.map +0 -1
  317. package/dist/components/Entrance.d.ts +0 -22
  318. package/dist/components/Entrance.d.ts.map +0 -1
  319. package/dist/components/EntranceView.android.d.ts +0 -4
  320. package/dist/components/EntranceView.android.d.ts.map +0 -1
  321. package/dist/components/EntranceView.d.ts +0 -18
  322. package/dist/components/EntranceView.d.ts.map +0 -1
  323. package/dist/components/EntranceView.ios-pad.d.ts +0 -3
  324. package/dist/components/EntranceView.ios-pad.d.ts.map +0 -1
  325. package/dist/components/EntranceView.ios-phone.d.ts +0 -3
  326. package/dist/components/EntranceView.ios-phone.d.ts.map +0 -1
  327. package/dist/components/EntranceView.macos.d.ts +0 -4
  328. package/dist/components/EntranceView.macos.d.ts.map +0 -1
  329. package/dist/components/FaceAvatar.d.ts +0 -16
  330. package/dist/components/FaceAvatar.d.ts.map +0 -1
  331. package/dist/components/GradientSurface.d.ts +0 -14
  332. package/dist/components/GradientSurface.d.ts.map +0 -1
  333. package/dist/components/MediaView.d.ts +0 -14
  334. package/dist/components/MediaView.d.ts.map +0 -1
  335. package/dist/components/ReactionPicker.d.ts +0 -10
  336. package/dist/components/ReactionPicker.d.ts.map +0 -1
  337. package/dist/components/SpaceView.android.d.ts +0 -2
  338. package/dist/components/SpaceView.android.d.ts.map +0 -1
  339. package/dist/components/SpaceView.d.ts +0 -33
  340. package/dist/components/SpaceView.d.ts.map +0 -1
  341. package/dist/components/SpaceView.ios-pad.d.ts +0 -2
  342. package/dist/components/SpaceView.ios-pad.d.ts.map +0 -1
  343. package/dist/components/SpaceView.ios-phone.d.ts +0 -2
  344. package/dist/components/SpaceView.ios-phone.d.ts.map +0 -1
  345. package/dist/components/SpaceView.macos.d.ts +0 -2
  346. package/dist/components/SpaceView.macos.d.ts.map +0 -1
  347. package/dist/components/SpaceView.shared.d.ts +0 -3
  348. package/dist/components/SpaceView.shared.d.ts.map +0 -1
  349. package/dist/components/episode-diagnostic-render-observer.d.ts +0 -2
  350. package/dist/components/episode-diagnostic-render-observer.d.ts.map +0 -1
  351. package/dist/components/logo/Logo.d.ts +0 -11
  352. package/dist/components/logo/Logo.d.ts.map +0 -1
  353. package/dist/components/native-animation-controller.d.ts +0 -7
  354. package/dist/components/native-animation-controller.d.ts.map +0 -1
  355. package/dist/components/native-chat.d.ts +0 -8
  356. package/dist/components/native-chat.d.ts.map +0 -1
  357. package/dist/components/native-entrance/entrance-controller-store.d.ts +0 -34
  358. package/dist/components/native-entrance/entrance-controller-store.d.ts.map +0 -1
  359. package/dist/components/native-entrance/useEntranceController.d.ts +0 -19
  360. package/dist/components/native-entrance/useEntranceController.d.ts.map +0 -1
  361. package/dist/components/native-joining-loading-animation.d.ts +0 -9
  362. package/dist/components/native-joining-loading-animation.d.ts.map +0 -1
  363. package/dist/components/native-space-view/AppearanceSettings.d.ts +0 -2
  364. package/dist/components/native-space-view/AppearanceSettings.d.ts.map +0 -1
  365. package/dist/components/native-space-view/FeedbackSheet.d.ts +0 -12
  366. package/dist/components/native-space-view/FeedbackSheet.d.ts.map +0 -1
  367. package/dist/components/native-space-view/ParticipantActionSheet.d.ts +0 -9
  368. package/dist/components/native-space-view/ParticipantActionSheet.d.ts.map +0 -1
  369. package/dist/components/native-space-view/SettingsSheet.d.ts +0 -7
  370. package/dist/components/native-space-view/SettingsSheet.d.ts.map +0 -1
  371. package/dist/components/native-space-view/SpaceActionMenu.d.ts +0 -10
  372. package/dist/components/native-space-view/SpaceActionMenu.d.ts.map +0 -1
  373. package/dist/components/native-space-view/SpaceBottomDock.android.d.ts +0 -4
  374. package/dist/components/native-space-view/SpaceBottomDock.android.d.ts.map +0 -1
  375. package/dist/components/native-space-view/SpaceChatAttachment.d.ts +0 -8
  376. package/dist/components/native-space-view/SpaceChatAttachment.d.ts.map +0 -1
  377. package/dist/components/native-space-view/SpaceChatSheet.d.ts +0 -5
  378. package/dist/components/native-space-view/SpaceChatSheet.d.ts.map +0 -1
  379. package/dist/components/native-space-view/SpaceGrid.android.d.ts +0 -8
  380. package/dist/components/native-space-view/SpaceGrid.android.d.ts.map +0 -1
  381. package/dist/components/native-space-view/SpaceMoreSheet.d.ts +0 -7
  382. package/dist/components/native-space-view/SpaceMoreSheet.d.ts.map +0 -1
  383. package/dist/components/native-space-view/SpacePanelSheet.d.ts +0 -5
  384. package/dist/components/native-space-view/SpacePanelSheet.d.ts.map +0 -1
  385. package/dist/components/native-space-view/SpacePeopleSheet.d.ts +0 -5
  386. package/dist/components/native-space-view/SpacePeopleSheet.d.ts.map +0 -1
  387. package/dist/components/native-space-view/SpaceStage.android.d.ts +0 -29
  388. package/dist/components/native-space-view/SpaceStage.android.d.ts.map +0 -1
  389. package/dist/components/native-space-view/SpaceSurfacePrimitives.d.ts +0 -30
  390. package/dist/components/native-space-view/SpaceSurfacePrimitives.d.ts.map +0 -1
  391. package/dist/components/native-space-view/SpaceTopBar.android.d.ts +0 -11
  392. package/dist/components/native-space-view/SpaceTopBar.android.d.ts.map +0 -1
  393. package/dist/components/native-space-view/SpaceWhiteboardSurface.d.ts +0 -15
  394. package/dist/components/native-space-view/SpaceWhiteboardSurface.d.ts.map +0 -1
  395. package/dist/components/native-space-view/diagnostics.d.ts +0 -48
  396. package/dist/components/native-space-view/diagnostics.d.ts.map +0 -1
  397. package/dist/components/native-space-view/format-space-duration.d.ts +0 -2
  398. package/dist/components/native-space-view/format-space-duration.d.ts.map +0 -1
  399. package/dist/components/native-space-view/native-space-grid-keys.d.ts +0 -3
  400. package/dist/components/native-space-view/native-space-grid-keys.d.ts.map +0 -1
  401. package/dist/components/native-space-view/native-space-page-store.d.ts +0 -8
  402. package/dist/components/native-space-view/native-space-page-store.d.ts.map +0 -1
  403. package/dist/components/native-space-view/space-chat-attachments.d.ts +0 -15
  404. package/dist/components/native-space-view/space-chat-attachments.d.ts.map +0 -1
  405. package/dist/components/native-space-view/space-panel-layout.d.ts +0 -10
  406. package/dist/components/native-space-view/space-panel-layout.d.ts.map +0 -1
  407. package/dist/components/native-space-view/space-progressive-surface-helpers.d.ts +0 -16
  408. package/dist/components/native-space-view/space-progressive-surface-helpers.d.ts.map +0 -1
  409. package/dist/components/native-space-view/space-progressive-surface-types.d.ts +0 -3
  410. package/dist/components/native-space-view/space-progressive-surface-types.d.ts.map +0 -1
  411. package/dist/components/native-space-view/types.d.ts +0 -24
  412. package/dist/components/native-space-view/types.d.ts.map +0 -1
  413. package/dist/components/native-space-view/useSpaceViewController.contract.d.ts +0 -41
  414. package/dist/components/native-space-view/useSpaceViewController.contract.d.ts.map +0 -1
  415. package/dist/components/native-space-view/useSpaceViewController.d.ts +0 -156
  416. package/dist/components/native-space-view/useSpaceViewController.d.ts.map +0 -1
  417. package/dist/components/native-space-view/useSpaceViewDerived.d.ts +0 -12
  418. package/dist/components/native-space-view/useSpaceViewDerived.d.ts.map +0 -1
  419. package/dist/components/native-space-view/useSpaceViewPanels.d.ts +0 -70
  420. package/dist/components/native-space-view/useSpaceViewPanels.d.ts.map +0 -1
  421. package/dist/feedback/native-capture.d.ts +0 -9
  422. package/dist/feedback/native-capture.d.ts.map +0 -1
  423. package/dist/feedback/native-evidence.d.ts +0 -3
  424. package/dist/feedback/native-evidence.d.ts.map +0 -1
  425. package/dist/hooks/entrance-preview-store.d.ts +0 -16
  426. package/dist/hooks/entrance-preview-store.d.ts.map +0 -1
  427. package/dist/hooks/useEntrancePreview.d.ts +0 -7
  428. package/dist/hooks/useEntrancePreview.d.ts.map +0 -1
  429. package/dist/hooks/useLayout.d.ts +0 -16
  430. package/dist/hooks/useLayout.d.ts.map +0 -1
  431. package/dist/hooks/usePanels.d.ts +0 -12
  432. package/dist/hooks/usePanels.d.ts.map +0 -1
  433. package/dist/ios-pad.d.ts +0 -2
  434. package/dist/ios-pad.d.ts.map +0 -1
  435. package/dist/ios-pad.js +0 -62
  436. package/dist/ios-phone.d.ts +0 -2
  437. package/dist/ios-phone.d.ts.map +0 -1
  438. package/dist/ios-phone.js +0 -62
  439. package/dist/ios.d.ts +0 -2
  440. package/dist/ios.d.ts.map +0 -1
  441. package/dist/ios.js +0 -62
  442. package/dist/macos.d.ts +0 -2
  443. package/dist/macos.d.ts.map +0 -1
  444. package/dist/macos.js +0 -62
  445. package/dist/space-client/cloudflare-rtk-native.d.ts +0 -3
  446. package/dist/space-client/cloudflare-rtk-native.d.ts.map +0 -1
  447. package/dist/telemetry.d.ts +0 -63
  448. package/dist/telemetry.d.ts.map +0 -1
  449. package/dist/ui/appearance.d.ts +0 -246
  450. package/dist/ui/appearance.d.ts.map +0 -1
  451. package/dist/ui/appearance.js +0 -14
  452. package/dist/ui/native-appearance-context.d.ts +0 -15
  453. package/dist/ui/native-appearance-context.d.ts.map +0 -1
  454. package/dist/ui/native-theme.d.ts +0 -17
  455. package/dist/ui/native-theme.d.ts.map +0 -1
  456. package/dist/ui/native-types.d.ts +0 -38
  457. package/dist/ui/native-types.d.ts.map +0 -1
  458. package/dist/ui/participant-avatar.d.ts +0 -21
  459. package/dist/ui/participant-avatar.d.ts.map +0 -1
  460. package/dist/ui/theme-tokens.d.ts +0 -25
  461. package/dist/ui/theme-tokens.d.ts.map +0 -1
  462. package/dist/ui/theme.d.ts +0 -404
  463. package/dist/ui/theme.d.ts.map +0 -1
  464. package/dist/ui/theme.js +0 -8
  465. package/dist/utils/native-space-layout.d.ts +0 -42
  466. package/dist/utils/native-space-layout.d.ts.map +0 -1
  467. package/src/android.ts +0 -1
  468. package/src/components/Chalk.tsx +0 -363
  469. package/src/components/ChatMessageList.tsx +0 -209
  470. package/src/components/Entrance.tsx +0 -42
  471. package/src/components/EntranceView.android.tsx +0 -274
  472. package/src/components/EntranceView.ios-pad.tsx +0 -326
  473. package/src/components/EntranceView.ios-phone.tsx +0 -271
  474. package/src/components/EntranceView.macos.tsx +0 -278
  475. package/src/components/EntranceView.tsx +0 -38
  476. package/src/components/FaceAvatar.tsx +0 -120
  477. package/src/components/GradientSurface.tsx +0 -23
  478. package/src/components/MediaView.tsx +0 -76
  479. package/src/components/ReactionPicker.tsx +0 -98
  480. package/src/components/SpaceView.android.tsx +0 -1
  481. package/src/components/SpaceView.ios-pad.tsx +0 -1
  482. package/src/components/SpaceView.ios-phone.tsx +0 -1
  483. package/src/components/SpaceView.macos.tsx +0 -1
  484. package/src/components/SpaceView.shared.tsx +0 -98
  485. package/src/components/SpaceView.tsx +0 -54
  486. package/src/components/episode-diagnostic-render-observer.ts +0 -12
  487. package/src/components/logo/Logo.tsx +0 -309
  488. package/src/components/native-animation-controller.ts +0 -36
  489. package/src/components/native-chat.ts +0 -23
  490. package/src/components/native-entrance/entrance-controller-store.ts +0 -112
  491. package/src/components/native-entrance/useEntranceController.ts +0 -60
  492. package/src/components/native-joining-loading-animation.ts +0 -26
  493. package/src/components/native-space-view/AppearanceSettings.tsx +0 -114
  494. package/src/components/native-space-view/FeedbackSheet.tsx +0 -296
  495. package/src/components/native-space-view/ParticipantActionSheet.tsx +0 -99
  496. package/src/components/native-space-view/SettingsSheet.tsx +0 -164
  497. package/src/components/native-space-view/SpaceActionMenu.tsx +0 -109
  498. package/src/components/native-space-view/SpaceBottomDock.android.tsx +0 -115
  499. package/src/components/native-space-view/SpaceChatAttachment.tsx +0 -105
  500. package/src/components/native-space-view/SpaceChatSheet.tsx +0 -184
  501. package/src/components/native-space-view/SpaceGrid.android.tsx +0 -323
  502. package/src/components/native-space-view/SpaceMoreSheet.tsx +0 -190
  503. package/src/components/native-space-view/SpacePanelSheet.tsx +0 -45
  504. package/src/components/native-space-view/SpacePeopleSheet.tsx +0 -116
  505. package/src/components/native-space-view/SpaceStage.android.tsx +0 -372
  506. package/src/components/native-space-view/SpaceSurfacePrimitives.tsx +0 -75
  507. package/src/components/native-space-view/SpaceTopBar.android.tsx +0 -113
  508. package/src/components/native-space-view/SpaceWhiteboardSurface.tsx +0 -69
  509. package/src/components/native-space-view/diagnostics.ts +0 -84
  510. package/src/components/native-space-view/format-space-duration.ts +0 -3
  511. package/src/components/native-space-view/native-space-grid-keys.ts +0 -6
  512. package/src/components/native-space-view/native-space-page-store.ts +0 -41
  513. package/src/components/native-space-view/space-chat-attachments.test.ts +0 -26
  514. package/src/components/native-space-view/space-chat-attachments.ts +0 -37
  515. package/src/components/native-space-view/space-panel-layout.ts +0 -10
  516. package/src/components/native-space-view/space-progressive-surface-helpers.ts +0 -33
  517. package/src/components/native-space-view/space-progressive-surface-types.ts +0 -3
  518. package/src/components/native-space-view/types.ts +0 -25
  519. package/src/components/native-space-view/useSpaceViewController.contract.ts +0 -34
  520. package/src/components/native-space-view/useSpaceViewController.ts +0 -416
  521. package/src/components/native-space-view/useSpaceViewDerived.ts +0 -29
  522. package/src/components/native-space-view/useSpaceViewPanels.ts +0 -170
  523. package/src/feedback/native-capture.ts +0 -62
  524. package/src/feedback/native-evidence.ts +0 -37
  525. package/src/hooks/entrance-preview-store.ts +0 -99
  526. package/src/hooks/useEntrancePreview.ts +0 -26
  527. package/src/hooks/useLayout.ts +0 -37
  528. package/src/hooks/usePanels.ts +0 -30
  529. package/src/ios-pad.ts +0 -1
  530. package/src/ios-phone.ts +0 -1
  531. package/src/ios.ts +0 -1
  532. package/src/macos.ts +0 -1
  533. package/src/space-client/cloudflare-rtk-native.ts +0 -104
  534. package/src/telemetry.ts +0 -234
  535. package/src/types/hugeicons-direct.d.ts +0 -4
  536. package/src/types/react-native-safe-area-context.d.ts +0 -8
  537. package/src/ui/appearance.ts +0 -808
  538. package/src/ui/native-appearance-context.tsx +0 -74
  539. package/src/ui/native-theme.tsx +0 -54
  540. package/src/ui/native-types.ts +0 -40
  541. package/src/ui/participant-avatar.ts +0 -47
  542. package/src/ui/theme-tokens.ts +0 -41
  543. package/src/ui/theme.ts +0 -214
  544. package/src/utils/native-space-layout.ts +0 -135
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,5 @@
1
+ // Metro resolves an imported audio file to an asset id that expo-audio plays.
2
+ declare module "*.wav" {
3
+ const asset: number;
4
+ export default asset;
5
+ }
@@ -0,0 +1,50 @@
1
+ /// <reference path="./assets.d.ts" />
2
+ import { createAudioPlayer, type AudioPlayer } from "expo-audio";
3
+ import error from "./assets/error.wav";
4
+ import hand from "./assets/hand.wav";
5
+ import join from "./assets/join.wav";
6
+ import knock from "./assets/knock.wav";
7
+ import leave from "./assets/leave.wav";
8
+ import message from "./assets/message.wav";
9
+ import mute from "./assets/mute.wav";
10
+ import recording from "./assets/recording.wav";
11
+ import test from "./assets/test.wav";
12
+ import unmute from "./assets/unmute.wav";
13
+
14
+ /**
15
+ * The call's sounds, rendered offline from the mockup's WebAudio synth so they sound the same:
16
+ * two rising notes for a join, two falling for a leave, two thuds for a knock, one light tone for
17
+ * a message, two bell notes for a raised hand, a tick for mute and unmute, three notes when
18
+ * recording starts, two low notes for an error, and three rising notes for Test speaker.
19
+ */
20
+ const sources = { join, leave, knock, message, hand, mute, unmute, recording, error, test } as const;
21
+
22
+ export type SoundName = keyof typeof sources;
23
+
24
+ const players = new Map<SoundName, AudioPlayer>();
25
+
26
+ /**
27
+ * Plays one sound when `enabled` (the persisted Sounds setting); Test speaker ignores the setting.
28
+ *
29
+ * Players keep the audio session active: expo-audio otherwise deactivates the shared iOS session
30
+ * after each sound, which would cut the call's audio. This module never calls `setAudioModeAsync`,
31
+ * because on Android that resets the audio mode and turns on the speakerphone mid-call. On iOS the
32
+ * silent switch mutes these sounds only outside a call; during a call WebRTC's play-and-record
33
+ * session plays them regardless.
34
+ */
35
+ export function playSound(name: SoundName, enabled: boolean): void {
36
+ if (!enabled && name !== "test") return;
37
+ let player = players.get(name);
38
+ if (!player) {
39
+ player = createAudioPlayer(sources[name], { keepAudioSessionActive: true });
40
+ players.set(name, player);
41
+ }
42
+ void player.seekTo(0);
43
+ player.play();
44
+ }
45
+
46
+ /** Frees the players when the call view goes away. */
47
+ export function releaseSounds(): void {
48
+ for (const player of players.values()) player.remove();
49
+ players.clear();
50
+ }
@@ -1,36 +1,29 @@
1
1
  import {
2
2
  AsyncStorageV1PendingTargetStore,
3
- CloudflareRTKClient,
4
3
  CloudflareSFUClient,
5
4
  createChalkChatFileHttpTransport,
6
5
  createChalkWhiteboardV1Client,
7
- createChalkWhiteboardV1FileHttpTransport,
6
+ createChalkWhiteboardV1FileDownloadTransport,
8
7
  createCloudflareSFUHTTPTransport,
9
8
  createReactNativeSyncLifecycle,
10
9
  createReactNativeWebSocketFactory,
11
10
  createV1SyncClient,
12
- type DiagnosticObservation,
13
11
  type GetAccess,
14
- type ReactNativeWebSocket,
15
12
  type ReactNativeWebSocketConstructor,
16
13
  type ReactNativeAsyncStorage,
17
14
  } from "@q9labsai/chalk-client";
18
15
  import { createSpaceClientForPlatform, type SpaceClientPlatform } from "@q9labsai/chalk-client/effect";
19
- import type { FeedbackSource } from "@q9labsai/chalk-client";
20
16
  import type { SpaceClient } from "@q9labsai/chalk-client";
21
17
  import { RTCPeerConnection, mediaDevices } from "@cloudflare/react-native-webrtc";
22
18
  import { AppState } from "react-native";
23
-
24
- import { authenticatedNativeCredential, bindNativeAuthenticatedTelemetry, createTelemetry, registerNativeJourneyContext, syncTransportCloseDiagnostic, type RtcPeerConnection, type TelemetryJourney } from "../telemetry";
25
- import { createNativeRealtimeKitClient } from "./cloudflare-rtk-native";
26
-
19
+ import { toNativeCaptureError } from "../media/native-capture-error";
20
+ import { ensureRandomUUID } from "./random-uuid";
27
21
  type PlatformDependencies = NonNullable<SpaceClientPlatform["dependencies"]>;
28
22
  type NativeMediaClient = ReturnType<NonNullable<PlatformDependencies["createMediaClient"]>>;
29
23
  type MediaFactoryInput = Parameters<NonNullable<PlatformDependencies["createMediaClient"]>>[0];
30
24
  type SyncFactoryInput = Parameters<NonNullable<PlatformDependencies["createSyncClient"]>>[0];
31
25
  type ChatFileFactoryInput = Parameters<NonNullable<PlatformDependencies["createChatFileTransport"]>>[0];
32
26
  type WhiteboardFactoryInput = Parameters<NonNullable<PlatformDependencies["createWhiteboardClient"]>>[0];
33
-
34
27
  export type NativeSpaceClientOptions = {
35
28
  readonly space: string;
36
29
  readonly getAccess: GetAccess;
@@ -41,18 +34,15 @@ export type NativeSpaceClientOptions = {
41
34
  readonly camera?: boolean;
42
35
  readonly syncStartupTimeoutMs?: number;
43
36
  readonly storage?: ReactNativeAsyncStorage;
44
- readonly telemetry?: TelemetryJourney;
45
- readonly feedbackSource?: FeedbackSource;
46
37
  };
47
-
48
38
  export function createNativeSpaceClient(options: NativeSpaceClientOptions): SpaceClient {
49
- const { storage, telemetry: journey } = options;
39
+ ensureRandomUUID();
40
+ const { storage } = options;
50
41
  const apiBaseURL = options.baseUrl ?? "https://api.chalkmeet.com";
51
42
  const syncURL = options.syncUrl ?? defaultSyncURL(apiBaseURL);
52
- const telemetry = journey ? createTelemetry(journey) : undefined;
53
- const fetch = telemetryFetch(journey);
43
+ const fetch = globalThis.fetch;
54
44
  const lifecycle = createReactNativeSyncLifecycle({ appState: AppState });
55
- const webSocket = createReactNativeWebSocketFactory(nativeWebSocketConstructor(journey));
45
+ const webSocket = createReactNativeWebSocketFactory(globalThis.WebSocket as unknown as ReactNativeWebSocketConstructor);
56
46
  const dependencies: PlatformDependencies = {
57
47
  clock: {
58
48
  now: () => Date.now(),
@@ -60,10 +50,16 @@ export function createNativeSpaceClient(options: NativeSpaceClientOptions): Spac
60
50
  clearTimeout: (handle) => globalThis.clearTimeout(handle as ReturnType<typeof globalThis.setTimeout>),
61
51
  },
62
52
  mediaDevices: {
63
- getUserMedia: async (constraints) => (await mediaDevices.getUserMedia(constraints)) as unknown as globalThis.MediaStream,
53
+ getUserMedia: async (constraints) => {
54
+ try {
55
+ return (await mediaDevices.getUserMedia(constraints)) as unknown as globalThis.MediaStream;
56
+ } catch (cause) {
57
+ throw toNativeCaptureError(cause);
58
+ }
59
+ },
64
60
  getDisplayMedia: async () => (await mediaDevices.getDisplayMedia()) as unknown as globalThis.MediaStream,
65
61
  },
66
- createMediaClient: (input) => createMediaClient(apiBaseURL, input, fetch, telemetry?.observePeerConnection, journey),
62
+ createMediaClient: (input) => createMediaClient(apiBaseURL, input, fetch),
67
63
  createSyncClient: (input) => createSyncClient(syncURL, input, lifecycle, webSocket, storage),
68
64
  createChatFileTransport: (input) => createChatFileTransport(apiBaseURL, input, fetch),
69
65
  createWhiteboardClient: options.whiteboardURL === null ? undefined : (input) => createWhiteboardClient(apiBaseURL, options.whiteboardURL ?? whiteboardURL(syncURL), input, fetch, lifecycle, webSocket),
@@ -74,88 +70,30 @@ export function createNativeSpaceClient(options: NativeSpaceClientOptions): Spac
74
70
  return () => subscription.remove();
75
71
  },
76
72
  };
77
-
78
73
  const client = createSpaceClientForPlatform(
79
74
  { space: options.space, getAccess: options.getAccess, baseUrl: apiBaseURL },
80
75
  {
81
76
  apiBaseUrl: apiBaseURL,
82
77
  syncUrl: syncURL,
83
78
  whiteboardUrl: options.whiteboardURL,
84
- telemetry: journey?.context,
85
79
  dependencies,
86
80
  fetch,
87
- syncStartupTimeoutMs: options.syncStartupTimeoutMs ?? 30_000,
81
+ syncStartupTimeoutMs: options.syncStartupTimeoutMs ?? 30000,
88
82
  initialMicrophoneEnabled: options.microphone,
89
83
  initialCameraEnabled: options.camera,
90
- onConnectionDiagnostic: (event) => journey?.recordDiagnostic(connectionDiagnostic(event)),
91
- ...(journey ? { recordReconnect: (observation) => journey.recordDiagnostic(observation) } : {}),
92
- feedbackSource: options.feedbackSource ?? "embedded",
93
84
  },
94
85
  );
95
- bindNativeAuthenticatedTelemetry(client, journey);
96
- registerNativeJourneyContext(client, journey, telemetry);
97
86
  return client;
98
87
  }
99
-
100
- type PlatformDiagnostic = Parameters<NonNullable<SpaceClientPlatform["onConnectionDiagnostic"]>>[0];
101
-
102
- function connectionDiagnostic(event: PlatformDiagnostic): DiagnosticObservation {
103
- if (event.event === "space_join_span" && event.step && event.spanId && event.outcome) {
104
- return {
105
- category: "connection",
106
- code: `space.join.${event.step}.${event.outcome}`,
107
- phase: joinTracePhase(event.step),
108
- state: event.outcome === "succeeded" ? "succeeded" : event.outcome === "failed" ? "failed" : "observed",
109
- ...(event.durationMs === undefined ? {} : { metricValue: event.durationMs }),
110
- attributes: {
111
- span_id: event.spanId,
112
- ...(event.parentSpanId ? { parent_span_id: event.parentSpanId } : {}),
113
- step: event.step,
114
- outcome: event.outcome,
115
- epoch: event.epoch,
116
- ...(event.code ? { failure_code: event.code } : {}),
117
- },
118
- };
119
- }
120
- return {
121
- category: "connection",
122
- code: event.event,
123
- phase: event.state === "joining" ? "signaling" : event.state === "leaving" || event.state === "left" ? "terminal" : "recovery",
124
- state: event.event.endsWith("_failed") || event.event.endsWith("_exhausted") ? "failed" : "observed",
125
- };
126
- }
127
-
128
- function joinTracePhase(step: NonNullable<PlatformDiagnostic["step"]>): "authentication" | "signaling" | "media" | "recovery" {
129
- switch (step) {
130
- case "acquire_initial_media":
131
- case "create_media_client":
132
- case "start_media":
133
- return "media";
134
- default:
135
- return "signaling";
136
- }
137
- }
138
-
139
- function createMediaClient(apiBaseURL: string, input: MediaFactoryInput, fetch: typeof globalThis.fetch, observePeerConnection: ((peerConnection: RtcPeerConnection) => () => void) | undefined, journey: TelemetryJourney | undefined): NativeMediaClient {
88
+ function createMediaClient(apiBaseURL: string, input: MediaFactoryInput, fetch: typeof globalThis.fetch): NativeMediaClient {
140
89
  const { subject } = input.access;
141
- if (input.access.media.provider === "cloudflare_rtk") {
142
- const client = new CloudflareRTKClient({
143
- authToken: input.access.media.clientPayload.token,
144
- participantId: subject.participantId,
145
- clientFactory: createNativeRealtimeKitClient,
146
- onError: input.onFailure,
147
- onScreenEnded: input.onScreenEnded,
148
- });
149
- return createRTKConnectionMediaClient(client);
150
- }
151
90
  const replaceMediaConnection = input.replaceMediaConnection;
152
91
  const client = new CloudflareSFUClient({
153
92
  bootstrap: input.access.media.clientPayload,
154
93
  participantId: subject.participantId,
155
94
  transport: createCloudflareSFUHTTPTransport({
156
95
  apiBaseURL,
157
- telemetry: input.telemetry,
158
- credential: () => authenticatedNativeCredential(input.credential, journey),
96
+ credential: input.credential,
159
97
  tenantId: subject.tenantId,
160
98
  spaceId: subject.spaceId,
161
99
  episodeId: subject.episodeId,
@@ -171,34 +109,13 @@ function createMediaClient(apiBaseURL: string, input: MediaFactoryInput, fetch:
171
109
  : undefined,
172
110
  peerConnectionFactory: (configuration) => {
173
111
  const connection = new RTCPeerConnection(configuration);
174
- observePeerConnection?.(connection as unknown as RtcPeerConnection);
175
112
  return connection as unknown as globalThis.RTCPeerConnection;
176
113
  },
177
- recordReconnect: input.recordReconnect,
178
114
  onError: input.onFailure,
179
115
  onScreenEnded: input.onScreenEnded,
180
116
  });
181
117
  return createSFUConnectionMediaClient(client);
182
118
  }
183
-
184
- function createRTKConnectionMediaClient(client: CloudflareRTKClient): NativeMediaClient {
185
- return {
186
- setLocalPublicationTarget: client.setLocalPublicationTarget.bind(client),
187
- observeLocalPublications: client.observeLocalPublications.bind(client),
188
- observeRemotePublications: client.observeRemotePublications.bind(client),
189
- start: client.start.bind(client),
190
- stop: client.stop.bind(client),
191
- restart: (input) => {
192
- if (!("provider" in input) || input.provider !== "cloudflare_rtk") throw new TypeError("The RealtimeKit adapter requires a Cloudflare RealtimeKit access grant");
193
- return client.restart(input);
194
- },
195
- prepareLocalTrack: client.prepareLocalTrack.bind(client),
196
- clearPreparedLocalTrack: client.clearPreparedLocalTrack.bind(client),
197
- getSnapshot: client.getSnapshot.bind(client),
198
- subscribe: client.subscribe.bind(client),
199
- };
200
- }
201
-
202
119
  function createSFUConnectionMediaClient(client: CloudflareSFUClient): NativeMediaClient {
203
120
  return {
204
121
  setLocalPublicationTarget: client.setLocalPublicationTarget.bind(client),
@@ -219,7 +136,6 @@ function createSFUConnectionMediaClient(client: CloudflareSFUClient): NativeMedi
219
136
  subscribe: client.subscribe.bind(client),
220
137
  };
221
138
  }
222
-
223
139
  function createSyncClient(syncURL: string, input: SyncFactoryInput, lifecycle: ReturnType<typeof createReactNativeSyncLifecycle>, webSocket: ReturnType<typeof createReactNativeWebSocketFactory>, storage: ReactNativeAsyncStorage | undefined) {
224
140
  const subject = input.access.subject;
225
141
  const scope = `${subject.tenantId}:${subject.episodeId}:${subject.participantId}`;
@@ -229,25 +145,16 @@ function createSyncClient(syncURL: string, input: SyncFactoryInput, lifecycle: R
229
145
  mediaPlane: input.media,
230
146
  lifecycle,
231
147
  webSocket,
232
- telemetry: input.telemetry,
233
- recordReconnect: input.recordReconnect,
234
148
  ...(storage ? { pendingStore: new AsyncStorageV1PendingTargetStore({ scope, storage }) } : {}),
235
149
  });
236
150
  }
237
-
238
151
  function createChatFileTransport(apiBaseURL: string, input: ChatFileFactoryInput, fetch: typeof globalThis.fetch) {
239
152
  return createChalkChatFileHttpTransport({ baseUrl: apiBaseURL, token: input.token, fetch });
240
153
  }
241
-
242
154
  function createWhiteboardClient(apiBaseURL: string, url: string, input: WhiteboardFactoryInput, fetch: typeof globalThis.fetch, lifecycle: ReturnType<typeof createReactNativeSyncLifecycle>, webSocket: ReturnType<typeof createReactNativeWebSocketFactory>) {
243
- let sceneId: string | null = null;
244
- const files = createChalkWhiteboardV1FileHttpTransport({
155
+ const files = createChalkWhiteboardV1FileDownloadTransport({
245
156
  baseUrl: apiBaseURL,
246
157
  token: input.token,
247
- sceneId: () => {
248
- if (sceneId === null) throw new TypeError("Whiteboard scene is not ready");
249
- return sceneId;
250
- },
251
158
  fetch,
252
159
  });
253
160
  return createChalkWhiteboardV1Client({
@@ -256,79 +163,12 @@ function createWhiteboardClient(apiBaseURL: string, url: string, input: Whiteboa
256
163
  files,
257
164
  lifecycle,
258
165
  webSocket,
166
+ onWatchdogReplacement: input.onWatchdogReplacement,
259
167
  onSummary: (summary) => {
260
- sceneId = summary.sceneId;
261
168
  input.onSummary(summary);
262
169
  },
263
170
  });
264
171
  }
265
-
266
- function telemetryFetch(journey: TelemetryJourney | undefined): typeof globalThis.fetch {
267
- if (!journey) return globalThis.fetch;
268
- return (input, init) => {
269
- const headers = new Headers(init?.headers);
270
- for (const [name, value] of Object.entries(journey.headers)) headers.set(name, value);
271
- return globalThis.fetch(input, { ...init, headers });
272
- };
273
- }
274
-
275
- function nativeWebSocketConstructor(journey: TelemetryJourney | undefined): ReactNativeWebSocketConstructor {
276
- const RuntimeWebSocket = globalThis.WebSocket as unknown as new (url: string, protocols?: string | string[], options?: { readonly headers?: Readonly<Record<string, string>> }) => ReactNativeWebSocket;
277
-
278
- return class ChalkNativeWebSocket implements ReactNativeWebSocket {
279
- onopen: ((event: unknown) => void) | null = null;
280
- onmessage: ((event: { readonly data: unknown }) => void) | null = null;
281
- onclose: ((event: { readonly code?: unknown; readonly reason?: unknown }) => void) | null = null;
282
- onerror: ((event: unknown) => void) | null = null;
283
- readonly #socket: ReactNativeWebSocket;
284
-
285
- constructor(url: string) {
286
- this.#socket = new RuntimeWebSocket(url, undefined, journey ? { headers: journey.headers } : undefined);
287
- this.#socket.onopen = (event) => this.onopen?.(event);
288
- this.#socket.onmessage = (event) => {
289
- recordSyncFrame(journey, "server_to_client", event.data);
290
- this.onmessage?.(event);
291
- };
292
- this.#socket.onclose = (event) => {
293
- recordSyncTransportClose(journey, event);
294
- this.onclose?.(event);
295
- };
296
- this.#socket.onerror = (event) => {
297
- journey?.recordDiagnostic({ category: "network", code: "sync_websocket_error", phase: "signaling", state: "failed" });
298
- this.onerror?.(event);
299
- };
300
- }
301
-
302
- send(data: string): void {
303
- recordSyncFrame(journey, "client_to_server", data);
304
- this.#socket.send(data);
305
- }
306
-
307
- close(code?: number, reason?: string): void {
308
- this.#socket.close(code, reason);
309
- }
310
- };
311
- }
312
-
313
- function recordSyncTransportClose(journey: TelemetryJourney | undefined, event: { readonly code?: unknown; readonly reason?: unknown }): void {
314
- if (!journey) return;
315
- journey.recordDiagnostic(syncTransportCloseDiagnostic(event));
316
- }
317
-
318
- function recordSyncFrame(journey: TelemetryJourney | undefined, direction: "client_to_server" | "server_to_client", data: unknown): void {
319
- if (!journey) return;
320
- let frameType = "binary";
321
- if (typeof data === "string") {
322
- try {
323
- const frame = JSON.parse(data) as { readonly type?: unknown };
324
- frameType = typeof frame.type === "string" ? frame.type : "unknown";
325
- } catch {
326
- frameType = "invalid_json";
327
- }
328
- }
329
- journey.recordSyncFrame({ direction, frameType });
330
- }
331
-
332
172
  function whiteboardURL(syncURL: string): string {
333
173
  const url = new URL(syncURL);
334
174
  url.pathname = "/v1/whiteboard";
@@ -336,7 +176,6 @@ function whiteboardURL(syncURL: string): string {
336
176
  url.hash = "";
337
177
  return url.toString();
338
178
  }
339
-
340
179
  function defaultSyncURL(apiBaseURL: string): string {
341
180
  const url = new URL(apiBaseURL);
342
181
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
@@ -0,0 +1,17 @@
1
+ import { randomUUID } from "expo-crypto";
2
+
3
+ /**
4
+ * JavaScriptCore on React Native has no Web Crypto, and the client calls `crypto.randomUUID()` for request and command keys
5
+ * and for its connection id, which must come from a secure source. Without it, Leave and media commands fail. This fills only
6
+ * what is missing with Expo's native secure generator, so runtimes with Web Crypto keep theirs.
7
+ */
8
+ export function ensureRandomUUID(): void {
9
+ const existing: Partial<Crypto> | undefined = globalThis.crypto;
10
+ if (typeof existing?.randomUUID === "function") return;
11
+ if (existing === undefined) {
12
+ Object.defineProperty(globalThis, "crypto", { configurable: true, value: { randomUUID } });
13
+ return;
14
+ }
15
+ // A partial Web Crypto, such as a getRandomValues polyfill, keeps its members and gains randomUUID.
16
+ Object.defineProperty(existing, "randomUUID", { configurable: true, value: randomUUID });
17
+ }
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import type { SpaceClientPlatform } from "@q9labsai/chalk-client/effect";
3
+ const mocks = vi.hoisted(() => ({ platform: vi.fn(), whiteboard: vi.fn() }));
4
+ vi.mock("react-native", () => ({ AppState: { currentState: "active", addEventListener: vi.fn(() => ({ remove: vi.fn() })) } }));
5
+ vi.mock("@cloudflare/react-native-webrtc", () => ({ RTCPeerConnection: vi.fn(), mediaDevices: {} }));
6
+ vi.mock("@q9labsai/chalk-client/effect", () => ({ createSpaceClientForPlatform: mocks.platform }));
7
+ vi.mock("@q9labsai/chalk-client", async (original) => ({ ...(await original<typeof import("@q9labsai/chalk-client")>()), createChalkWhiteboardV1Client: mocks.whiteboard }));
8
+ import { createNativeSpaceClient } from "./create-native-space-client";
9
+ describe("native whiteboard watchdog adapter", () => {
10
+ it("passes the shared core's replacement recorder without a journey option", () => {
11
+ createNativeSpaceClient({
12
+ space: "test",
13
+ getAccess: async () => {
14
+ throw new Error("unused");
15
+ },
16
+ });
17
+ const platform: SpaceClientPlatform | undefined = mocks.platform.mock.calls[0]?.[1];
18
+ const onWatchdogReplacement = vi.fn();
19
+ platform?.dependencies?.createWhiteboardClient?.({ token: async () => "unused", onSummary: vi.fn(), onWatchdogReplacement });
20
+ expect(mocks.whiteboard).toHaveBeenCalledOnce();
21
+ expect(mocks.whiteboard.mock.calls[0]?.[0].onWatchdogReplacement).toBe(onWatchdogReplacement);
22
+ });
23
+ });
@@ -0,0 +1,100 @@
1
+ import type { SpaceSnapshot } from "@q9labsai/chalk-client";
2
+ import { memo, useMemo, useRef } from "react";
3
+ import { Pressable, StyleSheet, View } from "react-native";
4
+ import { EmbeddedWhiteboard } from "../components/EmbeddedWhiteboard";
5
+ import { RtcVideoView } from "../components/RtcVideoView";
6
+ import { useSpaceClient } from "../context/space-client-context";
7
+ import { useDevScenario } from "../frame/dev-scenario";
8
+ import { useMeasuredRef } from "../frame/measurement";
9
+ import { Icon } from "../icons/Icon";
10
+ import { createNativeMediaStream } from "../media/native-webrtc";
11
+ import type { Frame } from "../motion/MovingFrame";
12
+ import { ChalkText } from "../primitives/ChalkText";
13
+ import { NameTag } from "../primitives/NameTag";
14
+ import { useTheme } from "../theme/theme";
15
+ import { radii } from "../theme/tokens";
16
+ import { useSpaceSelector } from "./space-selector";
17
+
18
+ export type SharedContent = { readonly kind: "screen"; readonly sharerId: string } | { readonly kind: "board" };
19
+
20
+ export type ContentTileProps = {
21
+ readonly content: SharedContent;
22
+ /** The content's box inside the tile, letterboxed to its aspect. */
23
+ readonly inner: Frame;
24
+ /** A small tile in the rows; tapping it brings the content back to the spotlight. */
25
+ readonly mini: boolean;
26
+ readonly onShowInSpotlight: () => void;
27
+ };
28
+
29
+ /** The shared screen or board as one stage tile (`.tile.content`), kept mounted while it moves. */
30
+ export const ContentTile = memo(function ContentTile({ content, inner, mini, onShowInSpotlight }: ContentTileProps): React.JSX.Element {
31
+ const { colors } = useTheme();
32
+ const tileStyle = [styles.tile, { backgroundColor: colors.tile }];
33
+ const tileRef = useMeasuredRef<View>("tile.content", tileStyle);
34
+ return (
35
+ <View ref={tileRef} style={tileStyle} testID="tile.content">
36
+ {content.kind === "screen" ? <ScreenShare inner={inner} mini={mini} onShowInSpotlight={onShowInSpotlight} sharerId={content.sharerId} /> : <Board mini={mini} onShowInSpotlight={onShowInSpotlight} />}
37
+ </View>
38
+ );
39
+ });
40
+
41
+ function ScreenShare({ sharerId, inner, mini, onShowInSpotlight }: { readonly sharerId: string; readonly inner: Frame; readonly mini: boolean; readonly onShowInSpotlight: () => void }): React.JSX.Element {
42
+ const { colors } = useTheme();
43
+ const select = useMemo(() => (snapshot: SpaceSnapshot) => snapshot.media.remote.find((media) => media.participantId === sharerId && media.source === "screen")?.track ?? null, [sharerId]);
44
+ const track = useSpaceSelector(select);
45
+ const selectName = useMemo(() => (snapshot: SpaceSnapshot) => snapshot.participants.roster.find((person) => person.participantId === sharerId)?.displayName ?? "", [sharerId]);
46
+ const sharerName = useSpaceSelector(selectName);
47
+ const slot = useDevScenario().screenSlots?.[sharerId];
48
+ const streamURL = useMemo(() => (track ? createNativeMediaStream(track).toURL() : null), [track]);
49
+ const name = `${sharerName.split(" ")[0]}’s screen`;
50
+
51
+ return (
52
+ <>
53
+ <View style={[styles.box, { left: inner.x, top: inner.y, width: inner.width, height: inner.height, backgroundColor: colors.tile }]} testID="tile.content.screen">
54
+ {slot ?? (streamURL ? <RtcVideoView objectFit="contain" streamURL={streamURL} style={StyleSheet.absoluteFill} /> : null)}
55
+ </View>
56
+ {mini ? <Pressable accessibilityLabel={`Show ${name} in spotlight`} accessibilityRole="button" onPress={onShowInSpotlight} style={StyleSheet.absoluteFill} testID="tile.content.open" /> : null}
57
+ <NameTag icon="share" name={name} testID="tile.content.name" />
58
+ </>
59
+ );
60
+ }
61
+
62
+ const selectBoard = (snapshot: SpaceSnapshot) => snapshot.whiteboard.engine.status;
63
+
64
+ /** The shared board, view-only today, through the embedded whiteboard. It loads only while a board is shared. */
65
+ function Board({ mini, onShowInSpotlight }: { readonly mini: boolean; readonly onShowInSpotlight: () => void }): React.JSX.Element {
66
+ const client = useSpaceClient();
67
+ const { colors, scheme } = useTheme();
68
+ const status = useSpaceSelector(selectBoard);
69
+ const chipStyle = [styles.viewOnly, { backgroundColor: colors.surface, borderColor: colors.lineStrong }];
70
+ const chipRef = useMeasuredRef<View>("tile.content.view-only", chipStyle);
71
+ // The transport changes when the engine resubscribes.
72
+ const transport = useMemo(() => client.whiteboard.transport(), [client, status]);
73
+ const journeyId = useRef(`board-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`).current;
74
+
75
+ return (
76
+ <>
77
+ {transport ? <EmbeddedWhiteboard canClear={false} canDraw={false} journeyId={journeyId} style={StyleSheet.absoluteFill} testID="tile.content.board" theme={scheme} transport={transport} /> : null}
78
+ {mini ? (
79
+ <>
80
+ <Pressable accessibilityLabel="Show the board in spotlight" accessibilityRole="button" onPress={onShowInSpotlight} style={StyleSheet.absoluteFill} testID="tile.content.open" />
81
+ <NameTag icon="pen" name="Board" testID="tile.content.name" />
82
+ </>
83
+ ) : (
84
+ <View accessibilityLiveRegion="polite" accessibilityRole="text" accessible ref={chipRef} style={chipStyle} testID="tile.content.view-only">
85
+ <Icon color={colors.textMuted} name="lock" size={16} />
86
+ <ChalkText tone="textSoft" variant="section">
87
+ View only
88
+ </ChalkText>
89
+ </View>
90
+ )}
91
+ </>
92
+ );
93
+ }
94
+
95
+ const styles = StyleSheet.create({
96
+ tile: { flex: 1, overflow: "hidden", borderRadius: radii.tilePhone },
97
+ box: { position: "absolute", overflow: "hidden" },
98
+ // `.vchip`: a 30 pt pill 12 pt in from the board's top-left corner, with a one-pixel ring.
99
+ viewOnly: { position: "absolute", left: 12, top: 12, height: 30, paddingHorizontal: 12, borderRadius: radii.round, borderWidth: 1, flexDirection: "row", alignItems: "center", gap: 6, zIndex: 3 },
100
+ });