diff --git a/package.json b/package.json index e80b03e50e4a..61610da314f6 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@internxt/css-config": "^1.1.0", "@internxt/eslint-config-internxt": "^2.0.1", "@internxt/lib": "^1.4.1", - "@internxt/sdk": "=1.14.2", + "@internxt/sdk": "1.15.6", "@internxt/ui": "0.1.1", "@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.19/jitsi-excalidraw-0.0.19.tgz", "@jitsi/js-utils": "2.6.7", @@ -280,4 +280,4 @@ "test-grid-ff": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.firefox.conf.ts", "test-grid-ff-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.firefox.conf.ts --spec" } -} \ No newline at end of file +} diff --git a/react/features/base/connection/actions.web.ts b/react/features/base/connection/actions.web.ts index 1c9182759547..f36349c58d82 100644 --- a/react/features/base/connection/actions.web.ts +++ b/react/features/base/connection/actions.web.ts @@ -15,6 +15,17 @@ import MeetingService from "../meet/services/meeting.service"; import { _connectInternal } from "./actions.any"; import logger from './logger'; +/** + * Helper function to leave a call with proper user identification (authenticated or anonymous) + * @param {string} roomId - The room ID to leave + * @returns {Promise} + */ +async function leaveCallWithUserIdentification(roomId: string): Promise { + const user = LocalStorageManager.instance.getUser(); + const anonymousUserId = user ? undefined : LocalStorageManager.instance.getAnonymousUUID(); + return await MeetingService.instance.leaveCall(roomId, anonymousUserId ? { userId: anonymousUserId } : undefined); +} + export * from "./actions.any"; /** @@ -119,7 +130,8 @@ export function hangup(requestFeedback = false, roomId?: string, feedbackTitle?: if (!roomId) { return Promise.reject(new Error("No roomId provided to hangup")); } - MeetingService.instance.leaveCall(roomId); + + await leaveCallWithUserIdentification(roomId); return APP.conference.hangup(requestFeedback, feedbackTitle, notifyOnConferenceTermination); }; @@ -128,7 +140,7 @@ export function hangup(requestFeedback = false, roomId?: string, feedbackTitle?: export async function cleanupAndReload(roomId: string) { try{ console.log('[RELOAD_PAGE]: Leaving the call'); - await MeetingService.instance.leaveCall(roomId); + await leaveCallWithUserIdentification(roomId); console.log('[RELOAD_PAGE]: Cleaning up the conference'); await APP.conference.cleanup(); } catch (error) { diff --git a/react/features/base/meet/services/__tests__/meeting.service.test.ts b/react/features/base/meet/services/__tests__/meeting.service.test.ts index f4475b6ce290..20c5798f3d91 100644 --- a/react/features/base/meet/services/__tests__/meeting.service.test.ts +++ b/react/features/base/meet/services/__tests__/meeting.service.test.ts @@ -2,6 +2,7 @@ import { CreateCallResponse, JoinCallPayload, JoinCallResponse, + LeaveCallPayload, UsersInCallResponse, } from "@internxt/sdk/dist/meet/types"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -197,12 +198,31 @@ describe("MeetingService", () => { expect(mockedGetMeet).toHaveBeenCalledTimes(1); expect(mockedGetMeet).toHaveBeenCalledWith(); expect(mockMeetClient.leaveCall).toHaveBeenCalledTimes(1); - expect(mockMeetClient.leaveCall).toHaveBeenCalledWith(mockCallId); - expect(mockMeetClient.leaveCall.mock.calls[0].length).toBe(1); + expect(mockMeetClient.leaveCall).toHaveBeenCalledWith(mockCallId, undefined); expect(mockMeetClient.leaveCall.mock.calls[0][0]).toBe(mockCallId); + expect(mockMeetClient.leaveCall.mock.calls[0][1]).toBeUndefined(); expect(result).toEqual(mockLeaveCallResponse); }); + it("When an anonymous user leaves a call with a userId payload, then the payload is forwarded to the SDK", async () => { + const mockCallId = "call-456"; + const mockPayload: LeaveCallPayload = { userId: "anon-uuid-789" }; + + const mockMeetClient = { + leaveCall: vi.fn().mockResolvedValue(undefined), + }; + + mockedGetMeet.mockReturnValue(mockMeetClient); + + await MeetingService.instance.leaveCall(mockCallId, mockPayload); + + expect(mockedGetMeet).toHaveBeenCalledTimes(1); + expect(mockMeetClient.leaveCall).toHaveBeenCalledTimes(1); + expect(mockMeetClient.leaveCall).toHaveBeenCalledWith(mockCallId, mockPayload); + expect(mockMeetClient.leaveCall.mock.calls[0][0]).toBe(mockCallId); + expect(mockMeetClient.leaveCall.mock.calls[0][1]).toEqual(mockPayload); + }); + it("When leaving a call fails, then an error is thrown", async () => { const mockCallId = "call-123"; const mockError = new Error("Failed to leave call"); @@ -217,8 +237,7 @@ describe("MeetingService", () => { expect(mockedGetMeet).toHaveBeenCalledTimes(1); expect(mockedGetMeet).toHaveBeenCalledWith(); expect(mockMeetClient.leaveCall).toHaveBeenCalledTimes(1); - expect(mockMeetClient.leaveCall).toHaveBeenCalledWith(mockCallId); - expect(mockMeetClient.leaveCall.mock.calls[0].length).toBe(1); + expect(mockMeetClient.leaveCall).toHaveBeenCalledWith(mockCallId, undefined); expect(mockMeetClient.leaveCall.mock.calls[0][0]).toBe(mockCallId); }); }); diff --git a/react/features/base/meet/services/meeting.service.ts b/react/features/base/meet/services/meeting.service.ts index 4dd4d6257768..4e643b3e0f74 100644 --- a/react/features/base/meet/services/meeting.service.ts +++ b/react/features/base/meet/services/meeting.service.ts @@ -2,6 +2,7 @@ import { CreateCallResponse, JoinCallPayload, JoinCallResponse, + LeaveCallPayload, UsersInCallResponse, } from "@internxt/sdk/dist/meet/types"; import { SdkManager } from "./sdk-manager.service"; @@ -33,9 +34,9 @@ class MeetingService { return await meetClient.joinCall(callId, payload); }; - public leaveCall = async (callId: string): Promise => { + public leaveCall = async (callId: string, payload?: LeaveCallPayload): Promise => { const meetClient = SdkManager.instance.getMeet(); - return await meetClient.leaveCall(callId); + return await meetClient.leaveCall(callId, payload); }; /** diff --git a/yarn.lock b/yarn.lock index 73e22a2a1235..8fa6bb5ad78e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2532,14 +2532,13 @@ dependencies: uuid "^11.1.0" -"@internxt/sdk@=1.14.2": - version "1.14.2" - resolved "https://registry.yarnpkg.com/@internxt/sdk/-/sdk-1.14.2.tgz#0ed6a0d7740d60124672dc385fa9a250aa1db82c" - integrity sha512-lqCFBiiuezyU79lMuxLa5fb1OOxtWtZyrUeEpxjV67wqoIrx/dTeCKIY32Ctq288x3VkOfILdHLrJ1BqNfC7GQ== +"@internxt/sdk@1.15.6": + version "1.15.6" + resolved "https://registry.yarnpkg.com/@internxt/sdk/-/sdk-1.15.6.tgz#f895cf12b160fd23c386e6d4d007ec29e51d9158" + integrity sha512-DRGlj2XArmBNa9wM55MbR9E4scNPDer+emtrugG1MSZvP/YOSv5XOes5j/df5ZUgMyRs9G0O7hwCtjn9XvW9YA== dependencies: - axios "1.13.5" - internxt-crypto "0.0.13" - uuid "13.0.0" + axios "1.13.6" + internxt-crypto "0.0.14" "@internxt/ui@0.1.1": version "0.1.1" @@ -2990,7 +2989,7 @@ dependencies: eslint-scope "5.1.1" -"@noble/ciphers@^2.0.1": +"@noble/ciphers@^2.0.1", "@noble/ciphers@^2.1.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-2.1.1.tgz#c8c74fcda8c3d1f88797d0ecda24f9fc8b92b052" integrity sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw== @@ -6543,10 +6542,10 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" -axios@1.13.5: - version "1.13.5" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.5.tgz#5e464688fa127e11a660a2c49441c009f6567a43" - integrity sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q== +axios@1.13.6: + version "1.13.6" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.6.tgz#c3f92da917dc209a15dd29936d20d5089b6b6c98" + integrity sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ== dependencies: follow-redirects "^1.15.11" form-data "^4.0.5" @@ -10415,11 +10414,12 @@ internal-slot@^1.1.0: hasown "^2.0.2" side-channel "^1.1.0" -internxt-crypto@0.0.13: - version "0.0.13" - resolved "https://registry.yarnpkg.com/internxt-crypto/-/internxt-crypto-0.0.13.tgz#90c83828a34667ecf6938ad7c22d94c9f0d9808b" - integrity sha512-V8Epf4oFZQZwMyIt8mcw7w36M+tryQ9VcfaiKtcruNW/129bawZnPXEeoOfLvAV+9OYlY2ZAwIYP0EtOD2ec6g== +internxt-crypto@0.0.14: + version "0.0.14" + resolved "https://registry.yarnpkg.com/internxt-crypto/-/internxt-crypto-0.0.14.tgz#1290b2a70190c23d25b83483de8200d9eafae00f" + integrity sha512-gIvqgou0r86kSk6x2t6pxAh9dJiob/sQ1Y3TdGnAF4Qq2RD++4Aq1b6NY2UqfUYV4vPhWsd2BkFS71jAyVrXpA== dependencies: + "@noble/ciphers" "^2.1.1" "@noble/hashes" "^2.0.1" "@noble/post-quantum" "^0.5.2" "@scure/bip39" "^2.0.1" @@ -16182,11 +16182,6 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@13.0.0, uuid@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-13.0.0.tgz#263dc341b19b4d755eb8fe36b78d95a6b65707e8" - integrity sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w== - uuid@8.3.2, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" @@ -16197,6 +16192,11 @@ uuid@^11.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== +uuid@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-13.0.0.tgz#263dc341b19b4d755eb8fe36b78d95a6b65707e8" + integrity sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w== + uuid@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"