@q9labsai/chalk-react-native 5.0.0 → 5.1.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 (252) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/android/build.gradle +38 -0
  3. package/android/compatibility/ModuleApiCompatibility.java +215 -0
  4. package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/ChalkAudioRouteModule.kt +5 -6
  5. package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/CommunicationDeviceListener.kt +23 -0
  6. package/dist/android/call-service.d.ts +0 -1
  7. package/dist/android/connection-service.d.ts +0 -1
  8. package/dist/avatar/FaceAvatar.d.ts +0 -1
  9. package/dist/avatar/tile-avatar-size.d.ts +0 -1
  10. package/dist/callkit/callkit.d.ts +0 -1
  11. package/dist/callkit/resolve-space-callkit-options.d.ts +0 -1
  12. package/dist/{chunk-OIBT2FNM.js → chunk-MBZRE4US.js} +2 -3
  13. package/dist/client.d.ts +0 -1
  14. package/dist/client.js +8 -5
  15. package/dist/clipboard-store.d.ts +0 -1
  16. package/dist/clipboard.d.ts +0 -1
  17. package/dist/components/EmbeddedWhiteboard.d.ts +0 -1
  18. package/dist/components/RtcVideoView.d.ts +0 -1
  19. package/dist/components/android-connection-service-controller.d.ts +0 -1
  20. package/dist/components/native-media-visibility.d.ts +0 -1
  21. package/dist/components/native-space-callkit-controller.d.ts +0 -1
  22. package/dist/components/native-space-view/screen-share-availability.d.ts +0 -1
  23. package/dist/components/rtc-video-view-availability.d.ts +0 -1
  24. package/dist/components/space-lifecycle.d.ts +0 -1
  25. package/dist/components/useAndroidCallService.d.ts +0 -1
  26. package/dist/components/useAndroidConnectionService.d.ts +0 -1
  27. package/dist/context/space-client-context.d.ts +0 -1
  28. package/dist/dev.d.ts +0 -1
  29. package/dist/diagnostics.d.ts +0 -1
  30. package/dist/dock/Dock.d.ts +0 -1
  31. package/dist/dock/LeaveMenu.d.ts +0 -1
  32. package/dist/dock/MoreSheet.d.ts +0 -1
  33. package/dist/dock/ReactionBurst.d.ts +0 -1
  34. package/dist/dock/RoutePicker.d.ts +0 -1
  35. package/dist/dock/audio-route.d.ts +0 -1
  36. package/dist/frame/CallFrame.d.ts +0 -1
  37. package/dist/frame/Chalk.d.ts +0 -1
  38. package/dist/frame/back-handler.d.ts +0 -1
  39. package/dist/frame/dev-scenario.d.ts +0 -1
  40. package/dist/frame/device-layout.d.ts +0 -1
  41. package/dist/frame/measurement.d.ts +0 -1
  42. package/dist/frame/portal.d.ts +0 -1
  43. package/dist/frame/preferences.d.ts +0 -1
  44. package/dist/frame/regions.d.ts +0 -1
  45. package/dist/haptics/haptics.d.ts +0 -1
  46. package/dist/header/CallDetailsSheet.d.ts +0 -1
  47. package/dist/header/Header.d.ts +0 -1
  48. package/dist/header/QrCode.d.ts +0 -1
  49. package/dist/hooks/external-store.d.ts +0 -1
  50. package/dist/hooks/space-hooks.d.ts +0 -1
  51. package/dist/icons/Icon.d.ts +0 -1
  52. package/dist/icons/icon-element.d.ts +0 -1
  53. package/dist/icons/icon-paths.d.ts +0 -1
  54. package/dist/index.d.ts +0 -1
  55. package/dist/index.js +45 -17
  56. package/dist/invites.d.ts +0 -1
  57. package/dist/limbo/Limbo.d.ts +0 -1
  58. package/dist/limbo/Veil.d.ts +0 -1
  59. package/dist/media/native-capture-error.d.ts +0 -1
  60. package/dist/media/native-webrtc.d.ts +0 -1
  61. package/dist/motion/MovingFrame.d.ts +0 -1
  62. package/dist/motion/motion.d.ts +0 -1
  63. package/dist/motion/presence.d.ts +0 -1
  64. package/dist/motion/press.d.ts +0 -1
  65. package/dist/platform/platform.d.ts +0 -1
  66. package/dist/primitives/BottomSheet.d.ts +0 -1
  67. package/dist/primitives/ChalkText.d.ts +0 -1
  68. package/dist/primitives/CopyButton.d.ts +0 -1
  69. package/dist/primitives/IconButton.d.ts +0 -1
  70. package/dist/primitives/Menu.d.ts +0 -1
  71. package/dist/primitives/NameTag.d.ts +0 -1
  72. package/dist/primitives/PillButton.d.ts +0 -1
  73. package/dist/primitives/SegmentedControl.d.ts +0 -1
  74. package/dist/primitives/SheetGroup.d.ts +0 -1
  75. package/dist/primitives/Switch.d.ts +0 -1
  76. package/dist/primitives/TileShell.d.ts +0 -1
  77. package/dist/primitives/announce.d.ts +0 -1
  78. package/dist/primitives/menu-placement.d.ts +0 -1
  79. package/dist/primitives/toast/Toast.d.ts +0 -1
  80. package/dist/primitives/toast/ToastStack.d.ts +0 -1
  81. package/dist/primitives/toast/toast-store.d.ts +0 -1
  82. package/dist/runtime.d.ts +0 -1
  83. package/dist/sheets/people-chat/ChatNotices.d.ts +0 -1
  84. package/dist/sheets/people-chat/ChatTab.d.ts +0 -1
  85. package/dist/sheets/people-chat/Composer.d.ts +0 -1
  86. package/dist/sheets/people-chat/PeopleChatSheet.d.ts +0 -1
  87. package/dist/sheets/people-chat/PeopleTab.d.ts +0 -1
  88. package/dist/sheets/people-chat/PhotoViewer.d.ts +0 -1
  89. package/dist/sheets/people-chat/TextField.d.ts +0 -1
  90. package/dist/sheets/people-chat/attachments.d.ts +0 -1
  91. package/dist/sheets/people-chat/chat-model.d.ts +0 -1
  92. package/dist/sheets/people-chat/people-model.d.ts +0 -1
  93. package/dist/sounds/sounds.d.ts +0 -1
  94. package/dist/space-client/create-native-space-client.d.ts +0 -1
  95. package/dist/space-client/random-uuid.d.ts +0 -1
  96. package/dist/stage/ContentTile.d.ts +0 -1
  97. package/dist/stage/ParticipantTile.d.ts +0 -1
  98. package/dist/stage/Stage.d.ts +0 -1
  99. package/dist/stage/TileSheet.d.ts +0 -1
  100. package/dist/stage/camera.d.ts +0 -1
  101. package/dist/stage/layout.d.ts +0 -1
  102. package/dist/stage/space-selector.d.ts +0 -1
  103. package/dist/stage/stage-view.d.ts +0 -1
  104. package/dist/status/CallOverlays.d.ts +1 -2
  105. package/dist/status/ChalkArrival.d.ts +0 -1
  106. package/dist/status/StatusPage.d.ts +0 -1
  107. package/dist/status/call-screen.d.ts +0 -1
  108. package/dist/theme/theme.d.ts +0 -1
  109. package/dist/theme/tokens.d.ts +0 -1
  110. package/dist/toasts/CallEventToasts.d.ts +1 -2
  111. package/dist/toasts/media-failure-copy.d.ts +2 -0
  112. package/dist/toasts/notices.d.ts +0 -1
  113. package/dist/ui/ChalkUI.d.ts +0 -1
  114. package/dist/ui.d.ts +0 -1
  115. package/dist/ui.js +1 -1
  116. package/dist/utils/build-chalk-invite-link.d.ts +0 -1
  117. package/dist/utils/ios-simulator.d.ts +0 -1
  118. package/dist/whiteboard/embedded-whiteboard-assets.d.ts +0 -1
  119. package/dist/whiteboard/embedded-whiteboard-viewport.d.ts +0 -1
  120. package/embedded/chalk-whiteboard/asset-manifest.json +2 -2
  121. package/embedded/chalk-whiteboard/renderer.js +579 -579
  122. package/package.json +8 -4
  123. package/src/components/rtc-video-view-availability.ts +1 -1
  124. package/src/dock/Dock.tsx +4 -2
  125. package/src/dock/MoreSheet.tsx +3 -2
  126. package/src/frame/CallFrame.tsx +4 -4
  127. package/src/frame/device-layout.tsx +2 -3
  128. package/src/space-client/create-native-space-client.ts +8 -5
  129. package/src/stage/TileSheet.tsx +5 -1
  130. package/src/status/CallOverlays.tsx +18 -3
  131. package/src/toasts/CallEventToasts.tsx +16 -7
  132. package/src/toasts/media-failure-copy.ts +10 -0
  133. package/dist/android/call-service.d.ts.map +0 -1
  134. package/dist/android/connection-service.d.ts.map +0 -1
  135. package/dist/avatar/FaceAvatar.d.ts.map +0 -1
  136. package/dist/avatar/tile-avatar-size.d.ts.map +0 -1
  137. package/dist/callkit/callkit.d.ts.map +0 -1
  138. package/dist/callkit/resolve-space-callkit-options.d.ts.map +0 -1
  139. package/dist/client.d.ts.map +0 -1
  140. package/dist/clipboard-store.d.ts.map +0 -1
  141. package/dist/clipboard.d.ts.map +0 -1
  142. package/dist/components/EmbeddedWhiteboard.d.ts.map +0 -1
  143. package/dist/components/RtcVideoView.d.ts.map +0 -1
  144. package/dist/components/android-connection-service-controller.d.ts.map +0 -1
  145. package/dist/components/native-media-visibility.d.ts.map +0 -1
  146. package/dist/components/native-space-callkit-controller.d.ts.map +0 -1
  147. package/dist/components/native-space-view/screen-share-availability.d.ts.map +0 -1
  148. package/dist/components/rtc-video-view-availability.d.ts.map +0 -1
  149. package/dist/components/space-lifecycle.d.ts.map +0 -1
  150. package/dist/components/useAndroidCallService.d.ts.map +0 -1
  151. package/dist/components/useAndroidConnectionService.d.ts.map +0 -1
  152. package/dist/context/space-client-context.d.ts.map +0 -1
  153. package/dist/dev.d.ts.map +0 -1
  154. package/dist/diagnostics.d.ts.map +0 -1
  155. package/dist/dock/Dock.d.ts.map +0 -1
  156. package/dist/dock/LeaveMenu.d.ts.map +0 -1
  157. package/dist/dock/MoreSheet.d.ts.map +0 -1
  158. package/dist/dock/ReactionBurst.d.ts.map +0 -1
  159. package/dist/dock/RoutePicker.d.ts.map +0 -1
  160. package/dist/dock/audio-route.d.ts.map +0 -1
  161. package/dist/frame/CallFrame.d.ts.map +0 -1
  162. package/dist/frame/Chalk.d.ts.map +0 -1
  163. package/dist/frame/back-handler.d.ts.map +0 -1
  164. package/dist/frame/dev-scenario.d.ts.map +0 -1
  165. package/dist/frame/device-layout.d.ts.map +0 -1
  166. package/dist/frame/measurement.d.ts.map +0 -1
  167. package/dist/frame/portal.d.ts.map +0 -1
  168. package/dist/frame/preferences.d.ts.map +0 -1
  169. package/dist/frame/regions.d.ts.map +0 -1
  170. package/dist/haptics/haptics.d.ts.map +0 -1
  171. package/dist/header/CallDetailsSheet.d.ts.map +0 -1
  172. package/dist/header/Header.d.ts.map +0 -1
  173. package/dist/header/QrCode.d.ts.map +0 -1
  174. package/dist/hooks/external-store.d.ts.map +0 -1
  175. package/dist/hooks/space-hooks.d.ts.map +0 -1
  176. package/dist/icons/Icon.d.ts.map +0 -1
  177. package/dist/icons/icon-element.d.ts.map +0 -1
  178. package/dist/icons/icon-paths.d.ts.map +0 -1
  179. package/dist/index.d.ts.map +0 -1
  180. package/dist/invites.d.ts.map +0 -1
  181. package/dist/limbo/Limbo.d.ts.map +0 -1
  182. package/dist/limbo/Veil.d.ts.map +0 -1
  183. package/dist/media/native-capture-error.d.ts.map +0 -1
  184. package/dist/media/native-webrtc.d.ts.map +0 -1
  185. package/dist/motion/MovingFrame.d.ts.map +0 -1
  186. package/dist/motion/motion.d.ts.map +0 -1
  187. package/dist/motion/presence.d.ts.map +0 -1
  188. package/dist/motion/press.d.ts.map +0 -1
  189. package/dist/platform/platform.d.ts.map +0 -1
  190. package/dist/primitives/BottomSheet.d.ts.map +0 -1
  191. package/dist/primitives/ChalkText.d.ts.map +0 -1
  192. package/dist/primitives/CopyButton.d.ts.map +0 -1
  193. package/dist/primitives/IconButton.d.ts.map +0 -1
  194. package/dist/primitives/Menu.d.ts.map +0 -1
  195. package/dist/primitives/NameTag.d.ts.map +0 -1
  196. package/dist/primitives/PillButton.d.ts.map +0 -1
  197. package/dist/primitives/SegmentedControl.d.ts.map +0 -1
  198. package/dist/primitives/SheetGroup.d.ts.map +0 -1
  199. package/dist/primitives/Switch.d.ts.map +0 -1
  200. package/dist/primitives/TileShell.d.ts.map +0 -1
  201. package/dist/primitives/announce.d.ts.map +0 -1
  202. package/dist/primitives/menu-placement.d.ts.map +0 -1
  203. package/dist/primitives/toast/Toast.d.ts.map +0 -1
  204. package/dist/primitives/toast/ToastStack.d.ts.map +0 -1
  205. package/dist/primitives/toast/toast-store.d.ts.map +0 -1
  206. package/dist/runtime.d.ts.map +0 -1
  207. package/dist/sheets/people-chat/ChatNotices.d.ts.map +0 -1
  208. package/dist/sheets/people-chat/ChatTab.d.ts.map +0 -1
  209. package/dist/sheets/people-chat/Composer.d.ts.map +0 -1
  210. package/dist/sheets/people-chat/PeopleChatSheet.d.ts.map +0 -1
  211. package/dist/sheets/people-chat/PeopleTab.d.ts.map +0 -1
  212. package/dist/sheets/people-chat/PhotoViewer.d.ts.map +0 -1
  213. package/dist/sheets/people-chat/TextField.d.ts.map +0 -1
  214. package/dist/sheets/people-chat/attachments.d.ts.map +0 -1
  215. package/dist/sheets/people-chat/chat-model.d.ts.map +0 -1
  216. package/dist/sheets/people-chat/people-model.d.ts.map +0 -1
  217. package/dist/sounds/sounds.d.ts.map +0 -1
  218. package/dist/space-client/create-native-space-client.d.ts.map +0 -1
  219. package/dist/space-client/random-uuid.d.ts.map +0 -1
  220. package/dist/stage/ContentTile.d.ts.map +0 -1
  221. package/dist/stage/ParticipantTile.d.ts.map +0 -1
  222. package/dist/stage/Stage.d.ts.map +0 -1
  223. package/dist/stage/TileSheet.d.ts.map +0 -1
  224. package/dist/stage/camera.d.ts.map +0 -1
  225. package/dist/stage/layout.d.ts.map +0 -1
  226. package/dist/stage/space-selector.d.ts.map +0 -1
  227. package/dist/stage/stage-view.d.ts.map +0 -1
  228. package/dist/status/CallOverlays.d.ts.map +0 -1
  229. package/dist/status/ChalkArrival.d.ts.map +0 -1
  230. package/dist/status/StatusPage.d.ts.map +0 -1
  231. package/dist/status/call-screen.d.ts.map +0 -1
  232. package/dist/theme/theme.d.ts.map +0 -1
  233. package/dist/theme/tokens.d.ts.map +0 -1
  234. package/dist/toasts/CallEventToasts.d.ts.map +0 -1
  235. package/dist/toasts/notices.d.ts.map +0 -1
  236. package/dist/ui/ChalkUI.d.ts.map +0 -1
  237. package/dist/ui.d.ts.map +0 -1
  238. package/dist/utils/build-chalk-invite-link.d.ts.map +0 -1
  239. package/dist/utils/ios-simulator.d.ts.map +0 -1
  240. package/dist/whiteboard/embedded-whiteboard-assets.d.ts.map +0 -1
  241. package/dist/whiteboard/embedded-whiteboard-viewport.d.ts.map +0 -1
  242. package/src/callkit/callkit.test.ts +0 -97
  243. package/src/components/native-space-view/screen-share-availability.test.ts +0 -16
  244. package/src/frame/regions.test.ts +0 -38
  245. package/src/media/native-capture-error.test.ts +0 -19
  246. package/src/primitives/menu-placement.test.ts +0 -50
  247. package/src/sheets/people-chat/people-chat-model.test.ts +0 -98
  248. package/src/space-client/whiteboard-watchdog.test.ts +0 -23
  249. package/src/stage/layout.test.ts +0 -77
  250. package/src/status/call-screen.test.ts +0 -42
  251. package/src/toasts/notices.test.ts +0 -92
  252. package/src/whiteboard/embedded-whiteboard-viewport.test.ts +0 -13
@@ -1,23 +0,0 @@
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
- });
@@ -1,77 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { nextStageOrder, stageLayout, type StageInput, type StageItem } from "./layout";
3
-
4
- // The D1 portrait stage from `frameRegions`. Expected frames come from the mockup's own `layout()`.
5
- const stage = { x: 8, y: 111, width: 377, height: 625 };
6
- const ids = (count: number) => Array.from({ length: count }, (_, index) => String(index));
7
- const input = (overrides: Partial<StageInput>): StageInput => ({ stage, portrait: true, layout: "spotlight", order: ids(6), spot: "1", pinned: null, content: null, ...overrides });
8
- const rounded = (item: StageItem) => [item.frame.x, item.frame.y, item.frame.width, item.frame.height].map((value) => Math.round(value * 10) / 10);
9
-
10
- describe("stageLayout", () => {
11
- it("floats you over the other person when two are in the call (P2)", () => {
12
- const [main, you] = stageLayout(input({ order: ids(2) }));
13
- expect(main).toMatchObject({ kind: "person", id: "1", frame: stage });
14
- expect(you).toMatchObject({ kind: "person", id: "0", float: true });
15
- if (you) expect(rounded(you)).toEqual([277, 123, 96, 128]);
16
- });
17
-
18
- it("puts the speaker big and everyone else in justified rows below (P3, G1)", () => {
19
- const items = stageLayout(input({}));
20
- expect(items.map((item) => (item.kind === "person" ? item.id : item.kind))).toEqual(["1", "0", "2", "3", "4", "5"]);
21
- expect(items[0]).toMatchObject({ big: true });
22
- expect(items.map(rounded)).toEqual([
23
- [8, 111, 377, 429],
24
- [8, 548, 120.3, 90],
25
- [136.3, 548, 120.3, 90],
26
- [264.7, 548, 120.3, 90],
27
- [8, 646, 184.5, 90],
28
- [200.5, 646, 184.5, 90],
29
- ]);
30
- });
31
-
32
- it("keeps a pinned person big over the speaker", () => {
33
- expect(stageLayout(input({ pinned: "4" }))[0]).toMatchObject({ kind: "person", id: "4", big: true });
34
- });
35
-
36
- it("fills the stage with 24 tiles in Grid (P4, G2)", () => {
37
- const items = stageLayout(input({ layout: "grid", order: ids(24) }));
38
- expect(items).toHaveLength(24);
39
- expect(items.every((item) => item.kind === "person" && Math.round(item.frame.width * 10) / 10 === 88.3)).toBe(true);
40
- });
41
-
42
- it("stands a phone share at full height with people beside it (C2, S4)", () => {
43
- const [share, ...rest] = stageLayout(input({ content: { kind: "screen", aspect: 9 / 16 } }));
44
- expect(share).toMatchObject({ kind: "content", mini: false });
45
- if (share) expect(rounded(share)).toEqual([8, 111, 249, 625]);
46
- expect(rest.every((item) => item.frame.x === 265 && item.frame.width === 120)).toBe(true);
47
- });
48
-
49
- it("gives a shared board the stage with one row of people and a +N tile (C3)", () => {
50
- const items = stageLayout(input({ content: { kind: "board", aspect: null } }));
51
- expect(items[0] && rounded(items[0])).toEqual([8, 111, 377, 511]);
52
- expect(items.at(-1)).toMatchObject({ kind: "more", count: 3 });
53
- });
54
-
55
- it("shows the share as a double tile in Grid", () => {
56
- const [share] = stageLayout(input({ layout: "grid", content: { kind: "screen", aspect: 16 / 9 } }));
57
- expect(share).toMatchObject({ kind: "content", mini: true });
58
- });
59
- });
60
-
61
- describe("nextStageOrder", () => {
62
- it("swaps a new speaker with the person in the spotlight, so only those two tiles move", () => {
63
- const start = nextStageOrder({ order: [], spot: null }, ["you", "a", "b", "c"], "you", null);
64
- expect(start).toEqual({ order: ["you", "a", "b", "c"], spot: "a" });
65
- expect(nextStageOrder(start, ["you", "a", "b", "c"], "you", "c")).toEqual({ order: ["you", "c", "b", "a"], spot: "c" });
66
- });
67
-
68
- it("ignores your own speech and keeps the same object when nothing changes", () => {
69
- const start = nextStageOrder({ order: [], spot: null }, ["you", "a", "b"], "you", null);
70
- expect(nextStageOrder(start, ["you", "a", "b"], "you", "you")).toBe(start);
71
- });
72
-
73
- it("drops leavers, appends newcomers and moves the spotlight off someone who left", () => {
74
- const start = { order: ["you", "a", "b"], spot: "a" };
75
- expect(nextStageOrder(start, ["you", "b", "d"], "you", null)).toEqual({ order: ["you", "b", "d"], spot: "b" });
76
- });
77
- });
@@ -1,42 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { callScreen } from "./call-screen";
3
-
4
- type ConnectionOptions = { readonly code?: "episode.ended" | "access.invalid"; readonly episodeEnded?: boolean; readonly removedByHost?: boolean };
5
-
6
- const connection = (status: Parameters<typeof callScreen>[0]["status"], { code, episodeEnded = false, removedByHost = false }: ConnectionOptions = {}) => ({
7
- status,
8
- episode: null,
9
- lastError: code ? { code, recoverable: false, message: "" } : null,
10
- episodeEnded,
11
- removedByHost,
12
- });
13
-
14
- describe("callScreen", () => {
15
- it("covers the call while it joins or reconnects", () => {
16
- expect(callScreen(connection("joining"), false)).toEqual({ kind: "joining" });
17
- expect(callScreen(connection("reconnecting"), false)).toEqual({ kind: "reconnecting" });
18
- expect(callScreen(connection("live"), false)).toEqual({ kind: "call" });
19
- });
20
-
21
- it("shows the person's own leave as left, even when the leave call failed", () => {
22
- expect(callScreen(connection("left"), true)).toEqual({ kind: "status", outcome: "left" });
23
- expect(callScreen(connection("left", { removedByHost: true }), true)).toEqual({ kind: "status", outcome: "left" });
24
- });
25
-
26
- it("shows removed only when the server reported a host removal", () => {
27
- expect(callScreen(connection("left", { removedByHost: true }), false)).toEqual({ kind: "status", outcome: "removed" });
28
- });
29
-
30
- it("shows a neutral exit for any other exit nobody asked for", () => {
31
- expect(callScreen(connection("left"), false)).toEqual({ kind: "status", outcome: "exited" });
32
- });
33
-
34
- it("shows the call ended when the Episode ends while the person is in it", () => {
35
- expect(callScreen(connection("left", { episodeEnded: true }), false)).toEqual({ kind: "status", outcome: "ended" });
36
- expect(callScreen(connection("left", { code: "episode.ended" }), false)).toEqual({ kind: "status", outcome: "ended" });
37
- });
38
-
39
- it("shows a failure as failed", () => {
40
- expect(callScreen(connection("failed", { code: "access.invalid" }), false)).toEqual({ kind: "status", outcome: "failed" });
41
- });
42
- });
@@ -1,92 +0,0 @@
1
- import type { Capability, Participant, SpaceSnapshot } from "@q9labsai/chalk-client";
2
- import { describe, expect, it } from "vitest";
3
- import { callNotices } from "./notices";
4
-
5
- const HOST: readonly Capability[] = ["endEpisode", "muteOthers"];
6
-
7
- function person(participantId: string, displayName: string, capabilities: readonly Capability[] = [], screenShare: "active" | "inactive" = "inactive"): Participant {
8
- return {
9
- participantId,
10
- displayName,
11
- role: capabilities.length ? "host" : "guest",
12
- eligibleRoles: [],
13
- capabilities,
14
- handRaised: false,
15
- media: { microphone: "inactive", camera: "inactive", screenShare },
16
- presence: { state: "connected", speaking: false, activeSpeaker: false },
17
- };
18
- }
19
-
20
- type Shape = {
21
- readonly status?: SpaceSnapshot["connection"]["status"];
22
- readonly roster?: readonly Participant[];
23
- readonly selfCapabilities?: readonly Capability[];
24
- readonly microphone?: "enabled" | "disabled";
25
- readonly requests?: SpaceSnapshot["media"]["incomingRequests"];
26
- readonly recording?: "recording" | "stopped";
27
- };
28
-
29
- function snapshot({ status = "live", roster = [], selfCapabilities = [], microphone = "disabled", requests = [], recording }: Shape): SpaceSnapshot {
30
- const local = (state: "enabled" | "disabled") => ({ source: "microphone" as const, state, track: null });
31
- return {
32
- connection: { status, episode: null, lastError: null },
33
- self: { participantId: "me", displayName: "Hasan", role: null, capabilities: selfCapabilities, handRaised: false, can: (capability) => selfCapabilities.includes(capability) },
34
- participants: { roster: [person("me", "Hasan", selfCapabilities), ...roster], admissionQueue: [] },
35
- media: {
36
- devices: { microphones: [], cameras: [], speakers: [] },
37
- selection: { microphone: null, camera: null, speaker: null },
38
- local: { microphone: local(microphone), camera: { ...local("disabled"), source: "camera" }, screen: { ...local("disabled"), source: "screen" } },
39
- remote: [],
40
- screenShare: { ...local("disabled"), source: "screen" },
41
- incomingRequests: requests,
42
- },
43
- chat: { status: "ready", messages: [], pendingSends: [], readReceipts: [], unreadCount: 0, pagination: { cursor: null, hasOlder: false, historyTruncated: false }, lastError: null },
44
- reactions: { active: [] },
45
- recording: { current: recording ? { recordingId: "r1", status: recording, failureCode: null } : null },
46
- whiteboard: { open: false, engine: { status: "unsubscribed", sceneId: null, revision: null, presenting: false, error: null } },
47
- offline: { pending: [], decisionNeeded: false, policy: "ask" },
48
- };
49
- }
50
-
51
- const nora = person("nora", "Nora Lindqvist", HOST);
52
- const sam = person("sam", "Sam Okafor");
53
-
54
- describe("callNotices", () => {
55
- it("says nothing while the roster arrives on join or empties on leave", () => {
56
- expect(callNotices(snapshot({ status: "joining" }), snapshot({ roster: [nora, sam] }), false)).toEqual([]);
57
- expect(callNotices(snapshot({ roster: [nora, sam] }), snapshot({ status: "left" }), false)).toEqual([]);
58
- });
59
-
60
- it("names people who join and leave, but never you", () => {
61
- expect(callNotices(snapshot({ roster: [nora] }), snapshot({ roster: [nora, sam] }), false)).toEqual([{ kind: "joined", name: "Sam Okafor" }]);
62
- expect(callNotices(snapshot({ roster: [nora, sam] }), snapshot({ roster: [nora] }), false)).toEqual([{ kind: "left", name: "Sam Okafor" }]);
63
- });
64
-
65
- it("tells you the host left and you're the host now, instead of a plain leave", () => {
66
- const notices = callNotices(snapshot({ roster: [nora, sam] }), snapshot({ roster: [sam], selfCapabilities: HOST }), false);
67
- expect(notices).toEqual([{ kind: "newHost", previousHost: "Nora" }]);
68
- });
69
-
70
- it("reports a host mute only when you didn't mute yourself", () => {
71
- const before = snapshot({ roster: [nora, sam], microphone: "enabled" });
72
- const after = snapshot({ roster: [nora, sam], microphone: "disabled" });
73
- expect(callNotices(before, after, false)).toEqual([{ kind: "mutedByHost", by: "Nora" }]);
74
- expect(callNotices(before, after, true)).toEqual([]);
75
- });
76
-
77
- it("reports each new request to unmute once", () => {
78
- const request = { requestId: "q1", kind: "unmute" as const, actorParticipantId: "nora", actorDisplayName: "Nora Lindqvist", expiresAt: "2026-10-18T12:00:00Z" };
79
- expect(callNotices(snapshot({ roster: [nora] }), snapshot({ roster: [nora], requests: [request] }), false)).toEqual([{ kind: "mediaRequest", request }]);
80
- expect(callNotices(snapshot({ roster: [nora], requests: [request] }), snapshot({ roster: [nora], requests: [request] }), false)).toEqual([]);
81
- });
82
-
83
- it("reports when someone else stops sharing", () => {
84
- const sharing = person("sam", "Sam Okafor", [], "active");
85
- expect(callNotices(snapshot({ roster: [sharing] }), snapshot({ roster: [sam] }), false)).toEqual([{ kind: "shareStopped", name: "Sam" }]);
86
- });
87
-
88
- it("reports recording starting and stopping", () => {
89
- expect(callNotices(snapshot({}), snapshot({ recording: "recording" }), false)).toEqual([{ kind: "recordingStarted" }]);
90
- expect(callNotices(snapshot({ recording: "recording" }), snapshot({ recording: "stopped" }), false)).toEqual([{ kind: "recordingStopped" }]);
91
- });
92
- });
@@ -1,13 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { createEmbeddedWhiteboardViewport } from "./embedded-whiteboard-viewport";
4
-
5
- describe("native embedded whiteboard viewport", () => {
6
- it("uses the measured Board rectangle rather than the device window", () => {
7
- expect(createEmbeddedWhiteboardViewport(640, 420, 2)).toEqual({ width: 640, height: 420, scale: 2 });
8
- });
9
-
10
- it("waits for a usable layout", () => {
11
- expect(createEmbeddedWhiteboardViewport(0, 420, 2)).toBeNull();
12
- });
13
- });