mediasfu-shared 1.2.1 → 1.2.3

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 (42) hide show
  1. package/CHANGELOG.md +17 -4
  2. package/README.md +145 -131
  3. package/dist/consumers/connectIps.d.ts.map +1 -1
  4. package/dist/consumers/index.cjs +1 -1
  5. package/dist/consumers/index.js +1 -1
  6. package/dist/{getParticipantMedia-DC_Nca8S.cjs → getParticipantMedia-AwwtMCTz.cjs} +4 -4
  7. package/dist/getParticipantMedia-AwwtMCTz.cjs.map +1 -0
  8. package/dist/{getParticipantMedia-Bu_aZlxe.js → getParticipantMedia-CyaOk2oD.js} +4 -4
  9. package/dist/getParticipantMedia-CyaOk2oD.js.map +1 -0
  10. package/dist/index.cjs +36 -7
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.js +37 -8
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.native.cjs +3 -3
  15. package/dist/index.native.js +3 -3
  16. package/dist/{joinLocalRoom-7ibqv7zZ.js → joinLocalRoom-Bu3gz27d.js} +2 -2
  17. package/dist/{joinLocalRoom-7ibqv7zZ.js.map → joinLocalRoom-Bu3gz27d.js.map} +1 -1
  18. package/dist/{joinLocalRoom-BJBDvTYh.cjs → joinLocalRoom-Cii5D5IG.cjs} +2 -2
  19. package/dist/{joinLocalRoom-BJBDvTYh.cjs.map → joinLocalRoom-Cii5D5IG.cjs.map} +1 -1
  20. package/dist/methods/recording/startRecording.d.ts.map +1 -1
  21. package/dist/methods/utils/headless/virtualBackground.d.ts +13 -1
  22. package/dist/methods/utils/headless/virtualBackground.d.ts.map +1 -1
  23. package/dist/methods/utils/virtualBackgroundCompositor.d.ts +4 -0
  24. package/dist/methods/utils/virtualBackgroundCompositor.d.ts.map +1 -1
  25. package/dist/sockets/SocketManager.d.ts +0 -27
  26. package/dist/sockets/SocketManager.d.ts.map +1 -1
  27. package/dist/types/index.cjs +2 -2
  28. package/dist/types/index.js +2 -2
  29. package/dist/{updateParticipantAudioDecibels-C_MygF6q.js → updateParticipantAudioDecibels-CnEXJBmc.js} +85 -13
  30. package/dist/updateParticipantAudioDecibels-CnEXJBmc.js.map +1 -0
  31. package/dist/{updateParticipantAudioDecibels-bZ6R8WHj.cjs → updateParticipantAudioDecibels-QZyahisU.cjs} +85 -13
  32. package/dist/updateParticipantAudioDecibels-QZyahisU.cjs.map +1 -0
  33. package/package.json +1 -1
  34. package/src/consumers/connectIps.ts +46 -7
  35. package/src/methods/recording/startRecording.ts +7 -1
  36. package/src/methods/utils/headless/virtualBackground.ts +34 -2
  37. package/src/methods/utils/virtualBackgroundCompositor.ts +18 -1
  38. package/src/sockets/SocketManager.ts +54 -7
  39. package/dist/getParticipantMedia-Bu_aZlxe.js.map +0 -1
  40. package/dist/getParticipantMedia-DC_Nca8S.cjs.map +0 -1
  41. package/dist/updateParticipantAudioDecibels-C_MygF6q.js.map +0 -1
  42. package/dist/updateParticipantAudioDecibels-bZ6R8WHj.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getParticipantMedia-AwwtMCTz.cjs","sources":["../src/methods/background/launchBackground.ts","../src/methods/breakoutRooms/handleStartBreakout.ts","../src/methods/breakoutRooms/handleStopBreakout.ts","../src/methods/breakoutRooms/launchBreakoutRooms.ts","../src/methods/coHost/launchCoHost.ts","../src/methods/coHostMethods/modifyCoHostSettings.ts","../src/methods/displaySettings/launchDisplaySettings.ts","../src/methods/displaySettings/modifyDisplaySettings.ts","../src/methods/exit/confirmExit.ts","../src/methods/exit/launchConfirmExit.ts","../src/methods/mediaSettings/launchMediaSettings.ts","../src/methods/menu/launchMenuModal.ts","../src/methods/message/launchMessages.ts","../src/methods/message/sendMessage.ts","../src/methods/participants/launchParticipants.ts","../src/methods/participants/messageParticipants.ts","../src/methods/participants/muteParticipants.ts","../src/methods/participants/removeParticipants.ts","../src/methods/polls/handleCreatePoll.ts","../src/methods/polls/handleEndPoll.ts","../src/methods/polls/handleVotePoll.ts","../src/methods/polls/launchPoll.ts","../src/methods/recording/checkPauseState.ts","../src/methods/recording/checkResumeState.ts","../src/methods/recording/confirmRecording.ts","../src/methods/recording/launchRecording.ts","../src/methods/recording/recordPauseTimer.ts","../src/methods/recording/recordUpdateTimer.ts","../src/methods/recording/recordResumeTimer.ts","../src/methods/recording/recordStartTimer.ts","../src/methods/recording/startRecording.ts","../src/methods/recording/stopRecording.ts","../src/methods/recording/updateRecording.ts","../src/methods/requests/launchRequests.ts","../src/methods/requests/respondToRequests.ts","../src/methods/settings/launchSettings.ts","../src/methods/stream/switchAudio.ts","../src/methods/stream/switchVideo.ts","../src/methods/stream/switchVideoAlt.ts","../src/methods/utils/getModalPosition.ts","../src/methods/waiting/launchWaiting.ts","../src/methods/waiting/respondToWaiting.ts","../src/methods/whiteboard/handleStartWhiteboard.ts","../src/methods/whiteboard/handleStopWhiteboard.ts","../src/methods/whiteboard/launchConfigureWhiteboard.ts","../src/methods/utils/headless/getRoomReadiness.ts","../src/methods/utils/headless/getMediaStreams.ts","../src/methods/utils/headless/getCurrentParams.ts","../src/methods/utils/headless/roomActions.ts","../src/methods/utils/headless/participantState.ts","../src/methods/utils/headless/mediaPermissions.ts","../src/methods/utils/headless/moderation.ts","../src/methods/utils/headless/sessionFeatures.ts","../src/methods/utils/headless/sessionExtras.ts","../src/methods/utils/headless/sessionControls.ts","../src/methods/utils/headless/playback.ts","../src/methods/utils/headless/viewerSession.ts","../src/methods/utils/headless/mediaProduction.ts","../src/methods/utils/getParticipantMedia.ts"],"sourcesContent":["export interface LaunchBackgroundOptions {\n updateIsBackgroundModalVisible: (isVisible: boolean) => void\n isBackgroundModalVisible: boolean\n}\n\nexport type LaunchBackgroundType = (options: LaunchBackgroundOptions) => void\n\n/**\n * Toggles the visibility of the background modal.\n */\nexport const launchBackground: LaunchBackgroundType = ({\n updateIsBackgroundModalVisible,\n isBackgroundModalVisible,\n}: LaunchBackgroundOptions): void => {\n updateIsBackgroundModalVisible(!isBackgroundModalVisible)\n}\n","import { Socket } from 'socket.io-client';\nimport type { ShowAlert } from '../../types/types';\n\n\n\nexport interface HandleStartBreakoutOptions {\n socket: Socket;\n localSocket?: Socket;\n breakoutRooms: Array<Array<{ name: string; breakRoom?: number | null }>>;\n newParticipantAction: string;\n roomName: string;\n breakOutRoomStarted: boolean;\n breakOutRoomEnded: boolean;\n showAlert?: ShowAlert;\n updateBreakOutRoomStarted: (started: boolean) => void;\n updateBreakOutRoomEnded: (ended: boolean) => void;\n onBreakoutRoomsClose: () => void;\n meetingDisplayType: string;\n updateMeetingDisplayType: (displayType: string) => void;\n}\n\nexport type HandleStartBreakoutType = (options: HandleStartBreakoutOptions) => void;\n\n/**\n * Handles the start of breakout rooms.\n * @function\n * @param {HandleStartBreakoutOptions} options - The options for starting breakout rooms.\n * @param {Socket} options.socket - The main socket instance.\n * @param {Socket} [options.localSocket] - The local socket instance (optional).\n * @param {Array<Array<{name: string, breakRoom: number | null}>>} options.breakoutRooms - The array of breakout rooms with participant data.\n * @param {string} options.newParticipantAction - The action to take for new participants.\n * @param {string} options.roomName - The name of the main room.\n * @param {boolean} options.breakOutRoomStarted - Whether breakout rooms have already started.\n * @param {boolean} options.breakOutRoomEnded - Whether breakout rooms have ended.\n * @param {ShowAlert} [options.showAlert] - Function to show alerts.\n * @param {Function} options.updateBreakOutRoomStarted - Function to update breakout room started state.\n * @param {Function} options.updateBreakOutRoomEnded - Function to update breakout room ended state.\n * @param {Function} options.onBreakoutRoomsClose - Function to close breakout rooms modal.\n * @param {string} options.meetingDisplayType - Current meeting display type.\n * @param {Function} options.updateMeetingDisplayType - Function to update meeting display type.\n * @returns {void}\n */\nexport const handleStartBreakout = ({\n socket,\n localSocket,\n breakoutRooms,\n newParticipantAction,\n roomName,\n breakOutRoomStarted,\n breakOutRoomEnded,\n showAlert,\n updateBreakOutRoomStarted,\n updateBreakOutRoomEnded,\n onBreakoutRoomsClose,\n meetingDisplayType,\n updateMeetingDisplayType,\n}: HandleStartBreakoutOptions): void => {\n const emitName = breakOutRoomStarted && !breakOutRoomEnded ? 'updateBreakout' : 'startBreakout';\n const filteredBreakoutRooms = breakoutRooms.map((room) =>\n room.map(({ name, breakRoom }) => ({ name, breakRoom }))\n );\n\n socket.emit(\n emitName,\n { breakoutRooms: filteredBreakoutRooms, newParticipantAction, roomName },\n (response: { success: boolean; reason: string }) => {\n if (response.success) {\n showAlert?.({ message: 'Breakout rooms active', type: 'success' });\n updateBreakOutRoomStarted(true);\n updateBreakOutRoomEnded(false);\n onBreakoutRoomsClose();\n if (meetingDisplayType !== 'all') {\n updateMeetingDisplayType('all');\n }\n } else {\n showAlert?.({ message: response.reason, type: 'danger' });\n }\n }\n );\n\n if (localSocket && localSocket.id) {\n try {\n localSocket.emit(\n emitName,\n { breakoutRooms: filteredBreakoutRooms, newParticipantAction, roomName },\n (response: { success: boolean; reason: string }) => {\n if (response.success) {\n // do nothing\n }\n }\n );\n } catch {\n console.log('Error starting local breakout rooms:');\n }\n }\n};\n","import { Socket } from 'socket.io-client';\nimport type { ShowAlert } from '../../types/types';\n\nexport interface HandleStopBreakoutOptions {\n socket: Socket;\n localSocket?: Socket;\n roomName: string;\n showAlert?: ShowAlert;\n updateBreakOutRoomStarted: (started: boolean) => void;\n updateBreakOutRoomEnded: (ended: boolean) => void;\n onBreakoutRoomsClose: () => void;\n meetingDisplayType: string;\n prevMeetingDisplayType: string;\n updateMeetingDisplayType: (displayType: string) => void;\n}\n\nexport type HandleStopBreakoutType = (options: HandleStopBreakoutOptions) => void;\n\n/**\n * Handles stopping breakout rooms.\n * @function\n * @param {HandleStopBreakoutOptions} options - The options for stopping breakout rooms.\n * @param {Socket} options.socket - The main socket instance.\n * @param {Socket} [options.localSocket] - The local socket instance (optional).\n * @param {string} options.roomName - The name of the main room.\n * @param {ShowAlert} [options.showAlert] - Function to show alerts.\n * @param {Function} options.updateBreakOutRoomStarted - Function to update breakout room started state.\n * @param {Function} options.updateBreakOutRoomEnded - Function to update breakout room ended state.\n * @param {Function} options.onBreakoutRoomsClose - Function to close breakout rooms modal.\n * @param {string} options.meetingDisplayType - Current meeting display type.\n * @param {string} options.prevMeetingDisplayType - Previous meeting display type.\n * @param {Function} options.updateMeetingDisplayType - Function to update meeting display type.\n * @returns {void}\n */\nexport const handleStopBreakout = ({\n socket,\n localSocket,\n roomName,\n showAlert,\n updateBreakOutRoomStarted,\n updateBreakOutRoomEnded,\n onBreakoutRoomsClose,\n meetingDisplayType,\n prevMeetingDisplayType,\n updateMeetingDisplayType,\n}: HandleStopBreakoutOptions): void => {\n socket.emit('stopBreakout', { roomName }, (response: { success: boolean; reason: string }) => {\n if (response.success) {\n showAlert?.({ message: 'Breakout rooms stopped', type: 'success' });\n updateBreakOutRoomStarted(false);\n updateBreakOutRoomEnded(true);\n onBreakoutRoomsClose();\n if (meetingDisplayType !== prevMeetingDisplayType) {\n updateMeetingDisplayType(prevMeetingDisplayType);\n }\n } else {\n showAlert?.({ message: response.reason, type: 'danger' });\n }\n });\n\n if (localSocket && localSocket.id) {\n try {\n localSocket.emit('stopBreakout', { roomName }, (response: { success: boolean; reason: string }) => {\n if (response.success) {\n // do nothing\n }\n });\n } catch {\n console.log('Error stopping local breakout rooms:');\n }\n }\n};\n","export interface LaunchBreakoutRoomsOptions {\n updateIsBreakoutRoomsModalVisible: (isVisible: boolean) => void\n isBreakoutRoomsModalVisible: boolean\n}\n\nexport type LaunchBreakoutRoomsType = (options: LaunchBreakoutRoomsOptions) => void\n\n/**\n * Launches the breakout rooms by toggling the visibility of the breakout rooms modal.\n *\n * @param {LaunchBreakoutRoomsOptions} options - The options object.\n * @param {Function} options.updateIsBreakoutRoomsModalVisible - Function to update the visibility state of the breakout rooms modal.\n * @param {boolean} options.isBreakoutRoomsModalVisible - Current visibility state of the breakout rooms modal.\n *\n * @example\n * ```typescript\n * const options: LaunchBreakoutRoomsOptions = {\n * updateIsBreakoutRoomsModalVisible: setModalVisible,\n * isBreakoutRoomsModalVisible: false,\n * }\n *\n * launchBreakoutRooms(options)\n * // Toggles the breakout rooms modal to visible.\n * ```\n */\nexport const launchBreakoutRooms: LaunchBreakoutRoomsType = ({\n updateIsBreakoutRoomsModalVisible,\n isBreakoutRoomsModalVisible,\n}) => {\n updateIsBreakoutRoomsModalVisible(!isBreakoutRoomsModalVisible)\n}\n","export interface LaunchCoHostOptions {\n updateIsCoHostModalVisible: (isVisible: boolean) => void\n isCoHostModalVisible: boolean\n}\n\nexport type LaunchCoHostType = (options: LaunchCoHostOptions) => void\n\n/**\n * Toggles the visibility of the co-host modal.\n *\n * @param {LaunchCoHostOptions} options - The options object.\n * @param {Function} options.updateIsCoHostModalVisible - Function to update the visibility state of the co-host modal.\n * @param {boolean} options.isCoHostModalVisible - Current visibility state of the co-host modal.\n *\n * @example\n * ```typescript\n * const options: LaunchCoHostOptions = {\n * updateIsCoHostModalVisible: setModalVisible,\n * isCoHostModalVisible: false,\n * }\n *\n * launchCoHost(options)\n * // Toggles the co-host modal to visible.\n * ```\n */\nexport const launchCoHost: LaunchCoHostType = ({ updateIsCoHostModalVisible, isCoHostModalVisible }) => {\n updateIsCoHostModalVisible(!isCoHostModalVisible)\n}\n","import type { Socket } from 'socket.io-client';\nimport type { ShowAlert, CoHostResponsibility } from '../../types/types';\n\n\nexport interface ModifyCoHostSettingsOptions {\n roomName: string;\n showAlert?: ShowAlert;\n selectedParticipant: string;\n coHost: string;\n coHostResponsibility: CoHostResponsibility[];\n updateIsCoHostModalVisible: (isVisible: boolean) => void;\n updateCoHostResponsibility: (coHostResponsibility: CoHostResponsibility[]) => void;\n updateCoHost: (coHost: string) => void;\n socket: Socket;\n}\n\nexport type ModifyCoHostSettingsType = (options: ModifyCoHostSettingsOptions) => Promise<void>;\n\n/**\n * Modifies the co-host settings for a given room.\n * @function\n * @param {ModifyCoHostSettingsOptions} options - The options for modifying co-host settings.\n * @param {string} options.roomName - The name of the room.\n * @param {ShowAlert} [options.showAlert] - Function to show an alert message.\n * @param {string} options.selectedParticipant - The participant selected to be co-host.\n * @param {string} options.coHost - The current co-host.\n * @param {CoHostResponsibility[]} options.coHostResponsibility - The responsibilities assigned to the co-host.\n * @param {Function} options.updateIsCoHostModalVisible - Function to update the visibility of the co-host modal.\n * @param {Function} options.updateCoHostResponsibility - Function to update the co-host responsibility.\n * @param {Function} options.updateCoHost - Function to update the co-host.\n * @param {Socket} options.socket - The socket instance for emitting events.\n * @returns {Promise<void>} A promise that resolves when the co-host settings have been modified.\n *\n * @example\n * ```typescript\n * const options: ModifyCoHostSettingsOptions = {\n * roomName: \"mainRoom\",\n * showAlert: (alert) => console.log(alert.message),\n * selectedParticipant: \"User123\",\n * coHost: \"No coHost\",\n * coHostResponsibility: [{ name: \"media\", value: true, dedicated: false }],\n * updateIsCoHostModalVisible: setModalVisible,\n * updateCoHostResponsibility: setCoHostResponsibility,\n * updateCoHost: setCoHost,\n * socket: socketInstance,\n * };\n *\n * modifyCoHostSettings(options);\n * // Sets User123 as the new co-host with specific responsibilities and emits the update event.\n * ```\n */\nexport const modifyCoHostSettings = async ({\n roomName,\n // showAlert,\n selectedParticipant,\n coHost,\n coHostResponsibility,\n updateIsCoHostModalVisible,\n updateCoHostResponsibility,\n updateCoHost,\n socket,\n}: ModifyCoHostSettingsOptions): Promise<void> => {\n // Check if the chat room is in demo mode\n // if (roomName.toLowerCase().startsWith('d')) {\n // showAlert?.({\n // message: 'You cannot add co-host in demo mode.',\n // type: 'danger',\n // duration: 3000,\n // });\n\n // return;\n // }\n\n let newCoHost = coHost;\n\n if (coHost !== 'No coHost' || (selectedParticipant && selectedParticipant !== 'Select a participant')) {\n if (selectedParticipant && selectedParticipant !== 'Select a participant') {\n newCoHost = selectedParticipant;\n updateCoHost(newCoHost);\n }\n\n updateCoHostResponsibility(coHostResponsibility);\n\n // Emit a socket event to update co-host information\n socket.emit('updateCoHost', {\n roomName,\n coHost: newCoHost,\n coHostResponsibility,\n });\n }\n\n // Close the co-host modal\n updateIsCoHostModalVisible(false);\n};\n","export interface LaunchDisplaySettingsOptions {\n updateIsDisplaySettingsModalVisible: (isVisible: boolean) => void\n isDisplaySettingsModalVisible: boolean\n}\n\nexport type LaunchDisplaySettingsType = (options: LaunchDisplaySettingsOptions) => void\n\n/**\n * Toggles the visibility of the display settings modal.\n *\n * @param {LaunchDisplaySettingsOptions} options - The options object.\n * @param {Function} options.updateIsDisplaySettingsModalVisible - Function to update the visibility state of the display settings modal.\n * @param {boolean} options.isDisplaySettingsModalVisible - Current visibility state of the display settings modal.\n *\n * @example\n * ```typescript\n * const options: LaunchDisplaySettingsOptions = {\n * updateIsDisplaySettingsModalVisible: setModalVisibilityFunction,\n * isDisplaySettingsModalVisible: false,\n * }\n *\n * launchDisplaySettings(options)\n * // This will open the display settings modal if it's currently closed, or close it if it's open.\n * ```\n */\nexport const launchDisplaySettings: LaunchDisplaySettingsType = ({\n updateIsDisplaySettingsModalVisible,\n isDisplaySettingsModalVisible,\n}) => {\n updateIsDisplaySettingsModalVisible(!isDisplaySettingsModalVisible)\n}\n","import type { ShowAlert, OnScreenChangesParameters, OnScreenChangesType } from '../../types/types'\n\n\nexport interface ModifyDisplaySettingsParameters extends OnScreenChangesParameters {\n showAlert?: ShowAlert\n meetingDisplayType: string\n autoWave: boolean\n forceFullDisplay: boolean\n showSubtitlesOnCards?: boolean\n meetingVideoOptimized: boolean\n islevel: string\n recordStarted: boolean\n recordResumed: boolean\n recordStopped: boolean\n recordPaused: boolean\n recordingDisplayType: 'video' | 'media' | 'all'\n recordingVideoOptimized: boolean\n prevForceFullDisplay: boolean\n prevMeetingDisplayType: string\n updateMeetingDisplayType: (displayType: string) => void\n updateAutoWave: (autoWave: boolean) => void\n updateForceFullDisplay: (forceFullDisplay: boolean) => void\n updateShowSubtitlesOnCards?: (showSubtitlesOnCards: boolean) => void\n updateMeetingVideoOptimized: (optimized: boolean) => void\n updatePrevForceFullDisplay: (forceFullDisplay: boolean) => void\n updatePrevMeetingDisplayType: (displayType: string) => void\n updateIsDisplaySettingsModalVisible: (isVisible: boolean) => void\n updateFirstAll: (firstAll: boolean) => void\n updateUpdateMainWindow: (update: boolean) => void\n breakOutRoomStarted: boolean\n breakOutRoomEnded: boolean\n\n // mediasfu functions\n onScreenChanges: OnScreenChangesType\n\n [key: string]: any\n}\n\nexport interface ModifyDisplaySettingsOptions {\n parameters: ModifyDisplaySettingsParameters\n}\n\n// Export the type definition for the function\nexport type ModifyDisplaySettingsType = (\n options: ModifyDisplaySettingsOptions\n) => Promise<void>\n\n/**\n * Modifies the display settings based on the provided parameters.\n *\n * @param {ModifyDisplaySettingsOptions} options - The options containing the parameters to modify the display settings.\n * @param {Object} options.parameters - The parameters for modifying the display settings.\n * @param {Function} options.parameters.showAlert - Function to show alert messages.\n * @param {string} options.parameters.meetingDisplayType - The current meeting display type.\n * @param {boolean} options.parameters.autoWave - Flag indicating if auto wave is enabled.\n * @param {boolean} options.parameters.forceFullDisplay - Flag indicating if full display is forced.\n * @param {boolean} options.parameters.meetingVideoOptimized - Flag indicating if the meeting video is optimized.\n * @param {string} options.parameters.islevel - The current level of the meeting.\n * @param {boolean} options.parameters.recordStarted - Flag indicating if recording has started.\n * @param {boolean} options.parameters.recordResumed - Flag indicating if recording has resumed.\n * @param {boolean} options.parameters.recordStopped - Flag indicating if recording has stopped.\n * @param {boolean} options.parameters.recordPaused - Flag indicating if recording is paused.\n * @param {string} options.parameters.recordingDisplayType - The current recording display type.\n * @param {boolean} options.parameters.recordingVideoOptimized - Flag indicating if the recording video is optimized.\n * @param {string} options.parameters.prevForceFullDisplay - The previous force full display value.\n * @param {string} options.parameters.prevMeetingDisplayType - The previous meeting display type.\n * @param {Function} options.parameters.updateMeetingDisplayType - Function to update the meeting display type.\n * @param {Function} options.parameters.updateAutoWave - Function to update the auto wave setting.\n * @param {Function} options.parameters.updateForceFullDisplay - Function to update the force full display setting.\n * @param {Function} options.parameters.updateMeetingVideoOptimized - Function to update the meeting video optimization setting.\n * @param {Function} options.parameters.updatePrevForceFullDisplay - Function to update the previous force full display setting.\n * @param {Function} options.parameters.updatePrevMeetingDisplayType - Function to update the previous meeting display type.\n * @param {Function} options.parameters.updateIsDisplaySettingsModalVisible - Function to update the visibility of the display settings modal.\n * @param {Function} options.parameters.updateFirstAll - Function to update the first all setting.\n * @param {Function} options.parameters.updateUpdateMainWindow - Function to update the main window.\n * @param {boolean} options.parameters.breakOutRoomStarted - Flag indicating if a breakout room has started.\n * @param {boolean} options.parameters.breakOutRoomEnded - Flag indicating if a breakout room has ended.\n * @param {Function} options.parameters.onScreenChanges - Function to handle screen changes.\n *\n * @example\n * ```typescript\n * const options: ModifyDisplaySettingsOptions = {\n * parameters: {\n * showAlert: showAlertFunction,\n * meetingDisplayType: \"video\",\n * autoWave: true,\n * forceFullDisplay: false,\n * meetingVideoOptimized: true,\n * islevel: \"2\",\n * recordStarted: true,\n * recordResumed: false,\n * recordStopped: false,\n * recordPaused: false,\n * recordingDisplayType: \"video\",\n * recordingVideoOptimized: true,\n * prevForceFullDisplay: false,\n * prevMeetingDisplayType: \"media\",\n * updateMeetingDisplayType: updateDisplayTypeFunction,\n * updateAutoWave: updateAutoWaveFunction,\n * updateForceFullDisplay: updateForceFullDisplayFunction,\n * updateMeetingVideoOptimized: updateVideoOptimizedFunction,\n * updatePrevForceFullDisplay: updatePrevForceFullFunction,\n * updatePrevMeetingDisplayType: updatePrevDisplayTypeFunction,\n * updateIsDisplaySettingsModalVisible: setModalVisibilityFunction,\n * updateFirstAll: setFirstAllFunction,\n * updateUpdateMainWindow: setMainWindowUpdateFunction,\n * breakOutRoomStarted: false,\n * breakOutRoomEnded: true,\n * onScreenChanges: onScreenChangesFunction\n * }\n * };\n *\n * await modifyDisplaySettings(options);\n * ```\n */\n\nexport const modifyDisplaySettings = async ({\n parameters\n}: ModifyDisplaySettingsOptions): Promise<void> => {\n // Destructure the parameters\n let {\n showAlert,\n meetingDisplayType,\n autoWave,\n forceFullDisplay,\n showSubtitlesOnCards = true,\n meetingVideoOptimized,\n islevel,\n recordStarted,\n recordResumed,\n recordStopped,\n recordPaused,\n recordingDisplayType,\n recordingVideoOptimized,\n prevForceFullDisplay,\n prevMeetingDisplayType,\n updateMeetingDisplayType,\n updateAutoWave,\n updateForceFullDisplay,\n updateShowSubtitlesOnCards,\n updateMeetingVideoOptimized,\n updatePrevForceFullDisplay,\n updatePrevMeetingDisplayType,\n updateIsDisplaySettingsModalVisible,\n updateFirstAll,\n updateUpdateMainWindow,\n breakOutRoomStarted,\n breakOutRoomEnded,\n onScreenChanges\n } = parameters\n\n // Update previous states\n updateAutoWave(autoWave)\n updateForceFullDisplay(forceFullDisplay)\n updateShowSubtitlesOnCards?.(showSubtitlesOnCards)\n\n if (\n islevel === '2' &&\n (recordStarted || recordResumed) &&\n !recordStopped &&\n !recordPaused\n ) {\n if (\n recordingDisplayType === 'video' &&\n meetingDisplayType === 'video' &&\n meetingVideoOptimized &&\n !recordingVideoOptimized\n ) {\n showAlert?.({\n message:\n 'Meeting display type can be either video, media, or all when recording display type is non-optimized video.',\n type: 'danger',\n duration: 3000\n })\n // Reset to previous values or handle as needed\n meetingDisplayType = recordingDisplayType\n updateMeetingDisplayType(meetingDisplayType)\n meetingVideoOptimized = recordingVideoOptimized\n updateMeetingVideoOptimized(meetingVideoOptimized)\n return\n } else if (\n recordingDisplayType === 'media' &&\n meetingDisplayType === 'video'\n ) {\n showAlert?.({\n message:\n 'Meeting display type can be either media or all when recording display type is media.',\n type: 'danger',\n duration: 3000\n })\n\n // Reset to previous values or handle as needed\n meetingDisplayType = recordingDisplayType\n updateMeetingDisplayType(meetingDisplayType)\n return\n } else if (\n recordingDisplayType === 'all' &&\n (meetingDisplayType === 'video' || meetingDisplayType === 'media')\n ) {\n showAlert?.({\n message:\n 'Meeting display type can be only all when recording display type is all.',\n type: 'danger',\n duration: 3000\n })\n // Reset to previous values or handle as needed\n meetingDisplayType = recordingDisplayType\n updateMeetingDisplayType(meetingDisplayType)\n return\n }\n }\n\n updateMeetingDisplayType(meetingDisplayType)\n updateMeetingVideoOptimized(meetingVideoOptimized)\n\n // Close the modal or perform additional actions\n updateIsDisplaySettingsModalVisible(false)\n\n if (\n prevMeetingDisplayType !== meetingDisplayType ||\n prevForceFullDisplay !== forceFullDisplay\n ) {\n if (\n breakOutRoomStarted &&\n !breakOutRoomEnded &&\n meetingDisplayType !== 'all'\n ) {\n showAlert?.({\n message:\n 'Breakout room is active. Display type can only be all.',\n type: 'danger'\n })\n meetingDisplayType = prevMeetingDisplayType\n updateMeetingDisplayType(prevMeetingDisplayType)\n return\n }\n\n updateFirstAll(meetingDisplayType !== 'all' ? true : false)\n updateUpdateMainWindow(true)\n await onScreenChanges({\n changed: true,\n parameters: { ...parameters, meetingDisplayType, forceFullDisplay }\n })\n updatePrevForceFullDisplay(forceFullDisplay)\n updatePrevMeetingDisplayType(meetingDisplayType)\n }\n}\n","import type { Socket } from 'socket.io-client'\n\nexport interface ConfirmExitOptions {\n socket: Socket\n localSocket?: Socket\n member: string\n roomName: string\n ban?: boolean\n /** Whether a host exit should end the room for everyone. Defaults to true. */\n endRoomOnHostExit?: boolean\n}\n\n// Export the type definition for the function\nexport type ConfirmExitType = (options: ConfirmExitOptions) => Promise<void>\n\n/**\n * Confirms the exit of a member from a room and optionally bans them.\n *\n * @param {ConfirmExitOptions} options - The options for confirming the exit.\n * @param {Socket} options.socket - The socket instance to emit the event.\n * @param {Socket} [options.localSocket] - The local socket instance to emit the event.\n * @param {string} options.member - The member who is exiting.\n * @param {string} options.roomName - The name of the room the member is exiting from.\n * @param {boolean} [options.ban=false] - Whether to ban the member from the room.\n * @param {boolean} [options.endRoomOnHostExit=true] - Whether a host exit ends the room for everyone.\n * @returns {Promise<void>} A promise that resolves when the exit is confirmed.\n *\n * @example\n * ```typescript\n * const options = {\n * socket: socketInstance,\n * localSocket: localSocketInstance,\n * member: \"JohnDoe\",\n * roomName: \"Room123\",\n * ban: false,\n * endRoomOnHostExit: false, // Let the host rejoin without ending the room.\n * };\n * await confirmExit(options);\n * ```\n */\n\nexport const confirmExit = async ({\n socket,\n localSocket,\n member,\n roomName,\n ban = false,\n endRoomOnHostExit = true\n}: ConfirmExitOptions): Promise<void> => {\n // Emit a socket event to disconnect the user from the room\n socket.emit('disconnectUser', {\n member: member,\n roomName: roomName,\n ban: ban,\n endRoomOnHostExit\n })\n\n if (localSocket && localSocket.id) {\n // Emit a local socket event to disconnect the user from the room\n localSocket.emit('disconnectUser', {\n member: member,\n roomName: roomName,\n ban: ban,\n endRoomOnHostExit\n })\n }\n}\n","export interface LaunchConfirmExitOptions {\n updateIsConfirmExitModalVisible: (isVisible: boolean) => void\n isConfirmExitModalVisible: boolean\n}\n\nexport type LaunchConfirmExitType = (options: LaunchConfirmExitOptions) => void\n\n/**\n * Toggles the visibility of the confirmation exit modal.\n *\n * @param {LaunchConfirmExitOptions} options - The options for launching the confirmation exit modal.\n * @param {Function} options.updateIsConfirmExitModalVisible - Function to update the visibility state of the confirmation exit modal.\n * @param {boolean} options.isConfirmExitModalVisible - Current visibility state of the confirmation exit modal.\n *\n * @example\n * ```typescript\n * const options = {\n * updateIsConfirmExitModalVisible: setIsConfirmExitModalVisible,\n * isConfirmExitModalVisible: false,\n * }\n * launchConfirmExit(options)\n * ```\n */\nexport const launchConfirmExit: LaunchConfirmExitType = ({\n updateIsConfirmExitModalVisible,\n isConfirmExitModalVisible,\n}) => {\n updateIsConfirmExitModalVisible(!isConfirmExitModalVisible)\n}\n","export interface LaunchMediaSettingsOptions {\n updateIsMediaSettingsModalVisible: (isVisible: boolean) => void\n isMediaSettingsModalVisible: boolean\n mediaDevices: MediaDevices\n audioInputs: MediaDeviceInfo[]\n videoInputs: MediaDeviceInfo[]\n updateAudioInputs: (inputs: MediaDeviceInfo[]) => void\n updateVideoInputs: (inputs: MediaDeviceInfo[]) => void\n}\n\nexport type LaunchMediaSettingsType = (options: LaunchMediaSettingsOptions) => Promise<void>\n\n/**\n * Launches the media settings modal and updates the available audio and video input devices.\n *\n * @param {LaunchMediaSettingsOptions} options - The options for launching media settings.\n * @param {Function} options.updateIsMediaSettingsModalVisible - Function to update the visibility state of the media settings modal.\n * @param {boolean} options.isMediaSettingsModalVisible - Current visibility state of the media settings modal.\n * @param {MediaDevices} options.mediaDevices - MediaDevices interface to enumerate media devices.\n * @param {MediaDeviceInfo[]} options.audioInputs - Array to store available audio input devices.\n * @param {MediaDeviceInfo[]} options.videoInputs - Array to store available video input devices.\n * @param {Function} options.updateAudioInputs - Function to update the available audio input devices.\n * @param {Function} options.updateVideoInputs - Function to update the available video input devices.\n * @returns {Promise<void>} A promise that resolves when the media settings have been updated.\n *\n * @example\n * ```typescript\n * launchMediaSettings({\n * updateIsMediaSettingsModalVisible: (isVisible) => console.log('Modal visible:', isVisible),\n * isMediaSettingsModalVisible: false,\n * mediaDevices: navigator.mediaDevices,\n * audioInputs: [],\n * videoInputs: [],\n * updateAudioInputs: (inputs) => console.log('Audio Inputs:', inputs),\n * updateVideoInputs: (inputs) => console.log('Video Inputs:', inputs),\n * })\n * ```\n */\nexport const launchMediaSettings: LaunchMediaSettingsType = async ({\n updateIsMediaSettingsModalVisible,\n isMediaSettingsModalVisible,\n mediaDevices,\n audioInputs,\n videoInputs,\n updateAudioInputs,\n updateVideoInputs,\n}) => {\n if (!isMediaSettingsModalVisible) {\n try {\n const devices = await mediaDevices.enumerateDevices()\n videoInputs = devices.filter((device) => device.kind === 'videoinput')\n audioInputs = devices.filter((device) => device.kind === 'audioinput')\n updateVideoInputs(videoInputs)\n updateAudioInputs(audioInputs)\n } catch (error) {\n console.log('Error getting media devices', error)\n }\n }\n\n updateIsMediaSettingsModalVisible(!isMediaSettingsModalVisible)\n}\n","export interface LaunchMenuModalOptions {\n updateIsMenuModalVisible: (isVisible: boolean) => void\n isMenuModalVisible: boolean\n}\n\nexport type LaunchMenuModalType = (options: LaunchMenuModalOptions) => void\n\n/**\n * Toggles the visibility of the menu modal.\n *\n * @param {LaunchMenuModalOptions} options - The options for launching the menu modal.\n * @param {Function} options.updateIsMenuModalVisible - Function to update the visibility state of the menu modal.\n * @param {boolean} options.isMenuModalVisible - Current visibility state of the menu modal.\n *\n * @example\n * ```typescript\n * launchMenuModal({\n * updateIsMenuModalVisible: (isVisible) => console.log(\"Menu modal visibility:\", isVisible),\n * isMenuModalVisible: false,\n * });\n * ```\n */\nexport const launchMenuModal: LaunchMenuModalType = ({\n updateIsMenuModalVisible,\n isMenuModalVisible,\n}) => {\n updateIsMenuModalVisible(!isMenuModalVisible)\n}\n","export interface LaunchMessagesOptions {\n updateIsMessagesModalVisible: (visible: boolean) => void\n isMessagesModalVisible: boolean\n}\n\nexport type LaunchMessagesType = (options: LaunchMessagesOptions) => void\n\n/**\n * Toggles the visibility state of the messages modal.\n *\n * @param {LaunchMessagesOptions} options - The options object.\n * @param {Function} options.updateIsMessagesModalVisible - Function to update the visibility state of the messages modal.\n * @param {boolean} options.isMessagesModalVisible - Current visibility state of the messages modal.\n *\n * @example\n * ```typescript\n * const options: LaunchMessagesOptions = {\n * updateIsMessagesModalVisible: setModalVisibilityFunction,\n * isMessagesModalVisible: false,\n * }\n *\n * launchMessages(options)\n * ```\n */\nexport const launchMessages: LaunchMessagesType = ({ updateIsMessagesModalVisible, isMessagesModalVisible }) => {\n updateIsMessagesModalVisible(!isMessagesModalVisible)\n}\n","import { Socket } from \"socket.io-client\";\nimport type {\n CoHostResponsibility,\n EventType,\n Message,\n ShowAlert,\n} from \"../../types/types\";\n\nexport interface SendMessageOptions {\n message: string;\n receivers: string[];\n group: boolean;\n messagesLength: number;\n member: string;\n sender: string;\n islevel: string;\n eventType?: EventType;\n showAlert?: ShowAlert;\n coHostResponsibility: CoHostResponsibility[];\n coHost: string;\n roomName: string;\n socket: Socket;\n chatSetting: string;\n}\n\n// Export the type\nexport type SendMessageType = (options: SendMessageOptions) => Promise<void>;\n\n/**\n * Sends a message to the server.\n *\n * @param {SendMessageOptions} options - The options for sending a message.\n * @param {string} options.message - The message content to be sent.\n * @param {string[]} options.receivers - The list of receivers for the message.\n * @param {boolean} options.group - Indicates if the message is for a group.\n * @param {number} options.messagesLength - The current number of messages.\n * @param {string} options.member - The member sending the message.\n * @param {string} options.sender - The sender of the message.\n * @param {string} options.islevel - The level of the sender (e.g., \"2\" for admin).\n * @param {EventType} [options.eventType] - The type of event (e.g., \"broadcast\", \"chat\", \"conference\").\n * @param {ShowAlert} [options.showAlert] - Function to show alerts to the user.\n * @param {CoHostResponsibility[]} options.coHostResponsibility - Array of co-host responsibilities.\n * @param {string} options.coHost - The co-host member name.\n * @param {string} options.roomName - The name of the room.\n * @param {Socket} options.socket - The socket instance for communication.\n * @param {string} options.chatSetting - The chat setting for the event room.\n * @returns {Promise<void>} A promise that resolves when the message is sent.\n *\n * @throws Will show an alert if the message count exceeds the limit, if the message is invalid, or if the user is not allowed to send a message.\n *\n * @example\n * ```typescript\n * await sendMessage({\n * message: \"Hello, World!\",\n * receivers: [\"user1\", \"user2\"],\n * group: true,\n * messagesLength: 50,\n * member: \"user3\",\n * sender: \"user3\",\n * islevel: \"2\",\n * eventType: \"chat\",\n * showAlert: ({ message, type }) => console.log(message, type),\n * coHostResponsibility: [{ name: \"chat\", value: true }],\n * coHost: \"coHostUser\",\n * roomName: \"mainRoom\",\n * socket: socketInstance,\n * chatSetting: \"allow\",\n * });\n * ```\n */\n\nexport const sendMessage = async ({\n message,\n receivers,\n group,\n messagesLength,\n member,\n sender,\n islevel,\n showAlert,\n coHostResponsibility,\n coHost,\n roomName,\n socket,\n chatSetting,\n}: SendMessageOptions): Promise<void> => {\n let chatValue = false;\n const normalizedReceivers = (receivers ?? []).filter(\n (receiver): receiver is string => typeof receiver === \"string\" && receiver.trim().length > 0,\n );\n\n // Check message count limit based on room type prefix\n if (\n (messagesLength > 100 && roomName.startsWith(\"d\")) ||\n (messagesLength > 500 && roomName.startsWith(\"s\")) ||\n (messagesLength > 100000 && roomName.startsWith(\"p\"))\n ) {\n showAlert?.({\n message: \"You have reached the maximum number of messages allowed.\",\n type: \"danger\",\n duration: 3000,\n });\n return;\n }\n\n // Check if message is valid\n if (!message || message === \"\") {\n showAlert?.({\n message: \"Message is not valid.\",\n type: \"danger\",\n duration: 3000,\n });\n return;\n }\n\n // Hosts need an explicit recipient. Attendees can open a direct thread to the host\n // without first replying to an existing message.\n if (normalizedReceivers.length < 1 && group === false && islevel === \"2\") {\n showAlert?.({\n message: \"Please select a message to reply to\",\n type: \"danger\",\n duration: 3000,\n });\n return;\n }\n\n // Create message object\n const messageObject: Message = {\n sender: sender ? sender : member,\n receivers: normalizedReceivers,\n message: message,\n timestamp: new Date().toLocaleTimeString(),\n group: group !== undefined && group !== null ? group : false,\n };\n\n try {\n // Check co-host responsibility for chat\n chatValue = coHostResponsibility.find((item) => item.name === \"chat\")?.value ?? false;\n } catch (error) {\n console.error(error);\n }\n\n if (islevel === \"2\" || (coHost === member && chatValue === true)) {\n // Allow sending message\n } else {\n // Check if user is allowed to send a message in the event room\n if (!chatSetting) {\n showAlert?.({\n message: \"You are not allowed to send a message in this event room\",\n type: \"danger\",\n duration: 3000,\n });\n return;\n }\n }\n\n // Send the message to the server\n socket.emit(\"sendMessage\", {\n messageObject: messageObject,\n roomName: roomName,\n });\n};\n","export interface LaunchParticipantsOptions {\n updateIsParticipantsModalVisible: (isVisible: boolean) => void\n isParticipantsModalVisible: boolean\n}\n\nexport type LaunchParticipantsType = (options: LaunchParticipantsOptions) => void\n\n/**\n * Toggles the visibility of the participants modal.\n *\n * @param {LaunchParticipantsOptions} options - The options for toggling the participants modal.\n * @param {Function} options.updateIsParticipantsModalVisible - Function to update the visibility state of the participants modal.\n * @param {boolean} options.isParticipantsModalVisible - Current visibility state of the participants modal.\n *\n * @example\n * ```typescript\n * launchParticipants({\n * updateIsParticipantsModalVisible: (isVisible) => setParticipantsModalVisible(isVisible),\n * isParticipantsModalVisible: true,\n * })\n * ```\n */\nexport const launchParticipants: LaunchParticipantsType = ({ updateIsParticipantsModalVisible, isParticipantsModalVisible }) => {\n updateIsParticipantsModalVisible(!isParticipantsModalVisible)\n}\n","import type { Participant, CoHostResponsibility, ShowAlert } from \"../../types/types\";\n\nexport interface MessageParticipantsOptions {\n coHostResponsibility?: CoHostResponsibility[];\n participant: Participant;\n member: string;\n islevel: string;\n showAlert?: ShowAlert;\n coHost: string;\n updateIsMessagesModalVisible: (isVisible: boolean) => void;\n updateDirectMessageDetails: (participant: Participant | null) => void;\n updateStartDirectMessage: (start: boolean) => void;\n}\n\n/**\n * Sends a direct message to a participant if the current member has the necessary permissions.\n *\n * @param {MessageParticipantsOptions} options - The options for messaging participants.\n * @param {CoHostResponsibility[]} options.coHostResponsibility - Array of responsibilities assigned to the co-host.\n * @param {Participant} options.participant - The participant to whom the message is to be sent.\n * @param {string} options.member - The current member attempting to send the message.\n * @param {string} options.islevel - The level of the current member.\n * @param {ShowAlert} [options.showAlert] - Function to show an alert message.\n * @param {string} options.coHost - The co-host member.\n * @param {Function} options.updateIsMessagesModalVisible - Function to update the visibility of the messages modal.\n * @param {Function} options.updateDirectMessageDetails - Function to update the details of the direct message.\n * @param {Function} options.updateStartDirectMessage - Function to start the direct message.\n *\n * @example\n * ```typescript\n * messageParticipants({\n * coHostResponsibility: [{ name: \"chat\", value: true }],\n * participant: { name: \"John Doe\", islevel: \"1\" },\n * member: \"currentMember\",\n * islevel: \"2\",\n * showAlert: (alert) => console.log(alert.message),\n * coHost: \"coHostMember\",\n * updateIsMessagesModalVisible: (isVisible) => setMessagesModalVisible(isVisible),\n * updateDirectMessageDetails: (participant) => setDirectMessageDetails(participant),\n * updateStartDirectMessage: (start) => setStartDirectMessage(start),\n * });\n * ```\n */\n\nexport const messageParticipants = ({\n coHostResponsibility = [],\n participant,\n member,\n islevel,\n showAlert,\n coHost,\n updateIsMessagesModalVisible,\n updateDirectMessageDetails,\n updateStartDirectMessage,\n}: MessageParticipantsOptions): void => {\n let chatValue = false;\n\n try {\n chatValue = coHostResponsibility.find((item) => item.name === \"chat\")?.value ?? false;\n } catch (error) {\n console.error(error);\n }\n\n if (islevel === \"2\" || (coHost === member && chatValue === true)) {\n if (participant.islevel !== \"2\") {\n updateDirectMessageDetails(participant);\n updateStartDirectMessage(true);\n updateIsMessagesModalVisible(true);\n }\n } else {\n showAlert?.({\n message: \"You are not allowed to send this message\",\n type: \"danger\",\n duration: 3000,\n });\n return;\n }\n};\n","import { Socket } from \"socket.io-client\";\nimport type { Participant, CoHostResponsibility, ShowAlert } from \"../../types/types\";\n\nexport interface MuteParticipantsOptions {\n socket: Socket;\n coHostResponsibility?: CoHostResponsibility[];\n participant: Participant;\n member: string;\n islevel: string;\n showAlert?: ShowAlert;\n coHost: string;\n roomName: string;\n}\n\n/**\n * Mutes a participant in a media session if the current member has the necessary permissions.\n *\n * @param {MuteParticipantsOptions} options - The options for muting participants.\n * @param {Socket} options.socket - The socket instance for communication.\n * @param {CoHostResponsibility[]} options.coHostResponsibility - List of co-host responsibilities.\n * @param {Participant} options.participant - The participant to be muted.\n * @param {string} options.member - The current member attempting to mute.\n * @param {string} options.islevel - The level of the current member.\n * @param {ShowAlert} [options.showAlert] - Optional function to show alerts.\n * @param {string} options.coHost - The co-host information.\n * @param {string} options.roomName - The name of the room.\n *\n * @example\n * ```typescript\n * muteParticipants({\n * socket,\n * coHostResponsibility: [{ name: \"media\", value: true }],\n * participant: { id: \"123\", name: \"John Doe\", muted: false, islevel: \"1\" },\n * member: \"currentMember\",\n * islevel: \"2\",\n * showAlert: (alert) => console.log(alert.message),\n * coHost: \"coHostMember\",\n * roomName: \"room1\",\n * });\n * ```\n */\n\nexport const muteParticipants = async ({\n socket,\n coHostResponsibility = [],\n participant,\n member,\n islevel,\n showAlert,\n coHost,\n roomName,\n}: MuteParticipantsOptions): Promise<void> => {\n let mediaValue = false;\n\n try {\n mediaValue =\n coHostResponsibility.find((item) => item.name === \"media\")?.value ?? false;\n } catch (error) {\n console.error(error);\n }\n\n if (islevel === \"2\" || (coHost === member && mediaValue)) {\n if (!participant.muted && participant.islevel !== \"2\") {\n const participantId = participant.id;\n socket.emit(\"controlMedia\", {\n participantId,\n participantName: participant.name,\n type: \"all\",\n roomName,\n });\n }\n } else {\n showAlert?.({\n message: \"You are not allowed to mute other participants\",\n type: \"danger\",\n duration: 3000,\n });\n }\n};\n","import { Socket } from 'socket.io-client';\nimport type { CoHostResponsibility, Participant, ShowAlert } from '../../types/types';\n\nexport interface RemoveParticipantsOptions {\n coHostResponsibility: CoHostResponsibility[];\n participant: Participant;\n member: string;\n islevel: string;\n showAlert?: ShowAlert;\n coHost: string;\n participants: Participant[];\n socket: Socket;\n roomName: string;\n updateParticipants: (participants: Participant[]) => void;\n}\n\n/**\n * Removes a participant from the room if the user has the necessary permissions.\n *\n * @param {RemoveParticipantsOptions} options - The options for removing a participant.\n * @param {CoHostResponsibility[]} options.coHostResponsibility - The responsibilities assigned to the co-host.\n * @param {Participant} options.participant - The participant to be removed from the room.\n * @param {string} options.member - The current member attempting to remove the participant.\n * @param {string} options.islevel - The level of the current member.\n * @param {ShowAlert} [options.showAlert] - Optional function to display an alert.\n * @param {string} options.coHost - The co-host identifier.\n * @param {Participant[]} options.participants - List of current participants.\n * @param {Socket} options.socket - The socket instance for communication.\n * @param {string} options.roomName - The name of the room.\n * @param {Function} options.updateParticipants - Function to update the participants list.\n *\n * @example\n * ```typescript\n * removeParticipants({\n * coHostResponsibility: [{ name: \"participants\", value: true }],\n * participant: { id: \"123\", name: \"John Doe\", islevel: \"1\" },\n * member: \"currentMember\",\n * islevel: \"2\",\n * showAlert: (alert) => console.log(alert.message),\n * coHost: \"coHostMember\",\n * participants: [{ id: \"123\", name: \"John Doe\", islevel: \"1\" }],\n * socket,\n * roomName: \"room1\",\n * updateParticipants: (updatedParticipants) => console.log(updatedParticipants),\n * });\n * ```\n */\n\nexport const removeParticipants = async ({\n coHostResponsibility,\n participant,\n member,\n islevel,\n showAlert,\n coHost,\n participants,\n socket,\n roomName,\n updateParticipants\n}: RemoveParticipantsOptions): Promise<void> => {\n let participantsValue = false;\n\n try {\n participantsValue =\n coHostResponsibility.find((item) => item.name === 'participants')?.value ?? false;\n } catch {\n participantsValue = false;\n }\n\n if (islevel === '2' || (coHost === member && participantsValue === true)) {\n if (participant.islevel !== '2') {\n const participantId = participant.id;\n\n // Emit a socket event to disconnect the user\n socket.emit('disconnectUserInitiate', {\n member: participant.name,\n roomName,\n id: participantId,\n });\n\n // Remove the participant from the local array\n const index = participants.findIndex((obj) => obj.name === participant.name);\n if (index !== -1) {\n participants.splice(index, 1);\n }\n\n // Update the participants array\n updateParticipants(participants);\n }\n } else {\n showAlert?.({\n message: 'You are not allowed to remove other participants',\n type: 'danger',\n duration: 3000,\n });\n }\n};\n","import { Socket } from \"socket.io-client\";\nimport type { ShowAlert } from \"../../types/types\";\n\ninterface NewPoll {\n question: string;\n type: string;\n options: string[];\n}\n\nexport interface HandleCreatePollOptions {\n poll: NewPoll;\n socket: Socket;\n roomName: string;\n showAlert?: ShowAlert;\n updateIsPollModalVisible: (visible: boolean) => void;\n}\n\n// Export the type definition for the function\nexport type HandleCreatePollType = (options: HandleCreatePollOptions) => Promise<void>;\n\n/**\n * Handles the creation of a poll by emitting a \"createPoll\" event with the provided details.\n *\n * @param {HandleCreatePollOptions} options - The options for creating the poll.\n * @param {NewPoll} options.poll - The poll object containing the poll question, type, and options.\n * @param {Socket} options.socket - The socket instance used to communicate with the server.\n * @param {string} options.roomName - The name of the room where the poll is created.\n * @param {Function} [options.showAlert] - Optional function to show alert messages.\n * @param {Function} options.updateIsPollModalVisible - Function to toggle the poll modal visibility.\n *\n * @example\n * ```typescript\n * handleCreatePoll({\n * poll: { question: \"Favorite color?\", type: \"singleChoice\", options: [\"Red\", \"Blue\", \"Green\"] },\n * socket: socketInstance,\n * roomName: \"roomA\",\n * showAlert: (message) => console.log(message),\n * updateIsPollModalVisible: (isVisible) => setIsPollModalVisible(isVisible),\n * });\n * ```\n */\n\nexport const handleCreatePoll = async ({\n poll,\n socket,\n roomName,\n showAlert,\n updateIsPollModalVisible,\n}: HandleCreatePollOptions): Promise<void> => {\n try {\n socket.emit(\n \"createPoll\",\n { roomName, poll },\n (response: { success: boolean; reason?: string }) => {\n if (response.success) {\n showAlert?.({ message: \"Poll created successfully\", type: \"success\" });\n updateIsPollModalVisible(false);\n } else {\n showAlert?.({ message: response.reason || \"Failed to create poll\", type: \"danger\" });\n }\n }\n );\n } catch (error) {\n console.error(\"Error creating poll:\", error);\n }\n};\n","import { Socket } from \"socket.io-client\";\nimport type { ShowAlert } from \"../../types/types\";\n\nexport interface HandleEndPollOptions {\n pollId: string;\n socket: Socket;\n showAlert?: ShowAlert;\n roomName: string;\n updateIsPollModalVisible: (isVisible: boolean) => void;\n}\n\n// Export the type definition for the function\nexport type HandleEndPollType = (options: HandleEndPollOptions) => Promise<void>;\n\n/**\n * Handles the end of a poll by emitting an \"endPoll\" event through the provided socket.\n * Displays an alert based on the success or failure of the operation.\n *\n * @param {HandleEndPollOptions} options - The options for ending the poll.\n * @param {string} options.pollId - The ID of the poll to end.\n * @param {Socket} options.socket - The socket instance to emit the event.\n * @param {Function} [options.showAlert] - Optional function to display alerts.\n * @param {string} options.roomName - The name of the room where the poll is being conducted.\n * @param {Function} options.updateIsPollModalVisible - Function to update the poll modal visibility.\n *\n * @example\n * ```typescript\n * handleEndPoll({\n * pollId: \"poll123\",\n * socket: socketInstance,\n * showAlert: (message) => console.log(message),\n * roomName: \"roomA\",\n * updateIsPollModalVisible: (isVisible) => setIsPollModalVisible(isVisible),\n * });\n * ```\n */\n\nexport const handleEndPoll = async ({\n pollId,\n socket,\n showAlert,\n roomName,\n updateIsPollModalVisible,\n}: HandleEndPollOptions): Promise<void> => {\n try {\n socket.emit(\n \"endPoll\",\n { roomName, poll_id: pollId },\n (response: { success: boolean; reason?: string }) => {\n if (response.success) {\n showAlert?.({\n message: \"Poll ended successfully\",\n type: \"success\",\n });\n updateIsPollModalVisible(false);\n } else {\n showAlert?.({ message: response.reason || \"Failed to end poll\", type: \"danger\" });\n }\n }\n );\n } catch (error) {\n console.error(\"Error ending poll:\", error);\n }\n};\n","import { Socket } from \"socket.io-client\";\nimport type { ShowAlert } from \"../../types/types\";\n\nexport interface HandleVotePollOptions {\n pollId: string;\n optionIndex: number;\n socket: Socket;\n showAlert?: ShowAlert;\n member: string;\n roomName: string;\n updateIsPollModalVisible: (isVisible: boolean) => void;\n}\n\n// Export the type definition for the function\nexport type HandleVotePollType = (options: HandleVotePollOptions) => Promise<void>;\n\n/**\n * Handles the voting process for a poll.\n *\n * @param {HandleVotePollOptions} options - The options for handling the vote.\n * @param {string} options.pollId - The ID of the poll.\n * @param {number} options.optionIndex - The index of the selected option.\n * @param {Socket} options.socket - The socket instance for communication.\n * @param {Function} [options.showAlert] - Optional function to show alerts.\n * @param {string} options.member - The member who is voting.\n * @param {string} options.roomName - The name of the room where the poll is conducted.\n * @param {Function} options.updateIsPollModalVisible - Function to update the visibility of the poll modal.\n *\n * @example\n * ```typescript\n * handleVotePoll({\n * pollId: \"poll123\",\n * optionIndex: 1,\n * socket: socketInstance,\n * showAlert: (message) => console.log(message),\n * member: \"user1\",\n * roomName: \"roomA\",\n * updateIsPollModalVisible: (isVisible) => setIsPollModalVisible(isVisible),\n * });\n * ```\n */\n\nexport const handleVotePoll = async ({\n pollId,\n optionIndex,\n socket,\n showAlert,\n member,\n roomName,\n updateIsPollModalVisible,\n}: HandleVotePollOptions): Promise<void> => {\n try {\n socket.emit(\n \"votePoll\",\n {\n roomName,\n poll_id: pollId,\n member,\n choice: optionIndex,\n },\n (response: { success: boolean; reason?: string }) => {\n if (response.success) {\n showAlert?.({\n message: \"Vote submitted successfully\",\n type: \"success\",\n });\n updateIsPollModalVisible(false);\n } else {\n showAlert?.({ message: response.reason || \"Failed to submit vote\", type: \"danger\" });\n }\n }\n );\n } catch (error) {\n console.error(\"Error submitting vote:\", error);\n }\n};\n","export interface LaunchPollOptions {\n updateIsPollModalVisible: (isVisible: boolean) => void\n isPollModalVisible: boolean\n}\n\nexport type LaunchPollType = (options: LaunchPollOptions) => void\n\n/**\n * Toggles the visibility of the poll modal.\n *\n * @param {LaunchPollOptions} options - The options for toggling the poll modal visibility.\n * @param {Function} options.updateIsPollModalVisible - Function to update the visibility state of the poll modal.\n * @param {boolean} options.isPollModalVisible - Current visibility state of the poll modal.\n *\n * @example\n * ```typescript\n * launchPoll({\n * updateIsPollModalVisible: (visible) => setIsPollModalVisible(visible),\n * isPollModalVisible: false,\n * })\n * ```\n */\nexport const launchPoll: LaunchPollType = ({ updateIsPollModalVisible, isPollModalVisible }) => {\n updateIsPollModalVisible(!isPollModalVisible)\n}\n","import type { ShowAlert } from '../../types/types'\n\nexport interface CheckPauseStateOptions {\n recordingMediaOptions: string\n recordingVideoPausesLimit: number\n recordingAudioPausesLimit: number\n pauseRecordCount: number\n showAlert?: ShowAlert\n}\n\nexport type CheckPauseStateType = (options: CheckPauseStateOptions) => Promise<boolean>\n\n/**\n * Checks if the recording can be paused based on the current pause count and the allowed pause limits.\n *\n * @param {Object} options - The options for checking the pause state.\n * @param {string} options.recordingMediaOptions - The type of media being recorded (\"video\" or \"audio\").\n * @param {number} options.recordingVideoPausesLimit - The maximum number of pauses allowed for video recordings.\n * @param {number} options.recordingAudioPausesLimit - The maximum number of pauses allowed for audio recordings.\n * @param {number} options.pauseRecordCount - The current count of pauses that have been made.\n * @param {Function} options.showAlert - Function to show an alert message if the pause limit is reached.\n *\n * @returns {Promise<boolean>} - Resolves to `true` if the recording can be paused, otherwise `false`.\n *\n * @example\n * ```typescript\n * const canPause = await checkPauseState({\n * recordingMediaOptions: 'audio',\n * recordingVideoPausesLimit: 3,\n * recordingAudioPausesLimit: 5,\n * pauseRecordCount: 4,\n * showAlert: ({ message }) => console.log(message),\n * })\n * ```\n */\nexport const checkPauseState: CheckPauseStateType = async ({\n recordingMediaOptions,\n recordingVideoPausesLimit,\n recordingAudioPausesLimit,\n pauseRecordCount,\n showAlert,\n}) => {\n const refLimit = recordingMediaOptions === 'video'\n ? recordingVideoPausesLimit\n : recordingAudioPausesLimit\n\n if (pauseRecordCount < refLimit) {\n return true\n }\n\n showAlert?.({\n message: 'You have reached the limit of pauses - you can choose to stop recording.',\n type: 'danger',\n duration: 3000,\n })\n return false\n}\n","export interface CheckResumeStateOptions {\n recordingMediaOptions: string\n recordingVideoPausesLimit: number\n recordingAudioPausesLimit: number\n pauseRecordCount: number\n}\n\nexport type CheckResumeStateType = (options: CheckResumeStateOptions) => Promise<boolean>\n\n/**\n * Checks if the recording can be resumed based on the media type and pause limits.\n *\n * @param {Object} options - The options for checking resume state.\n * @param {string} options.recordingMediaOptions - The type of media being recorded (\"video\" or \"audio\").\n * @param {number} options.recordingVideoPausesLimit - The maximum number of pauses allowed for video recording.\n * @param {number} options.recordingAudioPausesLimit - The maximum number of pauses allowed for audio recording.\n * @param {number} options.pauseRecordCount - The current number of pauses that have occurred.\n *\n * @returns {Promise<boolean>} - Resolves to `true` if the recording can be resumed, otherwise `false`.\n *\n * @example\n * ```typescript\n * const canResume = await checkResumeState({\n * recordingMediaOptions: 'video',\n * recordingVideoPausesLimit: 3,\n * recordingAudioPausesLimit: 5,\n * pauseRecordCount: 2,\n * })\n * ```\n */\nexport const checkResumeState: CheckResumeStateType = async ({\n recordingMediaOptions,\n recordingVideoPausesLimit,\n recordingAudioPausesLimit,\n pauseRecordCount,\n}) => {\n const refLimit = recordingMediaOptions === 'video'\n ? recordingVideoPausesLimit\n : recordingAudioPausesLimit\n\n return pauseRecordCount <= refLimit\n}\n","import type {\n ShowAlert,\n MainSpecs,\n DispSpecs,\n TextSpecs,\n EventType,\n UserRecordingParams,\n} from '../../types/types'\n\nexport interface ConfirmRecordingParameters {\n showAlert?: ShowAlert\n recordingMediaOptions: string\n recordingAudioOptions: string\n recordingVideoOptions: string\n recordingVideoType: string\n recordingDisplayType: 'video' | 'media' | 'all'\n recordingNameTags: boolean\n recordingBackgroundColor: string\n recordingNameTagsColor: string\n recordingOrientationVideo: string\n recordingAddHLS: boolean\n recordingAddText: boolean\n recordingCustomText: string\n recordingCustomTextPosition: string\n recordingCustomTextColor: string\n meetingDisplayType: string\n recordingVideoParticipantsFullRoomSupport: boolean\n recordingAllParticipantsSupport: boolean\n recordingVideoParticipantsSupport: boolean\n recordingSupportForOtherOrientation: boolean\n recordingPreferredOrientation: string\n recordingMultiFormatsSupport: boolean\n recordingVideoOptimized: boolean\n recordingAllParticipantsFullRoomSupport: boolean\n meetingVideoOptimized: boolean\n eventType: EventType\n breakOutRoomStarted: boolean\n breakOutRoomEnded: boolean\n updateRecordingDisplayType: (value: 'video' | 'media' | 'all') => void\n updateRecordingVideoOptimized: (value: boolean) => void\n updateUserRecordingParams: (params: UserRecordingParams) => void\n updateConfirmedToRecord: (value: boolean) => void\n getUpdatedAllParams: () => ConfirmRecordingParameters\n [key: string]: any\n}\n\nexport interface ConfirmRecordingOptions {\n parameters: ConfirmRecordingParameters\n}\n\nexport type ConfirmRecordingType = (options: ConfirmRecordingOptions) => Promise<void>\n\nconst ALERT_DURATION = 6000\nconst FULL_PARTICIPANT_RECORDING_ALERT_MESSAGE =\n 'You are not allowed to record videos of all participants while the meeting display is set to All. Switch the meeting display to Media and try again.'\n\n/**\n * Confirms the recording settings based on the provided parameters and updates the recording state.\n */\nexport const confirmRecording: ConfirmRecordingType = async ({\n parameters,\n}) => {\n parameters = parameters.getUpdatedAllParams()\n\n let {\n showAlert,\n recordingMediaOptions,\n recordingAudioOptions,\n recordingVideoOptions,\n recordingVideoType,\n recordingDisplayType,\n recordingNameTags,\n recordingBackgroundColor,\n recordingNameTagsColor,\n recordingOrientationVideo,\n recordingAddHLS,\n recordingAddText,\n recordingCustomText,\n recordingCustomTextPosition,\n recordingCustomTextColor,\n meetingDisplayType,\n recordingVideoParticipantsFullRoomSupport,\n recordingAllParticipantsSupport,\n recordingVideoParticipantsSupport,\n recordingSupportForOtherOrientation,\n recordingPreferredOrientation,\n recordingMultiFormatsSupport,\n recordingVideoOptimized,\n recordingAllParticipantsFullRoomSupport,\n meetingVideoOptimized,\n eventType,\n breakOutRoomStarted,\n breakOutRoomEnded,\n updateRecordingDisplayType,\n updateRecordingVideoOptimized,\n updateUserRecordingParams,\n updateConfirmedToRecord,\n } = parameters\n\n if (\n !recordingVideoParticipantsFullRoomSupport &&\n recordingVideoOptions === 'all' &&\n recordingMediaOptions === 'video'\n ) {\n if (meetingDisplayType === 'all' && !(breakOutRoomStarted && !breakOutRoomEnded)) {\n showAlert?.({\n message: FULL_PARTICIPANT_RECORDING_ALERT_MESSAGE,\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n }\n\n if (!recordingAllParticipantsSupport && recordingVideoOptions === 'all') {\n showAlert?.({\n message: 'You are only allowed to record yourself.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n\n if (!recordingVideoParticipantsSupport && recordingDisplayType === 'video') {\n showAlert?.({\n message: 'You are not allowed to record other video participants.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n\n if (!recordingSupportForOtherOrientation && recordingOrientationVideo === 'all') {\n showAlert?.({\n message: 'You are not allowed to record all orientations.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n\n if (\n (recordingPreferredOrientation === 'landscape' && recordingOrientationVideo === 'portrait') ||\n (recordingPreferredOrientation === 'portrait' && recordingOrientationVideo === 'landscape')\n ) {\n if (!recordingSupportForOtherOrientation) {\n showAlert?.({\n message: 'You are not allowed to record this orientation.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n }\n\n if (!recordingMultiFormatsSupport && recordingVideoType === 'all') {\n showAlert?.({\n message: 'You are not allowed to record all formats.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n\n if (eventType !== 'broadcast') {\n if (recordingMediaOptions === 'video') {\n if (meetingDisplayType === 'media' && recordingDisplayType === 'all') {\n showAlert?.({\n message:\n 'Recording display type can be either video, video optimized, or media when meeting display type is media.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n updateRecordingDisplayType(meetingDisplayType as 'video' | 'media' | 'all')\n return\n }\n\n if (meetingDisplayType === 'video') {\n if (recordingDisplayType === 'all' || recordingDisplayType === 'media') {\n showAlert?.({\n message:\n 'Recording display type can be either video or video optimized when meeting display type is video.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n updateRecordingDisplayType(meetingDisplayType as 'video' | 'media' | 'all')\n return\n }\n\n if (meetingVideoOptimized && !recordingVideoOptimized) {\n showAlert?.({\n message:\n 'Recording display type can only be video optimized when meeting display type is video optimized.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n updateRecordingVideoOptimized(meetingVideoOptimized)\n return\n }\n }\n } else {\n updateRecordingDisplayType('media')\n updateRecordingVideoOptimized(false)\n }\n }\n\n if (recordingDisplayType === 'all' && !recordingAllParticipantsFullRoomSupport) {\n showAlert?.({\n message: 'You can only record all participants with media.',\n type: 'danger',\n duration: ALERT_DURATION,\n })\n return\n }\n\n const mainSpecs: MainSpecs = {\n mediaOptions: recordingMediaOptions,\n audioOptions: recordingAudioOptions,\n videoOptions: recordingVideoOptions,\n videoType: recordingVideoType,\n videoOptimized: recordingVideoOptimized,\n recordingDisplayType,\n addHLS: recordingAddHLS,\n }\n\n const dispSpecs: DispSpecs = {\n nameTags: recordingNameTags,\n backgroundColor: recordingBackgroundColor,\n nameTagsColor: recordingNameTagsColor,\n orientationVideo: recordingOrientationVideo,\n }\n\n const textSpecs: TextSpecs = {\n addText: recordingAddText,\n customText: recordingCustomText,\n customTextPosition: recordingCustomTextPosition,\n customTextColor: recordingCustomTextColor,\n }\n\n const userRecordingParams = { mainSpecs, dispSpecs, textSpecs }\n\n updateUserRecordingParams(userRecordingParams)\n updateConfirmedToRecord(true)\n}\n","import type { ShowAlert } from '../../types/types'\n\nexport interface LaunchRecordingOptions {\n updateIsRecordingModalVisible: (visible: boolean) => void\n isRecordingModalVisible: boolean\n showAlert?: ShowAlert\n stopLaunchRecord: boolean\n canLaunchRecord: boolean\n recordingAudioSupport: boolean\n recordingVideoSupport: boolean\n updateCanRecord: (canRecord: boolean) => void\n updateClearedToRecord: (cleared: boolean) => void\n recordStarted: boolean\n recordPaused: boolean\n localUIMode: boolean\n [key: string]: any\n}\n\nexport type LaunchRecordingType = (options: LaunchRecordingOptions) => void\n\n/**\n * Launches the recording process based on various conditions and updates the UI accordingly.\n *\n * @param {Object} options - The options for launching the recording.\n * @param {Function} options.updateIsRecordingModalVisible - Function to update the visibility of the recording modal.\n * @param {boolean} options.isRecordingModalVisible - Indicates if the recording modal is currently visible.\n * @param {Function} options.showAlert - Function to show an alert message.\n * @param {boolean} options.stopLaunchRecord - Indicates if the recording launch should be stopped.\n * @param {boolean} options.canLaunchRecord - Indicates if the recording can be launched.\n * @param {boolean} options.recordingAudioSupport - Indicates if audio recording is supported.\n * @param {boolean} options.recordingVideoSupport - Indicates if video recording is supported.\n * @param {Function} options.updateCanRecord - Function to update the recording capability.\n * @param {Function} options.updateClearedToRecord - Function to update the cleared-to-record status.\n * @param {boolean} options.recordStarted - Indicates if the recording has started.\n * @param {boolean} options.recordPaused - Indicates if the recording is paused.\n * @param {boolean} options.localUIMode - Indicates if the local UI mode is active.\n *\n * @returns {void}\n *\n * @example\n * ```typescript\n * launchRecording({\n * updateIsRecordingModalVisible: (visible) => console.log(`Modal visible: ${visible}`),\n * isRecordingModalVisible: false,\n * showAlert: (alert) => console.log(alert.message),\n * stopLaunchRecord: false,\n * canLaunchRecord: true,\n * recordingAudioSupport: true,\n * recordingVideoSupport: true,\n * updateCanRecord: (canRecord) => console.log(`Can record: ${canRecord}`),\n * updateClearedToRecord: (cleared) => console.log(`Cleared to record: ${cleared}`),\n * recordStarted: false,\n * recordPaused: false,\n * localUIMode: false,\n * })\n * ```\n */\nexport const launchRecording: LaunchRecordingType = ({\n updateIsRecordingModalVisible,\n isRecordingModalVisible,\n showAlert,\n stopLaunchRecord,\n canLaunchRecord,\n recordingAudioSupport,\n recordingVideoSupport,\n updateCanRecord,\n updateClearedToRecord,\n recordStarted,\n recordPaused,\n localUIMode,\n}) => {\n if (!isRecordingModalVisible && stopLaunchRecord && !localUIMode) {\n showAlert?.({\n message: 'Recording has already ended or you are not allowed to record',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n if (!isRecordingModalVisible && canLaunchRecord && !localUIMode) {\n if (!recordingAudioSupport && !recordingVideoSupport) {\n showAlert?.({\n message: 'You are not allowed to record',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n updateClearedToRecord(false)\n updateCanRecord(false)\n }\n\n if (!isRecordingModalVisible && recordStarted && !recordPaused) {\n showAlert?.({\n message: 'You can only re-configure recording after pausing it',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n if (!isRecordingModalVisible && !recordingAudioSupport && !recordingVideoSupport && !localUIMode) {\n showAlert?.({\n message: 'You are not allowed to record',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n updateIsRecordingModalVisible(!isRecordingModalVisible)\n}\n","import type { ShowAlert } from '../../types/types'\n\nexport interface RecordPauseTimerOptions {\n stop?: boolean\n isTimerRunning: boolean\n canPauseResume: boolean\n showAlert?: ShowAlert\n}\n\nexport type RecordPauseTimerType = (options: RecordPauseTimerOptions) => boolean\n\n/**\n * Records the pause timer.\n *\n * @param {RecordPauseTimerOptions} options - The options for recording the pause timer.\n * @param {boolean} options.stop - A flag to stop the timer.\n * @param {boolean} options.isTimerRunning - Indicates if the timer is running.\n * @param {boolean} options.canPauseResume - Indicates if the timer can be paused or resumed.\n * @param {Function} options.showAlert - Function to show alerts.\n *\n * @returns {boolean} `true` if the timer can be paused or resumed, otherwise `false`.\n *\n * @example\n * ```typescript\n * const canPause = recordPauseTimer({\n * stop: false,\n * isTimerRunning: true,\n * canPauseResume: true,\n * showAlert: (alert) => console.log(alert.message),\n * })\n * ```\n */\nexport const recordPauseTimer: RecordPauseTimerType = ({\n stop = false,\n isTimerRunning,\n canPauseResume,\n showAlert,\n}) => {\n if (isTimerRunning && canPauseResume) {\n return true\n }\n\n const message = stop\n ? 'Can only stop after 15 seconds of starting or pausing or resuming recording'\n : 'Can only pause or resume after 15 seconds of starting or pausing or resuming recording'\n\n showAlert?.({\n message,\n type: 'danger',\n })\n return false\n}\n","export interface RecordUpdateTimerOptions {\n recordElapsedTime: number\n recordStartTime: number\n updateRecordElapsedTime: (elapsedTime: number) => void\n updateRecordingProgressTime: (formattedTime: string) => void\n}\n\nexport type RecordUpdateTimerType = (options: RecordUpdateTimerOptions) => void\n\n/**\n * Updates the recording timer by calculating the elapsed time since the recording started\n * and formatting it in HH:MM:SS format.\n *\n * @param {RecordUpdateTimerOptions} options - The options object.\n * @param {number} options.recordElapsedTime - The elapsed recording time in seconds.\n * @param {number} options.recordStartTime - The timestamp when the recording started.\n * @param {Function} options.updateRecordElapsedTime - Callback to update the elapsed recording time.\n * @param {Function} options.updateRecordingProgressTime - Callback to update the formatted recording time.\n *\n * @example\n * ```typescript\n * recordUpdateTimer({\n * recordElapsedTime: 0,\n * recordStartTime: Date.now(),\n * updateRecordElapsedTime: (elapsedTime) => console.log('Elapsed:', elapsedTime),\n * updateRecordingProgressTime: (formatted) => console.log('Progress:', formatted),\n * })\n * ```\n */\nexport const recordUpdateTimer: RecordUpdateTimerType = ({\n recordElapsedTime,\n recordStartTime,\n updateRecordElapsedTime,\n updateRecordingProgressTime,\n}) => {\n const padNumber = (value: number): string => value.toString().padStart(2, '0')\n\n const currentTime = new Date().getTime()\n let elapsedSeconds = recordElapsedTime\n elapsedSeconds = Math.floor((currentTime - recordStartTime) / 1000)\n updateRecordElapsedTime(elapsedSeconds)\n\n const hours = Math.floor(elapsedSeconds / 3600)\n const minutes = Math.floor((elapsedSeconds % 3600) / 60)\n const seconds = elapsedSeconds % 60\n const formattedTime = `${padNumber(hours)}:${padNumber(minutes)}:${padNumber(seconds)}`\n\n updateRecordingProgressTime(formattedTime)\n}\n","import type { ShowAlert } from '../../types/types'\nimport { recordUpdateTimer } from './recordUpdateTimer'\n\nexport interface RecordResumeTimerParameters {\n isTimerRunning: boolean\n canPauseResume: boolean\n recordElapsedTime: number\n recordStartTime: number\n recordTimerInterval?: ReturnType<typeof setInterval> | null\n showAlert?: ShowAlert\n recordPaused: boolean\n recordStopped: boolean\n roomName: string | null\n updateRecordStartTime: (time: number) => void\n updateRecordTimerInterval: (interval: ReturnType<typeof setInterval> | null) => void\n updateIsTimerRunning: (isRunning: boolean) => void\n updateCanPauseResume: (canPause: boolean) => void\n updateRecordElapsedTime: (elapsed: number) => void\n updateRecordingProgressTime: (formatted: string) => void\n getUpdatedAllParams: () => RecordResumeTimerParameters\n [key: string]: any\n}\n\nexport interface RecordResumeTimerOptions {\n parameters: RecordResumeTimerParameters\n}\n\nexport type RecordResumeTimerType = (options: RecordResumeTimerOptions) => Promise<boolean>\n\n/**\n * Resumes the recording timer if it is not already running and can be paused/resumed.\n */\nexport const recordResumeTimer: RecordResumeTimerType = async ({ parameters }) => {\n const { getUpdatedAllParams } = parameters\n parameters = getUpdatedAllParams()\n\n let {\n isTimerRunning,\n canPauseResume,\n recordElapsedTime,\n recordStartTime,\n recordTimerInterval,\n showAlert,\n updateRecordStartTime,\n updateRecordTimerInterval,\n updateIsTimerRunning,\n updateCanPauseResume,\n } = parameters\n\n if (!isTimerRunning && canPauseResume) {\n recordStartTime = new Date().getTime() - recordElapsedTime * 1000\n updateRecordStartTime(recordStartTime)\n\n recordTimerInterval = setInterval(() => {\n recordUpdateTimer({\n recordElapsedTime,\n recordStartTime,\n updateRecordElapsedTime: parameters.updateRecordElapsedTime,\n updateRecordingProgressTime: parameters.updateRecordingProgressTime,\n })\n\n parameters = getUpdatedAllParams()\n\n if (\n parameters.recordPaused ||\n parameters.recordStopped ||\n parameters.roomName === '' ||\n parameters.roomName === null\n ) {\n clearInterval(recordTimerInterval!)\n updateRecordTimerInterval(null)\n isTimerRunning = false\n updateIsTimerRunning(isTimerRunning)\n canPauseResume = false\n updateCanPauseResume(canPauseResume)\n }\n }, 1000)\n\n updateRecordTimerInterval(recordTimerInterval!)\n isTimerRunning = true\n updateIsTimerRunning(isTimerRunning)\n canPauseResume = false\n updateCanPauseResume(canPauseResume)\n return true\n }\n\n showAlert?.({\n type: 'danger',\n message: 'Can only pause or resume after 15 seconds of starting or pausing or resuming recording',\n })\n return false\n}\n","import { recordUpdateTimer } from './recordUpdateTimer'\n\nexport interface RecordStartTimerParameters {\n recordStartTime: number\n recordTimerInterval?: ReturnType<typeof setInterval> | null\n isTimerRunning: boolean\n canPauseResume: boolean\n recordChangeSeconds: number\n recordPaused: boolean\n recordStopped: boolean\n roomName: string | null\n updateRecordStartTime: (time: number) => void\n updateRecordTimerInterval: (interval: ReturnType<typeof setInterval> | null) => void\n updateIsTimerRunning: (isRunning: boolean) => void\n updateCanPauseResume: (canPause: boolean) => void\n recordElapsedTime: number\n updateRecordElapsedTime: (elapsed: number) => void\n updateRecordingProgressTime: (formatted: string) => void\n getUpdatedAllParams: () => RecordStartTimerParameters\n [key: string]: any\n}\n\nexport interface RecordStartTimerOptions {\n parameters: RecordStartTimerParameters\n}\n\nexport type RecordStartTimerType = (options: RecordStartTimerOptions) => Promise<void>\n\n/**\n * Starts a recording timer and manages its state.\n *\n * @param {RecordStartTimerOptions} options - The options for starting the recording timer.\n * @param {Function} options.parameters.getUpdatedAllParams - Function to get updated parameters.\n * @param {number} options.parameters.recordStartTime - The start time of the recording.\n * @param {number | null} options.parameters.recordTimerInterval - The interval ID for the recording timer.\n * @param {boolean} options.parameters.isTimerRunning - Flag indicating if the timer is running.\n * @param {boolean} options.parameters.canPauseResume - Flag indicating if pause/resume actions are enabled.\n * @param {number} options.parameters.recordChangeSeconds - The time after which pause/resume actions are enabled.\n * @param {Function} options.parameters.updateRecordStartTime - Function to update the recording start time.\n * @param {Function} options.parameters.updateRecordTimerInterval - Function to update the recording timer interval.\n * @param {Function} options.parameters.updateIsTimerRunning - Function to update the timer running state.\n * @param {Function} options.parameters.updateCanPauseResume - Function to update the pause/resume state.\n *\n * @example\n * ```typescript\n * await recordStartTimer({ parameters })\n * ```\n */\nexport const recordStartTimer: RecordStartTimerType = async ({ parameters }) => {\n const { getUpdatedAllParams } = parameters\n parameters = getUpdatedAllParams()\n\n let {\n recordStartTime,\n recordTimerInterval,\n isTimerRunning,\n canPauseResume,\n recordChangeSeconds,\n updateRecordStartTime,\n updateRecordTimerInterval,\n updateIsTimerRunning,\n updateCanPauseResume,\n } = parameters\n\n const enablePauseResume = (): void => {\n canPauseResume = true\n updateCanPauseResume(canPauseResume)\n }\n\n if (!isTimerRunning) {\n recordStartTime = new Date().getTime()\n updateRecordStartTime(recordStartTime)\n\n recordTimerInterval = setInterval(() => {\n recordUpdateTimer({\n recordElapsedTime: parameters.recordElapsedTime,\n recordStartTime,\n updateRecordElapsedTime: parameters.updateRecordElapsedTime,\n updateRecordingProgressTime: parameters.updateRecordingProgressTime,\n })\n\n parameters = getUpdatedAllParams()\n\n if (\n parameters.recordPaused ||\n parameters.recordStopped ||\n parameters.roomName === '' ||\n parameters.roomName === null\n ) {\n clearInterval(recordTimerInterval!)\n updateRecordTimerInterval(null)\n isTimerRunning = false\n updateIsTimerRunning(isTimerRunning)\n canPauseResume = false\n updateCanPauseResume(canPauseResume)\n }\n }, 1000)\n\n updateRecordTimerInterval(recordTimerInterval)\n isTimerRunning = true\n updateIsTimerRunning(isTimerRunning)\n canPauseResume = false\n updateCanPauseResume(canPauseResume)\n setTimeout(enablePauseResume, recordChangeSeconds)\n }\n}\n","import type { Socket } from 'socket.io-client'\nimport {\n recordStartTimer,\n type RecordStartTimerParameters,\n} from './recordStartTimer'\nimport {\n recordResumeTimer,\n type RecordResumeTimerParameters,\n} from './recordResumeTimer'\nimport type { UserRecordingParams, ShowAlert } from '../../types/types'\n\nexport interface StartRecordingParameters\n extends RecordStartTimerParameters,\n RecordResumeTimerParameters {\n roomName: string\n userRecordingParams: UserRecordingParams\n socket: Socket\n localSocket?: Socket\n updateIsRecordingModalVisible: (visible: boolean) => void\n confirmedToRecord: boolean\n showAlert?: ShowAlert\n recordingMediaOptions: string\n videoAlreadyOn: boolean\n audioAlreadyOn: boolean\n recordStarted: boolean\n recordPaused: boolean\n recordResumed: boolean\n recordStopped: boolean\n startReport: boolean\n endReport: boolean\n canRecord: boolean\n updateClearedToRecord: (cleared: boolean) => void\n updateRecordStarted: (started: boolean) => void\n updateRecordPaused: (paused: boolean) => void\n updateRecordResumed: (resumed: boolean) => void\n updateStartReport: (started: boolean) => void\n updateEndReport: (ended: boolean) => void\n updateCanRecord: (canRecord: boolean) => void\n whiteboardStarted: boolean\n whiteboardEnded: boolean\n rePort: StartRecordingRePort\n captureCanvasStream: StartRecordingCaptureCanvasStream\n getUpdatedAllParams: () => StartRecordingParameters\n [key: string]: any\n}\n\nexport type StartRecordingRePort = (options: {\n restart?: boolean\n parameters: any\n}) => Promise<void>\n\nexport type StartRecordingCaptureCanvasStream = (options: {\n parameters: any\n start?: boolean\n}) => Promise<void>\n\nexport interface StartRecordingOptions {\n parameters: StartRecordingParameters\n}\n\nexport type StartRecordingType = (\n options: StartRecordingOptions,\n) => Promise<boolean | undefined>\n\n/**\n * Starts the recording process based on the provided parameters.\n *\n * @param {StartRecordingOptions} options - The options for starting the recording.\n * @param {object} options.parameters - The parameters required for starting the recording.\n * @param {string} options.parameters.roomName - The name of the room where recording is to be started.\n * @param {object} options.parameters.userRecordingParams - User-specific recording parameters.\n * @param {object} options.parameters.socket - The socket instance for communication.\n * @param {object} options.parameters.localSocket - The local socket instance for communication.\n * @param {function} options.parameters.updateIsRecordingModalVisible - Function to update the visibility of the recording modal.\n * @param {boolean} options.parameters.confirmedToRecord - Flag indicating if the user has confirmed to record.\n * @param {function} options.parameters.showAlert - Function to show alerts.\n * @param {string} options.parameters.recordingMediaOptions - The media options for recording (e.g., \"video\", \"audio\").\n * @param {boolean} options.parameters.videoAlreadyOn - Flag indicating if the video is already on.\n * @param {boolean} options.parameters.audioAlreadyOn - Flag indicating if the audio is already on.\n * @param {boolean} options.parameters.recordStarted - Flag indicating if the recording has started.\n * @param {boolean} options.parameters.recordPaused - Flag indicating if the recording is paused.\n * @param {boolean} options.parameters.recordResumed - Flag indicating if the recording is resumed.\n * @param {boolean} options.parameters.recordStopped - Flag indicating if the recording is stopped.\n * @param {boolean} options.parameters.startReport - Flag indicating if the start report is active.\n * @param {boolean} options.parameters.endReport - Flag indicating if the end report is active.\n * @param {boolean} options.parameters.canRecord - Flag indicating if recording is allowed.\n * @param {function} options.parameters.updateClearedToRecord - Function to update the cleared to record status.\n * @param {function} options.parameters.updateRecordStarted - Function to update the record started status.\n * @param {function} options.parameters.updateRecordPaused - Function to update the record paused status.\n * @param {function} options.parameters.updateRecordResumed - Function to update the record resumed status.\n * @param {function} options.parameters.updateStartReport - Function to update the start report status.\n * @param {function} options.parameters.updateEndReport - Function to update the end report status.\n * @param {function} options.parameters.updateCanRecord - Function to update the can record status.\n * @param {boolean} options.parameters.whiteboardStarted - Flag indicating if the whiteboard has started.\n * @param {boolean} options.parameters.whiteboardEnded - Flag indicating if the whiteboard has ended.\n * @param {function} options.parameters.rePort - Function to report the recording status.\n * @param {function} options.parameters.captureCanvasStream - Function to capture the canvas stream.\n *\n * @returns {Promise<boolean | undefined>} - A promise that resolves to a boolean indicating if the recording attempt was successful, or undefined if not applicable.\n *\n * @example\n * ```typescript\n * startRecording({\n * parameters: {\n * roomName: \"Room101\",\n * userRecordingParams: myUserRecordingParams,\n * socket: mySocket,\n * localSocket: myLocalSocket,\n * updateIsRecordingModalVisible: setIsRecordingModalVisible,\n * confirmedToRecord: true,\n * showAlert: myShowAlert,\n * recordingMediaOptions: \"video\",\n * videoAlreadyOn: true,\n * audioAlreadyOn: true,\n * recordStarted: false,\n * recordPaused: false,\n * recordResumed: false,\n * recordStopped: false,\n * startReport: false,\n * endReport: false,\n * canRecord: true,\n * updateClearedToRecord: setClearedToRecord,\n * updateRecordStarted: setRecordStarted,\n * updateRecordPaused: setRecordPaused,\n * updateRecordResumed: setRecordResumed,\n * updateStartReport: setStartReport,\n * updateEndReport: setEndReport,\n * updateCanRecord: setCanRecord,\n * whiteboardStarted: true,\n * whiteboardEnded: false,\n * rePort: myRePort,\n * captureCanvasStream: myCaptureCanvasStream,\n * },\n * })\n * ```\n */\nexport const startRecording: StartRecordingType = async ({\n parameters,\n}) => {\n parameters = parameters.getUpdatedAllParams()\n\n let {\n roomName,\n userRecordingParams,\n socket,\n localSocket,\n updateIsRecordingModalVisible,\n confirmedToRecord,\n showAlert,\n recordingMediaOptions,\n videoAlreadyOn,\n audioAlreadyOn,\n recordStarted,\n recordPaused,\n recordResumed,\n recordStopped,\n startReport,\n endReport,\n canRecord,\n updateClearedToRecord,\n updateRecordStarted,\n updateRecordPaused,\n updateRecordResumed,\n updateStartReport,\n updateEndReport,\n updateCanRecord,\n whiteboardStarted,\n whiteboardEnded,\n rePort,\n captureCanvasStream,\n } = parameters\n\n if (!confirmedToRecord) {\n showAlert?.({\n message: 'You must click confirm before you can start recording',\n type: 'danger',\n })\n return false\n }\n\n if (recordingMediaOptions === 'video' && !videoAlreadyOn) {\n showAlert?.({\n message: 'You must turn on your video before you can start recording',\n type: 'danger',\n })\n return false\n }\n\n if (recordingMediaOptions === 'audio' && !audioAlreadyOn) {\n showAlert?.({\n message: 'You must turn on your audio before you can start recording',\n type: 'danger',\n })\n return false\n }\n\n updateClearedToRecord(true)\n\n let action = 'startRecord'\n if (recordStarted && recordPaused && !recordResumed && !recordStopped) {\n action = 'resumeRecord'\n }\n\n let recAttempt = false\n const socketRef = localSocket && localSocket.connected ? localSocket : socket\n\n await new Promise<void>((resolve) => {\n socketRef.emit(\n action,\n { roomName, userRecordingParams },\n async ({ success, reason }: { success: boolean; reason: string }) => {\n if (success) {\n recordStarted = true\n startReport = true\n endReport = false\n recordPaused = false\n recAttempt = true\n\n updateRecordStarted(recordStarted)\n updateStartReport(startReport)\n updateEndReport(endReport)\n updateRecordPaused(recordPaused)\n\n if (action === 'startRecord') {\n // restart: force an immediate updateScreenClient. Without it,\n // rePort only emits when activeNames or screenStates differ from\n // their previous values — and nothing has changed at the moment a\n // recording starts, so the recorder got no layout until something\n // later did (a speaker change, a join, a share). Resume already\n // forced it; start now matches.\n await rePort({ restart: true, parameters: parameters.getUpdatedAllParams() })\n await recordStartTimer({ parameters })\n } else {\n updateRecordResumed(true)\n await rePort({ restart: true, parameters: parameters.getUpdatedAllParams() })\n await recordResumeTimer({ parameters })\n }\n } else {\n showAlert?.({\n message: `Recording could not start - ${reason}`,\n type: 'danger',\n })\n canRecord = true\n startReport = false\n endReport = true\n recAttempt = false\n\n updateCanRecord(canRecord)\n updateStartReport(startReport)\n updateEndReport(endReport)\n }\n\n resolve()\n },\n )\n })\n\n try {\n if (\n recAttempt &&\n whiteboardStarted &&\n !whiteboardEnded &&\n recordingMediaOptions === 'video'\n ) {\n await captureCanvasStream({ parameters: parameters.getUpdatedAllParams() })\n }\n } catch (error) {\n console.error('Error capturing canvas stream:', error)\n }\n\n updateIsRecordingModalVisible(false)\n\n return recAttempt\n}\n","import type { Socket } from 'socket.io-client'\nimport { recordPauseTimer } from './recordPauseTimer'\nimport type { ShowAlert } from '../../types/types'\n\nexport interface StopRecordingParameters {\n roomName: string\n socket: Socket\n localSocket?: Socket\n showAlert?: ShowAlert\n startReport: boolean\n endReport: boolean\n recordStarted: boolean\n recordPaused: boolean\n recordStopped: boolean\n updateRecordPaused: (paused: boolean) => void\n updateRecordStopped: (stopped: boolean) => void\n updateStartReport: (startReport: boolean) => void\n updateEndReport: (endReport: boolean) => void\n updateShowRecordButtons: (show: boolean) => void\n whiteboardStarted: boolean\n whiteboardEnded: boolean\n recordingMediaOptions: string\n captureCanvasStream: (options: { parameters: any; start?: boolean }) => void\n getUpdatedAllParams: () => StopRecordingParameters\n [key: string]: any\n}\n\nexport interface StopRecordingOptions {\n parameters: StopRecordingParameters\n}\n\nexport type StopRecordingType = (options: StopRecordingOptions) => Promise<void>\n\n/**\n * Stops the recording process if it has been started and not yet stopped.\n */\nexport const stopRecording: StopRecordingType = async ({ parameters }) => {\n let {\n roomName,\n socket,\n localSocket,\n showAlert,\n startReport,\n endReport,\n recordStarted,\n recordPaused,\n recordStopped,\n updateRecordPaused,\n updateRecordStopped,\n updateStartReport,\n updateEndReport,\n updateShowRecordButtons,\n whiteboardStarted,\n whiteboardEnded,\n recordingMediaOptions,\n captureCanvasStream,\n } = parameters\n\n let recAttempt = false\n\n if (recordStarted && !recordStopped) {\n const stop = recordPauseTimer({\n stop: true,\n isTimerRunning: parameters.isTimerRunning,\n canPauseResume: parameters.canPauseResume,\n showAlert: parameters.showAlert,\n })\n\n if (stop) {\n const action = 'stopRecord'\n\n const socketRef = localSocket && localSocket.connected ? localSocket : socket\n\n await new Promise<void>((resolve) => {\n socketRef.emit(\n action,\n { roomName },\n ({ success, reason, recordState }: { success: boolean; reason: string; recordState: string }) => {\n if (success) {\n startReport = false\n endReport = true\n recordPaused = false\n recordStopped = true\n recAttempt = true\n\n updateStartReport(startReport)\n updateEndReport(endReport)\n updateRecordPaused(recordPaused)\n updateRecordStopped(recordStopped)\n showAlert?.({ message: 'Recording Stopped', type: 'success' })\n updateShowRecordButtons(false)\n } else {\n const reasonMessage = `Recording Stop Failed: ${reason}; the recording is currently ${recordState}`\n showAlert?.({ message: reasonMessage, type: 'danger' })\n recAttempt = false\n }\n\n resolve()\n },\n )\n })\n\n try {\n if (\n recAttempt &&\n whiteboardStarted &&\n !whiteboardEnded &&\n recordingMediaOptions === 'video'\n ) {\n captureCanvasStream({ parameters: parameters.getUpdatedAllParams(), start: false })\n }\n } catch (error) {\n console.error('Error capturing canvas stream:', error)\n }\n } else {\n return\n }\n } else {\n showAlert?.({\n message: 'Recording is not started yet or already stopped',\n type: 'danger',\n })\n }\n}\n","import type { Socket } from 'socket.io-client'\nimport { checkPauseState } from './checkPauseState'\nimport { checkResumeState } from './checkResumeState'\nimport { recordPauseTimer } from './recordPauseTimer'\nimport {\n recordResumeTimer,\n type RecordResumeTimerParameters,\n} from './recordResumeTimer'\nimport type { ShowAlert, UserRecordingParams } from '../../types/types'\n\nexport interface UpdateRecordingParameters extends RecordResumeTimerParameters {\n roomName: string\n userRecordingParams: UserRecordingParams\n socket: Socket\n localSocket?: Socket\n updateIsRecordingModalVisible: (visible: boolean) => void\n confirmedToRecord: boolean\n showAlert?: ShowAlert\n recordingMediaOptions: string\n videoAlreadyOn: boolean\n audioAlreadyOn: boolean\n recordStarted: boolean\n recordPaused: boolean\n recordResumed: boolean\n recordStopped: boolean\n recordChangeSeconds: number\n pauseRecordCount: number\n startReport: boolean\n endReport: boolean\n canRecord: boolean\n canPauseResume: boolean\n updateCanPauseResume: (canPauseResume: boolean) => void\n updatePauseRecordCount: (count: number) => void\n updateClearedToRecord: (cleared: boolean) => void\n updateRecordPaused: (paused: boolean) => void\n updateRecordResumed: (resumed: boolean) => void\n updateStartReport: (start: boolean) => void\n updateEndReport: (end: boolean) => void\n updateCanRecord: (canRecord: boolean) => void\n rePort: UpdateRecordingRePort\n getUpdatedAllParams: () => UpdateRecordingParameters\n [key: string]: any\n}\n\nexport type UpdateRecordingRePort = (options: {\n restart?: boolean\n parameters: any\n}) => Promise<void>\n\nexport interface UpdateRecordingOptions {\n parameters: UpdateRecordingParameters\n}\n\nexport type UpdateRecordingType = (options: UpdateRecordingOptions) => Promise<void>\n\n/**\n * Updates the recording state based on the provided parameters.\n */\nexport const updateRecording: UpdateRecordingType = async ({ parameters }) => {\n let {\n roomName,\n userRecordingParams,\n socket,\n localSocket,\n updateIsRecordingModalVisible,\n confirmedToRecord,\n showAlert,\n recordingMediaOptions,\n videoAlreadyOn,\n audioAlreadyOn,\n recordStarted,\n recordPaused,\n recordResumed,\n recordStopped,\n recordChangeSeconds,\n pauseRecordCount,\n startReport,\n endReport,\n canRecord,\n canPauseResume,\n updateCanPauseResume,\n updatePauseRecordCount,\n updateClearedToRecord,\n updateRecordPaused,\n updateRecordResumed,\n updateStartReport,\n updateEndReport,\n updateCanRecord,\n rePort,\n } = parameters\n\n if (recordStopped) {\n showAlert?.({\n message: 'Recording has already stopped',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n if (recordingMediaOptions === 'video' && !videoAlreadyOn) {\n showAlert?.({\n message: 'You must turn on your video before you can start recording',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n if (recordingMediaOptions === 'audio' && !audioAlreadyOn) {\n showAlert?.({\n message: 'You must turn on your audio before you can start recording',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n const socketRef = localSocket && localSocket.connected ? localSocket : socket\n\n if (recordStarted && !recordPaused && !recordStopped) {\n const proceed = await checkPauseState({\n recordingMediaOptions,\n recordingVideoPausesLimit: parameters.recordingVideoPausesLimit,\n recordingAudioPausesLimit: parameters.recordingAudioPausesLimit,\n pauseRecordCount,\n showAlert,\n })\n\n if (!proceed) return\n\n const record = recordPauseTimer({\n stop: false,\n isTimerRunning: parameters.isTimerRunning,\n canPauseResume: parameters.canPauseResume,\n showAlert,\n })\n\n if (record) {\n const action = 'pauseRecord'\n await new Promise<void>((resolve) => {\n socketRef.emit(\n action,\n { roomName },\n async ({ success, reason, recordState, pauseCount }: { success: boolean; reason: string; recordState: string; pauseCount: number }) => {\n pauseRecordCount = pauseCount\n updatePauseRecordCount(pauseRecordCount)\n\n if (success) {\n startReport = false\n endReport = true\n recordPaused = true\n updateStartReport(startReport)\n updateEndReport(endReport)\n updateRecordPaused(recordPaused)\n\n showAlert?.({\n message: 'Recording paused',\n type: 'success',\n duration: 3000,\n })\n\n updateIsRecordingModalVisible(false)\n\n setTimeout(() => {\n canPauseResume = true\n updateCanPauseResume(canPauseResume)\n }, recordChangeSeconds)\n } else {\n showAlert?.({\n message: `Recording Pause Failed: ${reason}; the current state is: ${recordState}`,\n type: 'danger',\n duration: 3000,\n })\n }\n resolve()\n },\n )\n })\n }\n } else if (recordStarted && recordPaused && !recordStopped) {\n if (!confirmedToRecord) {\n showAlert?.({\n message: 'You must click confirm before you can start recording',\n type: 'danger',\n duration: 3000,\n })\n return\n }\n\n const proceed = await checkResumeState({\n recordingMediaOptions,\n recordingVideoPausesLimit: parameters.recordingVideoPausesLimit,\n recordingAudioPausesLimit: parameters.recordingAudioPausesLimit,\n pauseRecordCount,\n })\n\n if (!proceed) return\n\n const resume = await recordResumeTimer({ parameters })\n if (resume) {\n updateClearedToRecord(true)\n\n const action = 'resumeRecord'\n await new Promise<void>((resolve) => {\n socketRef.emit(\n action,\n { roomName, userRecordingParams },\n async ({ success, reason }: { success: boolean; reason: string }) => {\n if (success) {\n recordResumed = true\n recordPaused = false\n\n updateRecordPaused(recordPaused)\n updateRecordResumed(recordResumed)\n\n await rePort({ restart: true, parameters: parameters.getUpdatedAllParams() })\n } else {\n showAlert?.({\n message: `Recording could not resume - ${reason}`,\n type: 'danger',\n duration: 3000,\n })\n }\n canRecord = true\n startReport = false\n endReport = true\n\n updateCanRecord(canRecord)\n updateStartReport(startReport)\n updateEndReport(endReport)\n\n resolve()\n },\n )\n })\n\n updateIsRecordingModalVisible(false)\n\n setTimeout(() => {\n updateCanPauseResume(true)\n }, recordChangeSeconds)\n }\n }\n}\n","export interface LaunchRequestsOptions {\n updateIsRequestsModalVisible: (isVisible: boolean) => void\n isRequestsModalVisible: boolean\n}\n\nexport type LaunchRequestsType = (options: LaunchRequestsOptions) => void\n\n/**\n * Toggles the visibility state of the requests modal.\n *\n * @param {LaunchRequestsOptions} options - The options for launching requests.\n * @param {Function} options.updateIsRequestsModalVisible - Function to update the visibility state of the requests modal.\n * @param {boolean} options.isRequestsModalVisible - Current visibility state of the requests modal.\n *\n * @example\n * ```typescript\n * launchRequests({\n * updateIsRequestsModalVisible: setRequestsModalVisible,\n * isRequestsModalVisible: true,\n * })\n * ```\n */\nexport const launchRequests: LaunchRequestsType = ({ updateIsRequestsModalVisible, isRequestsModalVisible }) => {\n updateIsRequestsModalVisible(!isRequestsModalVisible)\n}\n","import { Socket } from \"socket.io-client\";\nimport type { Request, RequestResponse } from \"../../types/types\";\n\nexport interface RespondToRequestsOptions {\n socket: Socket;\n request: Request;\n updateRequestList: (newRequestList: Request[]) => void;\n requestList?: Request[];\n action: string;\n roomName: string;\n}\n\n// Export the type definition for the function\nexport type RespondToRequestsType = (options: RespondToRequestsOptions) => Promise<void>;\n\n/**\n * Responds to incoming requests by updating the request list and emitting a response to the server.\n *\n * @param {Object} options - The options for responding to requests.\n * @param {Socket} options.socket - The socket instance used to emit the response.\n * @param {Request} options.request - The request object containing details of the request.\n * @param {Function} options.updateRequestList - The function to update the request list.\n * @param {Request[]} options.requestList - The current list of requests.\n * @param {string} options.action - The action to be taken on the request.\n * @param {string} options.roomName - The name of the room to which the response should be emitted.\n *\n * @returns {Promise<void>} A promise that resolves when the response has been emitted.\n * \n * @example\n * ```typescript\n * respondToRequests({\n * socket,\n * request: { id: \"123\", name: \"John\", icon: \"fa-microphone\" },\n * updateRequestList: setRequestList,\n * requestList: currentRequests,\n * action: \"accept\",\n * roomName: \"mainRoom\"\n * });\n * ```\n */\n\nexport const respondToRequests = async ({\n socket,\n request,\n updateRequestList,\n requestList = [],\n action,\n roomName,\n}: RespondToRequestsOptions): Promise<void> => {\n if (!request || typeof request !== \"object\") {\n return;\n }\n\n if (!updateRequestList) {\n console.warn(\"[respondToRequests] Missing updateRequestList handler; aborting emit.\");\n return;\n }\n\n const currentList = Array.isArray(requestList) ? requestList : [];\n\n const requestIdRaw = (request as { id?: string | number }).id;\n const requestIcon = (request as { icon?: string }).icon;\n const requestName = (request as { name?: string }).name;\n\n if (requestIdRaw === undefined || requestIcon === undefined || requestName === undefined) {\n console.warn(\"[respondToRequests] Request payload is missing required fields; aborting emit.\", request);\n return;\n }\n\n const requestId = String(requestIdRaw);\n\n if (!requestId || !requestIcon || !requestName) {\n console.warn(\"[respondToRequests] Request payload contains empty fields; aborting emit.\", request);\n return;\n }\n\n // Filter out the request from the request list\n const newRequestList = currentList.filter(\n (request_) =>\n !(\n request_ &&\n request_.id === requestId &&\n request_.icon === requestIcon &&\n request_.name === requestName\n )\n );\n\n // Update the request list with the filtered list\n updateRequestList(newRequestList);\n\n // Prepare the request response\n const requestResponse: RequestResponse = {\n id: requestId,\n name: requestName,\n type: requestIcon,\n action,\n };\n\n // Emit the request response to the server\n const socketReady = socket && typeof (socket as Socket).emit === \"function\";\n\n if (!socketReady) {\n console.warn(\"[respondToRequests] Socket is not ready; skipping emit.\");\n return;\n }\n\n (socket as Socket).emit(\"updateUserofRequestStatus\", { requestResponse, roomName });\n};\n","export interface LaunchSettingsOptions {\n updateIsSettingsModalVisible: (isVisible: boolean) => void\n isSettingsModalVisible: boolean\n}\n\nexport type LaunchSettingsType = (options: LaunchSettingsOptions) => void\n\n/**\n * Toggles the visibility state of the settings modal.\n *\n * @param {LaunchSettingsOptions} options - The options for launching settings.\n * @param {Function} options.updateIsSettingsModalVisible - Function to update the visibility state of the settings modal.\n * @param {boolean} options.isSettingsModalVisible - Current visibility state of the settings modal.\n *\n * @example\n * ```typescript\n * launchSettings({\n * isSettingsModalVisible: false,\n * updateIsSettingsModalVisible: (visible) => setSettingsModalVisible(visible),\n * })\n * ```\n */\nexport const launchSettings: LaunchSettingsType = ({ updateIsSettingsModalVisible, isSettingsModalVisible }) => {\n updateIsSettingsModalVisible(!isSettingsModalVisible)\n}\n","import type { SwitchUserAudioType, SwitchUserAudioParameters } from '../../types/types';\n\nexport interface SwitchAudioParameters extends SwitchUserAudioParameters {\n defAudioID: string\n userDefaultAudioInputDevice: string\n prevAudioInputDevice: string\n updateUserDefaultAudioInputDevice: (deviceId: string) => void\n updatePrevAudioInputDevice: (deviceId: string) => void\n\n // mediasfu functions\n switchUserAudio: SwitchUserAudioType\n\n getUpdatedAllParams: () => SwitchAudioParameters\n [key: string]: any\n}\n\nexport interface SwitchAudioOptions {\n audioPreference: string\n parameters: SwitchAudioParameters\n}\n\n// Export the type definition for the function\nexport type SwitchAudioType = (options: SwitchAudioOptions) => Promise<void>\n\n/**\n * Switches the audio input device based on user preference.\n *\n * @param {SwitchAudioOptions} options - The function parameters.\n * @returns {Promise<void>}\n *\n * @example\n * ```typescript\n * switchAudio({\n * audioPreference: \"newAudioDeviceID\",\n * parameters: {\n * defAudioID: \"defaultAudioDeviceID\",\n * userDefaultAudioInputDevice: \"currentAudioDeviceID\",\n * prevAudioInputDevice: \"previousAudioDeviceID\",\n * updateUserDefaultAudioInputDevice: (deviceId) => setUserDefaultAudio(deviceId),\n * updatePrevAudioInputDevice: (deviceId) => setPrevAudioDevice(deviceId),\n * switchUserAudio: switchUserAudioFunction,\n * getUpdatedAllParams: getUpdatedParamsFunction\n * }\n * });\n * ```\n */\n\nexport const switchAudio = async ({\n audioPreference,\n parameters\n}: SwitchAudioOptions): Promise<void> => {\n let {\n defAudioID,\n userDefaultAudioInputDevice,\n prevAudioInputDevice,\n updateUserDefaultAudioInputDevice,\n updatePrevAudioInputDevice,\n\n //mediasfu functions\n switchUserAudio\n } = parameters\n\n if (audioPreference !== defAudioID) {\n prevAudioInputDevice = userDefaultAudioInputDevice\n updatePrevAudioInputDevice(prevAudioInputDevice)\n userDefaultAudioInputDevice = audioPreference\n updateUserDefaultAudioInputDevice(userDefaultAudioInputDevice)\n\n if (defAudioID) {\n await switchUserAudio({ audioPreference, parameters })\n }\n }\n}\n","import type { ShowAlert, SwitchUserVideoType, SwitchUserVideoParameters } from '../../types/types'\n\n\nexport interface SwitchVideoParameters extends SwitchUserVideoParameters {\n recordStarted: boolean\n recordResumed: boolean\n recordStopped: boolean\n recordPaused: boolean\n recordingMediaOptions: string\n videoAlreadyOn: boolean\n userDefaultVideoInputDevice: string\n defVideoID: string\n allowed: boolean\n updateDefVideoID: (deviceId: string) => void\n updatePrevVideoInputDevice: (deviceId: string) => void\n updateUserDefaultVideoInputDevice: (deviceId: string) => void\n updateIsMediaSettingsModalVisible: (isVisible: boolean) => void\n showAlert?: ShowAlert\n\n // Mediasfu functions\n switchUserVideo: SwitchUserVideoType\n\n [key: string]: any\n}\n\nexport interface SwitchVideoOptions {\n videoPreference: string\n parameters: SwitchVideoParameters\n}\n\n// Export the type definition for the function\nexport type SwitchVideoType = (options: SwitchVideoOptions) => Promise<void>\n\n/**\n * Switches the user's video device based on the provided video preference.\n *\n * @param {SwitchVideoOptions} options - The function parameters.\n * @returns {Promise<void>}\n *\n * @example\n * ```typescript\n * switchVideo({\n * videoPreference: \"newVideoDeviceID\",\n * parameters: {\n * recordStarted: true,\n * recordResumed: false,\n * recordStopped: false,\n * recordPaused: false,\n * recordingMediaOptions: \"video\",\n * videoAlreadyOn: true,\n * userDefaultVideoInputDevice: \"currentVideoDeviceID\",\n * defVideoID: \"defaultVideoDeviceID\",\n * allowed: true,\n * updateDefVideoID: (deviceId) => setDefVideoID(deviceId),\n * updatePrevVideoInputDevice: (deviceId) => setPrevVideoDevice(deviceId),\n * updateUserDefaultVideoInputDevice: (deviceId) => setUserDefaultVideo(deviceId),\n * updateIsMediaSettingsModalVisible: (isVisible) => setMediaSettingsModal(isVisible),\n * showAlert: (alertOptions) => showAlert(alertOptions),\n * switchUserVideo: switchUserVideoFunction,\n * }\n * });\n * ```\n */\n\nexport const switchVideo = async ({\n videoPreference,\n parameters\n}: SwitchVideoOptions): Promise<void> => {\n let {\n recordStarted,\n recordResumed,\n recordStopped,\n recordPaused,\n recordingMediaOptions,\n videoAlreadyOn,\n userDefaultVideoInputDevice,\n defVideoID,\n allowed,\n updateDefVideoID,\n updatePrevVideoInputDevice,\n updateUserDefaultVideoInputDevice,\n updateIsMediaSettingsModalVisible,\n\n //mediasfu functions\n showAlert,\n switchUserVideo\n } = parameters\n\n // Check if recording is in progress and whether the selected video device is the default one\n let checkoff = false\n if ((recordStarted || recordResumed) && !recordStopped && !recordPaused) {\n if (recordingMediaOptions === 'video') {\n checkoff = true\n }\n }\n\n // Check camera access permission\n if (!allowed) {\n showAlert?.({\n message:\n 'Allow access to your camera by starting it for the first time.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n\n // Check video state and display appropriate alert messages\n if (checkoff) {\n if (videoAlreadyOn) {\n showAlert?.({\n message: 'Please turn off your video before switching.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n } else {\n if (!videoAlreadyOn) {\n showAlert?.({\n message: 'Please turn on your video before switching.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n }\n\n // Set default video ID if not already set\n if (!defVideoID) {\n defVideoID = userDefaultVideoInputDevice ?? 'default'\n updateDefVideoID(defVideoID)\n }\n\n // Switch video only if the selected video device is different from the default\n if (videoPreference !== defVideoID) {\n const prevVideoInputDevice = userDefaultVideoInputDevice\n updatePrevVideoInputDevice(prevVideoInputDevice)\n\n userDefaultVideoInputDevice = videoPreference\n updateUserDefaultVideoInputDevice(userDefaultVideoInputDevice)\n\n if (defVideoID) {\n updateIsMediaSettingsModalVisible(false)\n await switchUserVideo({ videoPreference, checkoff, parameters })\n }\n }\n}\n","import type { ShowAlert, SwitchUserVideoAltParameters, SwitchUserVideoAltType } from '../../types/types'\n\n\nexport interface SwitchVideoAltParameters extends SwitchUserVideoAltParameters {\n recordStarted: boolean\n recordResumed: boolean\n recordStopped: boolean\n recordPaused: boolean\n recordingMediaOptions: string\n videoAlreadyOn: boolean\n currentFacingMode: string\n prevFacingMode: string\n allowed: boolean\n audioOnlyRoom: boolean\n updateCurrentFacingMode: (mode: string) => void\n updatePrevFacingMode: (mode: string) => void\n updateIsMediaSettingsModalVisible: (isVisible: boolean) => void\n showAlert?: ShowAlert\n\n // mediasfu functions\n switchUserVideoAlt: SwitchUserVideoAltType\n\n getUpdatedAllParams: () => SwitchVideoAltParameters\n [key: string]: any\n}\n\nexport interface SwitchVideoAltOptions {\n parameters: SwitchVideoAltParameters\n}\n\n// Export the type definition for the function\nexport type SwitchVideoAltType = (\n options: SwitchVideoAltOptions\n) => Promise<void>\n\n/**\n * Switches the user's video device with alternate logic, taking into account recording state and camera access permissions.\n *\n * @param {SwitchVideoAltOptions} options - The parameters object containing necessary variables.\n * @returns {Promise<void>}\n *\n * @example\n * ```typescript\n * switchVideoAlt({\n * parameters: {\n * recordStarted: true,\n * recordResumed: false,\n * recordStopped: false,\n * recordPaused: false,\n * recordingMediaOptions: 'video',\n * videoAlreadyOn: true,\n * currentFacingMode: 'user',\n * prevFacingMode: 'environment',\n * allowed: true,\n * audioOnlyRoom: false,\n * updateCurrentFacingMode: (mode) => setCurrentFacingMode(mode),\n * updatePrevFacingMode: (mode) => setPrevFacingMode(mode),\n * updateIsMediaSettingsModalVisible: (isVisible) => setMediaSettingsModal(isVisible),\n * showAlert: (alertOptions) => showAlert(alertOptions),\n * switchUserVideoAlt: switchUserVideoAltFunction,\n * }\n * });\n * ```\n */\n\nexport const switchVideoAlt = async ({\n parameters\n}: SwitchVideoAltOptions): Promise<void> => {\n let {\n recordStarted,\n recordResumed,\n recordStopped,\n recordPaused,\n recordingMediaOptions,\n videoAlreadyOn,\n currentFacingMode,\n prevFacingMode,\n allowed,\n audioOnlyRoom,\n updateCurrentFacingMode,\n updateIsMediaSettingsModalVisible,\n updatePrevFacingMode,\n\n showAlert,\n\n //media functions\n switchUserVideoAlt\n } = parameters\n\n if (audioOnlyRoom) {\n showAlert?.({\n message: 'You cannot turn on your camera in an audio-only event.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n\n let checkoff = false\n if (\n (recordStarted || recordResumed) &&\n !recordStopped &&\n !recordPaused &&\n recordingMediaOptions === 'video'\n ) {\n checkoff = true\n }\n\n if (!allowed) {\n showAlert?.({\n message:\n 'Allow access to your camera by starting it for the first time.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n\n if (checkoff) {\n if (videoAlreadyOn) {\n showAlert?.({\n message: 'Please turn off your video before switching.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n } else {\n if (!videoAlreadyOn) {\n showAlert?.({\n message: 'Please turn on your video before switching.',\n type: 'danger',\n duration: 3000\n })\n return\n }\n }\n\n // Camera switching logic\n prevFacingMode = currentFacingMode\n updatePrevFacingMode(prevFacingMode)\n\n currentFacingMode = currentFacingMode === 'environment' ? 'user' : 'environment'\n updateCurrentFacingMode(currentFacingMode)\n\n updateIsMediaSettingsModalVisible(false)\n await switchUserVideoAlt({\n videoPreference: currentFacingMode,\n checkoff,\n parameters\n })\n}\n","import { ModalPositionStyle } from '../../types/shared-base-types';\n\nexport interface GetModalPositionOptions {\n position: string;\n}\n\nexport type GetModalPositionType = (options: GetModalPositionOptions) => ModalPositionStyle;\n\nexport const getModalPosition = ({ position }: GetModalPositionOptions): ModalPositionStyle => {\n switch (position) {\n case 'center':\n return { justifyContent: 'center', alignItems: 'center' };\n case 'topLeft':\n return { justifyContent: 'flex-start', alignItems: 'flex-start' };\n case 'topRight':\n return { justifyContent: 'flex-start', alignItems: 'flex-end' };\n case 'bottomLeft':\n return { justifyContent: 'flex-end', alignItems: 'flex-start' };\n case 'bottomRight':\n default:\n return { justifyContent: 'flex-end', alignItems: 'flex-end' };\n }\n};","export interface LaunchWaitingOptions {\n updateIsWaitingModalVisible: (visible: boolean) => void\n isWaitingModalVisible: boolean\n}\n\nexport type LaunchWaitingType = (options: LaunchWaitingOptions) => void\n\n/**\n * Toggles the visibility of the waiting modal.\n *\n * @param {LaunchWaitingOptions} options - The options for toggling the waiting modal visibility.\n * @param {Function} options.updateIsWaitingModalVisible - Function to update the visibility state of the waiting modal.\n * @param {boolean} options.isWaitingModalVisible - Current visibility state of the waiting modal.\n *\n * @example\n * ```typescript\n * const options = {\n * updateIsWaitingModalVisible: (visible: boolean) => console.log('Waiting modal visibility updated:', visible),\n * isWaitingModalVisible: true,\n * }\n * launchWaiting(options)\n * ```\n */\nexport const launchWaiting: LaunchWaitingType = ({ updateIsWaitingModalVisible, isWaitingModalVisible }) => {\n updateIsWaitingModalVisible(!isWaitingModalVisible)\n}\n","import { Socket } from \"socket.io-client\";\nimport type { WaitingRoomParticipant } from \"../../types/types\";\n\nexport interface RespondToWaitingOptions {\n participantId: string;\n participantName: string;\n updateWaitingList: (waitingList: WaitingRoomParticipant[]) => void;\n waitingList?: WaitingRoomParticipant[];\n type: string | boolean;\n roomName: string;\n socket: Socket;\n}\n\n// Export the type definition for the function\nexport type RespondToWaitingType = (options: RespondToWaitingOptions) => Promise<void>;\n\n/**\n * Responds to a participant waiting to join a room by either allowing or denying their entry.\n *\n * @param {RespondToWaitingOptions} options - The options for responding to the waiting participant.\n * @param {string} options.participantId - The ID of the participant.\n * @param {string} options.participantName - The name of the participant.\n * @param {Function} options.updateWaitingList - The function to update the waiting list.\n * @param {WaitingRoomParticipant[]} options.waitingList - The current waiting list of participants.\n * @param {boolean | string} options.type - The type of response, either \"true\" or \"false\".\n * @param {string} options.roomName - The name of the room.\n * @param {Socket} options.socket - The socket instance to emit events.\n * \n * @example\n * ```typescript\n * const options = {\n * participantId: \"12345\",\n * participantName: \"John Doe\",\n * updateWaitingList: (list) => console.log(\"Updated Waiting List:\", list),\n * waitingList: [{ id: \"12345\", name: \"John Doe\" }],\n * type: true,\n * roomName: \"room1\",\n * socket: socketInstance,\n * };\n * respondToWaiting(options);\n * ```\n */\n\nexport const respondToWaiting = async ({\n participantId,\n participantName,\n updateWaitingList,\n waitingList = [],\n type,\n roomName,\n socket,\n}: RespondToWaitingOptions): Promise<void> => {\n if (!participantId || !participantName) {\n return;\n }\n\n if (!updateWaitingList) {\n console.warn('[respondToWaiting] Missing updateWaitingList handler; aborting emit.');\n return;\n }\n\n if (!socket || typeof (socket as Socket).emit !== 'function') {\n console.warn('[respondToWaiting] Socket is not ready; skipping emit.');\n return;\n }\n\n // Filter out the participant from the waiting list\n const newWaitingList = waitingList.filter((item) => item.name !== participantName);\n\n // Update the waiting list\n updateWaitingList(newWaitingList);\n\n const responseType = type === \"true\" || type === true ? \"true\" : \"false\";\n\n // Emit an event to allow or deny the participant based on the response type\n socket.emit(\"allowUserIn\", {\n participantId,\n participantName,\n type: responseType,\n roomName,\n });\n};\n","import type { Socket } from 'socket.io-client';\nimport type { ShowAlert, WhiteboardUser } from '../../types/types';\n\n\nexport interface HandleStartWhiteboardOptions {\n socket: Socket;\n whiteboardUsers: WhiteboardUser[];\n roomName: string;\n whiteboardStarted: boolean;\n whiteboardEnded: boolean;\n showAlert?: ShowAlert;\n updateWhiteboardStarted: (started: boolean) => void;\n updateWhiteboardEnded: (ended: boolean) => void;\n updateIsConfigureWhiteboardModalVisible: (isVisible: boolean) => void;\n}\n\nexport type HandleStartWhiteboardType = (options: HandleStartWhiteboardOptions) => Promise<boolean>;\n\n/**\n * Handles the start of a whiteboard session.\n * @function\n * @param {HandleStartWhiteboardOptions} options - The options for starting the whiteboard.\n * @param {Socket} options.socket - The socket instance for communication.\n * @param {WhiteboardUser[]} options.whiteboardUsers - Array of users assigned to the whiteboard.\n * @param {string} options.roomName - The name of the room.\n * @param {boolean} options.whiteboardStarted - Whether the whiteboard has already started.\n * @param {boolean} options.whiteboardEnded - Whether the whiteboard has ended.\n * @param {ShowAlert} [options.showAlert] - Function to show alerts.\n * @param {Function} options.updateWhiteboardStarted - Function to update whiteboard started state.\n * @param {Function} options.updateWhiteboardEnded - Function to update whiteboard ended state.\n * @param {Function} options.updateIsConfigureWhiteboardModalVisible - Function to close the configure modal.\n * @returns {Promise<boolean>}\n */\nexport const handleStartWhiteboard = async ({\n socket,\n whiteboardUsers,\n roomName,\n whiteboardStarted,\n whiteboardEnded,\n showAlert,\n updateWhiteboardStarted,\n updateWhiteboardEnded,\n updateIsConfigureWhiteboardModalVisible,\n}: HandleStartWhiteboardOptions): Promise<boolean> => {\n const emitName = whiteboardStarted && !whiteboardEnded ? 'updateWhiteboard' : 'startWhiteboard';\n const filteredWhiteboardUsers = whiteboardUsers.map(({ name, useBoard }) => ({ name, useBoard }));\n\n return new Promise((resolve) => {\n socket.emit(\n emitName,\n { whiteboardUsers: filteredWhiteboardUsers, roomName },\n (response: { success: boolean; reason?: string }) => {\n if (response.success) {\n showAlert?.({ message: 'Whiteboard active', type: 'success' });\n updateWhiteboardStarted(true);\n updateWhiteboardEnded(false);\n updateIsConfigureWhiteboardModalVisible(false);\n } else {\n showAlert?.({ message: response.reason || 'Failed to start whiteboard', type: 'danger' });\n }\n resolve(response.success);\n }\n );\n });\n};\n","import type { Socket } from 'socket.io-client';\nimport type { ShowAlert } from '../../types/types';\n\nexport interface HandleStopWhiteboardOptions {\n socket: Socket;\n roomName: string;\n showAlert?: ShowAlert;\n updateWhiteboardStarted: (started: boolean) => void;\n updateWhiteboardEnded: (ended: boolean) => void;\n updateIsConfigureWhiteboardModalVisible: (isVisible: boolean) => void;\n}\n\nexport type HandleStopWhiteboardType = (options: HandleStopWhiteboardOptions) => Promise<boolean>;\n\n/**\n * Handles stopping a whiteboard session.\n * @function\n * @param {HandleStopWhiteboardOptions} options - The options for stopping the whiteboard.\n * @param {Socket} options.socket - The socket instance for communication.\n * @param {string} options.roomName - The name of the room.\n * @param {ShowAlert} [options.showAlert] - Function to show alerts.\n * @param {Function} options.updateWhiteboardStarted - Function to update whiteboard started state.\n * @param {Function} options.updateWhiteboardEnded - Function to update whiteboard ended state.\n * @param {Function} options.updateIsConfigureWhiteboardModalVisible - Function to close the configure modal.\n * @returns {Promise<boolean>}\n */\nexport const handleStopWhiteboard = async ({\n socket,\n roomName,\n showAlert,\n updateWhiteboardStarted,\n updateWhiteboardEnded,\n updateIsConfigureWhiteboardModalVisible,\n}: HandleStopWhiteboardOptions): Promise<boolean> => {\n return new Promise((resolve) => {\n socket.emit('stopWhiteboard', { roomName }, (response: { success: boolean; reason?: string }) => {\n if (response.success) {\n showAlert?.({ message: 'Whiteboard stopped', type: 'success' });\n updateWhiteboardStarted(false);\n updateWhiteboardEnded(true);\n updateIsConfigureWhiteboardModalVisible(false);\n } else {\n showAlert?.({ message: response.reason || 'Failed to stop whiteboard', type: 'danger' });\n }\n resolve(response.success);\n });\n });\n};\n","export interface LaunchConfigureWhiteboardOptions {\n updateIsConfigureWhiteboardModalVisible: (visible: boolean) => void\n isConfigureWhiteboardModalVisible: boolean\n}\n\nexport type LaunchConfigureWhiteboardType = (options: LaunchConfigureWhiteboardOptions) => void\n\n/**\n * Toggles the visibility of the configure whiteboard modal.\n *\n * @param {LaunchConfigureWhiteboardOptions} options - The options for toggling the whiteboard modal visibility.\n * @param {Function} options.updateIsConfigureWhiteboardModalVisible - Function to update the visibility state of the configure whiteboard modal.\n * @param {boolean} options.isConfigureWhiteboardModalVisible - Current visibility state of the configure whiteboard modal.\n *\n * @example\n * ```typescript\n * const options = {\n * updateIsConfigureWhiteboardModalVisible: (visible: boolean) => console.log('Modal visibility updated:', visible),\n * isConfigureWhiteboardModalVisible: false,\n * }\n * launchConfigureWhiteboard(options)\n * ```\n */\nexport const launchConfigureWhiteboard: LaunchConfigureWhiteboardType = ({\n updateIsConfigureWhiteboardModalVisible,\n isConfigureWhiteboardModalVisible,\n}) => {\n updateIsConfigureWhiteboardModalVisible(!isConfigureWhiteboardModalVisible)\n}\n","import { HeadlessOptions, RoomReadiness } from './headlessTypes';\n\nexport type GetRoomReadinessType = (options: HeadlessOptions) => RoomReadiness;\n\n/**\n * Is the room actually usable yet?\n *\n * Headless consumers repeatedly re-derive this same predicate and each one picks\n * a slightly different subset, so a control fires before the transport exists\n * and fails silently. The five conditions below are the real gate: a room name,\n * a member identity, server-side validation, a connected emittable socket, and a\n * loaded mediasoup device.\n *\n * `reason` is safe to show a user — it names what is still pending, never an\n * endpoint, credential, or internal identifier.\n *\n * @example\n * ```ts\n * import { getRoomReadiness } from 'mediasfu-shared';\n *\n * const { ready, reason } = getRoomReadiness({ parameters });\n * if (!ready) return <p>{reason}</p>;\n * ```\n */\nexport function getRoomReadiness({ parameters }: HeadlessOptions): RoomReadiness {\n const source = parameters || {};\n if (!source.roomName) {\n return { ready: false, reason: 'Waiting for the room name.' };\n }\n if (!source.member) {\n return { ready: false, reason: 'Waiting for the participant identity.' };\n }\n if (source.validated !== true) {\n return { ready: false, reason: 'Waiting for MediaSFU to validate the room.' };\n }\n const socket = source.socket;\n if (!socket || socket.connected !== true) {\n return { ready: false, reason: 'Connecting to the MediaSFU room.' };\n }\n if (typeof socket.emit !== 'function') {\n return { ready: false, reason: 'The room signal is not ready yet.' };\n }\n if (source.device?.loaded !== true) {\n return { ready: false, reason: 'Waiting for the MediaSFU media device.' };\n }\n return { ready: true, reason: '' };\n}\n\nexport default getRoomReadiness;\n","import { Participant, Stream } from '../../../types/types';\nimport { HeadlessOptions, HeadlessParameters, ResolvedMedia } from './headlessTypes';\n\n/**\n * MediaSFU seeds its own grid collections with a self marker rather than a real\n * producer. Rendering it as a remote peer shows the local user twice.\n */\nconst SELF_PRODUCER_IDS = new Set(['youyou', 'youyouyou']);\n\nfunction toMediaStream(value: any): MediaStream | null {\n if (value && typeof value.getTracks === 'function') return value as MediaStream;\n const nested = value?.stream;\n return nested && typeof nested.getTracks === 'function'\n ? (nested as MediaStream)\n : null;\n}\n\n\n/**\n * A stream is only renderable if it still carries a live track of that kind.\n *\n * MediaSFU keeps `localStreamVideo` assigned after the camera is switched off —\n * the track goes `enabled: false` or `readyState: 'ended'` rather than the\n * field being cleared. Returning it regardless paints a black <video> instead\n * of falling back to an audio or identity card.\n *\n * `enabled` is only meaningful for local media: the app clears it when the user\n * turns their own camera off. It is never applied to remote tracks, where\n * `muted: true` is a normal transient state before the first frame decodes.\n */\nfunction hasRenderableTrack(\n stream: MediaStream | null,\n kind: 'video' | 'audio',\n requireEnabled: boolean\n): stream is MediaStream {\n if (!stream || typeof stream.getTracks !== 'function') return false;\n try {\n return stream.getTracks().some(\n (track) =>\n track.kind === kind &&\n track.readyState === 'live' &&\n (!requireEnabled || track.enabled !== false)\n );\n } catch {\n return false;\n }\n}\n\nfunction collect(\n entries: (Participant | Stream)[] | undefined\n): (Participant | Stream)[] {\n return Array.isArray(entries) ? entries : [];\n}\n\nfunction dedupe(entries: (Participant | Stream)[]): ResolvedMedia[] {\n const seen = new Set<string>();\n const resolved: ResolvedMedia[] = [];\n for (const entry of entries) {\n const producerId = (entry as any)?.producerId || '';\n if (SELF_PRODUCER_IDS.has(producerId)) continue;\n const stream = toMediaStream(entry);\n if (!hasRenderableTrack(stream, 'video', false)) continue;\n const key = producerId || stream.id || '';\n if (key && seen.has(key)) continue;\n if (key) seen.add(key);\n resolved.push({\n stream,\n producerId,\n name: (entry as any)?.name || '',\n });\n }\n return resolved;\n}\n\nexport type GetRemoteVideoStreamsType = (\n options: HeadlessOptions\n) => ResolvedMedia[];\n\n/**\n * Every remote camera in the room, in render order.\n *\n * Two details make this hard to get right by hand, and both are why headless\n * integrations lose the host's video:\n *\n * - **`oldAllStreams` matters.** During normal conference layout processing the\n * SDK moves a stream out of `allVideoStreams` into `oldAllStreams`. Reading\n * only `allVideoStreams` makes the host disappear mid-call.\n * - **The self marker must go.** `allVideoStreams` is seeded with a\n * `producerId: 'youyou'` placeholder for the local user.\n *\n * Entries are de-duplicated by `producerId`, falling back to the stream id, so a\n * stream present in both collections is returned once.\n *\n * @example\n * ```ts\n * import { getRemoteVideoStreams } from 'mediasfu-shared';\n *\n * const remotes = getRemoteVideoStreams({ parameters });\n * const primary = remotes[0]?.stream ?? null;\n * ```\n */\nexport function getRemoteVideoStreams({\n parameters,\n}: HeadlessOptions): ResolvedMedia[] {\n const source: HeadlessParameters = parameters || {};\n return dedupe([\n ...collect(source.oldAllStreams),\n ...collect(source.allVideoStreams),\n ]);\n}\n\nexport type GetRemoteAudioStreamsType = (\n options: HeadlessOptions\n) => ResolvedMedia[];\n\n/**\n * Every remote audio producer in the room.\n *\n * Note that for *hearing* participants you normally want\n * {@link getAudioGridComponents} instead — MediaSFU prepares its own audio\n * elements and mounting those is what actually plays sound. This helper is for\n * cases where you need the raw `MediaStream` (recording, analysis, metering).\n */\nexport function getRemoteAudioStreams({\n parameters,\n}: HeadlessOptions): ResolvedMedia[] {\n const source: HeadlessParameters = parameters || {};\n return dedupe(collect(source.allAudioStreams));\n}\n\nexport type GetLocalVideoStreamType = (\n options: HeadlessOptions\n) => MediaStream | null;\n\n/**\n * The local camera stream to render as the self-view.\n *\n * The virtual-background case is the one everyone misses: when `keepBackground`\n * is on, the stream that carries the processed frames is `virtualStream`, and\n * `localStreamVideo` still holds the raw camera. Rendering the wrong one shows\n * the user their unprocessed background. This mirrors the SDK's own grid rule.\n *\n * Returns `null` when the camera is off, so a falsy result is a truthful\n * \"no self-view\" rather than something to paint black.\n *\n * Note: transport state such as `videoParams` or `videoProducer` is **not**\n * renderable media and is deliberately never consulted here.\n */\nexport function getLocalVideoStream({\n parameters,\n}: HeadlessOptions): MediaStream | null {\n const source: HeadlessParameters = parameters || {};\n if (source.keepBackground && source.virtualStream) {\n const virtual = toMediaStream(source.virtualStream);\n if (hasRenderableTrack(virtual, 'video', true)) return virtual;\n }\n const camera = toMediaStream(source.localStreamVideo);\n if (hasRenderableTrack(camera, 'video', true)) return camera;\n const combined = toMediaStream(source.localStream);\n return hasRenderableTrack(combined, 'video', true) ? combined : null;\n}\n\nexport type GetLocalAudioStreamType = (\n options: HeadlessOptions\n) => MediaStream | null;\n\n/** The local microphone stream, or `null` when the mic is off. */\nexport function getLocalAudioStream({\n parameters,\n}: HeadlessOptions): MediaStream | null {\n const source: HeadlessParameters = parameters || {};\n const mic = toMediaStream(source.localStreamAudio);\n if (hasRenderableTrack(mic, 'audio', true)) return mic;\n const combined = toMediaStream(source.localStream);\n return hasRenderableTrack(combined, 'audio', true) ? combined : null;\n}\n\nexport interface ScreenShareState {\n /** The stream to render, local or remote, or `null` when nobody is sharing. */\n stream: MediaStream | null;\n /** True when the stream is this user's own screen. */\n isLocal: boolean;\n /** True when any screen share is active in the room. */\n active: boolean;\n}\n\nexport type GetScreenShareStreamType = (\n options: HeadlessOptions\n) => ScreenShareState;\n\n/**\n * The active screen share, remote first.\n *\n * `remoteScreenStream` is an array in some SDK paths and a bare object in\n * others; both shapes are handled here so callers do not have to guess.\n *\n * @example\n * ```ts\n * const share = getScreenShareStream({ parameters });\n * const primary = share.stream ?? remotes[0]?.stream ?? localVideo;\n * ```\n */\nexport function getScreenShareStream({\n parameters,\n}: HeadlessOptions): ScreenShareState {\n const source: HeadlessParameters = parameters || {};\n const remoteRaw: any = source.remoteScreenStream;\n const remote = Array.isArray(remoteRaw)\n ? toMediaStream(remoteRaw[0])\n : toMediaStream(remoteRaw);\n // Liveness matters most here. When a sharer stops, the SDK ends the track but\n // `remoteScreenStream` keeps referencing it, so a viewer that trusts the field\n // renders a dead track — a screen share that \"ends\" into a black stage.\n // `enabled` is not required: it is a local-only flag and never set on a\n // received screen track.\n if (hasRenderableTrack(remote, 'video', false)) {\n return { stream: remote, isLocal: false, active: true };\n }\n\n const local = toMediaStream(source.localStreamScreen);\n if (hasRenderableTrack(local, 'video', true)) {\n return { stream: local, isLocal: true, active: true };\n }\n\n return {\n stream: null,\n isLocal: false,\n active: Boolean(source.shareScreenStarted || source.shared),\n };\n}\n\nexport type GetAudioGridComponentsType = (options: HeadlessOptions) => any[];\n\n/**\n * The prepared audio elements to mount so participants are actually audible.\n *\n * Mount **all** of them. Truncating this list to the participants you happen to\n * draw on screen silently mutes everyone else — audio playback is decoupled from\n * your video layout. The usual pattern is a visually hidden container:\n *\n * @example\n * ```tsx\n * import { getAudioGridComponents } from 'mediasfu-shared';\n *\n * <div style={{ position: 'absolute', width: 1, height: 1, opacity: 0 }}>\n * <AudioGrid componentsToRender={getAudioGridComponents({ parameters })} />\n * </div>\n * ```\n */\nexport function getAudioGridComponents({ parameters }: HeadlessOptions): any[] {\n const source: HeadlessParameters = parameters || {};\n return [\n ...(Array.isArray(source.audioOnlyStreams) ? source.audioOnlyStreams : []),\n ...(Array.isArray(source.translationStreams) ? source.translationStreams : []),\n ].filter(Boolean);\n}\n","import { HeadlessOptions, HeadlessParameters } from './headlessTypes';\n\nexport type GetCurrentParamsType = (\n options: HeadlessOptions\n) => HeadlessParameters;\n\n/**\n * Read the freshest parameter bag **without** triggering a republish.\n *\n * `parameters.getUpdatedAllParams()` looks like a getter but is not one: it\n * reassigns `sourceParameters` and calls `updateSourceParameters` as a side\n * effect. Calling it from a React event handler or a polling loop therefore\n * re-enters your own update path, which at best causes a render storm and at\n * worst locks the tab before `getUserMedia` resolves.\n *\n * MediaSFU components now publish a pure `getCurrentParams()` on the bag; this\n * helper uses it when present and otherwise returns the bag you already hold.\n * It never calls `getUpdatedAllParams()` and never throws.\n *\n * @example\n * ```ts\n * import { getCurrentParams } from 'mediasfu-shared';\n *\n * // Safe inside a click handler — no re-entrant publish.\n * const live = getCurrentParams({ parameters: parameterStore.getCurrent() });\n * await live.clickVideo({ parameters: live });\n * ```\n */\nexport function getCurrentParams({\n parameters,\n}: HeadlessOptions): HeadlessParameters {\n const source = parameters || {};\n if (typeof source.getCurrentParams === 'function') {\n try {\n const refreshed = source.getCurrentParams();\n if (refreshed && typeof refreshed === 'object') return refreshed;\n } catch {\n // Fall through to the bag the caller already holds.\n }\n }\n return source;\n}\n\nexport default getCurrentParams;\n","import { confirmExit } from '../../exit/confirmExit';\nimport { sendMessage } from '../../message/sendMessage';\nimport { HeadlessOptions, HeadlessParameters } from './headlessTypes';\nimport { getCurrentParams } from './getCurrentParams';\nimport { getRoomReadiness } from './getRoomReadiness';\n\nexport interface HeadlessActionResult {\n ok: boolean;\n /** Empty when `ok`; otherwise a short, user-safe explanation. */\n error: string;\n}\n\n/**\n * Prefer `localSocket` when it is usable, matching how the SDK routes chat.\n * Falls back to the primary room socket.\n */\nfunction usableSocket(parameters: HeadlessParameters): any {\n return (\n [parameters?.localSocket, parameters?.socket].find(\n (socket) => socket?.connected === true && typeof socket.emit === 'function'\n ) || null\n );\n}\n\nexport interface LeaveRoomOptions extends HeadlessOptions {\n /** Ban the member on the way out. Requires host privileges. */\n ban?: boolean;\n /** Whether a host exit should end the room for everyone. Defaults to true. */\n endRoomOnHostExit?: boolean;\n}\n\nexport type LeaveRoomType = (\n options: LeaveRoomOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Leave the room from a headless surface.\n *\n * Without this you have to pull `socket`, `localSocket`, `member` and `roomName`\n * off the bag yourself and hand them to `confirmExit` — four chances to pass a\n * stale value, and a silent no-op when you do.\n *\n * Never throws: a failed exit comes back as `{ ok: false, error }` so a Leave\n * button can report why rather than appearing to work.\n *\n * @example\n * ```ts\n * import { leaveRoom } from 'mediasfu-shared';\n *\n * const result = await leaveRoom({\n * parameters: parameterStore.getCurrent(),\n * endRoomOnHostExit: false,\n * });\n * if (!result.ok) setNotice(result.error);\n * ```\n */\nexport async function leaveRoom({\n parameters,\n ban = false,\n endRoomOnHostExit = true,\n}: LeaveRoomOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const socket = live?.socket;\n if (!socket || typeof socket.emit !== 'function') {\n return {\n ok: false,\n error: 'Room exit is unavailable until the signaling connection is ready.',\n };\n }\n if (!live?.member || !live?.roomName) {\n return { ok: false, error: 'Room exit is unavailable until the room is joined.' };\n }\n await confirmExit({\n socket,\n localSocket: live.localSocket,\n member: live.member,\n roomName: live.roomName,\n ban,\n endRoomOnHostExit,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The room exit request failed.' };\n }\n}\n\nexport interface SendChatMessageOptions extends HeadlessOptions {\n message: string;\n /** Specific recipients. Empty (default) sends to the group. */\n receivers?: string[];\n /** Send to everyone. Defaults to true when `receivers` is empty. */\n group?: boolean;\n}\n\nexport type SendChatMessageType = (\n options: SendChatMessageOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Send a chat message from a headless surface.\n *\n * `sendMessage` takes eleven fields that all have to be lifted off the bag in\n * the right combination; this resolves them for you, including the\n * `localSocket`-before-`socket` preference the SDK uses for chat.\n *\n * @example\n * ```ts\n * import { sendChatMessage } from 'mediasfu-shared';\n *\n * await sendChatMessage({ parameters, message: 'Hello everyone' });\n * await sendChatMessage({ parameters, message: 'Just you', receivers: ['Paul'] });\n * ```\n */\nexport async function sendChatMessage({\n parameters,\n message,\n receivers = [],\n group,\n}: SendChatMessageOptions): Promise<HeadlessActionResult> {\n try {\n const trimmed = String(message ?? '').trim();\n if (!trimmed) return { ok: false, error: 'The message is empty.' };\n\n const live = getCurrentParams({ parameters });\n const socket = usableSocket(live);\n if (!socket) {\n return { ok: false, error: 'Chat is unavailable until the room connection is ready.' };\n }\n if (!live?.roomName) {\n return { ok: false, error: 'Chat is unavailable until the room is joined.' };\n }\n\n await sendMessage({\n member: live.member || '',\n islevel: live.islevel || '1',\n showAlert: live.showAlert,\n coHostResponsibility: live.coHostResponsibility || [],\n coHost: live.coHost || '',\n chatSetting: live.chatSetting || '',\n message: trimmed,\n roomName: live.roomName,\n messagesLength: Array.isArray(live.messages) ? live.messages.length : 0,\n receivers,\n group: group ?? receivers.length === 0,\n sender: live.member || '',\n socket,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The message could not be sent.' };\n }\n}\n\nexport interface RunMediaControlOptions extends HeadlessOptions {\n /** Which control to run. */\n control:\n | 'clickAudio'\n | 'clickVideo'\n | 'clickScreenShare'\n | 'switchAudio'\n | 'switchVideo'\n | 'switchVideoAlt';\n /** Extra arguments, e.g. `{ audioPreference: deviceId }` for `switchAudio`. */\n extra?: Record<string, any>;\n}\n\nexport type RunMediaControlType = (\n options: RunMediaControlOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Invoke a media control safely from a headless surface.\n *\n * Gates on {@link getRoomReadiness} first — firing `clickVideo` before the\n * transport exists fails silently and looks like a dead button — then resolves\n * the control off the current bag rather than a snapshot the caller captured\n * earlier.\n *\n * @example\n * ```ts\n * import { runMediaControl } from 'mediasfu-shared';\n *\n * await runMediaControl({ parameters, control: 'clickVideo' });\n * await runMediaControl({\n * parameters,\n * control: 'switchVideo',\n * extra: { videoPreference: deviceId },\n * });\n * ```\n */\nexport async function runMediaControl({\n parameters,\n control,\n extra,\n}: RunMediaControlOptions): Promise<HeadlessActionResult> {\n const live = getCurrentParams({ parameters });\n const readiness = getRoomReadiness({ parameters: live });\n if (!readiness.ready) return { ok: false, error: readiness.reason };\n\n const method = live?.[control];\n if (typeof method !== 'function') {\n return { ok: false, error: `The SDK ${control} control is unavailable.` };\n }\n\n // MediaSFU's media controls return void and report refusals — \"Access denied\n // by host\", \"A request is pending\", recording locks, audio-only events —\n // exclusively through showAlert. Without this, a control the host has blocked\n // resolves normally and we would report success for something that did not\n // happen. Compare the alert before and after and treat a new danger/warning\n // as the failure reason.\n const alertBefore = live?.alertMessage || '';\n try {\n await method({ ...(extra || {}), parameters: live });\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The media control failed.' };\n }\n\n const settled = getCurrentParams({ parameters: live });\n const alertAfter = settled?.alertMessage || '';\n const alertType = settled?.alertType;\n if (\n alertAfter\n && alertAfter !== alertBefore\n && (alertType === 'danger' || alertType === 'warning')\n ) {\n return { ok: false, error: alertAfter };\n }\n return { ok: true, error: '' };\n}\n","import { Participant } from '../../../types/types';\nimport { HeadlessOptions, HeadlessParameters } from './headlessTypes';\n\n/** MediaSFU writes 'none' rather than an empty string when a producer is absent. */\nfunction hasProducer(value: unknown): boolean {\n return (\n typeof value === 'string' &&\n value.length > 3 &&\n value.toLowerCase() !== 'none'\n );\n}\n\nfunction participantList(parameters: HeadlessParameters): Participant[] {\n const source = parameters || {};\n const primary = Array.isArray(source.participants) ? source.participants : [];\n if (primary.length > 0) return primary;\n return Array.isArray(source.participantsAll) ? source.participantsAll : [];\n}\n\nexport interface ParticipantMediaState {\n participant: Participant | null;\n /** The participant's own display name, or '' when unresolved. */\n name: string;\n /** True when this row is the local user. */\n isSelf: boolean;\n /** True when the participant is a host (islevel '2'). */\n isHost: boolean;\n /** True when the participant is publishing a camera. */\n hasVideo: boolean;\n /** True when the participant is publishing a microphone. */\n hasAudio: boolean;\n /** True when the participant's microphone is muted. */\n muted: boolean;\n /** The camera producer id, or '' when not publishing. */\n videoProducerId: string;\n /** The microphone producer id, or '' when not publishing. */\n audioProducerId: string;\n}\n\nexport interface GetParticipantMediaStateOptions extends HeadlessOptions {\n /** Match by display name. */\n name?: string;\n /** Match by participant id. Takes precedence over `name`. */\n id?: string;\n}\n\nexport type GetParticipantMediaStateType = (\n options: GetParticipantMediaStateOptions\n) => ParticipantMediaState;\n\n/**\n * Whether a participant is publishing, and what to label them.\n *\n * \"Is this person on camera?\" is not `participant.muted` and not the presence of\n * a stream in your grid — it is whether `videoID` holds a real producer\n * reference. MediaSFU writes the string `'none'` rather than an empty value when\n * there is no producer, which is why a naive truthiness check reports everyone\n * as publishing.\n *\n * @example\n * ```ts\n * import { getParticipantMediaState } from 'mediasfu-shared';\n *\n * const paul = getParticipantMediaState({ parameters, name: 'Paul' });\n * if (paul.hasVideo) renderCamera(paul.videoProducerId);\n * ```\n */\nexport function getParticipantMediaState({\n parameters,\n name = '',\n id = '',\n}: GetParticipantMediaStateOptions): ParticipantMediaState {\n const source = parameters || {};\n const participants = participantList(source);\n const participant =\n (id ? participants.find((part) => part.id === id) : undefined) ||\n (name ? participants.find((part) => part.name === name) : undefined) ||\n null;\n\n const videoProducerId = hasProducer(participant?.videoID)\n ? (participant!.videoID as string)\n : '';\n const audioProducerId = hasProducer(participant?.audioID)\n ? (participant!.audioID as string)\n : '';\n\n return {\n participant,\n name: participant?.name || '',\n isSelf: Boolean(participant?.name && participant.name === source.member),\n isHost: String(participant?.islevel) === '2',\n hasVideo: Boolean(videoProducerId),\n hasAudio: Boolean(audioProducerId),\n muted: participant?.muted === true,\n videoProducerId,\n audioProducerId,\n };\n}\n\nexport type ListParticipantMediaStatesType = (\n options: HeadlessOptions\n) => ParticipantMediaState[];\n\n/** {@link getParticipantMediaState} for everyone currently in the room. */\nexport function listParticipantMediaStates({\n parameters,\n}: HeadlessOptions): ParticipantMediaState[] {\n const source = parameters || {};\n return participantList(source).map((participant) =>\n getParticipantMediaState({\n parameters: source,\n id: participant.id,\n name: participant.name,\n })\n );\n}\n\nexport interface ActiveSpeaker {\n /** Loudest participant's display name, or '' when the room is quiet. */\n name: string;\n /** That participant's average loudness. */\n level: number;\n participant: Participant | null;\n}\n\nexport type GetActiveSpeakerType = (options: HeadlessOptions) => ActiveSpeaker;\n\n/**\n * The loudest participant right now.\n *\n * Reads `audioDecibels`, which the SDK maintains per participant. MediaSFU's own\n * grids treat roughly 127.5 as the noise floor, so quieter rooms report no\n * active speaker rather than flickering between people.\n *\n * @example\n * ```ts\n * const speaker = getActiveSpeaker({ parameters });\n * if (speaker.name) highlight(speaker.name);\n * ```\n */\nexport function getActiveSpeaker({ parameters }: HeadlessOptions): ActiveSpeaker {\n const source = parameters || {};\n const decibels = Array.isArray(source.audioDecibels) ? source.audioDecibels : [];\n const participants = participantList(source);\n\n let best: { name: string; averageLoudness: number } | null = null;\n for (const entry of decibels) {\n if (!entry?.name || typeof entry.averageLoudness !== 'number') continue;\n if (entry.averageLoudness <= 127.5) continue;\n if (!best || entry.averageLoudness > best.averageLoudness) best = entry;\n }\n if (!best) return { name: '', level: 0, participant: null };\n\n return {\n name: best.name,\n level: best.averageLoudness,\n participant: participants.find((part) => part.name === best!.name) || null,\n };\n}\n\nexport interface MediaDeviceList {\n cameras: MediaDeviceInfo[];\n microphones: MediaDeviceInfo[];\n}\n\nexport type ListMediaDevicesType = (\n options: HeadlessOptions\n) => Promise<MediaDeviceList>;\n\n/**\n * Cameras and microphones available for a device picker.\n *\n * Uses the SDK's own `getMediaDevicesList` when the bag exposes it, so the\n * result reflects the same `mediaDevices` instance the SDK captures with;\n * otherwise falls back to `navigator.mediaDevices.enumerateDevices()`.\n *\n * Labels are blank until the user has granted permission once — call this after\n * the first successful capture if you need readable device names.\n *\n * @example\n * ```ts\n * const { cameras } = await listMediaDevices({ parameters });\n * await runMediaControl({\n * parameters,\n * control: 'switchVideo',\n * extra: { videoPreference: cameras[1].deviceId },\n * });\n * ```\n */\nexport async function listMediaDevices({\n parameters,\n}: HeadlessOptions): Promise<MediaDeviceList> {\n const source = parameters || {};\n try {\n if (typeof source.getMediaDevicesList === 'function') {\n const [cameras, microphones] = await Promise.all([\n source.getMediaDevicesList('videoinput'),\n source.getMediaDevicesList('audioinput'),\n ]);\n return {\n cameras: Array.isArray(cameras) ? cameras : [],\n microphones: Array.isArray(microphones) ? microphones : [],\n };\n }\n const devices = await navigator.mediaDevices.enumerateDevices();\n return {\n cameras: devices.filter((device) => device.kind === 'videoinput'),\n microphones: devices.filter((device) => device.kind === 'audioinput'),\n };\n } catch {\n return { cameras: [], microphones: [] };\n }\n}\n\nexport interface SelectedDevices {\n /** Device id of the camera currently in use, or '' when none is selected. */\n cameraId: string;\n /** Device id of the microphone currently in use, or '' when none is selected. */\n microphoneId: string;\n /** Cameras the SDK has enumerated for this room. */\n cameras: MediaDeviceInfo[];\n /** Microphones the SDK has enumerated for this room. */\n microphones: MediaDeviceInfo[];\n}\n\nexport type GetSelectedDevicesType = (options: HeadlessOptions) => SelectedDevices;\n\n/**\n * Which camera and microphone the SDK is actually using, plus the device lists\n * it has already enumerated.\n *\n * Unlike {@link listMediaDevices} this is synchronous and needs no permission\n * prompt: it reads `userDefaultVideoInputDevice` / `userDefaultAudioInputDevice`\n * and the `videoInputs` / `audioInputs` the SDK populated during setup. Use it\n * to mark the current entry in a device picker; use `listMediaDevices` when you\n * need a freshly enumerated list.\n *\n * @example\n * ```tsx\n * const { cameras, cameraId } = getSelectedDevices({ parameters });\n * <select value={cameraId} onChange={(e) => room.controls.selectCamera(e.target.value)}>\n * {cameras.map((d) => <option key={d.deviceId} value={d.deviceId}>{d.label}</option>)}\n * </select>\n * ```\n */\nexport function getSelectedDevices({ parameters }: HeadlessOptions): SelectedDevices {\n const source = parameters || {};\n return {\n cameraId: source.userDefaultVideoInputDevice || '',\n microphoneId: source.userDefaultAudioInputDevice || '',\n cameras: Array.isArray(source.videoInputs) ? source.videoInputs : [],\n microphones: Array.isArray(source.audioInputs) ? source.audioInputs : [],\n };\n}\n","import { HeadlessOptions, HeadlessParameters } from './headlessTypes';\n\nexport interface MediaPermission {\n /** True when turning this media ON would be accepted right now. */\n allowed: boolean;\n /** Empty when allowed; otherwise the reason, phrased for a user. */\n reason: string;\n /**\n * True when enabling is possible but needs the host to approve first\n * (`audioSetting`/`videoSetting` of 'approval'). The control still works —\n * it raises a request rather than turning media on immediately.\n */\n needsApproval: boolean;\n}\n\nexport interface MediaPermissions {\n microphone: MediaPermission;\n camera: MediaPermission;\n screenShare: MediaPermission;\n /** True when the local user is a host (islevel '2') and bypasses most gates. */\n isHost: boolean;\n /** True when focus mode is on and the local user is not a panelist. */\n focusModeBlocked: boolean;\n}\n\nexport type GetMediaPermissionsType = (\n options: HeadlessOptions\n) => MediaPermissions;\n\nfunction isPanelist(parameters: HeadlessParameters): boolean {\n const panelists = Array.isArray(parameters.panelists) ? parameters.panelists : [];\n return panelists.some((entry: any) => entry?.name === parameters.member);\n}\n\n/**\n * Can this user turn their mic, camera or screen share on *right now*?\n *\n * MediaSFU decides this inside `clickAudio` / `clickVideo` / `clickScreenShare`,\n * which return `void` and report a refusal only through `showAlert`. That means\n * a headless surface finds out a control was blocked *after* the user pressed\n * it — the button looks broken. This evaluates the same gates up front so you\n * can disable the control and say why instead.\n *\n * The branches mirror the SDK's own order: audio-only rooms, host recording\n * locks, `adminRestrictSetting`, focus-mode panelist restrictions, and the\n * `allow` / `approval` / `disallow` settings. Host (`islevel === '2'`) bypasses\n * the participant-level gates, exactly as the controls do.\n *\n * Note this cannot predict two cases: room capacity checks, which the SDK\n * resolves by asking the server (`checkProduce`), and OS-level device\n * permission, which only surfaces when capture is attempted. Treat a `false`\n * here as authoritative and a `true` as \"nothing known blocks it\".\n *\n * @example\n * ```tsx\n * const perms = getMediaPermissions({ parameters });\n * <button disabled={!perms.microphone.allowed} title={perms.microphone.reason}>\n * {perms.microphone.needsApproval ? 'Ask to unmute' : 'Unmute'}\n * </button>\n * ```\n */\nexport function getMediaPermissions({ parameters }: HeadlessOptions): MediaPermissions {\n const source: HeadlessParameters = parameters || {};\n const isHost = String(source.islevel) === '2';\n const recording = Boolean(source.recordStarted || source.recordResumed)\n && !(source.recordPaused || source.recordStopped);\n const focusModeBlocked = Boolean(source.panelistsFocused) && !isHost && !isPanelist(source);\n\n const evaluate = (\n kind: 'audio' | 'video' | 'screenshare'\n ): MediaPermission => {\n const allow = (): MediaPermission => ({ allowed: true, reason: '', needsApproval: false });\n const deny = (reason: string): MediaPermission => ({ allowed: false, reason, needsApproval: false });\n\n // An audio-only room refuses every visual producer outright.\n if (source.audioOnlyRoom && kind !== 'audio') {\n return deny('This is an audio-only event.');\n }\n // The host cannot drop media the recording depends on.\n if (isHost && recording) {\n if (kind === 'audio' && source.recordingMediaOptions === 'audio') {\n return deny('Pause or stop the recording before changing your microphone.');\n }\n if (kind === 'video' && source.recordingMediaOptions === 'video') {\n return deny('Pause or stop the recording before changing your camera.');\n }\n }\n if (isHost) return allow();\n\n if (source.adminRestrictSetting) {\n return deny('Access denied by the host.');\n }\n if (focusModeBlocked && kind === 'audio' && source.muteOthersMic) {\n return deny('Only panelists can unmute while focus mode is active.');\n }\n if (focusModeBlocked && kind === 'video' && source.muteOthersCamera) {\n return deny('Only panelists can enable video while focus mode is active.');\n }\n\n const setting = kind === 'audio'\n ? source.audioSetting\n : kind === 'video'\n ? source.videoSetting\n : source.screenshareSetting;\n if (setting === 'disallow') {\n return deny('The host has disabled this for participants.');\n }\n if (setting === 'approval') {\n // Not a refusal: the control raises a request to the host.\n return { allowed: true, reason: 'The host must approve this.', needsApproval: true };\n }\n return allow();\n };\n\n return {\n microphone: evaluate('audio'),\n camera: evaluate('video'),\n screenShare: evaluate('screenshare'),\n isHost,\n focusModeBlocked,\n };\n}\n\nexport default getMediaPermissions;\n","import { Participant } from '../../../types/types';\nimport { removeParticipants } from '../../participants/removeParticipants';\nimport { respondToWaiting } from '../../waiting/respondToWaiting';\nimport { respondToRequests } from '../../requests/respondToRequests';\nimport { modifyCoHostSettings } from '../../coHostMethods/modifyCoHostSettings';\nimport { HeadlessOptions, HeadlessParameters } from './headlessTypes';\nimport { getCurrentParams } from './getCurrentParams';\nimport { HeadlessActionResult } from './roomActions';\n\n/** The co-host responsibility keys MediaSFU recognises. */\nexport type ModerationArea = 'media' | 'participants' | 'chat' | 'waiting';\n\nexport interface ModerationPermissions {\n /** True when the local user is the host (islevel '2'). */\n isHost: boolean;\n /** True when the local user is the room's co-host. */\n isCoHost: boolean;\n /** Turn other participants' camera/mic/screen off. */\n canControlMedia: boolean;\n /** Remove or ban participants. */\n canManageParticipants: boolean;\n /** Moderate chat. */\n canManageChat: boolean;\n /** Admit or deny people in the waiting room. */\n canManageWaitingRoom: boolean;\n}\n\nexport type GetModerationPermissionsType = (\n options: HeadlessOptions\n) => ModerationPermissions;\n\nfunction hasResponsibility(\n parameters: HeadlessParameters,\n area: ModerationArea\n): boolean {\n const list = Array.isArray(parameters?.coHostResponsibility)\n ? parameters.coHostResponsibility\n : [];\n return list.find((item: any) => item?.name === area)?.value === true;\n}\n\n/**\n * What the local user is allowed to moderate.\n *\n * MediaSFU's rule is `islevel === '2' || (coHost === member && <area>.value)`,\n * and it is enforced *inside* each action — an unauthorised call is swallowed\n * with an alert rather than returning an error. That makes it very easy to ship\n * a moderation button that silently does nothing for co-hosts. Gate your UI on\n * this instead.\n *\n * @example\n * ```ts\n * import { getModerationPermissions } from 'mediasfu-shared';\n *\n * const perms = getModerationPermissions({ parameters });\n * <button disabled={!perms.canControlMedia}>Mute everyone</button>\n * ```\n */\nexport function getModerationPermissions({\n parameters,\n}: HeadlessOptions): ModerationPermissions {\n const source = parameters || {};\n const isHost = String(source.islevel) === '2';\n const isCoHost = Boolean(source.coHost && source.coHost === source.member);\n const allow = (area: ModerationArea) =>\n isHost || (isCoHost && hasResponsibility(source, area));\n return {\n isHost,\n isCoHost,\n canControlMedia: allow('media'),\n canManageParticipants: allow('participants'),\n canManageChat: allow('chat'),\n canManageWaitingRoom: allow('waiting'),\n };\n}\n\nfunction participantList(parameters: HeadlessParameters): Participant[] {\n const source = parameters || {};\n const primary = Array.isArray(source.participants) ? source.participants : [];\n if (primary.length > 0) return primary;\n return Array.isArray(source.participantsAll) ? source.participantsAll : [];\n}\n\nfunction findParticipant(\n parameters: HeadlessParameters,\n { id, name }: { id?: string; name?: string }\n): Participant | null {\n const participants = participantList(parameters);\n return (\n (id ? participants.find((part) => part.id === id) : undefined) ||\n (name ? participants.find((part) => part.name === name) : undefined) ||\n null\n );\n}\n\nexport interface SetParticipantMediaOptions extends HeadlessOptions {\n /** Participant display name. */\n name?: string;\n /** Participant id. Takes precedence over `name`. */\n id?: string;\n /** Which media to switch off. */\n kind: 'audio' | 'video' | 'screenshare' | 'all';\n}\n\nexport type SetParticipantMediaType = (\n options: SetParticipantMediaOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Turn a participant's media off as host or authorised co-host.\n *\n * This is one-directional by design: MediaSFU lets a moderator *stop* someone's\n * camera, microphone or screen share, but cannot start it on their behalf — the\n * participant must re-enable it themselves.\n *\n * The SDK's own `controlMedia` consumer only emits for `type: 'audio'` and\n * `type: 'video'`; `'all'` and `'screenshare'` fall through its guard and do\n * nothing. This helper emits the `controlMedia` event directly with the same\n * permission and self-protection checks applied uniformly, so every kind works.\n * Hosts (`islevel === '2'`) cannot be muted by anyone, including other hosts.\n *\n * @example\n * ```ts\n * import { setParticipantMedia } from 'mediasfu-shared';\n *\n * await setParticipantMedia({ parameters, name: 'Paul', kind: 'video' });\n * await setParticipantMedia({ parameters, name: 'Paul', kind: 'all' });\n * ```\n */\nexport async function setParticipantMedia({\n parameters,\n name = '',\n id = '',\n kind,\n}: SetParticipantMediaOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const permissions = getModerationPermissions({ parameters: live });\n if (!permissions.canControlMedia) {\n return {\n ok: false,\n error: 'You are not allowed to control media for other participants.',\n };\n }\n const socket = live?.socket;\n if (!socket || typeof socket.emit !== 'function' || !live?.roomName) {\n return { ok: false, error: 'The room connection is not ready.' };\n }\n const participant = findParticipant(live, { id, name });\n if (!participant) return { ok: false, error: 'That participant is not in the room.' };\n if (String(participant.islevel) === '2') {\n return { ok: false, error: 'A host’s media cannot be turned off.' };\n }\n\n socket.emit('controlMedia', {\n participantId: participant.id,\n participantName: participant.name,\n type: kind,\n roomName: live.roomName,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The media control failed.' };\n }\n}\n\nexport interface ModerateParticipantOptions extends HeadlessOptions {\n name?: string;\n id?: string;\n}\n\n/** Mute a participant's microphone. See {@link setParticipantMedia}. */\nexport function muteParticipant(\n options: ModerateParticipantOptions\n): Promise<HeadlessActionResult> {\n return setParticipantMedia({ ...options, kind: 'audio' });\n}\n\n/** Turn a participant's camera off. See {@link setParticipantMedia}. */\nexport function disableParticipantVideo(\n options: ModerateParticipantOptions\n): Promise<HeadlessActionResult> {\n return setParticipantMedia({ ...options, kind: 'video' });\n}\n\n/** Stop a participant's screen share. See {@link setParticipantMedia}. */\nexport function stopParticipantScreenShare(\n options: ModerateParticipantOptions\n): Promise<HeadlessActionResult> {\n return setParticipantMedia({ ...options, kind: 'screenshare' });\n}\n\nexport interface MuteEveryoneOptions extends HeadlessOptions {\n /** Which media to switch off for everyone. Defaults to `audio`. */\n kind?: 'audio' | 'video' | 'screenshare' | 'all';\n}\n\nexport type MuteEveryoneType = (\n options: MuteEveryoneOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Turn media off for every non-host participant.\n *\n * MediaSFU has no bulk primitive, so this fans out per participant. Hosts and\n * the local user are skipped. Succeeds if at least one participant was\n * actioned; reports the failure otherwise.\n */\nexport async function muteEveryone({\n parameters,\n kind = 'audio',\n}: MuteEveryoneOptions): Promise<HeadlessActionResult> {\n const live = getCurrentParams({ parameters });\n const permissions = getModerationPermissions({ parameters: live });\n if (!permissions.canControlMedia) {\n return {\n ok: false,\n error: 'You are not allowed to control media for other participants.',\n };\n }\n const targets = participantList(live).filter(\n (part) => String(part.islevel) !== '2' && part.name !== live.member\n );\n if (targets.length === 0) return { ok: false, error: 'There is nobody else to mute.' };\n\n const results = await Promise.all(\n targets.map((part) =>\n setParticipantMedia({ parameters: live, id: part.id, name: part.name, kind })\n )\n );\n const failed = results.filter((result) => !result.ok);\n if (failed.length === results.length) {\n return { ok: false, error: failed[0]?.error || 'No participant could be muted.' };\n }\n return { ok: true, error: '' };\n}\n\nexport type RemoveParticipantType = (\n options: ModerateParticipantOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Remove a participant from the room.\n *\n * @example\n * ```ts\n * await removeParticipant({ parameters, name: 'Paul' });\n * ```\n */\nexport async function removeParticipant({\n parameters,\n name = '',\n id = '',\n}: ModerateParticipantOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const permissions = getModerationPermissions({ parameters: live });\n if (!permissions.canManageParticipants) {\n return { ok: false, error: 'You are not allowed to remove participants.' };\n }\n const participant = findParticipant(live, { id, name });\n if (!participant) return { ok: false, error: 'That participant is not in the room.' };\n if (String(participant.islevel) === '2') {\n return { ok: false, error: 'A host cannot be removed.' };\n }\n await removeParticipants({\n coHostResponsibility: live.coHostResponsibility || [],\n participant,\n member: live.member || '',\n islevel: live.islevel || '1',\n showAlert: live.showAlert,\n coHost: live.coHost || '',\n participants: participantList(live),\n socket: live.socket,\n roomName: live.roomName || '',\n updateParticipants: live.updateParticipants,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The participant could not be removed.' };\n }\n}\n\nexport interface RespondToWaitingParticipantOptions extends HeadlessOptions {\n name?: string;\n id?: string;\n /** True to admit, false to deny. */\n admit: boolean;\n}\n\nexport type RespondToWaitingParticipantType = (\n options: RespondToWaitingParticipantOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Admit or deny somebody waiting to join.\n *\n * Reads `waitingRoomList` off the bag, so you only supply the person's name or\n * id and whether to let them in.\n *\n * @example\n * ```ts\n * for (const person of parameters.waitingRoomList ?? []) {\n * await respondToWaitingParticipant({ parameters, id: person.id, admit: true });\n * }\n * ```\n */\nexport async function respondToWaitingParticipant({\n parameters,\n name = '',\n id = '',\n admit,\n}: RespondToWaitingParticipantOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const permissions = getModerationPermissions({ parameters: live });\n if (!permissions.canManageWaitingRoom) {\n return { ok: false, error: 'You are not allowed to manage the waiting room.' };\n }\n const waitingList = Array.isArray(live.waitingRoomList) ? live.waitingRoomList : [];\n const entry =\n (id ? waitingList.find((person: any) => person?.id === id) : undefined) ||\n (name ? waitingList.find((person: any) => person?.name === name) : undefined);\n if (!entry) return { ok: false, error: 'That person is no longer waiting to join.' };\n\n await respondToWaiting({\n participantId: entry.id,\n participantName: entry.name,\n updateWaitingList: live.updateWaitingRoomList,\n waitingList,\n type: admit,\n roomName: live.roomName || '',\n socket: live.socket,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return {\n ok: false,\n error: error?.message || 'The waiting-room response failed.',\n };\n }\n}\n\nexport interface RespondToParticipantRequestOptions extends HeadlessOptions {\n /** The request id from `parameters.requestList`. */\n requestId?: string;\n /** Or match by requester name. */\n name?: string;\n /** True to approve, false to reject. */\n approve: boolean;\n}\n\nexport type RespondToParticipantRequestType = (\n options: RespondToParticipantRequestOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Approve or reject a participant request (raise hand, ask to share, ask to\n * speak). Requests live on `parameters.requestList`; each carries an `icon`\n * naming the capability being asked for.\n */\nexport async function respondToParticipantRequest({\n parameters,\n requestId = '',\n name = '',\n approve,\n}: RespondToParticipantRequestOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const permissions = getModerationPermissions({ parameters: live });\n if (!permissions.canManageParticipants) {\n return { ok: false, error: 'You are not allowed to respond to requests.' };\n }\n const requestList = Array.isArray(live.requestList) ? live.requestList : [];\n const request =\n (requestId\n ? requestList.find((item: any) => item?.id === requestId)\n : undefined) ||\n (name\n ? requestList.find(\n (item: any) => item?.name === name || item?.username === name\n )\n : undefined);\n if (!request) return { ok: false, error: 'That request is no longer pending.' };\n\n await respondToRequests({\n socket: live.socket,\n request,\n updateRequestList: live.updateRequestList,\n requestList,\n action: approve ? 'accepted' : 'rejected',\n roomName: live.roomName || '',\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The request response failed.' };\n }\n}\n\nexport interface SetCoHostOptions extends HeadlessOptions {\n /** Participant to promote. Pass '' to clear the current co-host. */\n name: string;\n /** Areas the co-host may moderate. Defaults to media + participants. */\n areas?: ModerationArea[];\n}\n\nexport type SetCoHostType = (\n options: SetCoHostOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Promote a participant to co-host and choose what they may moderate.\n *\n * Only the host may do this. Areas not listed are explicitly disabled, so this\n * sets the complete responsibility set rather than merging with the previous one.\n *\n * @example\n * ```ts\n * await setCoHost({ parameters, name: 'Paul', areas: ['media', 'waiting'] });\n * ```\n */\nexport async function setCoHost({\n parameters,\n name,\n areas = ['media', 'participants'],\n}: SetCoHostOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (String(live.islevel) !== '2') {\n return { ok: false, error: 'Only the host can assign a co-host.' };\n }\n const all: ModerationArea[] = ['media', 'participants', 'chat', 'waiting'];\n const responsibilities = all.map((area) => ({\n name: area,\n value: areas.includes(area),\n dedicated: false,\n }));\n\n await modifyCoHostSettings({\n roomName: live.roomName || '',\n showAlert: live.showAlert,\n selectedParticipant: name,\n coHost: live.coHost || '',\n coHostResponsibility: responsibilities,\n updateIsCoHostModalVisible:\n live.updateIsCoHostModalVisible || (() => undefined),\n updateCoHostResponsibility: live.updateCoHostResponsibility,\n updateCoHost: live.updateCoHost,\n socket: live.socket,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The co-host update failed.' };\n }\n}\n","import { confirmRecording } from '../../recording/confirmRecording';\nimport { startRecording } from '../../recording/startRecording';\nimport { stopRecording } from '../../recording/stopRecording';\nimport { updateRecording } from '../../recording/updateRecording';\nimport { handleCreatePoll } from '../../polls/handleCreatePoll';\nimport { handleVotePoll } from '../../polls/handleVotePoll';\nimport { handleEndPoll } from '../../polls/handleEndPoll';\nimport { HeadlessOptions, HeadlessParameters } from './headlessTypes';\nimport { getCurrentParams } from './getCurrentParams';\nimport { HeadlessActionResult } from './roomActions';\n\nconst noop = () => undefined;\n\n/* ------------------------------------------------------------------ *\n * Recording\n * ------------------------------------------------------------------ */\n\nexport type RecordingStatus =\n | 'unavailable'\n | 'idle'\n | 'recording'\n | 'paused'\n | 'stopped';\n\nexport interface RecordingState {\n status: RecordingStatus;\n /** True while frames are being captured right now. */\n active: boolean;\n /** The local user may start/stop recording. */\n canRecord: boolean;\n /** 'video' | 'audio' — what the room is configured to capture. */\n mediaOptions: string;\n /** Seconds elapsed, as reported by the SDK. */\n elapsedSeconds: number;\n}\n\nexport type GetRecordingStateType = (options: HeadlessOptions) => RecordingState;\n\n/**\n * Collapse MediaSFU's four recording booleans into one status.\n *\n * The SDK tracks `recordStarted`, `recordPaused`, `recordResumed` and\n * `recordStopped` independently, and they overlap — after a pause/resume cycle\n * `recordStarted` and `recordResumed` are both true. Deriving \"is it recording?\"\n * from any single flag gives the wrong answer at least once per session.\n *\n * @example\n * ```ts\n * const recording = getRecordingState({ parameters });\n * if (recording.status === 'paused') showResumeButton();\n * ```\n */\nexport function getRecordingState({ parameters }: HeadlessOptions): RecordingState {\n const source: HeadlessParameters = parameters || {};\n const canRecord = source.canRecord === true;\n let status: RecordingStatus = 'idle';\n if (!canRecord && !source.recordStarted) status = 'unavailable';\n else if (source.recordStopped) status = 'stopped';\n else if (source.recordStarted && source.recordPaused) status = 'paused';\n else if (source.recordStarted) status = 'recording';\n\n return {\n status,\n active: status === 'recording',\n canRecord,\n mediaOptions: source.recordingMediaOptions || 'video',\n elapsedSeconds: Number(source.recordElapsedTime) || 0,\n };\n}\n\nexport type RecordingActionType = (\n options: HeadlessOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Start recording.\n *\n * MediaSFU requires `confirmRecording` before `startRecording` — it validates\n * the room's recording settings against the current layout and populates the\n * state `startRecording` then reads. Calling `startRecording` alone appears to\n * do nothing. This runs both steps in order.\n *\n * @example\n * ```ts\n * import { startRoomRecording } from 'mediasfu-shared';\n *\n * const result = await startRoomRecording({ parameters });\n * if (!result.ok) setNotice(result.error);\n * ```\n */\nexport async function startRoomRecording({\n parameters,\n}: HeadlessOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (live.canRecord !== true) {\n return { ok: false, error: 'Recording is not available in this room.' };\n }\n if (live.recordStarted && !live.recordStopped) {\n return { ok: false, error: 'Recording has already started.' };\n }\n await confirmRecording({ parameters: live as any });\n const refreshed = getCurrentParams({ parameters: live });\n await startRecording({ parameters: refreshed as any });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Recording could not be started.' };\n }\n}\n\n/** Pause an active recording. */\nexport async function pauseRoomRecording({\n parameters,\n}: HeadlessOptions): Promise<HeadlessActionResult> {\n return toggleRecordingPause(parameters, true);\n}\n\n/** Resume a paused recording. */\nexport async function resumeRoomRecording({\n parameters,\n}: HeadlessOptions): Promise<HeadlessActionResult> {\n return toggleRecordingPause(parameters, false);\n}\n\nasync function toggleRecordingPause(\n parameters: HeadlessParameters,\n pause: boolean\n): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const state = getRecordingState({ parameters: live });\n if (state.status !== (pause ? 'recording' : 'paused')) {\n return {\n ok: false,\n error: pause\n ? 'There is no active recording to pause.'\n : 'There is no paused recording to resume.',\n };\n }\n // `updateRecording` is the SDK's pause/resume toggle; it decides direction\n // from the current recordPaused state, which we just validated.\n await updateRecording({ parameters: live as any });\n return { ok: true, error: '' };\n } catch (error: any) {\n return {\n ok: false,\n error: error?.message || 'The recording state could not be changed.',\n };\n }\n}\n\n/** Stop recording. The file becomes available through the MediaSFU API. */\nexport async function stopRoomRecording({\n parameters,\n}: HeadlessOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (!live.recordStarted || live.recordStopped) {\n return { ok: false, error: 'There is no active recording to stop.' };\n }\n await stopRecording({ parameters: live as any });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Recording could not be stopped.' };\n }\n}\n\n/* ------------------------------------------------------------------ *\n * Whiteboard\n * ------------------------------------------------------------------ */\n\nexport interface WhiteboardState {\n /** True while a whiteboard session is running. */\n active: boolean;\n /** The local user may start one. */\n canStart: boolean;\n /** Participants granted drawing rights. */\n users: any[];\n /** Maximum participants the room's plan allows on a whiteboard. */\n limit: number;\n /** The live canvas element, when the SDK has created one. */\n canvas: HTMLCanvasElement | null;\n}\n\nexport type GetWhiteboardStateType = (\n options: HeadlessOptions\n) => WhiteboardState;\n\n/**\n * Current whiteboard session state.\n *\n * `whiteboardStarted` alone is not enough — the SDK leaves it true after a\n * session ends and sets `whiteboardEnded` alongside it, so \"active\" is\n * `started && !ended`.\n */\nexport function getWhiteboardState({ parameters }: HeadlessOptions): WhiteboardState {\n const source: HeadlessParameters = parameters || {};\n return {\n active: source.whiteboardStarted === true && source.whiteboardEnded !== true,\n canStart: source.canStartWhiteboard === true,\n users: Array.isArray(source.whiteboardUsers) ? source.whiteboardUsers : [],\n limit: Number(source.whiteboardLimit) || 0,\n canvas: source.canvasWhiteboard || null,\n };\n}\n\nexport interface StartWhiteboardOptions extends HeadlessOptions {\n /** Participants allowed to draw. Defaults to the room's current selection. */\n users?: any[];\n}\n\nexport type StartWhiteboardType = (\n options: StartWhiteboardOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Start (or reconfigure) the shared whiteboard.\n *\n * Emits `startWhiteboard` for a new session and `updateWhiteboard` when one is\n * already running, matching the SDK's own modal. Breakout rooms and the\n * whiteboard are mutually exclusive, which is checked here.\n *\n * This applies the session state only. Layout follow-up (`onScreenChanges`,\n * `prepopulateUserMedia`, main-pane sizing) is deliberately left to you, since a\n * headless surface owns its own layout.\n *\n * @example\n * ```ts\n * await startWhiteboard({ parameters, users: [{ name: 'Paul' }] });\n * ```\n */\nexport async function startWhiteboard({\n parameters,\n users,\n}: StartWhiteboardOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (live.breakOutRoomStarted && !live.breakOutRoomEnded) {\n return {\n ok: false,\n error: 'The whiteboard cannot start while breakout rooms are active.',\n };\n }\n const socket = live?.socket;\n if (!socket || typeof socket.emit !== 'function' || !live?.roomName) {\n return { ok: false, error: 'The room connection is not ready.' };\n }\n const state = getWhiteboardState({ parameters: live });\n if (!state.active && !state.canStart) {\n return { ok: false, error: 'You are not allowed to start the whiteboard.' };\n }\n const whiteboardUsers = users ?? state.users;\n if (state.limit > 0 && whiteboardUsers.length > state.limit) {\n return {\n ok: false,\n error: `The whiteboard allows at most ${state.limit} participants.`,\n };\n }\n\n const event = state.active ? 'updateWhiteboard' : 'startWhiteboard';\n const response = await new Promise<any>((resolve) => {\n socket.emit(event, { whiteboardUsers, roomName: live.roomName }, resolve);\n });\n if (!response?.success) {\n return {\n ok: false,\n error: response?.reason || 'The whiteboard could not be started.',\n };\n }\n live.updateWhiteboardStarted?.(true);\n live.updateWhiteboardEnded?.(false);\n live.updateWhiteboardUsers?.(whiteboardUsers);\n live.updateCanStartWhiteboard?.(false);\n return { ok: true, error: '' };\n } catch (error: any) {\n return {\n ok: false,\n error: error?.message || 'The whiteboard could not be started.',\n };\n }\n}\n\nexport type StopWhiteboardType = (\n options: HeadlessOptions\n) => Promise<HeadlessActionResult>;\n\n/** End the shared whiteboard session. */\nexport async function stopWhiteboard({\n parameters,\n}: HeadlessOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const socket = live?.socket;\n if (!socket || typeof socket.emit !== 'function' || !live?.roomName) {\n return { ok: false, error: 'The room connection is not ready.' };\n }\n if (!getWhiteboardState({ parameters: live }).active) {\n return { ok: false, error: 'The whiteboard is not running.' };\n }\n const response = await new Promise<any>((resolve) => {\n socket.emit('stopWhiteboard', { roomName: live.roomName }, resolve);\n });\n if (!response?.success) {\n return {\n ok: false,\n error: response?.reason || 'The whiteboard could not be stopped.',\n };\n }\n live.updateWhiteboardStarted?.(false);\n live.updateWhiteboardEnded?.(true);\n return { ok: true, error: '' };\n } catch (error: any) {\n return {\n ok: false,\n error: error?.message || 'The whiteboard could not be stopped.',\n };\n }\n}\n\n/* ------------------------------------------------------------------ *\n * Polls\n * ------------------------------------------------------------------ */\n\nexport interface PollState {\n /** Every poll the room has seen. */\n polls: any[];\n /** The poll currently open for voting, if any. */\n active: any | null;\n}\n\nexport type GetPollStateType = (options: HeadlessOptions) => PollState;\n\n/** Polls in the room, plus whichever one is currently open. */\nexport function getPollState({ parameters }: HeadlessOptions): PollState {\n const source: HeadlessParameters = parameters || {};\n const polls = Array.isArray(source.polls) ? source.polls : [];\n const active =\n source.poll && source.poll.status === 'active'\n ? source.poll\n : polls.find((entry: any) => entry?.status === 'active') || null;\n return { polls, active };\n}\n\nexport interface CreatePollOptions extends HeadlessOptions {\n question: string;\n options: string[];\n /** Defaults to 'custom'. */\n type?: string;\n}\n\nexport type CreateRoomPollType = (\n options: CreatePollOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Open a poll.\n *\n * @example\n * ```ts\n * await createRoomPoll({\n * parameters,\n * question: 'Ship on Friday?',\n * options: ['Yes', 'No'],\n * });\n * ```\n */\nexport async function createRoomPoll({\n parameters,\n question,\n options,\n type = 'custom',\n}: CreatePollOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (!question?.trim()) return { ok: false, error: 'The poll needs a question.' };\n if (!Array.isArray(options) || options.length < 2) {\n return { ok: false, error: 'The poll needs at least two options.' };\n }\n await handleCreatePoll({\n poll: { question, options, type } as any,\n socket: live.socket,\n roomName: live.roomName || '',\n showAlert: live.showAlert,\n updateIsPollModalVisible: live.updateIsPollModalVisible || noop,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The poll could not be created.' };\n }\n}\n\nexport interface VotePollOptions extends HeadlessOptions {\n pollId: string;\n optionIndex: number;\n}\n\n/** Cast a vote in an open poll. */\nexport async function voteInRoomPoll({\n parameters,\n pollId,\n optionIndex,\n}: VotePollOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n await handleVotePoll({\n pollId,\n optionIndex,\n socket: live.socket,\n showAlert: live.showAlert,\n member: live.member || '',\n roomName: live.roomName || '',\n updateIsPollModalVisible: live.updateIsPollModalVisible || noop,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The vote could not be cast.' };\n }\n}\n\nexport interface EndPollOptions extends HeadlessOptions {\n pollId: string;\n}\n\n/** Close a poll. Host only. */\nexport async function endRoomPoll({\n parameters,\n pollId,\n}: EndPollOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (String(live.islevel) !== '2') {\n return { ok: false, error: 'Only the host can end a poll.' };\n }\n await handleEndPoll({\n pollId,\n socket: live.socket,\n showAlert: live.showAlert,\n roomName: live.roomName || '',\n updateIsPollModalVisible: live.updateIsPollModalVisible || noop,\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The poll could not be ended.' };\n }\n}\n\n/* ------------------------------------------------------------------ *\n * Breakout rooms\n * ------------------------------------------------------------------ */\n\nexport interface BreakoutState {\n /** True while breakout rooms are running. */\n active: boolean;\n /** The local user may start them. */\n canStart: boolean;\n /** Room composition as the SDK holds it. */\n rooms: any[];\n /** The breakout room the local user is in, or -1. */\n currentRoom: number;\n}\n\nexport type GetBreakoutStateType = (options: HeadlessOptions) => BreakoutState;\n\n/**\n * Breakout-room state.\n *\n * Same `started && !ended` shape as the whiteboard, and the two are mutually\n * exclusive — check this before offering a whiteboard control.\n */\nexport function getBreakoutState({ parameters }: HeadlessOptions): BreakoutState {\n const source: HeadlessParameters = parameters || {};\n return {\n active:\n source.breakOutRoomStarted === true && source.breakOutRoomEnded !== true,\n canStart: source.canStartBreakout === true,\n rooms: Array.isArray(source.breakoutRooms) ? source.breakoutRooms : [],\n currentRoom:\n typeof source.hostNewRoom === 'number' ? source.hostNewRoom : -1,\n };\n}\n","import { HeadlessOptions, HeadlessParameters } from './headlessTypes';\n\n/* ------------------------------------------------------------------ *\n * Recording notices and limits\n * ------------------------------------------------------------------ */\n\nexport interface RecordingNotice {\n /** The SDK's current recording notice, or '' when there is none. */\n message: string;\n /** Formatted elapsed time as the SDK reports it (e.g. \"00:12:04\"). */\n elapsed: string;\n /** Elapsed seconds. */\n elapsedSeconds: number;\n /** True while pause/resume is permitted (the SDK enforces a cooldown). */\n canPauseResume: boolean;\n /** Pauses used so far. */\n pausesUsed: number;\n /** Pauses allowed for the active media type; 0 when unpublished. */\n pauseLimit: number;\n /** True when the pause allowance is exhausted. */\n pauseLimitReached: boolean;\n}\n\nexport type GetRecordingNoticeType = (options: HeadlessOptions) => RecordingNotice;\n\n/**\n * The user-facing side of recording: the notice, the timer, and the pause\n * allowance.\n *\n * Pause limits are per media type — `recordingAudioPausesLimit` vs\n * `recordingVideoPausesLimit` — and the SDK picks by `recordingMediaOptions`.\n * Reading the wrong one reports the wrong allowance, which is why this is a\n * helper rather than a field read. Complements `getRecordingState`, which\n * covers only the start/pause/resume/stop status.\n */\nexport function getRecordingNotice({ parameters }: HeadlessOptions): RecordingNotice {\n const source: HeadlessParameters = parameters || {};\n const isAudio = source.recordingMediaOptions === 'audio';\n const pauseLimit = Number(\n isAudio ? source.recordingAudioPausesLimit : source.recordingVideoPausesLimit\n ) || 0;\n const pausesUsed = Number(source.pauseRecordCount) || 0;\n return {\n message: source.recordingNotice || '',\n elapsed: source.recordingProgressTime || '00:00:00',\n elapsedSeconds: Number(source.recordElapsedTime) || 0,\n canPauseResume: source.canPauseResume === true,\n pausesUsed,\n pauseLimit,\n pauseLimitReached: pauseLimit > 0 && pausesUsed >= pauseLimit,\n };\n}\n\nexport interface RecordingCapabilities {\n /** Recording audio at all. */\n audio: boolean;\n /** Recording video at all. */\n video: boolean;\n /** Recording every participant, not just the active speaker. */\n allParticipants: boolean;\n /** Recording every participant's video. */\n videoParticipants: boolean;\n /** Adding an HLS output. */\n hls: boolean;\n /** Max people included in an audio recording; 0 when unpublished. */\n audioPeopleLimit: number;\n /** Max people included in a video recording; 0 when unpublished. */\n videoPeopleLimit: number;\n}\n\nexport type GetRecordingCapabilitiesType = (\n options: HeadlessOptions\n) => RecordingCapabilities;\n\n/**\n * What this room's plan actually permits recording.\n *\n * These are entitlement flags the server publishes per room, so a UI should\n * gate on them rather than offering options the room will refuse.\n */\nexport function getRecordingCapabilities({\n parameters,\n}: HeadlessOptions): RecordingCapabilities {\n const source: HeadlessParameters = parameters || {};\n return {\n audio: source.recordingAudioSupport === true,\n video: source.recordingVideoSupport === true,\n allParticipants: source.recordingAllParticipantsSupport === true,\n videoParticipants: source.recordingVideoParticipantsSupport === true,\n hls: source.recordingAddHLS === true,\n audioPeopleLimit: Number(source.recordingAudioPeopleLimit) || 0,\n videoPeopleLimit: Number(source.recordingVideoPeopleLimit) || 0,\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Translation\n * ------------------------------------------------------------------ */\n\nexport interface TranslationPreference {\n /** Language applied to every speaker, or null when unset. */\n globalLanguage: string | null;\n /** Per-speaker overrides, keyed by speaker id. */\n perSpeaker: { speakerId: string; language: string | null; wantOriginal: boolean }[];\n}\n\nexport interface TranslationState extends TranslationPreference {\n /** True when any translation is currently being consumed. */\n active: boolean;\n /** Languages the room currently has translation producers for. */\n availableLanguages: string[];\n}\n\nexport type GetTranslationStateType = (options: HeadlessOptions) => TranslationState;\n\n/**\n * What the listener is currently hearing, and what is on offer.\n *\n * `listenerTranslationPreferences.perSpeaker` is a `Map` on the bag, which does\n * not survive serialisation or spread; this returns a plain array so it can be\n * rendered and compared normally. Translation audio itself already reaches the\n * user through `getAudioGridComponents`, which folds in `translationStreams`.\n */\nexport function getTranslationState({ parameters }: HeadlessOptions): TranslationState {\n const source: HeadlessParameters = parameters || {};\n const preferences: any = source.listenerTranslationPreferences || {};\n const perSpeakerMap = preferences.perSpeaker;\n const perSpeaker = perSpeakerMap instanceof Map\n ? Array.from(perSpeakerMap.values())\n : Array.isArray(perSpeakerMap) ? perSpeakerMap : [];\n\n const speakerStates: any = source.speakerTranslationStates;\n const languages = new Set<string>();\n const collect = (value: any) => {\n if (value?.language) languages.add(value.language);\n };\n if (speakerStates instanceof Map) speakerStates.forEach(collect);\n else if (Array.isArray(speakerStates)) speakerStates.forEach(collect);\n perSpeaker.forEach(collect);\n if (preferences.globalLanguage) languages.add(preferences.globalLanguage);\n\n return {\n globalLanguage: preferences.globalLanguage ?? null,\n perSpeaker,\n active: Boolean(\n preferences.globalLanguage\n || perSpeaker.some((entry) => entry?.language && !entry.wantOriginal)\n ),\n availableLanguages: Array.from(languages),\n };\n}\n\nexport interface SetTranslationPreferenceOptions extends HeadlessOptions {\n /** Language for every speaker. `null` restores the original audio. */\n language?: string | null;\n /** Limit the change to one speaker. */\n speakerId?: string;\n /** Explicitly prefer the untranslated audio for this speaker. */\n wantOriginal?: boolean;\n}\n\nexport type SetTranslationPreferenceType = (\n options: SetTranslationPreferenceOptions\n) => { ok: boolean; error: string };\n\n/**\n * Choose a translation language, globally or for one speaker.\n *\n * Delegates to the SDK's `updateListenerTranslationPreferences`, which is what\n * syncs the choice to the server for routing and billing — setting the bag's\n * fields directly would change local state without telling the server.\n */\nexport function setTranslationPreference({\n parameters,\n language = null,\n speakerId,\n wantOriginal = false,\n}: SetTranslationPreferenceOptions): { ok: boolean; error: string } {\n const source: HeadlessParameters = parameters || {};\n const update = source.updateListenerTranslationPreferences;\n if (typeof update !== 'function') {\n return { ok: false, error: 'Translation is not available in this room.' };\n }\n try {\n const current: any = source.listenerTranslationPreferences || {};\n const perSpeaker = current.perSpeaker instanceof Map\n ? new Map(current.perSpeaker)\n : new Map();\n if (speakerId) {\n perSpeaker.set(speakerId, { speakerId, language, wantOriginal });\n update({ perSpeaker, globalLanguage: current.globalLanguage ?? null });\n } else {\n update({ perSpeaker, globalLanguage: language });\n }\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The translation preference could not be set.' };\n }\n}\n\n/* ------------------------------------------------------------------ *\n * Panelists and focus mode\n * ------------------------------------------------------------------ */\n\nexport interface FocusModeState {\n /** True while focus mode is active. */\n active: boolean;\n /** Participants permitted to speak/appear while focus mode is on. */\n panelists: { name: string; [key: string]: any }[];\n /** True when the local user is one of them. */\n selfIsPanelist: boolean;\n /** True when focus mode silences non-panelist microphones. */\n mutesMicrophones: boolean;\n /** True when focus mode blocks non-panelist cameras. */\n mutesCameras: boolean;\n}\n\nexport type GetFocusModeStateType = (options: HeadlessOptions) => FocusModeState;\n\n/**\n * Focus-mode (\"only panelists\") state.\n *\n * The field is `muteOthersCamera`, not `muteOthersVideo` — worth stating,\n * because the neighbouring flag is `muteOthersMic` and the asymmetry invites a\n * wrong guess. {@link getMediaPermissions} already applies these rules to the\n * local user; this exposes the room-level picture for a roster UI.\n */\nexport function getFocusModeState({ parameters }: HeadlessOptions): FocusModeState {\n const source: HeadlessParameters = parameters || {};\n const panelists = Array.isArray(source.panelists) ? source.panelists : [];\n return {\n active: source.panelistsFocused === true,\n panelists,\n selfIsPanelist: panelists.some((entry: any) => entry?.name === source.member),\n mutesMicrophones: source.muteOthersMic === true,\n mutesCameras: source.muteOthersCamera === true,\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Virtual background\n * ------------------------------------------------------------------ */\n\nexport interface VirtualBackgroundState {\n /** True when a processed (background-applied) stream is being published. */\n active: boolean;\n /** The processed stream, when one exists. */\n stream: MediaStream | null;\n /** The background currently applied, if the SDK reports one. */\n appliedBackground: any;\n /** The image the user selected, if any. */\n selectedImage: string | null;\n}\n\nexport type GetVirtualBackgroundStateType = (\n options: HeadlessOptions\n) => VirtualBackgroundState;\n\n/**\n * Read-only virtual-background state.\n *\n * **You do not need this to render the right self-view.**\n * `getLocalVideoStream` already returns the processed `virtualStream` whenever\n * `keepBackground` is on, and the raw camera otherwise — the same rule the SDK's\n * own grid uses. Rendering `localStreamVideo` directly is what shows a user\n * their *unprocessed* background, so prefer the helper and ignore this.\n *\n * This exists for UI that needs to *describe* the state (\"Background on\"), not\n * to choose a stream.\n *\n * Known gap: applying or clearing a background is still modal-driven in the SDK\n * (`isBackgroundModalVisible` / `autoClickBackground`), so a `returnUI={false}`\n * surface cannot currently turn a background on by itself. Reading works\n * headlessly; controlling does not.\n */\nexport function getVirtualBackgroundState({\n parameters,\n}: HeadlessOptions): VirtualBackgroundState {\n const source: HeadlessParameters = parameters || {};\n const stream = (source.virtualStream || source.processedStream) as MediaStream | null;\n return {\n active: source.keepBackground === true && Boolean(stream),\n stream: stream || null,\n appliedBackground: source.appliedBackground ?? null,\n selectedImage: source.selectedImage ?? null,\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Local playback control (per-participant)\n * ------------------------------------------------------------------ */\n\nexport interface SetParticipantPlaybackOptions extends HeadlessOptions {\n /** Participant display name. */\n name?: string;\n /** Producer id, when you already hold one. */\n producerId?: string;\n /** Which of their tracks to affect. Defaults to both. */\n kind?: 'audio' | 'video' | 'all';\n /** True to stop receiving, false to resume. */\n paused: boolean;\n}\n\nexport type SetParticipantPlaybackType = (\n options: SetParticipantPlaybackOptions\n) => Promise<{ ok: boolean; error: string; affected: number }>;\n\n/**\n * Producer ids this viewer has locally paused.\n *\n * Module-level rather than on the parameter bag: the SDK owns that bag and\n * rebuilds it, and this is a purely local preference that must survive those\n * rebuilds so `reapplyLocalPlayback` can re-assert it after a layout pass.\n */\nconst LOCALLY_PAUSED = new Set<string>();\n\n/**\n * Stop or resume playing one participant's media **for you only**.\n *\n * This is a local, per-viewer control — \"don't play this person to me right\n * now\". It pauses the mediasoup consumer, so the server stops sending that\n * track to you: it saves bandwidth as well as silencing them, and it is\n * invisible to everyone else. It is NOT moderation — the participant keeps\n * publishing and other people keep receiving. Use `setParticipantMedia` from\n * the moderation module to actually stop someone's media for the room.\n *\n * Note this is deliberately not `resumePauseStreams`, which the SDK drives from\n * the active-speaker layout (`dispActiveNames`) and will happily undo a manual\n * choice on its next pass. This targets the consumer directly.\n *\n * @example\n * ```ts\n * // Stop hearing and seeing Paul locally\n * await setParticipantPlayback({ parameters, name: 'Paul', paused: true });\n * // Just their audio\n * await setParticipantPlayback({ parameters, name: 'Paul', kind: 'audio', paused: true });\n * ```\n */\nexport async function setParticipantPlayback({\n parameters,\n name = '',\n producerId = '',\n kind = 'all',\n paused,\n}: SetParticipantPlaybackOptions): Promise<{ ok: boolean; error: string; affected: number }> {\n try {\n const source: HeadlessParameters = parameters || {};\n const participants = Array.isArray(source.participants) ? source.participants : [];\n const participant = name\n ? participants.find((part: any) => part?.name === name)\n : undefined;\n\n const targets = new Set<string>();\n if (producerId) targets.add(producerId);\n const usable = (value: unknown) =>\n typeof value === 'string' && value.length > 3 && value.toLowerCase() !== 'none';\n if (participant) {\n if (kind !== 'video' && usable(participant.audioID)) targets.add(participant.audioID as string);\n if (kind !== 'audio' && usable(participant.videoID)) targets.add(participant.videoID as string);\n }\n if (targets.size === 0) {\n return { ok: false, error: 'That participant is not publishing anything to pause.', affected: 0 };\n }\n\n const transports = Array.isArray(source.consumerTransports) ? source.consumerTransports : [];\n let affected = 0;\n for (const entry of transports as any[]) {\n const consumer = entry?.consumer;\n const id = entry?.producerId || consumer?.producerId;\n if (!consumer || !targets.has(id)) continue;\n if (kind !== 'all' && consumer.track?.kind !== kind) continue;\n try {\n if (paused && typeof consumer.pause === 'function') {\n await consumer.pause();\n LOCALLY_PAUSED.add(id);\n affected += 1;\n } else if (!paused && typeof consumer.resume === 'function') {\n await consumer.resume();\n LOCALLY_PAUSED.delete(id);\n affected += 1;\n }\n } catch {\n // One failed consumer must not abort the rest.\n }\n }\n return affected > 0\n ? { ok: true, error: '', affected }\n : { ok: false, error: 'No matching incoming stream was found.', affected: 0 };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The playback change failed.', affected: 0 };\n }\n}\n\n/* ------------------------------------------------------------------ *\n * Breakout room composition\n * ------------------------------------------------------------------ */\n\nexport type BreakoutParticipantRef = { name: string; breakRoom: number };\n\nexport interface SetBreakoutRoomsOptions extends HeadlessOptions {\n /** Room composition: index in the outer array is the room number. */\n rooms: BreakoutParticipantRef[][];\n /** What happens to people who join later. Defaults to the room's setting. */\n newParticipantAction?: string;\n}\n\nexport type SetBreakoutRoomsType = (\n options: SetBreakoutRoomsOptions\n) => Promise<{ ok: boolean; error: string }>;\n\n/**\n * Publish a full breakout-room composition.\n *\n * The SDK models breakout rooms as an array of arrays — outer index is the room\n * number, inner entries are `{ name, breakRoom }`. Adding, removing, or moving\n * someone is therefore just editing that array and re-emitting it; there is no\n * per-participant verb. `startBreakout` opens them, `updateBreakout` amends a\n * running set, and the SDK picks by whether they are already started.\n *\n * Prefer {@link assignParticipantToBreakoutRoom} for single-person changes.\n */\nexport async function setBreakoutRooms({\n parameters,\n rooms,\n newParticipantAction,\n}: SetBreakoutRoomsOptions): Promise<{ ok: boolean; error: string }> {\n try {\n const source: HeadlessParameters = parameters || {};\n const socket = source.socket;\n if (!socket || typeof socket.emit !== 'function' || !source.roomName) {\n return { ok: false, error: 'The room connection is not ready.' };\n }\n if (String(source.islevel) !== '2') {\n return { ok: false, error: 'Only the host can change breakout rooms.' };\n }\n const running = source.breakOutRoomStarted === true && source.breakOutRoomEnded !== true;\n const event = running ? 'updateBreakout' : 'startBreakout';\n // Strip anything beyond the two fields the server accepts.\n const payload = (Array.isArray(rooms) ? rooms : []).map((room) =>\n (Array.isArray(room) ? room : []).map(({ name, breakRoom }) => ({ name, breakRoom }))\n );\n\n const response = await new Promise<any>((resolve) => {\n socket.emit(\n event,\n {\n breakoutRooms: payload,\n newParticipantAction: newParticipantAction || source.newParticipantAction || 'autoAssignNewRoom',\n roomName: source.roomName,\n },\n resolve\n );\n });\n if (!response?.success) {\n return { ok: false, error: response?.reason || 'The breakout rooms could not be updated.' };\n }\n source.updateBreakoutRooms?.(payload);\n source.updateBreakOutRoomStarted?.(true);\n source.updateBreakOutRoomEnded?.(false);\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The breakout rooms could not be updated.' };\n }\n}\n\nexport interface AssignParticipantToBreakoutRoomOptions extends HeadlessOptions {\n /** Participant display name. */\n name: string;\n /** Destination room index, or `null` to remove them from breakout rooms. */\n room: number | null;\n newParticipantAction?: string;\n}\n\nexport type AssignParticipantToBreakoutRoomType = (\n options: AssignParticipantToBreakoutRoomOptions\n) => Promise<{ ok: boolean; error: string }>;\n\n/**\n * Add, move, or remove one participant, without rebuilding the whole array.\n *\n * Covers all three cases the composition array makes awkward by hand:\n * `room: 1` adds them to room 1 (or moves them there from wherever they are),\n * `room: null` removes them from breakout rooms entirely. Empty trailing rooms\n * are preserved, because room numbers are positional and collapsing them would\n * silently renumber everyone else.\n *\n * @example\n * ```ts\n * await assignParticipantToBreakoutRoom({ parameters, name: 'Ada', room: 0 }); // add\n * await assignParticipantToBreakoutRoom({ parameters, name: 'Ada', room: 1 }); // move 0 -> 1\n * await assignParticipantToBreakoutRoom({ parameters, name: 'Ada', room: null }); // remove\n * ```\n */\nexport async function assignParticipantToBreakoutRoom({\n parameters,\n name,\n room,\n newParticipantAction,\n}: AssignParticipantToBreakoutRoomOptions): Promise<{ ok: boolean; error: string }> {\n const source: HeadlessParameters = parameters || {};\n if (!name) return { ok: false, error: 'A participant name is required.' };\n\n const current: BreakoutParticipantRef[][] = Array.isArray(source.breakoutRooms)\n ? source.breakoutRooms.map((entry: any) => (Array.isArray(entry) ? [...entry] : []))\n : [];\n // Remove them from wherever they are, keeping room indices stable.\n const next = current.map((entry) => entry.filter((person: any) => person?.name !== name));\n\n if (room !== null && room !== undefined) {\n if (!Number.isInteger(room) || room < 0) {\n return { ok: false, error: 'The destination room must be a room index.' };\n }\n while (next.length <= room) next.push([]);\n next[room].push({ name, breakRoom: room });\n }\n return setBreakoutRooms({ parameters: source, rooms: next, newParticipantAction });\n}\n\nexport type StopBreakoutRoomsType = (\n options: HeadlessOptions\n) => Promise<{ ok: boolean; error: string }>;\n\n/** Close every breakout room and return everyone to the main room. */\nexport async function stopBreakoutRooms({\n parameters,\n}: HeadlessOptions): Promise<{ ok: boolean; error: string }> {\n try {\n const source: HeadlessParameters = parameters || {};\n const socket = source.socket;\n if (!socket || typeof socket.emit !== 'function' || !source.roomName) {\n return { ok: false, error: 'The room connection is not ready.' };\n }\n if (String(source.islevel) !== '2') {\n return { ok: false, error: 'Only the host can stop breakout rooms.' };\n }\n const response = await new Promise<any>((resolve) => {\n socket.emit('stopBreakout', { roomName: source.roomName }, resolve);\n });\n if (!response?.success) {\n return { ok: false, error: response?.reason || 'The breakout rooms could not be stopped.' };\n }\n source.updateBreakOutRoomStarted?.(false);\n source.updateBreakOutRoomEnded?.(true);\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The breakout rooms could not be stopped.' };\n }\n}\n\nexport type ReapplyLocalPlaybackType = (\n options: HeadlessOptions\n) => Promise<{ ok: boolean; error: string; affected: number }>;\n\n/**\n * Re-assert every local playback choice.\n *\n * Call this whenever media changes — `onMediaChanged` is the natural place. The\n * SDK layout pass resumes consumers it believes should be visible, which would\n * otherwise silently undo \"do not play this person to me\" the moment the active\n * speaker changes. Without this the feature appears to work and then quietly\n * stops working, which is worse than not having it.\n *\n * A no-op when nothing is locally paused.\n */\nexport async function reapplyLocalPlayback({\n parameters,\n}: HeadlessOptions): Promise<{ ok: boolean; error: string; affected: number }> {\n if (LOCALLY_PAUSED.size === 0) return { ok: true, error: '', affected: 0 };\n try {\n const source: HeadlessParameters = parameters || {};\n const transports = Array.isArray(source.consumerTransports) ? source.consumerTransports : [];\n let affected = 0;\n for (const entry of transports as any[]) {\n const consumer = entry?.consumer;\n const id = entry?.producerId || consumer?.producerId;\n if (!consumer || !LOCALLY_PAUSED.has(id)) continue;\n if (consumer.paused === true) continue;\n try {\n if (typeof consumer.pause === 'function') { await consumer.pause(); affected += 1; }\n } catch {\n // Re-assertion is best-effort; a closed consumer is not an error.\n }\n }\n return { ok: true, error: '', affected };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Playback could not be re-applied.', affected: 0 };\n }\n}\n\n/** Producer ids currently muted for this viewer only. */\nexport function getLocallyPausedProducerIds(): string[] {\n return Array.from(LOCALLY_PAUSED);\n}\n","import { HeadlessOptions, HeadlessParameters } from './headlessTypes';\nimport { getCurrentParams } from './getCurrentParams';\nimport { HeadlessActionResult } from './roomActions';\nimport { modifySettings } from '../../settings/modifySettings';\nimport { switchVideo } from '../../stream/switchVideo';\nimport { switchVideoAlt } from '../../stream/switchVideoAlt';\nimport { switchAudio } from '../../stream/switchAudio';\n\n/**\n * Run an SDK control and turn its refusal into a real error.\n *\n * MediaSFU's stream methods resolve void and report refusals — host blocked,\n * request pending, audio-only event — only through `showAlert`. Without\n * comparing the alert across the call, a blocked switch looks like a success.\n * `runMediaControl` does this for controls published on the parameter bag;\n * these three are not on it and must be imported, hence the local copy.\n */\nasync function invokeChecked(\n live: HeadlessParameters,\n run: () => Promise<void>\n): Promise<HeadlessActionResult> {\n const alertBefore = live?.alertMessage || '';\n try {\n await run();\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The device switch failed.' };\n }\n const settled = getCurrentParams({ parameters: live });\n const alertAfter = settled?.alertMessage || '';\n const alertType = settled?.alertType;\n if (alertAfter && alertAfter !== alertBefore\n && (alertType === 'danger' || alertType === 'warning')) {\n return { ok: false, error: alertAfter };\n }\n return { ok: true, error: '' };\n}\n\n/* ------------------------------------------------------------------ *\n * Device switching\n * ------------------------------------------------------------------ */\n\nexport interface SwitchDeviceOptions extends HeadlessOptions {\n /** `deviceId` from `listMediaDevices()`. */\n deviceId: string;\n}\n\nexport type SwitchCameraType = (options: SwitchDeviceOptions) => Promise<HeadlessActionResult>;\n\n/**\n * Switch to a different camera.\n *\n * Pairs with `listMediaDevices()` / `getSelectedDevices()`, which could\n * previously only report devices with no way to act on them.\n *\n * Goes through the SDK's own `switchUserVideo`, so the producer track is\n * replaced on the existing transport — remote viewers see the new camera\n * without the call renegotiating — and host restrictions still apply. A refusal\n * (blocked by the host, audio-only event) is returned as `ok: false` with the\n * reason rather than resolving silently.\n *\n * @example\n * ```ts\n * const { video } = await listMediaDevices();\n * await switchCamera({ parameters, deviceId: video[1].deviceId });\n * ```\n */\nexport async function switchCamera({\n parameters,\n deviceId,\n}: SwitchDeviceOptions): Promise<HeadlessActionResult> {\n if (!deviceId) return { ok: false, error: 'A camera deviceId is required.' };\n const live = getCurrentParams({ parameters });\n return invokeChecked(live, () => switchVideo({ videoPreference: deviceId, parameters: live as any }));\n}\n\n/**\n * Flip between the front and rear cameras.\n *\n * This toggles — the SDK's `switchVideoAlt` swaps whichever facing mode is\n * current and takes no target, so there is no way to ask for \"front\"\n * specifically. Use `switchCamera` with a deviceId when you need to land on a\n * particular camera; use this on mobile, where device ids are unstable across\n * sessions but the flip gesture is what users expect.\n */\nexport async function flipCamera({ parameters }: HeadlessOptions): Promise<HeadlessActionResult> {\n const live = getCurrentParams({ parameters });\n return invokeChecked(live, () => switchVideoAlt({ parameters: live as any }));\n}\n\nexport type SwitchMicrophoneType = (options: SwitchDeviceOptions) => Promise<HeadlessActionResult>;\n\n/** Switch to a different microphone. The audio counterpart of `switchCamera`. */\nexport async function switchMicrophone({\n parameters,\n deviceId,\n}: SwitchDeviceOptions): Promise<HeadlessActionResult> {\n if (!deviceId) return { ok: false, error: 'A microphone deviceId is required.' };\n const live = getCurrentParams({ parameters });\n return invokeChecked(live, () => switchAudio({ audioPreference: deviceId, parameters: live as any }));\n}\n\n/* ------------------------------------------------------------------ *\n * Room media policy (host)\n * ------------------------------------------------------------------ */\n\n/** 'allow' — anyone may; 'approval' — must ask the host; 'disallow' — nobody may. */\nexport type RoomPolicyValue = 'allow' | 'approval' | 'disallow';\n\nexport interface SetRoomMediaPolicyOptions extends HeadlessOptions {\n audio?: RoomPolicyValue;\n video?: RoomPolicyValue;\n screenshare?: RoomPolicyValue;\n chat?: RoomPolicyValue;\n}\n\n/**\n * Set what participants are allowed to do — the room-wide policy behind the\n * SDK's settings modal.\n *\n * This is the *rule*, not a one-off action: `setParticipantMedia` (moderation)\n * turns one person's camera off now, whereas `video: 'approval'` here means\n * everyone must ask before turning one on. `getMediaPermissions()` reads the\n * same four values back.\n *\n * Host only. Any value left undefined keeps its current setting.\n *\n * @example\n * ```ts\n * await setRoomMediaPolicy({ parameters, audio: 'approval', screenshare: 'disallow' });\n * ```\n */\nexport async function setRoomMediaPolicy({\n parameters,\n audio,\n video,\n screenshare,\n chat,\n}: SetRoomMediaPolicyOptions): Promise<HeadlessActionResult> {\n const live = getCurrentParams({ parameters });\n if (String(live.islevel) !== '2') {\n return { ok: false, error: 'Only the host can change room settings.' };\n }\n if (!live.socket) {\n return { ok: false, error: 'The room connection is not ready yet.' };\n }\n try {\n // Imported rather than read off the parameter bag: unlike the media\n // controls, `modifySettings` is not published on it.\n await modifySettings({\n roomName: live.roomName || '',\n // The SDK requires all four on every call, so unspecified values are\n // filled from current state — otherwise changing one would blank the rest.\n audioSet: audio || live.audioSetting || 'allow',\n videoSet: video || live.videoSetting || 'allow',\n screenshareSet: screenshare || live.screenshareSetting || 'allow',\n chatSet: chat || live.chatSetting || 'allow',\n socket: live.socket,\n showAlert: live.showAlert,\n updateAudioSetting: live.updateAudioSetting,\n updateVideoSetting: live.updateVideoSetting,\n updateScreenshareSetting: live.updateScreenshareSetting,\n updateChatSetting: live.updateChatSetting,\n updateIsSettingsModalVisible: live.updateIsSettingsModalVisible || (() => {}),\n });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The room settings could not be updated.' };\n }\n}\n\n/* ------------------------------------------------------------------ *\n * Reads\n * ------------------------------------------------------------------ */\n\nexport interface ChatMessage {\n sender: string;\n message: string;\n timestamp: string;\n /** Recipients — empty/[] means it went to everyone. */\n receivers: string[];\n /** True when this is a direct message rather than a room-wide one. */\n direct: boolean;\n /** True when the local user sent it. */\n mine: boolean;\n}\n\nexport interface GetChatMessagesOptions extends HeadlessOptions {\n /** 'all' (default), 'group' for room-wide only, or 'direct' for DMs only. */\n scope?: 'all' | 'group' | 'direct';\n /** Only messages exchanged with this person. Implies direct messages. */\n withPerson?: string;\n}\n\n/**\n * Read the chat.\n *\n * `sendChatMessage` existed with no way to read replies, so a headless surface\n * could talk but not listen. Direct messages are flagged and filterable, since\n * rendering a DM in the room-wide thread leaks it to the wrong audience.\n *\n * Call from `onMediaChanged` or a render to get the current list.\n */\nexport function getChatMessages({\n parameters,\n scope = 'all',\n withPerson = '',\n}: GetChatMessagesOptions): ChatMessage[] {\n const source: HeadlessParameters = parameters || {};\n const raw = Array.isArray(source.messages) ? source.messages : [];\n const me = source.member || '';\n\n return raw\n .map((entry: any) => {\n const receivers = Array.isArray(entry?.receivers) ? entry.receivers : [];\n return {\n sender: entry?.sender || '',\n message: entry?.message || '',\n timestamp: entry?.timestamp || '',\n receivers,\n // MediaSFU marks group messages with an empty receivers list; anything\n // addressed is a DM.\n direct: receivers.length > 0,\n mine: entry?.sender === me,\n } as ChatMessage;\n })\n .filter((message) => {\n if (scope === 'group' && message.direct) return false;\n if (scope === 'direct' && !message.direct) return false;\n if (withPerson) {\n return message.sender === withPerson || message.receivers.includes(withPerson);\n }\n return true;\n });\n}\n\nexport interface PendingApprovals {\n /** People held in the waiting room. */\n waiting: { name: string; id: string }[];\n /** Requests to unmute, turn a camera on, share, or chat. */\n requests: { id: string; name: string; icon: string; username: string }[];\n /** Total items needing a host decision. */\n total: number;\n}\n\n/**\n * Everything currently awaiting a host decision.\n *\n * `respondToWaitingParticipant` and `respondToParticipantRequest` could act on\n * these but nothing could list them, so a headless host had no way to know a\n * decision was pending. Badge `total` and render the two lists.\n */\nexport function getPendingApprovals({ parameters }: HeadlessOptions): PendingApprovals {\n const source: HeadlessParameters = parameters || {};\n const waitingRaw = Array.isArray(source.waitingRoomList) ? source.waitingRoomList : [];\n const requestRaw = Array.isArray(source.requestList) ? source.requestList : [];\n\n const waiting = waitingRaw.map((entry: any) => ({\n name: entry?.name || '',\n id: entry?.id || '',\n }));\n const requests = requestRaw.map((entry: any) => ({\n id: entry?.id || '',\n name: entry?.name || '',\n // 'fa-microphone' | 'fa-video' | 'fa-desktop' | 'fa-comments' — what they asked for.\n icon: entry?.icon || '',\n username: entry?.username || entry?.name || '',\n }));\n\n return { waiting, requests, total: waiting.length + requests.length };\n}\n\nexport interface SessionTimer {\n /** Elapsed wall time, formatted by the SDK (e.g. \"12:04\"). */\n elapsed: string;\n /**\n * True while the server is asking whether you are still there — see\n * `getPresenceCheck`, which you must answer or be disconnected.\n */\n presenceCheckPending: boolean;\n}\n\n/**\n * How long the session has been running.\n *\n * Deliberately does not report \"time remaining\": the server sends that on the\n * `meetingTimeRemaining` event, which the SDK forwards straight to `showAlert`\n * without storing it. There is no field to read, and inventing one from the\n * last alert would be a guess. Watch `showAlert` if you need the warning.\n */\nexport function getSessionTimer({ parameters }: HeadlessOptions): SessionTimer {\n const source: HeadlessParameters = parameters || {};\n return {\n elapsed: source.meetingProgressTime || '00:00',\n presenceCheckPending: Boolean(source.isConfirmHereModalVisible),\n };\n}\n\nexport interface PresenceCheck {\n /** True while the \"are you still there?\" check is waiting on an answer. */\n pending: boolean;\n}\n\n/**\n * Whether the server is currently asking if you are still there.\n *\n * **This matters more headlessly than it looks.** On an idle room the server\n * emits `meetingStillThere`, and the SDK opens a modal that counts down and\n * then emits `disconnectUser`. With `returnUI={false}` that modal is still\n * mounted — inside a root collapsed to 0×0 — so the countdown runs invisibly\n * and the session is dropped with nothing shown and nothing to click.\n *\n * Poll this (from `onMediaChanged`, or a timer) and call `confirmStillHere`\n * to stay in the room.\n */\nexport function getPresenceCheck({ parameters }: HeadlessOptions): PresenceCheck {\n const source: HeadlessParameters = parameters || {};\n return { pending: Boolean(source.isConfirmHereModalVisible) };\n}\n\n/**\n * Answer the \"are you still there?\" check and stay in the room.\n *\n * Closing the check is the whole answer — the SDK only disconnects on the\n * countdown expiring, so cancelling it is what keeps the session alive. Safe to\n * call when nothing is pending.\n */\nexport function confirmStillHere({ parameters }: HeadlessOptions): HeadlessActionResult {\n const live = getCurrentParams({ parameters });\n const update = live.updateIsConfirmHereModalVisible;\n if (typeof update !== 'function') {\n return { ok: false, error: 'The presence check control is unavailable.' };\n }\n update(false);\n return { ok: true, error: '' };\n}\n","import { HeadlessOptions, HeadlessParameters } from './headlessTypes';\n\n/**\n * Explicit playback: HLS and WHEP.\n *\n * **This is deliberately not part of the media-card surface.** WebRTC media is\n * *auto-consumed* — the SDK subscribes for you, and `getRemoteVideoStreams` /\n * `getAudioGridComponents` hand you what already arrived. HLS and WHEP are the\n * opposite: nothing is consumed until you ask, because each one opens a\n * connection the room did not ask for and would otherwise pay for.\n *\n * So the API here is imperative — `attachPlayback` / `detachPlayback` — rather\n * than a reactive getter. Mixing these into the media cards would mean every\n * room silently opened an HLS or WHEP connection whether or not anything\n * rendered it.\n *\n * When to reach for which:\n *\n * | | latency | cost per viewer | use it for |\n * | --- | --- | --- | --- |\n * | WebRTC (auto) | sub-second | an SFU consumer | anyone who takes part |\n * | WHEP | sub-second | an SFU consumer | standards-based egress to non-SDK players |\n * | HLS | seconds | a CDN request | audiences too large to fan out over the SFU |\n *\n * A large passive audience on HLS is the reason this exists: it moves the\n * expensive part — media fan-out — off the SFU.\n */\n\nexport type PlaybackProtocol = 'hls' | 'whep';\n\nexport interface PlaybackSource {\n protocol: PlaybackProtocol;\n url: string;\n}\n\n/**\n * Playback URLs the server has published for this room.\n *\n * Returns nothing when the room has none — HLS and WHEP are provisioned\n * server-side, so absence means \"not enabled for this room\", not an error.\n */\nexport function getPlaybackSources({ parameters }: HeadlessOptions): PlaybackSource[] {\n const source: HeadlessParameters = parameters || {};\n const sources: PlaybackSource[] = [];\n const push = (protocol: PlaybackProtocol, url: unknown) => {\n if (typeof url === 'string' && /^https:\\/\\//i.test(url)) sources.push({ protocol, url });\n };\n push('hls', source.hlsUrl || source.hlsPlaybackUrl || source.playbackUrl);\n push('whep', source.whepUrl || source.whepPlaybackUrl);\n return sources;\n}\n\n/** A running playback. Always `detachPlayback` it — none of this is garbage-collected. */\nexport interface PlaybackHandle {\n protocol: PlaybackProtocol;\n url: string;\n /** The media, when the protocol produces one directly (WHEP). */\n stream: MediaStream | null;\n /** Release the connection, the player, and the element's source. */\n detach: () => void;\n}\n\nexport interface AttachPlaybackOptions {\n /** Playback URL, or a `PlaybackSource` from `getPlaybackSources`. */\n source: string | PlaybackSource;\n /** The element to play into. Required for HLS; optional for WHEP. */\n video?: HTMLVideoElement | null;\n /** Force a protocol. Inferred from the URL when omitted. */\n protocol?: PlaybackProtocol;\n /**\n * Factory returning an hls.js instance, e.g. `() => new Hls({ lowLatencyMode: true })`.\n *\n * Required for HLS anywhere except Safari, and injected rather than imported\n * so hls.js never becomes a dependency of this SDK — most rooms never play\n * HLS, and React Native cannot use it at all.\n */\n hlsFactory?: () => any;\n /** Extra headers for the WHEP POST, e.g. an auth token. */\n headers?: Record<string, string>;\n /** ICE servers for WHEP. Defaults to the room's own when available. */\n iceServers?: RTCIceServer[];\n}\n\nfunction inferProtocol(url: string, explicit?: PlaybackProtocol): PlaybackProtocol {\n if (explicit) return explicit;\n return /\\.m3u8(\\?|$)/i.test(url) ? 'hls' : 'whep';\n}\n\n/**\n * Whether this element can genuinely play HLS from a plain `src`.\n *\n * **`canPlayType` alone is a trap.** Chrome answers `\"maybe\"` for\n * `application/vnd.apple.mpegurl` and then plays nothing — setting `src` there\n * produces a permanently black video with no error at all.\n *\n * The reliable signal is Media Source Extensions: where MSE exists, hls.js is\n * the right player (this is hls.js's own documented rule). Native playback is\n * only trusted where MSE is absent, which is iOS Safari — the one place hls.js\n * cannot run and native HLS genuinely works.\n */\nfunction canPlayHlsNatively(video: HTMLVideoElement): boolean {\n const claimsSupport = typeof video.canPlayType === 'function'\n && video.canPlayType('application/vnd.apple.mpegurl') !== '';\n const hasMse = typeof MediaSource !== 'undefined'\n || typeof (globalThis as any).ManagedMediaSource !== 'undefined';\n return claimsSupport && !hasMse;\n}\n\nasync function attachHls(\n url: string,\n video: HTMLVideoElement | null | undefined,\n hlsFactory?: () => any\n): Promise<PlaybackHandle> {\n if (!video) throw new Error('HLS playback needs a <video> element.');\n\n // Prefer the injected player wherever one is available: hls.js works on every\n // browser that supports MSE, including desktop Safari, and gives one code path\n // for live-edge handling rather than two.\n if (typeof hlsFactory !== 'function' && canPlayHlsNatively(video)) {\n video.src = url;\n const play = video.play?.();\n play?.catch?.(() => {});\n return {\n protocol: 'hls',\n url,\n stream: null,\n detach: () => { video.removeAttribute('src'); video.load?.(); },\n };\n }\n\n if (typeof hlsFactory !== 'function') {\n throw new Error(\n 'HLS needs an hlsFactory on this browser. Pass () => new Hls(...) from hls.js; '\n + 'it is not bundled with the SDK. Only iOS Safari, which has no Media Source '\n + 'Extensions, plays HLS without one — Chrome reports that it can and then '\n + 'plays nothing.'\n );\n }\n const hls = hlsFactory();\n hls.loadSource(url);\n hls.attachMedia(video);\n return {\n protocol: 'hls',\n url,\n stream: null,\n detach: () => {\n try { hls.destroy(); } catch { /* already destroyed */ }\n video.removeAttribute('src');\n },\n };\n}\n\n/**\n * WHEP: POST an SDP offer, receive an answer, play the tracks.\n *\n * Implemented directly against RTCPeerConnection rather than via a library —\n * WHEP is a small, standard exchange and a dependency here would be larger than\n * the protocol.\n */\nasync function attachWhep(\n url: string,\n video: HTMLVideoElement | null | undefined,\n headers: Record<string, string> = {},\n iceServers?: RTCIceServer[]\n): Promise<PlaybackHandle> {\n if (typeof RTCPeerConnection === 'undefined') {\n throw new Error('WHEP playback needs WebRTC support.');\n }\n const pc = new RTCPeerConnection(iceServers?.length ? { iceServers } : undefined);\n const stream = new MediaStream();\n\n // recvonly: this is egress. Adding transceivers up front means the offer\n // advertises both kinds even before any track arrives.\n pc.addTransceiver('video', { direction: 'recvonly' });\n pc.addTransceiver('audio', { direction: 'recvonly' });\n pc.ontrack = (event: RTCTrackEvent) => {\n if (event.track) stream.addTrack(event.track);\n if (video && video.srcObject !== stream) {\n video.srcObject = stream;\n const play = video.play?.();\n play?.catch?.(() => {});\n }\n };\n\n let resourceUrl = '';\n try {\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/sdp', ...headers },\n body: offer.sdp || '',\n });\n if (!response.ok) {\n throw new Error(`The WHEP endpoint refused the request (${response.status}).`);\n }\n // The Location header names the session, and DELETEing it is the only way\n // to tell the server to stop sending. Without it a closed page keeps a\n // session alive server-side.\n const location = response.headers.get('Location') || '';\n resourceUrl = location ? new URL(location, url).toString() : '';\n\n const answer = await response.text();\n await pc.setRemoteDescription({ type: 'answer', sdp: answer });\n } catch (error) {\n pc.close();\n throw error;\n }\n\n return {\n protocol: 'whep',\n url,\n stream,\n detach: () => {\n if (resourceUrl) {\n // Best-effort and deliberately unawaited: teardown often runs during\n // page unload, where waiting is not an option.\n try { void fetch(resourceUrl, { method: 'DELETE', headers }); } catch { /* ignore */ }\n }\n try { pc.close(); } catch { /* already closed */ }\n stream.getTracks().forEach((track) => track.stop());\n if (video && video.srcObject === stream) video.srcObject = null;\n },\n };\n}\n\nexport type AttachPlaybackType = (options: AttachPlaybackOptions) => Promise<PlaybackHandle>;\n\n/**\n * Start an explicit playback.\n *\n * @example\n * ```ts\n * import Hls from 'hls.js';\n *\n * const [source] = getPlaybackSources({ parameters });\n * const handle = await attachPlayback({\n * source,\n * video: videoRef.current,\n * hlsFactory: () => new Hls({ lowLatencyMode: true }),\n * });\n * // later, always:\n * detachPlayback(handle);\n * ```\n */\nexport async function attachPlayback({\n source,\n video,\n protocol,\n hlsFactory,\n headers,\n iceServers,\n}: AttachPlaybackOptions): Promise<PlaybackHandle> {\n const url = typeof source === 'string' ? source : source?.url || '';\n if (!url) throw new Error('A playback URL is required.');\n const resolved = typeof source === 'string'\n ? inferProtocol(url, protocol)\n : (protocol || source.protocol || inferProtocol(url));\n\n return resolved === 'hls'\n ? attachHls(url, video, hlsFactory)\n : attachWhep(url, video, headers, iceServers);\n}\n\n/** Stop a playback and release everything it holds. Safe to call twice. */\nexport function detachPlayback(handle: PlaybackHandle | null | undefined): void {\n if (!handle || typeof handle.detach !== 'function') return;\n try { handle.detach(); } catch { /* teardown must not throw */ }\n}\n\n/* ------------------------------------------------------------------ *\n * WHIP — the ingest counterpart\n * ------------------------------------------------------------------ */\n\nexport interface PublishWhipOptions {\n /** The WHIP endpoint. */\n url: string;\n /** The stream to publish. */\n stream: MediaStream;\n headers?: Record<string, string>;\n iceServers?: RTCIceServer[];\n}\n\n/**\n * Publish a stream to a WHIP endpoint.\n *\n * The symmetric counterpart of WHEP, and equally explicit. This is *not* how\n * you publish into a MediaSFU room — use `produceMedia` for that, which goes\n * through the room's own transport and respects its capture entitlements. WHIP\n * is for pushing to a standards-based ingest that is not this room.\n */\nexport async function publishWhip({\n url,\n stream,\n headers = {},\n iceServers,\n}: PublishWhipOptions): Promise<PlaybackHandle> {\n if (typeof RTCPeerConnection === 'undefined') {\n throw new Error('WHIP publishing needs WebRTC support.');\n }\n if (!stream?.getTracks?.().length) throw new Error('A stream with at least one track is required.');\n\n const pc = new RTCPeerConnection(iceServers?.length ? { iceServers } : undefined);\n stream.getTracks().forEach((track) => pc.addTrack(track, stream));\n\n let resourceUrl = '';\n try {\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/sdp', ...headers },\n body: offer.sdp || '',\n });\n if (!response.ok) throw new Error(`The WHIP endpoint refused the request (${response.status}).`);\n const location = response.headers.get('Location') || '';\n resourceUrl = location ? new URL(location, url).toString() : '';\n await pc.setRemoteDescription({ type: 'answer', sdp: await response.text() });\n } catch (error) {\n pc.close();\n throw error;\n }\n\n return {\n protocol: 'whep',\n url,\n stream,\n detach: () => {\n if (resourceUrl) {\n try { void fetch(resourceUrl, { method: 'DELETE', headers }); } catch { /* ignore */ }\n }\n try { pc.close(); } catch { /* already closed */ }\n },\n };\n}\n","/**\n * Viewers who are part of a session without joining the room.\n *\n * **Why this exists.** Joining a MediaSFU room auto-consumes WebRTC: the SDK\n * creates consumers from the server's `newProducer` events, unconditionally —\n * there is no receive-nothing mode. For a large passive audience watching over\n * HLS that is pure waste: transports, consumers and layout churn for media they\n * will never render. Joining and then pausing the consumers is worse than it\n * looks, because the layout pass keeps resuming them.\n *\n * So an HLS viewer does not join at all. They hold a *viewer session* instead —\n * enough to be counted, to raise a hand, and to be told when the host approves —\n * and they only perform a real SDK join at the moment they reach the floor.\n *\n * How that session is stored is deliberately not decided here. The transport,\n * lifecycle and state machine are the SDK's business; issuing playback URLs and\n * tracking presence belong to whatever backend you run. You supply a\n * `ViewerSessionProvider`; this drives it. Same reasoning as `hlsFactory`: the\n * SDK owns the mechanism, the app owns the dependency.\n */\n\nexport type ViewerSessionPhase =\n | 'idle'\n | 'joining'\n | 'watching'\n | 'requested'\n | 'approved'\n | 'left'\n | 'error';\n\nexport interface ViewerSessionIdentity {\n /** Opaque id for this viewer, issued by the provider. */\n viewerId: string;\n /** The room being watched. */\n roomName: string;\n /** Where to play from. Absent until the provider issues one. */\n playbackUrl?: string;\n /** 'hls' or 'whep'; inferred from the URL when omitted. */\n protocol?: 'hls' | 'whep';\n /** Anything the provider needs handed back on later calls. */\n token?: string;\n [key: string]: any;\n}\n\nexport interface ViewerSessionStatus {\n /** True once the host has approved this viewer for the floor. */\n approved: boolean;\n /** True while a request is outstanding. */\n pending?: boolean;\n /** Free-text reason when a request was refused. */\n reason?: string;\n /** Provider may refresh the playback URL (signed URLs expire). */\n playbackUrl?: string;\n}\n\n/**\n * What your backend has to do. Only `join` is required — a provider that just\n * hands back a playback URL is a valid provider, it simply cannot support\n * promotion.\n */\nexport interface ViewerSessionProvider {\n join(options: {\n roomName: string;\n displayName?: string;\n signal?: AbortSignal;\n }): Promise<ViewerSessionIdentity>;\n /** Keep the viewer counted as present. */\n heartbeat?(options: { session: ViewerSessionIdentity; signal?: AbortSignal }): Promise<void>;\n /** Raise a hand for the floor. */\n requestPromotion?(options: { session: ViewerSessionIdentity; signal?: AbortSignal }): Promise<void>;\n /** Has the host decided yet? */\n poll?(options: { session: ViewerSessionIdentity; signal?: AbortSignal }): Promise<ViewerSessionStatus>;\n /** Release the session. */\n leave?(options: { session: ViewerSessionIdentity }): Promise<void>;\n}\n\nexport interface ViewerSessionSnapshot {\n phase: ViewerSessionPhase;\n session: ViewerSessionIdentity | null;\n status: ViewerSessionStatus | null;\n error: string;\n /** True when the provider can accept a promotion request at all. */\n canRequestPromotion: boolean;\n}\n\nexport interface CreateViewerSessionOptions {\n provider: ViewerSessionProvider;\n roomName: string;\n displayName?: string;\n /** Poll interval for approval, ms. Defaults to 5000. */\n pollIntervalMs?: number;\n /** Heartbeat interval, ms. Defaults to 30000. Ignored without a heartbeat. */\n heartbeatIntervalMs?: number;\n /** Called on every state change. */\n onChange?: (snapshot: ViewerSessionSnapshot) => void;\n}\n\nexport interface ViewerSessionHandle {\n /** Current state, readable at any time. */\n getSnapshot: () => ViewerSessionSnapshot;\n /** Register with the provider and begin watching. */\n start: () => Promise<ViewerSessionSnapshot>;\n /** Raise a hand for the floor. */\n requestPromotion: () => Promise<ViewerSessionSnapshot>;\n /** Stop everything and release the session. */\n stop: () => Promise<void>;\n}\n\nconst MIN_INTERVAL_MS = 1000;\n\n/**\n * Drive a viewer session.\n *\n * Deliberately framework-agnostic — no hooks, no observables — so the same\n * implementation serves React, Vue and Angular. Wrap it in whatever your\n * framework prefers.\n *\n * @example\n * ```ts\n * const viewer = createViewerSession({\n * provider: myProvider,\n * roomName,\n * onChange: (snapshot) => setState(snapshot),\n * });\n * await viewer.start(); // watching over HLS, never joined\n * await viewer.requestPromotion(); // hand raised\n * // when snapshot.phase === 'approved', perform a real SDK join.\n * ```\n */\nexport function createViewerSession({\n provider,\n roomName,\n displayName,\n pollIntervalMs = 5000,\n heartbeatIntervalMs = 30000,\n onChange,\n}: CreateViewerSessionOptions): ViewerSessionHandle {\n let snapshot: ViewerSessionSnapshot = {\n phase: 'idle',\n session: null,\n status: null,\n error: '',\n canRequestPromotion: typeof provider?.requestPromotion === 'function',\n };\n let pollTimer: any = null;\n let heartbeatTimer: any = null;\n let stopped = false;\n\n const emit = (next: Partial<ViewerSessionSnapshot>) => {\n snapshot = { ...snapshot, ...next };\n try {\n onChange?.(snapshot);\n } catch {\n // A consumer's observer must never break the session.\n }\n };\n\n const clearTimers = () => {\n if (pollTimer) { clearInterval(pollTimer); pollTimer = null; }\n if (heartbeatTimer) { clearInterval(heartbeatTimer); heartbeatTimer = null; }\n };\n\n const startTimers = () => {\n clearTimers();\n if (typeof provider.poll === 'function') {\n pollTimer = setInterval(async () => {\n if (stopped || !snapshot.session) return;\n try {\n const status = await provider.poll!({ session: snapshot.session });\n if (stopped) return;\n // A refreshed URL matters: signed playback URLs expire mid-session,\n // and a silently dead player looks like a broken stream.\n const session = status?.playbackUrl\n ? { ...snapshot.session, playbackUrl: status.playbackUrl }\n : snapshot.session;\n emit({\n status,\n session,\n phase: status?.approved ? 'approved' : snapshot.phase === 'requested' ? 'requested' : 'watching',\n });\n // Once approved there is nothing left to poll for.\n if (status?.approved) clearTimers();\n } catch {\n // Transient poll failures are normal; the session is not lost.\n }\n }, Math.max(MIN_INTERVAL_MS, pollIntervalMs));\n }\n if (typeof provider.heartbeat === 'function') {\n heartbeatTimer = setInterval(() => {\n if (stopped || !snapshot.session) return;\n Promise.resolve(provider.heartbeat!({ session: snapshot.session })).catch(() => {});\n }, Math.max(MIN_INTERVAL_MS, heartbeatIntervalMs));\n }\n };\n\n return {\n getSnapshot: () => snapshot,\n\n async start() {\n if (snapshot.phase !== 'idle' && snapshot.phase !== 'left' && snapshot.phase !== 'error') {\n return snapshot;\n }\n stopped = false;\n emit({ phase: 'joining', error: '' });\n try {\n const session = await provider.join({ roomName, displayName });\n if (stopped) return snapshot;\n if (!session?.viewerId) throw new Error('The viewer session provider returned no viewerId.');\n emit({ phase: 'watching', session, error: '' });\n startTimers();\n } catch (error: any) {\n emit({ phase: 'error', error: error?.message || 'The viewer session could not start.' });\n }\n return snapshot;\n },\n\n async requestPromotion() {\n if (!snapshot.session) {\n emit({ error: 'Start the viewer session before requesting the floor.' });\n return snapshot;\n }\n if (typeof provider.requestPromotion !== 'function') {\n emit({ error: 'This viewer session provider does not support promotion.' });\n return snapshot;\n }\n try {\n await provider.requestPromotion({ session: snapshot.session });\n emit({ phase: 'requested', error: '' });\n } catch (error: any) {\n emit({ error: error?.message || 'The request could not be sent.' });\n }\n return snapshot;\n },\n\n async stop() {\n stopped = true;\n clearTimers();\n const session = snapshot.session;\n emit({ phase: 'left' });\n if (session && typeof provider.leave === 'function') {\n // Best-effort: teardown often runs during unload.\n try { await provider.leave({ session }); } catch { /* ignore */ }\n }\n },\n };\n}\n","import { streamSuccessVideo } from '../../../consumers/streamSuccessVideo';\nimport { streamSuccessAudio } from '../../../consumers/streamSuccessAudio';\nimport { streamSuccessScreen } from '../../../consumers/streamSuccessScreen';\nimport { disconnectSendTransportVideo } from '../../../consumers/disconnectSendTransportVideo';\nimport { disconnectSendTransportAudio } from '../../../consumers/disconnectSendTransportAudio';\nimport { disconnectSendTransportScreen } from '../../../consumers/disconnectSendTransportScreen';\nimport { HeadlessOptions, HeadlessParameters } from './headlessTypes';\nimport { getCurrentParams } from './getCurrentParams';\nimport { getRoomReadiness } from './getRoomReadiness';\nimport { HeadlessActionResult } from './roomActions';\n\nexport type ProducerKind = 'video' | 'audio' | 'screen';\n\nfunction hasLiveTrack(stream: MediaStream | null | undefined, kind: 'video' | 'audio'): boolean {\n if (!stream || typeof stream.getTracks !== 'function') return false;\n try {\n return stream\n .getTracks()\n .some((track) => track.kind === kind && track.readyState === 'live');\n } catch {\n return false;\n }\n}\n\n/** `VidCons` allows a bare number or a {ideal,max,min} shape. */\nfunction capOf(value: any): number {\n if (typeof value === 'number') return value;\n if (value && typeof value === 'object') {\n const candidate = value.max ?? value.ideal;\n if (typeof candidate === 'number') return candidate;\n }\n return 0;\n}\n\nexport interface CaptureLimits {\n width: number;\n height: number;\n frameRate: number;\n}\n\nexport interface GetCaptureLimitsOptions extends HeadlessOptions {\n /** Camera and screen share have separate ceilings. Defaults to camera. */\n kind?: ProducerKind;\n}\n\nexport type GetCaptureLimitsType = (options: GetCaptureLimitsOptions) => CaptureLimits;\n\n/**\n * The room's allowed capture ceiling — the same `vidCons` / `frameRate` that\n * `clickVideo` feeds to `getUserMedia`. Zero means \"no ceiling published\".\n */\nexport function getCaptureLimits({ parameters, kind = 'video' }: GetCaptureLimitsOptions): CaptureLimits {\n const source: HeadlessParameters = parameters || {};\n // Screen share is governed by targetWidth/targetHeight (what startShareScreen\n // passes to getDisplayMedia), not by the camera's vidCons.\n if (kind === 'screen') {\n return {\n width: Number(source.targetWidth) || 0,\n height: Number(source.targetHeight) || 0,\n frameRate: Number(source.frameRate) || 30,\n };\n }\n const vidCons: any = source.vidCons || {};\n return {\n width: capOf(vidCons.width),\n height: capOf(vidCons.height),\n frameRate: Number(source.frameRate) || 0,\n };\n}\n\n/**\n * Clamp an incoming track to the room's capture ceiling before it is published.\n *\n * This matters because the publish path here is deliberately *not* `clickVideo`.\n * `clickVideo` applies `vidCons`/`frameRate` when it calls `getUserMedia`;\n * `streamSuccessVideo` — which every produce* helper calls — never re-applies\n * them to a track it is handed. Encoding limits still apply either way\n * (`vParams`/`hParams` carry the `maxBitrate` ladder and are attached at\n * `producerTransport.produce`), so bandwidth stays capped, but *capture\n * dimensions and frame rate* would otherwise be unbounded.\n *\n * Order: try `applyConstraints` first, then verify with `getSettings`. Sources\n * such as `canvas.captureStream()` frequently reject or ignore constraints, so\n * verification is the part that actually enforces — an over-size track that\n * cannot be clamped is refused rather than published.\n */\nasync function enforceCaptureLimits(\n stream: MediaStream,\n parameters: HeadlessParameters,\n kind: ProducerKind,\n allowUnconstrained: boolean\n): Promise<{ ok: boolean; error: string }> {\n if (kind === 'audio') return { ok: true, error: '' };\n const limits = getCaptureLimits({ parameters, kind });\n if (!limits.width && !limits.height && !limits.frameRate) return { ok: true, error: '' };\n\n let track: MediaStreamTrack | undefined;\n try {\n track = stream.getVideoTracks()[0];\n } catch {\n return { ok: true, error: '' };\n }\n if (!track) return { ok: true, error: '' };\n\n const constraints: MediaTrackConstraints = {};\n if (limits.width) constraints.width = { max: limits.width };\n if (limits.height) constraints.height = { max: limits.height };\n if (limits.frameRate) constraints.frameRate = { max: limits.frameRate };\n try {\n await track.applyConstraints(constraints);\n } catch {\n // Canvas and element captures commonly reject this; verification below decides.\n }\n\n let settings: MediaTrackSettings = {};\n try {\n settings = track.getSettings?.() || {};\n } catch {\n return { ok: true, error: '' };\n }\n // A source that reports nothing cannot be verified either way; let it through\n // rather than block a legitimate publish on missing metadata.\n if (!settings.width && !settings.height && !settings.frameRate) {\n return { ok: true, error: '' };\n }\n\n const over: string[] = [];\n if (limits.width && settings.width && settings.width > limits.width) {\n over.push(`width ${settings.width} > ${limits.width}`);\n }\n if (limits.height && settings.height && settings.height > limits.height) {\n over.push(`height ${settings.height} > ${limits.height}`);\n }\n if (limits.frameRate && settings.frameRate && settings.frameRate > limits.frameRate + 1) {\n over.push(`frameRate ${Math.round(settings.frameRate)} > ${limits.frameRate}`);\n }\n if (over.length === 0) return { ok: true, error: '' };\n if (allowUnconstrained) return { ok: true, error: '' };\n\n return {\n ok: false,\n error: `This source exceeds the room's capture allowance (${over.join(', ')}). `\n + 'Reduce the source size or frame rate before publishing.',\n };\n}\n\nexport interface ProduceMediaOptions extends HeadlessOptions {\n /** The stream to publish. Must carry at least one live track of the right kind. */\n stream: MediaStream;\n /** What to publish it as. */\n kind: ProducerKind;\n /**\n * Publish even when the source exceeds the room's `vidCons`/`frameRate`\n * ceiling and cannot be clamped. Off by default: the ceiling is a room\n * entitlement, so bypassing it must be a deliberate, visible choice.\n */\n allowUnconstrained?: boolean;\n}\n\nexport type ProduceMediaType = (\n options: ProduceMediaOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Publish **any** MediaStream to the room — not just the camera or microphone.\n *\n * `clickVideo` / `clickAudio` call `getUserMedia` internally, so they can only\n * ever publish a real device. Anything else — a `<canvas>` capture, a `<video>`\n * element playing a file, a Web Audio destination, a processed or synthesised\n * track, a virtual camera — previously required monkey-patching\n * `navigator.mediaDevices.getUserMedia` around the call, which is racy and\n * leaks if the control throws. This publishes your stream directly.\n *\n * The stream stays yours: stop its tracks when you are done, or call\n * {@link stopProducing} to tear the producer down first.\n *\n * @example Publish a canvas as your camera\n * ```ts\n * import { produceMedia } from 'mediasfu-shared';\n *\n * const canvas = document.querySelector('canvas')!;\n * const stream = canvas.captureStream(30);\n * await produceMedia({ parameters, stream, kind: 'video' });\n * ```\n *\n * @example Publish a video file's audio and video\n * ```ts\n * const el = document.querySelector('video')!;\n * const stream = (el as any).captureStream();\n * await produceMedia({ parameters, stream, kind: 'video' });\n * await produceMedia({ parameters, stream, kind: 'audio' });\n * ```\n */\nexport async function produceMedia({\n parameters,\n stream,\n kind,\n allowUnconstrained = false,\n}: ProduceMediaOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n const readiness = getRoomReadiness({ parameters: live });\n if (!readiness.ready) return { ok: false, error: readiness.reason };\n\n const trackKind = kind === 'audio' ? 'audio' : 'video';\n if (!hasLiveTrack(stream, trackKind)) {\n return {\n ok: false,\n error: `The stream has no live ${trackKind} track to publish.`,\n };\n }\n\n // The room's capture ceiling is an entitlement, and this path bypasses\n // clickVideo, which is where the SDK normally applies it.\n const limited = await enforceCaptureLimits(stream, live, kind, allowUnconstrained);\n if (!limited.ok) return limited;\n\n if (kind === 'audio') {\n await streamSuccessAudio({ stream, parameters: live as any });\n } else if (kind === 'screen') {\n await streamSuccessScreen({ stream, parameters: live as any });\n } else {\n await streamSuccessVideo({ stream, parameters: live as any });\n }\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The media could not be published.' };\n }\n}\n\nexport interface StopProducingOptions extends HeadlessOptions {\n kind: ProducerKind;\n}\n\nexport type StopProducingType = (\n options: StopProducingOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Tear down one of your producers without touching the others.\n *\n * `clickVideo`/`clickAudio` toggle capture *and* transport together. When you\n * published a custom stream you usually want to stop only the transport and\n * keep owning the stream (to swap sources without a visible gap, for example).\n *\n * @example Swap the published camera for a canvas without dropping the call\n * ```ts\n * await stopProducing({ parameters, kind: 'video' });\n * await produceMedia({ parameters, stream: canvasStream, kind: 'video' });\n * ```\n */\nexport async function stopProducing({\n parameters,\n kind,\n}: StopProducingOptions): Promise<HeadlessActionResult> {\n try {\n const live = getCurrentParams({ parameters });\n if (kind === 'audio') {\n await disconnectSendTransportAudio({ parameters: live as any });\n } else if (kind === 'screen') {\n await disconnectSendTransportScreen({ parameters: live as any });\n } else {\n await disconnectSendTransportVideo({ parameters: live as any });\n }\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The producer could not be stopped.' };\n }\n}\n\nexport interface ProduceCanvasOptions extends HeadlessOptions {\n canvas: HTMLCanvasElement;\n /** Capture frame rate. Defaults to 30. */\n frameRate?: number;\n /** Publish as the camera (default) or as a screen share. */\n as?: 'video' | 'screen';\n}\n\nexport type ProduceCanvasType = (\n options: ProduceCanvasOptions\n) => Promise<HeadlessActionResult & { stream: MediaStream | null }>;\n\n/**\n * Publish a `<canvas>` as video — slides, a whiteboard, a game, a generated\n * overlay, a test pattern.\n *\n * Returns the captured stream so you can stop its tracks when finished.\n *\n * @example\n * ```ts\n * const { ok, stream } = await produceCanvas({ parameters, canvas, frameRate: 15 });\n * // later\n * stream?.getTracks().forEach((track) => track.stop());\n * ```\n */\nexport async function produceCanvas({\n parameters,\n canvas,\n frameRate = 30,\n as = 'video',\n}: ProduceCanvasOptions): Promise<HeadlessActionResult & { stream: MediaStream | null }> {\n try {\n if (!canvas || typeof (canvas as any).captureStream !== 'function') {\n return {\n ok: false,\n error: 'This canvas cannot be captured in the current browser.',\n stream: null,\n };\n }\n const stream: MediaStream = (canvas as any).captureStream(frameRate);\n const result = await produceMedia({ parameters, stream, kind: as });\n if (!result.ok) {\n stream.getTracks().forEach((track) => track.stop());\n return { ...result, stream: null };\n }\n return { ...result, stream };\n } catch (error: any) {\n return {\n ok: false,\n error: error?.message || 'The canvas could not be published.',\n stream: null,\n };\n }\n}\n\nexport interface ProduceElementOptions extends HeadlessOptions {\n /** A playing `<video>` or `<audio>` element. */\n element: HTMLMediaElement;\n /** Publish the video track. Defaults to true for `<video>`. */\n withVideo?: boolean;\n /** Publish the audio track. Defaults to true. */\n withAudio?: boolean;\n}\n\nexport type ProduceElementType = (\n options: ProduceElementOptions\n) => Promise<HeadlessActionResult & { stream: MediaStream | null }>;\n\n/**\n * Publish a playing `<video>` or `<audio>` element — media co-watching, a\n * pre-recorded intro, background music, an HLS or MP4 source.\n *\n * The element must actually be playing: a paused element captures no frames, and\n * browsers block autoplay with audio until the user has interacted with the page.\n *\n * @example\n * ```ts\n * const el = document.querySelector('video')!;\n * await el.play();\n * await produceElement({ parameters, element: el });\n * ```\n */\nexport async function produceElement({\n parameters,\n element,\n withVideo,\n withAudio = true,\n}: ProduceElementOptions): Promise<HeadlessActionResult & { stream: MediaStream | null }> {\n try {\n const capture =\n (element as any)?.captureStream || (element as any)?.mozCaptureStream;\n if (typeof capture !== 'function') {\n return {\n ok: false,\n error: 'This element cannot be captured in the current browser.',\n stream: null,\n };\n }\n const stream: MediaStream = capture.call(element);\n const wantsVideo = withVideo ?? hasLiveTrack(stream, 'video');\n\n const results: HeadlessActionResult[] = [];\n if (wantsVideo && hasLiveTrack(stream, 'video')) {\n results.push(await produceMedia({ parameters, stream, kind: 'video' }));\n }\n if (withAudio && hasLiveTrack(stream, 'audio')) {\n results.push(await produceMedia({ parameters, stream, kind: 'audio' }));\n }\n if (results.length === 0) {\n return { ok: false, error: 'The element has no live tracks yet.', stream: null };\n }\n const failure = results.find((result) => !result.ok);\n if (failure) return { ...failure, stream };\n return { ok: true, error: '', stream };\n } catch (error: any) {\n return {\n ok: false,\n error: error?.message || 'The element could not be published.',\n stream: null,\n };\n }\n}\n\nexport interface ProduceDisplayOptions extends HeadlessOptions {\n /** Passed to `getDisplayMedia`. Defaults to `{ video: true }`. */\n constraints?: DisplayMediaStreamOptions;\n /** Also publish the captured system/tab audio when the user shares it. */\n withAudio?: boolean;\n}\n\nexport type ProduceDisplayType = (\n options: ProduceDisplayOptions\n) => Promise<HeadlessActionResult & { stream: MediaStream | null }>;\n\n/**\n * Start a screen share from a headless surface.\n *\n * `getDisplayMedia` must be called from a user gesture, so invoke this directly\n * in a click handler — not after an `await`.\n *\n * @example\n * ```tsx\n * <button onClick={() => produceDisplay({ parameters })}>Share screen</button>\n * ```\n */\nexport async function produceDisplay({\n parameters,\n constraints = { video: true },\n withAudio = false,\n}: ProduceDisplayOptions): Promise<HeadlessActionResult & { stream: MediaStream | null }> {\n try {\n const mediaDevices: any =\n (parameters as HeadlessParameters)?.mediaDevices ||\n (typeof navigator !== 'undefined' ? navigator.mediaDevices : null);\n if (!mediaDevices || typeof mediaDevices.getDisplayMedia !== 'function') {\n return {\n ok: false,\n error: 'Screen capture is unavailable in this browser.',\n stream: null,\n };\n }\n const stream: MediaStream = await mediaDevices.getDisplayMedia({\n ...constraints,\n ...(withAudio ? { audio: true } : {}),\n });\n const result = await produceMedia({ parameters, stream, kind: 'screen' });\n if (!result.ok) {\n stream.getTracks().forEach((track) => track.stop());\n return { ...result, stream: null };\n }\n if (withAudio && hasLiveTrack(stream, 'audio')) {\n await produceMedia({ parameters, stream, kind: 'audio' });\n }\n return { ...result, stream };\n } catch (error: any) {\n // A user dismissing the picker rejects here; that is not an error worth shouting about.\n const name = error?.name || '';\n if (name === 'NotAllowedError' || name === 'AbortError') {\n return { ok: false, error: 'Screen sharing was cancelled.', stream: null };\n }\n return {\n ok: false,\n error: error?.message || 'The screen could not be shared.',\n stream: null,\n };\n }\n}\n\nexport interface ReplaceProducerTrackOptions extends HeadlessOptions {\n /** The replacement track. Its kind decides which producer is swapped. */\n track: MediaStreamTrack;\n}\n\nexport type ReplaceProducerTrackType = (\n options: ReplaceProducerTrackOptions\n) => Promise<HeadlessActionResult>;\n\n/**\n * Swap the track on a live producer without renegotiating.\n *\n * This is the seamless path for switching camera, applying or removing a\n * background effect, or moving between media sources: remote participants see\n * no interruption, because the producer and its transport stay up.\n *\n * @example\n * ```ts\n * const processed = applyBackgroundBlur(cameraTrack);\n * await replaceProducerTrack({ parameters, track: processed });\n * ```\n */\nexport async function replaceProducerTrack({\n parameters,\n track,\n}: ReplaceProducerTrackOptions): Promise<HeadlessActionResult> {\n try {\n if (!track || track.readyState !== 'live') {\n return { ok: false, error: 'The replacement track is not live.' };\n }\n const live = getCurrentParams({ parameters });\n const producer =\n track.kind === 'audio'\n ? live.audioProducer || live.localAudioProducer\n : live.videoProducer || live.localVideoProducer;\n if (!producer || typeof producer.replaceTrack !== 'function') {\n return {\n ok: false,\n error: `There is no live ${track.kind} producer to replace.`,\n };\n }\n await producer.replaceTrack({ track });\n return { ok: true, error: '' };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'The track could not be replaced.' };\n }\n}\n","import { Participant, Stream } from '../../types/types';\n\nexport interface GetParticipantMediaOptions {\n /**\n * A participant id, or a producer id when the caller already holds one.\n */\n id?: string;\n /** A participant display name. Used when `id` resolves nothing. */\n name?: string;\n /** Which media to resolve. Defaults to `video`. */\n kind?: 'video' | 'audio';\n /**\n * The MediaSFU parameter bag — the object handed to `updateSourceParameters`,\n * or anything exposing `participants`, `allVideoStreams` and `allAudioStreams`.\n */\n parameters: {\n participants?: Participant[];\n allVideoStreams?: (Participant | Stream)[];\n allAudioStreams?: (Participant | Stream)[];\n getCurrentParams?: () => any;\n getUpdatedAllParams?: () => any;\n [key: string]: any;\n };\n}\n\nexport type GetParticipantMediaType = (\n options: GetParticipantMediaOptions\n) => Promise<MediaStream | null>;\n\n/**\n * Resolve a participant's live MediaStream from a MediaSFU parameter bag.\n *\n * This is the SDK-level counterpart of the `getParticipantMedia` helper that\n * MediaSFU components publish through `sourceParameters`. That helper remains\n * available for backwards compatibility; prefer this export when you drive the\n * SDK headlessly (`returnUI={false}`) and only hold the parameter bag.\n *\n * Resolution order:\n * 1. `parameters.participants` matched by `id`, then by `name`.\n * 2. The matched participant's `videoID` / `audioID`, looked up against\n * `allVideoStreams` / `allAudioStreams` by `producerId`. These collections\n * are keyed by producer id only — a participant's `id` is its membership id\n * and never matches, which is why an id-keyed lookup silently returns null.\n * 3. `id` treated directly as a producer id, for callers that already hold one.\n *\n * @example\n * ```ts\n * import { getParticipantMedia } from 'mediasfu-reactjs';\n *\n * const stream = await getParticipantMedia({\n * name: 'Paul',\n * kind: 'video',\n * parameters: sourceParameters.current,\n * });\n * if (stream) videoElement.srcObject = stream;\n * ```\n */\nexport async function getParticipantMedia({\n id = '',\n name = '',\n kind = 'video',\n parameters,\n}: GetParticipantMediaOptions): Promise<MediaStream | null> {\n try {\n if (!parameters) return null;\n // Prefer the freshest bag when the caller holds an older snapshot.\n const live =\n typeof parameters.getCurrentParams === 'function'\n ? parameters.getCurrentParams() || parameters\n : parameters;\n\n const participants: Participant[] = Array.isArray(live.participants)\n ? live.participants\n : [];\n const streams: (Participant | Stream)[] = Array.isArray(\n kind === 'video' ? live.allVideoStreams : live.allAudioStreams\n )\n ? kind === 'video'\n ? live.allVideoStreams\n : live.allAudioStreams\n : [];\n if (streams.length === 0) return null;\n\n let participant = id\n ? participants.find((part) => part.id === id)\n : undefined;\n if (!participant && name) {\n participant = participants.find((part) => part.name === name);\n }\n\n const producerId = participant\n ? kind === 'video'\n ? participant.videoID\n : participant.audioID\n : '';\n if (producerId) {\n const match = streams.find((stream) => stream.producerId === producerId);\n if (match && match.stream) return match.stream;\n }\n\n if (id) {\n const direct = streams.find((stream) => stream.producerId === id);\n if (direct && direct.stream) return direct.stream;\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nexport default getParticipantMedia;\n"],"names":["participantList","collect","modifySettings","streamSuccessAudio","streamSuccessScreen","streamSuccessVideo","disconnectSendTransportAudio","disconnectSendTransportScreen","disconnectSendTransportVideo"],"mappings":"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"}