@whereby.com/core 0.15.2 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  var toolkit = require('@reduxjs/toolkit');
4
4
  var media = require('@whereby.com/media');
5
+ var events$1 = require('events');
5
6
  var Chrome111_js = require('mediasoup-client/lib/handlers/Chrome111.js');
6
7
  var nodeBtoa = require('btoa');
7
8
  var axios = require('axios');
8
- var EventEmitter = require('events');
9
9
 
10
10
  function createAppAsyncThunk(typePrefix, payloadCreator) {
11
11
  return toolkit.createAsyncThunk(typePrefix, payloadCreator);
@@ -45,9 +45,9 @@ const createReactor = (selectors, callback) => {
45
45
  });
46
46
  };
47
47
 
48
- const coreVersion = "0.15.2";
48
+ const coreVersion = "0.16.1";
49
49
 
50
- const initialState$e = {
50
+ const initialState$f = {
51
51
  isNodeSdk: false,
52
52
  isActive: false,
53
53
  roomName: null,
@@ -58,7 +58,7 @@ const initialState$e = {
58
58
  };
59
59
  const appSlice = toolkit.createSlice({
60
60
  name: "app",
61
- initialState: initialState$e,
61
+ initialState: initialState$f,
62
62
  reducers: {
63
63
  doAppStart: (state, action) => {
64
64
  const url = new URL(action.payload.roomUrl);
@@ -103,6 +103,8 @@ const signalEvents = {
103
103
  roomSessionEnded: createSignalEventAction("roomSessionEnded"),
104
104
  screenshareStarted: createSignalEventAction("screenshareStarted"),
105
105
  screenshareStopped: createSignalEventAction("screenshareStopped"),
106
+ spotlightAdded: createSignalEventAction("spotlightAdded"),
107
+ spotlightRemoved: createSignalEventAction("spotlightRemoved"),
106
108
  streamingStopped: createSignalEventAction("streamingStopped"),
107
109
  videoEnabled: createSignalEventAction("videoEnabled"),
108
110
  };
@@ -112,14 +114,16 @@ const ROOM_ACTION_PERMISSIONS_BY_ROLE = {
112
114
  canRequestAudioEnable: ["host"],
113
115
  canKickClient: ["host"],
114
116
  canEndMeeting: ["host"],
117
+ canAskToSpeak: ["host"],
118
+ canSpotlight: ["host"],
115
119
  };
116
- const initialState$d = {
120
+ const initialState$e = {
117
121
  roomKey: null,
118
122
  roleName: "none",
119
123
  };
120
124
  const authorizationSlice = toolkit.createSlice({
121
125
  name: "authorization",
122
- initialState: initialState$d,
126
+ initialState: initialState$e,
123
127
  reducers: {
124
128
  setRoomKey: (state, action) => {
125
129
  return Object.assign(Object.assign({}, state), { roomKey: action.payload });
@@ -143,6 +147,8 @@ const selectIsAuthorizedToLockRoom = toolkit.createSelector(selectAuthorizationR
143
147
  const selectIsAuthorizedToRequestAudioEnable = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canRequestAudioEnable.includes(localParticipantRole));
144
148
  const selectIsAuthorizedToKickClient = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canKickClient.includes(localParticipantRole));
145
149
  const selectIsAuthorizedToEndMeeting = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canEndMeeting.includes(localParticipantRole));
150
+ const selectIsAuthorizedToAskToSpeak = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canAskToSpeak.includes(localParticipantRole));
151
+ const selectIsAuthorizedToSpotlight = toolkit.createSelector(selectAuthorizationRoleName, (localParticipantRole) => ROOM_ACTION_PERMISSIONS_BY_ROLE.canSpotlight.includes(localParticipantRole));
146
152
 
147
153
  /******************************************************************************
148
154
  Copyright (c) Microsoft Corporation.
@@ -188,13 +194,13 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
188
194
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
189
195
  };
190
196
 
191
- const initialState$c = {
197
+ const initialState$d = {
192
198
  isFetching: false,
193
199
  data: null,
194
200
  };
195
201
  const deviceCredentialsSlice = toolkit.createSlice({
196
202
  name: "deviceCredentials",
197
- initialState: initialState$c,
203
+ initialState: initialState$d,
198
204
  reducers: {},
199
205
  extraReducers: (builder) => {
200
206
  builder.addCase(doGetDeviceCredentials.pending, (state) => {
@@ -254,6 +260,8 @@ function forwardSocketEvents(socket, dispatch) {
254
260
  socket.on("cloud_recording_started", (payload) => dispatch(signalEvents.cloudRecordingStarted(payload)));
255
261
  socket.on("cloud_recording_stopped", () => dispatch(signalEvents.cloudRecordingStopped()));
256
262
  socket.on("streaming_stopped", () => dispatch(signalEvents.streamingStopped()));
263
+ socket.on("spotlight_added", (payload) => dispatch(signalEvents.spotlightAdded(payload)));
264
+ socket.on("spotlight_removed", (payload) => dispatch(signalEvents.spotlightRemoved(payload)));
257
265
  }
258
266
  const SIGNAL_BASE_URL = "wss://signal.appearin.net" ;
259
267
  function createSocket() {
@@ -264,7 +272,7 @@ function createSocket() {
264
272
  };
265
273
  return new media.ServerSocket(socketHost, socketOverrides);
266
274
  }
267
- const initialState$b = {
275
+ const initialState$c = {
268
276
  deviceIdentified: false,
269
277
  isIdentifyingDevice: false,
270
278
  status: "ready",
@@ -272,7 +280,7 @@ const initialState$b = {
272
280
  };
273
281
  const signalConnectionSlice = toolkit.createSlice({
274
282
  name: "signalConnection",
275
- initialState: initialState$b,
283
+ initialState: initialState$c,
276
284
  reducers: {
277
285
  socketConnecting: (state) => {
278
286
  return Object.assign(Object.assign({}, state), { status: "connecting" });
@@ -376,12 +384,12 @@ startAppListening({
376
384
  },
377
385
  });
378
386
 
379
- const initialState$a = {
387
+ const initialState$b = {
380
388
  chatMessages: [],
381
389
  };
382
390
  const chatSlice = toolkit.createSlice({
383
391
  name: "chat",
384
- initialState: initialState$a,
392
+ initialState: initialState$b,
385
393
  reducers: {},
386
394
  extraReducers(builder) {
387
395
  builder.addCase(signalEvents.chatMessage, (state, action) => {
@@ -593,9 +601,11 @@ function parseUnverifiedRoomKeyData(roomKey) {
593
601
  const initialLocalMediaState = {
594
602
  busyDeviceIds: [],
595
603
  cameraEnabled: false,
604
+ currentSpeakerDeviceId: "default",
596
605
  devices: [],
597
606
  isSettingCameraDevice: false,
598
607
  isSettingMicrophoneDevice: false,
608
+ isSettingSpeakerDevice: false,
599
609
  isTogglingCamera: false,
600
610
  lowDataMode: false,
601
611
  microphoneEnabled: false,
@@ -627,6 +637,10 @@ const localMediaSlice = toolkit.createSlice({
627
637
  setCurrentMicrophoneDeviceId(state, action) {
628
638
  return Object.assign(Object.assign({}, state), { currentMicrophoneDeviceId: action.payload.deviceId });
629
639
  },
640
+ setCurrentSpeakerDeviceId(state, action) {
641
+ var _a;
642
+ return Object.assign(Object.assign({}, state), { currentSpeakerDeviceId: (_a = action.payload.deviceId) !== null && _a !== void 0 ? _a : "default" });
643
+ },
630
644
  toggleLowDataModeEnabled(state, action) {
631
645
  var _a;
632
646
  return Object.assign(Object.assign({}, state), { lowDataMode: (_a = action.payload.enabled) !== null && _a !== void 0 ? _a : !state.lowDataMode });
@@ -709,7 +723,7 @@ const localMediaSlice = toolkit.createSlice({
709
723
  });
710
724
  },
711
725
  });
712
- const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, toggleLowDataModeEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
726
+ const { deviceBusy, setCurrentCameraDeviceId, setCurrentMicrophoneDeviceId, setCurrentSpeakerDeviceId, toggleCameraEnabled, toggleMicrophoneEnabled, toggleLowDataModeEnabled, setLocalMediaOptions, setLocalMediaStream, localMediaStopped, localStreamMetadataUpdated, } = localMediaSlice.actions;
713
727
  const doToggleCamera = createAppAsyncThunk("localMedia/doToggleCamera", (_, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
714
728
  const state = getState();
715
729
  const stream = selectLocalMediaStream(state);
@@ -899,6 +913,7 @@ const selectBusyDeviceIds = (state) => state.localMedia.busyDeviceIds;
899
913
  const selectCameraDeviceError = (state) => state.localMedia.cameraDeviceError;
900
914
  const selectCurrentCameraDeviceId = (state) => state.localMedia.currentCameraDeviceId;
901
915
  const selectCurrentMicrophoneDeviceId = (state) => state.localMedia.currentMicrophoneDeviceId;
916
+ const selectCurrentSpeakerDeviceId = (state) => state.localMedia.currentSpeakerDeviceId;
902
917
  const selectIsCameraEnabled = (state) => state.localMedia.cameraEnabled;
903
918
  const selectIsMicrophoneEnabled = (state) => state.localMedia.microphoneEnabled;
904
919
  const selectIsLowDataModeEnabled = (state) => state.localMedia.lowDataMode;
@@ -1035,7 +1050,7 @@ startAppListening({
1035
1050
  },
1036
1051
  });
1037
1052
 
1038
- const initialState$9 = {
1053
+ const initialState$a = {
1039
1054
  displayName: "",
1040
1055
  id: "",
1041
1056
  isAudioEnabled: true,
@@ -1045,34 +1060,14 @@ const initialState$9 = {
1045
1060
  isScreenSharing: false,
1046
1061
  roleName: "none",
1047
1062
  clientClaim: undefined,
1063
+ stickyReaction: undefined,
1048
1064
  };
1049
- const doEnableAudio = createAppAsyncThunk("localParticipant/doEnableAudio", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
1050
- const state = getState();
1051
- const socket = selectSignalConnectionRaw(state).socket;
1052
- socket === null || socket === void 0 ? void 0 : socket.emit("enable_audio", { enabled: payload.enabled });
1053
- return payload.enabled;
1054
- }));
1055
- const doEnableVideo = createAppAsyncThunk("localParticipant/doEnableVideo", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
1056
- const state = getState();
1057
- const socket = selectSignalConnectionRaw(state).socket;
1058
- socket === null || socket === void 0 ? void 0 : socket.emit("enable_video", { enabled: payload.enabled });
1059
- return payload.enabled;
1060
- }));
1061
- const doSetDisplayName = createAppAsyncThunk("localParticipant/doSetDisplayName", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
1062
- const state = getState();
1063
- const socket = selectSignalConnectionRaw(state).socket;
1064
- socket === null || socket === void 0 ? void 0 : socket.emit("send_client_metadata", {
1065
- type: "UserData",
1066
- payload,
1067
- });
1068
- return payload.displayName;
1069
- }));
1070
1065
  const localParticipantSlice = toolkit.createSlice({
1071
1066
  name: "localParticipant",
1072
- initialState: initialState$9,
1067
+ initialState: initialState$a,
1073
1068
  reducers: {
1074
- doSetLocalParticipant: (state, action) => {
1075
- return Object.assign(Object.assign({}, state), action.payload);
1069
+ doSetDisplayName: (state, action) => {
1070
+ return Object.assign(Object.assign({}, state), { displayName: action.payload.displayName });
1076
1071
  },
1077
1072
  },
1078
1073
  extraReducers: (builder) => {
@@ -1085,8 +1080,8 @@ const localParticipantSlice = toolkit.createSlice({
1085
1080
  builder.addCase(doEnableVideo.fulfilled, (state, action) => {
1086
1081
  return Object.assign(Object.assign({}, state), { isVideoEnabled: action.payload });
1087
1082
  });
1088
- builder.addCase(doSetDisplayName.fulfilled, (state, action) => {
1089
- return Object.assign(Object.assign({}, state), { displayName: action.payload });
1083
+ builder.addCase(doSetLocalStickyReaction.fulfilled, (state, action) => {
1084
+ return Object.assign(Object.assign({}, state), { stickyReaction: action.payload });
1090
1085
  });
1091
1086
  builder.addCase(signalEvents.roomJoined, (state, action) => {
1092
1087
  var _a, _b;
@@ -1095,11 +1090,64 @@ const localParticipantSlice = toolkit.createSlice({
1095
1090
  });
1096
1091
  },
1097
1092
  });
1098
- const { doSetLocalParticipant } = localParticipantSlice.actions;
1093
+ const { doSetDisplayName } = localParticipantSlice.actions;
1094
+ const doEnableAudio = createAppAsyncThunk("localParticipant/doEnableAudio", (payload, { dispatch, getState }) => __awaiter(void 0, void 0, void 0, function* () {
1095
+ const state = getState();
1096
+ const socket = selectSignalConnectionRaw(state).socket;
1097
+ socket === null || socket === void 0 ? void 0 : socket.emit("enable_audio", { enabled: payload.enabled });
1098
+ if (payload.enabled) {
1099
+ dispatch(doSetLocalStickyReaction({ enabled: false }));
1100
+ }
1101
+ return payload.enabled;
1102
+ }));
1103
+ const doEnableVideo = createAppAsyncThunk("localParticipant/doEnableVideo", (payload, { getState }) => __awaiter(void 0, void 0, void 0, function* () {
1104
+ const state = getState();
1105
+ const socket = selectSignalConnectionRaw(state).socket;
1106
+ socket === null || socket === void 0 ? void 0 : socket.emit("enable_video", { enabled: payload.enabled });
1107
+ return payload.enabled;
1108
+ }));
1109
+ const doSetLocalStickyReaction = createAppAsyncThunk("localParticipant/doSetLocalStickyReaction", (payload, { getState, rejectWithValue }) => __awaiter(void 0, void 0, void 0, function* () {
1110
+ var _a;
1111
+ const state = getState();
1112
+ const currentStickyReaction = selectLocalParticipantStickyReaction(state);
1113
+ const stickyReactionCurrentlyEnabled = Boolean(currentStickyReaction);
1114
+ const enabled = (_a = payload.enabled) !== null && _a !== void 0 ? _a : !stickyReactionCurrentlyEnabled;
1115
+ if (enabled === stickyReactionCurrentlyEnabled) {
1116
+ return rejectWithValue(currentStickyReaction);
1117
+ }
1118
+ const stickyReaction = enabled ? { reaction: "✋", timestamp: new Date().toISOString() } : null;
1119
+ return stickyReaction;
1120
+ }));
1121
+ const doSendClientMetadata = createAppThunk(() => (_, getState) => {
1122
+ const state = getState();
1123
+ const socket = selectSignalConnectionRaw(state).socket;
1124
+ const payload = {
1125
+ displayName: selectLocalParticipantDisplayName(state),
1126
+ stickyReaction: selectLocalParticipantStickyReaction(state),
1127
+ };
1128
+ socket === null || socket === void 0 ? void 0 : socket.emit("send_client_metadata", {
1129
+ type: "UserData",
1130
+ payload,
1131
+ });
1132
+ });
1099
1133
  const selectLocalParticipantRaw = (state) => state.localParticipant;
1100
1134
  const selectSelfId = (state) => state.localParticipant.id;
1135
+ const selectLocalParticipantDisplayName = (state) => state.localParticipant.displayName;
1101
1136
  const selectLocalParticipantClientClaim = (state) => state.localParticipant.clientClaim;
1102
1137
  const selectLocalParticipantIsScreenSharing = (state) => state.localParticipant.isScreenSharing;
1138
+ const selectLocalParticipantStickyReaction = (state) => state.localParticipant.stickyReaction;
1139
+ const selectLocalParticipantView = toolkit.createSelector(selectLocalParticipantRaw, selectLocalMediaStream, (participant, localStream) => {
1140
+ const clientView = {
1141
+ id: participant.id,
1142
+ clientId: participant.id,
1143
+ displayName: participant.displayName,
1144
+ stream: localStream,
1145
+ isLocalClient: true,
1146
+ isAudioEnabled: participant.isAudioEnabled,
1147
+ isVideoEnabled: participant.isVideoEnabled,
1148
+ };
1149
+ return clientView;
1150
+ });
1103
1151
  startAppListening({
1104
1152
  actionCreator: toggleCameraEnabled,
1105
1153
  effect: ({ payload }, { dispatch, getState }) => {
@@ -1116,15 +1164,18 @@ startAppListening({
1116
1164
  dispatch(doEnableAudio({ enabled: enabled || !isAudioEnabled }));
1117
1165
  },
1118
1166
  });
1167
+ createReactor([selectLocalParticipantDisplayName, selectLocalParticipantStickyReaction], ({ dispatch }) => {
1168
+ dispatch(doSendClientMetadata());
1169
+ });
1119
1170
 
1120
- const initialState$8 = {
1171
+ const initialState$9 = {
1121
1172
  status: "inactive",
1122
1173
  stream: null,
1123
1174
  error: null,
1124
1175
  };
1125
1176
  const localScreenshareSlice = toolkit.createSlice({
1126
1177
  name: "localScreenshare",
1127
- initialState: initialState$8,
1178
+ initialState: initialState$9,
1128
1179
  reducers: {
1129
1180
  stopScreenshare(state, action) {
1130
1181
  return Object.assign(Object.assign({}, state), { status: "inactive", stream: null });
@@ -1193,60 +1244,6 @@ startAppListening({
1193
1244
  },
1194
1245
  });
1195
1246
 
1196
- const initialState$7 = {
1197
- data: null,
1198
- isFetching: false,
1199
- error: null,
1200
- };
1201
- const organizationSlice = toolkit.createSlice({
1202
- initialState: initialState$7,
1203
- name: "organization",
1204
- reducers: {},
1205
- extraReducers: (builder) => {
1206
- builder.addCase(doOrganizationFetch.pending, (state) => {
1207
- return Object.assign(Object.assign({}, state), { isFetching: true });
1208
- });
1209
- builder.addCase(doOrganizationFetch.fulfilled, (state, action) => {
1210
- if (!action.payload)
1211
- return Object.assign(Object.assign({}, state), { isFetching: true });
1212
- return Object.assign(Object.assign({}, state), { isFetching: false, data: action.payload });
1213
- });
1214
- builder.addCase(doOrganizationFetch.rejected, (state) => {
1215
- return Object.assign(Object.assign({}, state), { isFetching: false, error: true });
1216
- });
1217
- },
1218
- });
1219
- const doOrganizationFetch = createAppAsyncThunk("organization/doOrganizationFetch", (_, { extra, getState }) => __awaiter(void 0, void 0, void 0, function* () {
1220
- try {
1221
- const roomUrl = selectAppRoomUrl(getState());
1222
- const organization = yield extra.services.fetchOrganizationFromRoomUrl(roomUrl || "");
1223
- if (!organization) {
1224
- throw new Error("Invalid room url");
1225
- }
1226
- return organization;
1227
- }
1228
- catch (error) {
1229
- console.error(error);
1230
- }
1231
- }));
1232
- const selectOrganizationRaw = (state) => state.organization;
1233
- const selectOrganizationId = (state) => { var _a; return (_a = state.organization.data) === null || _a === void 0 ? void 0 : _a.organizationId; };
1234
- const selectShouldFetchOrganization = toolkit.createSelector(selectAppIsActive, selectOrganizationRaw, selectDeviceCredentialsRaw, (appIsActive, organization, deviceCredentials) => {
1235
- if (appIsActive &&
1236
- !organization.data &&
1237
- !organization.isFetching &&
1238
- !organization.error &&
1239
- !deviceCredentials.isFetching) {
1240
- return true;
1241
- }
1242
- return false;
1243
- });
1244
- createReactor([selectShouldFetchOrganization], ({ dispatch }, shouldFetchOrganization) => {
1245
- if (shouldFetchOrganization) {
1246
- dispatch(doOrganizationFetch());
1247
- }
1248
- });
1249
-
1250
1247
  function createRtcEventAction(name) {
1251
1248
  return toolkit.createAction(`rtcConnection/event/${name}`);
1252
1249
  }
@@ -1348,12 +1345,12 @@ function addStream(state, payload) {
1348
1345
  presentationStream: stream,
1349
1346
  });
1350
1347
  }
1351
- const initialState$6 = {
1348
+ const initialState$8 = {
1352
1349
  remoteParticipants: [],
1353
1350
  };
1354
1351
  const remoteParticipantsSlice = toolkit.createSlice({
1355
1352
  name: "remoteParticipants",
1356
- initialState: initialState$6,
1353
+ initialState: initialState$8,
1357
1354
  reducers: {
1358
1355
  streamStatusUpdated: (state, action) => {
1359
1356
  let newState = state;
@@ -1417,9 +1414,10 @@ const remoteParticipantsSlice = toolkit.createSlice({
1417
1414
  console.warn(error || "Client metadata error received");
1418
1415
  return state;
1419
1416
  }
1420
- const { clientId, displayName } = payload;
1417
+ const { clientId, displayName, stickyReaction } = payload;
1421
1418
  return updateParticipant(state, clientId, {
1422
1419
  displayName,
1420
+ stickyReaction,
1423
1421
  });
1424
1422
  });
1425
1423
  builder.addCase(signalEvents.screenshareStarted, (state, action) => {
@@ -1435,87 +1433,79 @@ const remoteParticipantsSlice = toolkit.createSlice({
1435
1433
  const { participantStreamAdded, participantStreamIdAdded, streamStatusUpdated } = remoteParticipantsSlice.actions;
1436
1434
  const doRequestAudioEnable = createAppAuthorizedThunk((state) => selectIsAuthorizedToRequestAudioEnable(state), (payload) => (_, getState) => {
1437
1435
  const state = getState();
1436
+ const canEnableRemoteAudio = selectIsAuthorizedToAskToSpeak(state);
1437
+ if (payload.enable && !canEnableRemoteAudio) {
1438
+ console.warn("Not authorized to perform this action");
1439
+ return;
1440
+ }
1438
1441
  const socket = selectSignalConnectionRaw(state).socket;
1439
1442
  socket === null || socket === void 0 ? void 0 : socket.emit("request_audio_enable", payload);
1440
1443
  });
1441
1444
  const selectRemoteParticipantsRaw = (state) => state.remoteParticipants;
1442
1445
  const selectRemoteParticipants = (state) => state.remoteParticipants.remoteParticipants;
1443
- const selectScreenshares = toolkit.createSelector(selectLocalScreenshareStream, selectRemoteParticipants, (localScreenshareStream, remoteParticipants) => {
1444
- const screenshares = [];
1445
- if (localScreenshareStream) {
1446
- screenshares.push({
1447
- id: localScreenshareStream.id || "local-screenshare",
1448
- participantId: "local",
1449
- hasAudioTrack: localScreenshareStream.getTracks().some((track) => track.kind === "audio"),
1450
- stream: localScreenshareStream,
1451
- isLocal: true,
1452
- });
1453
- }
1454
- for (const participant of remoteParticipants) {
1455
- if (participant.presentationStream) {
1456
- screenshares.push({
1457
- id: participant.presentationStream.id || `pres-${participant.id}`,
1458
- participantId: participant.id,
1459
- hasAudioTrack: participant.presentationStream.getTracks().some((track) => track.kind === "audio"),
1460
- stream: participant.presentationStream,
1461
- isLocal: false,
1462
- });
1463
- }
1464
- }
1465
- return screenshares;
1466
- });
1446
+ const selectNumParticipants = toolkit.createSelector(selectRemoteParticipants, (clients) => clients.filter((c) => !NON_PERSON_ROLES.includes(c.roleName)).length + 1);
1467
1447
 
1468
- const initialState$5 = {
1469
- isLocked: false,
1448
+ const initialState$7 = {
1449
+ data: null,
1450
+ isFetching: false,
1451
+ error: null,
1470
1452
  };
1471
- const roomSlice = toolkit.createSlice({
1472
- name: "room",
1473
- initialState: initialState$5,
1453
+ const organizationSlice = toolkit.createSlice({
1454
+ initialState: initialState$7,
1455
+ name: "organization",
1474
1456
  reducers: {},
1475
1457
  extraReducers: (builder) => {
1476
- builder.addCase(signalEvents.roomJoined, (state, action) => {
1477
- const { error, isLocked } = action.payload;
1478
- if (error) {
1479
- return state;
1480
- }
1481
- return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1458
+ builder.addCase(doOrganizationFetch.pending, (state) => {
1459
+ return Object.assign(Object.assign({}, state), { isFetching: true });
1482
1460
  });
1483
- builder.addCase(signalEvents.roomLocked, (state, action) => {
1484
- const { isLocked } = action.payload;
1485
- return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1461
+ builder.addCase(doOrganizationFetch.fulfilled, (state, action) => {
1462
+ if (!action.payload)
1463
+ return Object.assign(Object.assign({}, state), { isFetching: true });
1464
+ return Object.assign(Object.assign({}, state), { isFetching: false, data: action.payload });
1465
+ });
1466
+ builder.addCase(doOrganizationFetch.rejected, (state) => {
1467
+ return Object.assign(Object.assign({}, state), { isFetching: false, error: true });
1486
1468
  });
1487
1469
  },
1488
1470
  });
1489
- const doLockRoom = createAppAuthorizedThunk((state) => selectIsAuthorizedToLockRoom(state), (payload) => (_, getState) => {
1490
- const state = getState();
1491
- const { socket } = selectSignalConnectionRaw(state);
1492
- socket === null || socket === void 0 ? void 0 : socket.emit("set_lock", { locked: payload.locked });
1493
- });
1494
- const doKickParticipant = createAppAuthorizedThunk((state) => selectIsAuthorizedToKickClient(state), (payload) => (_, getState) => {
1495
- const state = getState();
1496
- const { socket } = selectSignalConnectionRaw(state);
1497
- socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientId: payload.clientId, reasonId: "kick" });
1498
- });
1499
- const doEndMeeting = createAppAuthorizedThunk((state) => selectIsAuthorizedToEndMeeting(state), (payload) => (dispatch, getState) => {
1500
- const state = getState();
1501
- const clientsToKick = selectRemoteParticipants(state).map((c) => c.id);
1502
- if (clientsToKick.length) {
1503
- const { socket } = selectSignalConnectionRaw(state);
1504
- socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientIds: clientsToKick, reasonId: "end-meeting" });
1471
+ const doOrganizationFetch = createAppAsyncThunk("organization/doOrganizationFetch", (_, { extra, getState }) => __awaiter(void 0, void 0, void 0, function* () {
1472
+ try {
1473
+ const roomUrl = selectAppRoomUrl(getState());
1474
+ const organization = yield extra.services.fetchOrganizationFromRoomUrl(roomUrl || "");
1475
+ if (!organization) {
1476
+ throw new Error("Invalid room url");
1477
+ }
1478
+ return organization;
1505
1479
  }
1506
- if (!payload.stayBehind) {
1507
- dispatch(doAppStop());
1480
+ catch (error) {
1481
+ console.error(error);
1482
+ }
1483
+ }));
1484
+ const selectOrganizationRaw = (state) => state.organization;
1485
+ const selectOrganizationId = (state) => { var _a; return (_a = state.organization.data) === null || _a === void 0 ? void 0 : _a.organizationId; };
1486
+ const selectShouldFetchOrganization = toolkit.createSelector(selectAppIsActive, selectOrganizationRaw, selectDeviceCredentialsRaw, (appIsActive, organization, deviceCredentials) => {
1487
+ if (appIsActive &&
1488
+ !organization.data &&
1489
+ !organization.isFetching &&
1490
+ !organization.error &&
1491
+ !deviceCredentials.isFetching) {
1492
+ return true;
1493
+ }
1494
+ return false;
1495
+ });
1496
+ createReactor([selectShouldFetchOrganization], ({ dispatch }, shouldFetchOrganization) => {
1497
+ if (shouldFetchOrganization) {
1498
+ dispatch(doOrganizationFetch());
1508
1499
  }
1509
1500
  });
1510
- const selectRoomIsLocked = (state) => state.room.isLocked;
1511
1501
 
1512
- const initialState$4 = {
1502
+ const initialState$6 = {
1513
1503
  session: null,
1514
1504
  status: "ready",
1515
1505
  error: null,
1516
1506
  };
1517
1507
  const roomConnectionSlice = toolkit.createSlice({
1518
- initialState: initialState$4,
1508
+ initialState: initialState$6,
1519
1509
  name: "roomConnection",
1520
1510
  reducers: {
1521
1511
  connectionStatusChanged: (state, action) => {
@@ -1674,6 +1664,249 @@ startAppListening({
1674
1664
  },
1675
1665
  });
1676
1666
 
1667
+ const emitter = new events$1.EventEmitter();
1668
+ function createNotificationEvent(payload) {
1669
+ const notificationEvent = Object.assign(Object.assign({}, payload), { timestamp: Date.now() });
1670
+ return notificationEvent;
1671
+ }
1672
+ const initialNotificationsState = {
1673
+ emitter,
1674
+ events: [],
1675
+ };
1676
+ const notificationsSlice = toolkit.createSlice({
1677
+ name: "notifications",
1678
+ initialState: initialNotificationsState,
1679
+ reducers: {
1680
+ addNotification: (state, action) => {
1681
+ return Object.assign(Object.assign({}, state), { events: [...state.events, Object.assign({}, action.payload)] });
1682
+ },
1683
+ doClearNotifications: (state) => {
1684
+ return Object.assign(Object.assign({}, state), { events: [] });
1685
+ },
1686
+ },
1687
+ });
1688
+ const { doClearNotifications } = notificationsSlice.actions;
1689
+ const doSetNotification = createAppThunk((payload) => (dispatch, getState) => {
1690
+ dispatch(notificationsSlice.actions.addNotification(payload));
1691
+ const state = getState();
1692
+ const emitter = selectNotificationsEmitter(state);
1693
+ emitter.emit(payload.type, payload);
1694
+ emitter.emit("*", payload);
1695
+ });
1696
+ const selectNotificationsRaw = (state) => state.notifications;
1697
+ const selectNotificationsEvents = (state) => state.notifications.events;
1698
+ const selectNotificationsEmitter = (state) => state.notifications.emitter;
1699
+ startAppListening({
1700
+ actionCreator: signalEvents.chatMessage,
1701
+ effect: ({ payload }, { dispatch, getState }) => {
1702
+ const state = getState();
1703
+ const client = selectRemoteParticipants(state).find(({ id }) => id === payload.senderId);
1704
+ if (!client) {
1705
+ console.warn("Could not find remote client that sent chat message");
1706
+ return;
1707
+ }
1708
+ dispatch(doSetNotification(createNotificationEvent({
1709
+ type: "chatMessageReceived",
1710
+ message: `${client.displayName} says: ${payload.text}`,
1711
+ props: {
1712
+ client,
1713
+ chatMessage: {
1714
+ senderId: payload.senderId,
1715
+ timestamp: payload.timestamp,
1716
+ text: payload.text,
1717
+ },
1718
+ },
1719
+ })));
1720
+ },
1721
+ });
1722
+ startAppListening({
1723
+ actionCreator: signalEvents.audioEnableRequested,
1724
+ effect: ({ payload }, { dispatch, getState }) => {
1725
+ const { enable, requestedByClientId } = payload;
1726
+ const state = getState();
1727
+ const client = selectRemoteParticipants(state).find(({ id }) => id === requestedByClientId);
1728
+ if (!client) {
1729
+ console.warn("Could not find remote client that requested a local audio change");
1730
+ return;
1731
+ }
1732
+ dispatch(doSetNotification(createNotificationEvent({
1733
+ type: enable ? "requestAudioEnable" : "requestAudioDisable",
1734
+ message: enable
1735
+ ? `${client.displayName} has requested for you to speak`
1736
+ : `${client.displayName} has muted your microphone`,
1737
+ props: {
1738
+ client,
1739
+ enable,
1740
+ },
1741
+ })));
1742
+ },
1743
+ });
1744
+ startAppListening({
1745
+ actionCreator: signalEvents.clientMetadataReceived,
1746
+ effect: (action, { dispatch, getOriginalState, getState }) => {
1747
+ var _a;
1748
+ const { error, payload } = action.payload;
1749
+ if (error || !payload) {
1750
+ return;
1751
+ }
1752
+ const { clientId, stickyReaction } = payload;
1753
+ const state = getState();
1754
+ const canAskToSpeak = selectIsAuthorizedToAskToSpeak(state);
1755
+ if (!canAskToSpeak) {
1756
+ return;
1757
+ }
1758
+ const client = selectRemoteParticipants(state).find(({ id }) => id === clientId);
1759
+ if (!client) {
1760
+ console.warn("Could not find remote client that provided updated metadata");
1761
+ return;
1762
+ }
1763
+ const previousState = getOriginalState();
1764
+ const previousClient = selectRemoteParticipants(previousState).find(({ id }) => id === clientId);
1765
+ if ((!stickyReaction && !(previousClient === null || previousClient === void 0 ? void 0 : previousClient.stickyReaction)) ||
1766
+ (stickyReaction === null || stickyReaction === void 0 ? void 0 : stickyReaction.timestamp) === ((_a = previousClient === null || previousClient === void 0 ? void 0 : previousClient.stickyReaction) === null || _a === void 0 ? void 0 : _a.timestamp)) {
1767
+ return;
1768
+ }
1769
+ dispatch(doSetNotification(createNotificationEvent({
1770
+ type: stickyReaction ? "remoteHandRaised" : "remoteHandLowered",
1771
+ message: `${client.displayName} ${stickyReaction ? "raised" : "lowered"} their hand`,
1772
+ props: {
1773
+ client,
1774
+ stickyReaction,
1775
+ },
1776
+ })));
1777
+ },
1778
+ });
1779
+ createReactor([selectSignalStatus], ({ dispatch, getState }, signalStatus) => {
1780
+ const state = getState();
1781
+ const roomConnectionStatus = selectRoomConnectionStatus(state);
1782
+ if (["left", "kicked"].includes(roomConnectionStatus)) {
1783
+ return;
1784
+ }
1785
+ if (signalStatus === "disconnected") {
1786
+ dispatch(doSetNotification(createNotificationEvent({
1787
+ type: "signalTrouble",
1788
+ message: `Network connection lost. Trying to reconnect you...`,
1789
+ props: {},
1790
+ })));
1791
+ }
1792
+ else if (signalStatus === "connected") {
1793
+ dispatch(doSetNotification(createNotificationEvent({
1794
+ type: "signalOk",
1795
+ message: `Network connection available`,
1796
+ props: {},
1797
+ })));
1798
+ }
1799
+ });
1800
+
1801
+ function isStreamerClient(client) {
1802
+ return client.roleName === "streamer";
1803
+ }
1804
+ function isRecorderClient(client) {
1805
+ return client.roleName === "recorder";
1806
+ }
1807
+ const initialState$5 = {
1808
+ isLocked: false,
1809
+ };
1810
+ const roomSlice = toolkit.createSlice({
1811
+ name: "room",
1812
+ initialState: initialState$5,
1813
+ reducers: {},
1814
+ extraReducers: (builder) => {
1815
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
1816
+ const { error, isLocked } = action.payload;
1817
+ if (error) {
1818
+ return state;
1819
+ }
1820
+ return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1821
+ });
1822
+ builder.addCase(signalEvents.roomLocked, (state, action) => {
1823
+ const { isLocked } = action.payload;
1824
+ return Object.assign(Object.assign({}, state), { isLocked: Boolean(isLocked) });
1825
+ });
1826
+ },
1827
+ });
1828
+ const doLockRoom = createAppAuthorizedThunk((state) => selectIsAuthorizedToLockRoom(state), (payload) => (_, getState) => {
1829
+ const state = getState();
1830
+ const { socket } = selectSignalConnectionRaw(state);
1831
+ socket === null || socket === void 0 ? void 0 : socket.emit("set_lock", { locked: payload.locked });
1832
+ });
1833
+ const doKickParticipant = createAppAuthorizedThunk((state) => selectIsAuthorizedToKickClient(state), (payload) => (_, getState) => {
1834
+ const state = getState();
1835
+ const { socket } = selectSignalConnectionRaw(state);
1836
+ socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientId: payload.clientId, reasonId: "kick" });
1837
+ });
1838
+ const doEndMeeting = createAppAuthorizedThunk((state) => selectIsAuthorizedToEndMeeting(state), (payload) => (dispatch, getState) => {
1839
+ const state = getState();
1840
+ const clientsToKick = selectRemoteParticipants(state).map((c) => c.id);
1841
+ if (clientsToKick.length) {
1842
+ const { socket } = selectSignalConnectionRaw(state);
1843
+ socket === null || socket === void 0 ? void 0 : socket.emit("kick_client", { clientIds: clientsToKick, reasonId: "end-meeting" });
1844
+ }
1845
+ if (!payload.stayBehind) {
1846
+ dispatch(doAppStop());
1847
+ }
1848
+ });
1849
+ const selectRoomIsLocked = (state) => state.room.isLocked;
1850
+ const selectScreenshares = toolkit.createSelector(selectLocalScreenshareStream, selectRemoteParticipants, (localScreenshareStream, remoteParticipants) => {
1851
+ const screenshares = [];
1852
+ if (localScreenshareStream) {
1853
+ screenshares.push({
1854
+ id: localScreenshareStream.id || "local-screenshare",
1855
+ participantId: "local",
1856
+ hasAudioTrack: localScreenshareStream.getTracks().some((track) => track.kind === "audio"),
1857
+ stream: localScreenshareStream,
1858
+ isLocal: true,
1859
+ });
1860
+ }
1861
+ for (const participant of remoteParticipants) {
1862
+ if (participant.presentationStream) {
1863
+ screenshares.push({
1864
+ id: participant.presentationStream.id || `pres-${participant.id}`,
1865
+ participantId: participant.id,
1866
+ hasAudioTrack: participant.presentationStream.getTracks().some((track) => track.kind === "audio"),
1867
+ stream: participant.presentationStream,
1868
+ isLocal: false,
1869
+ });
1870
+ }
1871
+ }
1872
+ return screenshares;
1873
+ });
1874
+ const selectRemoteClientViews = toolkit.createSelector(selectLocalScreenshareStream, selectLocalParticipantRaw, selectRemoteParticipants, (localScreenshareStream, localParticipant, remoteParticipants) => {
1875
+ const views = [];
1876
+ if (localScreenshareStream) {
1877
+ const isScreenshareAudioEnabled = !!localScreenshareStream.getAudioTracks().length;
1878
+ views.push({
1879
+ clientId: localParticipant.id,
1880
+ displayName: "Your screenshare",
1881
+ id: "local-screenshare",
1882
+ isAudioEnabled: isScreenshareAudioEnabled,
1883
+ isLocalClient: true,
1884
+ isPresentation: true,
1885
+ isVideoEnabled: true,
1886
+ stream: localScreenshareStream,
1887
+ });
1888
+ }
1889
+ for (const c of remoteParticipants) {
1890
+ if (isStreamerClient(c) || isRecorderClient(c)) {
1891
+ continue;
1892
+ }
1893
+ const { presentationStream } = c, clientView = __rest(c, ["presentationStream"]);
1894
+ const displayName = c.displayName || "Guest";
1895
+ const isPresentationActive = presentationStream && presentationStream.active;
1896
+ const presentationId = "pres-" + c.id;
1897
+ const isStreamActive = c.stream && c.stream.active;
1898
+ const isVideoEnabled = c.isVideoEnabled;
1899
+ views.push(Object.assign(Object.assign(Object.assign({}, clientView), { clientId: c.id, displayName, hasActivePresentation: !!isPresentationActive }), (c.isVideoEnabled ? { isVideoEnabled } : {})));
1900
+ if (isPresentationActive) {
1901
+ views.push(Object.assign(Object.assign(Object.assign({}, clientView), { clientId: c.id, stream: c.presentationStream, displayName: `Screenshare (${displayName})`, id: presentationId, isPresentation: true, isVideoEnabled: true }), (isStreamActive && { isRecording: null })));
1902
+ }
1903
+ }
1904
+ return views;
1905
+ });
1906
+ const selectAllClientViews = toolkit.createSelector(selectLocalParticipantView, selectRemoteClientViews, (localParticipant, remoteParticipants) => {
1907
+ return [localParticipant, ...remoteParticipants];
1908
+ });
1909
+
1677
1910
  const createWebRtcEmitter = (dispatch) => {
1678
1911
  return {
1679
1912
  emit: (eventName, data) => {
@@ -1690,7 +1923,7 @@ const createWebRtcEmitter = (dispatch) => {
1690
1923
  },
1691
1924
  };
1692
1925
  };
1693
- const initialState$3 = {
1926
+ const initialState$4 = {
1694
1927
  dispatcherCreated: false,
1695
1928
  error: null,
1696
1929
  isCreatingDispatcher: false,
@@ -1703,7 +1936,7 @@ const initialState$3 = {
1703
1936
  };
1704
1937
  const rtcConnectionSlice = toolkit.createSlice({
1705
1938
  name: "rtcConnection",
1706
- initialState: initialState$3,
1939
+ initialState: initialState$4,
1707
1940
  reducers: {
1708
1941
  isAcceptingStreams: (state, action) => {
1709
1942
  return Object.assign(Object.assign({}, state), { isAcceptingStreams: action.payload });
@@ -1713,7 +1946,7 @@ const rtcConnectionSlice = toolkit.createSlice({
1713
1946
  return Object.assign(Object.assign({}, state), { reportedStreamResolutions: Object.assign(Object.assign({}, state.reportedStreamResolutions), { [streamId]: { width, height } }) });
1714
1947
  },
1715
1948
  rtcDisconnected: () => {
1716
- return Object.assign({}, initialState$3);
1949
+ return Object.assign({}, initialState$4);
1717
1950
  },
1718
1951
  rtcDispatcherCreated: (state, action) => {
1719
1952
  return Object.assign(Object.assign({}, state), { dispatcherCreated: true, rtcManagerDispatcher: action.payload });
@@ -2011,7 +2244,7 @@ const rtcAnalyticsCustomEvents = {
2011
2244
  getOutput: () => ({}),
2012
2245
  },
2013
2246
  displayName: {
2014
- actions: [doSetDisplayName.fulfilled],
2247
+ actions: [doSetDisplayName],
2015
2248
  rtcEventName: "displayName",
2016
2249
  getValue: (state) => selectAppDisplayName(state),
2017
2250
  getOutput: (value) => ({ displayName: value }),
@@ -2078,11 +2311,11 @@ const makeComparable = (value) => {
2078
2311
  return JSON.stringify(value);
2079
2312
  return value;
2080
2313
  };
2081
- const initialState$2 = {
2314
+ const initialState$3 = {
2082
2315
  reportedValues: {},
2083
2316
  };
2084
2317
  const rtcAnalyticsSlice = toolkit.createSlice({
2085
- initialState: initialState$2,
2318
+ initialState: initialState$3,
2086
2319
  name: "rtcAnalytics",
2087
2320
  reducers: {
2088
2321
  updateReportedValues(state, action) {
@@ -2142,6 +2375,92 @@ createReactor([selectRtcManagerInitialized], ({ dispatch }, selectRtcManagerInit
2142
2375
  }
2143
2376
  });
2144
2377
 
2378
+ function streamIdForClient({ isPresentation, stream }) {
2379
+ var _a, _b;
2380
+ return isPresentation ? (_b = (_a = stream === null || stream === void 0 ? void 0 : stream.outboundId) !== null && _a !== void 0 ? _a : stream === null || stream === void 0 ? void 0 : stream.inboundId) !== null && _b !== void 0 ? _b : stream === null || stream === void 0 ? void 0 : stream.id : "0";
2381
+ }
2382
+ function isClientSpotlighted({ spotlights, isPresentation, clientId, stream, }) {
2383
+ return !!spotlights.find((s) => {
2384
+ const streamId = streamIdForClient({ isPresentation, stream });
2385
+ return s.clientId === clientId && s.streamId === streamId;
2386
+ });
2387
+ }
2388
+ function mergeSpotlight(spotlights, spotlight) {
2389
+ const found = spotlights.find((s) => s.clientId === spotlight.clientId && s.streamId === spotlight.streamId);
2390
+ if (found) {
2391
+ return spotlights;
2392
+ }
2393
+ return spotlights.concat(spotlight);
2394
+ }
2395
+ function mapSpotlightsToClientViews(spotlights, clientViews) {
2396
+ return spotlights.reduce((acc, s) => {
2397
+ const clientView = clientViews.find((c) => s.clientId === c.clientId && s.streamId === streamIdForClient(c));
2398
+ if (clientView && !acc.includes(clientView)) {
2399
+ acc.push(clientView);
2400
+ }
2401
+ return acc;
2402
+ }, []);
2403
+ }
2404
+ const initialState$2 = {
2405
+ sorted: [],
2406
+ };
2407
+ const spotlightsSlice = toolkit.createSlice({
2408
+ name: "spotlights",
2409
+ initialState: initialState$2,
2410
+ reducers: {},
2411
+ extraReducers: (builder) => {
2412
+ builder.addCase(signalEvents.roomJoined, (state, action) => {
2413
+ if (!action.payload.room) {
2414
+ return state;
2415
+ }
2416
+ const { spotlights } = action.payload.room;
2417
+ return Object.assign(Object.assign({}, state), { sorted: spotlights });
2418
+ });
2419
+ builder.addCase(signalEvents.spotlightAdded, (state, action) => {
2420
+ const { clientId, streamId } = action.payload;
2421
+ return Object.assign(Object.assign({}, state), { sorted: mergeSpotlight(state.sorted, { clientId, streamId }) });
2422
+ });
2423
+ builder.addCase(signalEvents.spotlightRemoved, (state, action) => {
2424
+ const { clientId, streamId } = action.payload;
2425
+ return Object.assign(Object.assign({}, state), { sorted: state.sorted.filter((s) => !(s.clientId === clientId && s.streamId === streamId)) });
2426
+ });
2427
+ builder.addMatcher(toolkit.isAnyOf(signalEvents.clientKicked, signalEvents.clientLeft), (state, action) => {
2428
+ const { clientId } = action.payload;
2429
+ return Object.assign(Object.assign({}, state), { sorted: state.sorted.filter((s) => s.clientId !== clientId) });
2430
+ });
2431
+ },
2432
+ });
2433
+ const doSpotlightParticipant = createAppAuthorizedThunk((state) => selectIsAuthorizedToSpotlight(state), ({ id }) => (_, getState) => {
2434
+ const state = getState();
2435
+ const clientView = selectAllClientViews(state).find((c) => c.clientId === id);
2436
+ if (!clientView) {
2437
+ return;
2438
+ }
2439
+ const { socket } = selectSignalConnectionRaw(state);
2440
+ const streamId = streamIdForClient(clientView);
2441
+ const payload = { clientId: clientView.id, streamId: streamId !== null && streamId !== void 0 ? streamId : "0" };
2442
+ socket === null || socket === void 0 ? void 0 : socket.emit("add_spotlight", payload);
2443
+ });
2444
+ const doRemoveSpotlight = createAppAuthorizedThunk((state) => selectIsAuthorizedToSpotlight(state), ({ id }) => (_, getState) => {
2445
+ const state = getState();
2446
+ const clientView = selectAllClientViews(state).find((c) => c.clientId === id);
2447
+ if (!clientView) {
2448
+ return;
2449
+ }
2450
+ const { socket } = selectSignalConnectionRaw(state);
2451
+ const streamId = streamIdForClient(clientView);
2452
+ const payload = { clientId: clientView.id, streamId: streamId !== null && streamId !== void 0 ? streamId : "0" };
2453
+ socket === null || socket === void 0 ? void 0 : socket.emit("remove_spotlight", payload);
2454
+ });
2455
+ const selectSpotlightsRaw = (state) => state.spotlights;
2456
+ const selectSpotlights = (state) => state.spotlights.sorted;
2457
+ const selectIsLocalParticipantSpotlighted = toolkit.createSelector(selectLocalParticipantRaw, selectSpotlights, (localParticipant, spotlights) => {
2458
+ return isClientSpotlighted({ clientId: localParticipant.id, stream: localParticipant.stream, spotlights });
2459
+ });
2460
+ const selectSpotlightedClientViews = toolkit.createSelector(selectAllClientViews, selectSpotlights, (clientViews, spotlights) => {
2461
+ return mapSpotlightsToClientViews(spotlights, clientViews);
2462
+ });
2463
+
2145
2464
  const initialState$1 = {
2146
2465
  isStreaming: false,
2147
2466
  error: null,
@@ -2226,6 +2545,7 @@ const appReducer = toolkit.combineReducers({
2226
2545
  localMedia: localMediaSlice.reducer,
2227
2546
  localParticipant: localParticipantSlice.reducer,
2228
2547
  localScreenshare: localScreenshareSlice.reducer,
2548
+ notifications: notificationsSlice.reducer,
2229
2549
  organization: organizationSlice.reducer,
2230
2550
  remoteParticipants: remoteParticipantsSlice.reducer,
2231
2551
  room: roomSlice.reducer,
@@ -2233,6 +2553,7 @@ const appReducer = toolkit.combineReducers({
2233
2553
  rtcAnalytics: rtcAnalyticsSlice.reducer,
2234
2554
  rtcConnection: rtcConnectionSlice.reducer,
2235
2555
  signalConnection: signalConnectionSlice.reducer,
2556
+ spotlights: spotlightsSlice.reducer,
2236
2557
  streaming: streamingSlice.reducer,
2237
2558
  waitingParticipants: waitingParticipantsSlice.reducer,
2238
2559
  });
@@ -2618,7 +2939,7 @@ var localStorage$1 = localStorage;
2618
2939
  const events = {
2619
2940
  CREDENTIALS_SAVED: "credentials_saved",
2620
2941
  };
2621
- class CredentialsService extends EventEmitter {
2942
+ class CredentialsService extends events$1.EventEmitter {
2622
2943
  constructor({ deviceService, credentialsStore, }) {
2623
2944
  super();
2624
2945
  this._deviceService = deviceService;
@@ -3240,18 +3561,19 @@ class RoomService {
3240
3561
  }
3241
3562
 
3242
3563
  class RoomParticipant {
3243
- constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled }) {
3564
+ constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled, stickyReaction }) {
3244
3565
  this.isLocalParticipant = false;
3245
3566
  this.displayName = displayName;
3246
3567
  this.id = id;
3247
3568
  this.stream = stream;
3248
3569
  this.isAudioEnabled = isAudioEnabled;
3249
3570
  this.isVideoEnabled = isVideoEnabled;
3571
+ this.stickyReaction = stickyReaction;
3250
3572
  }
3251
3573
  }
3252
3574
  class LocalParticipant extends RoomParticipant {
3253
- constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled }) {
3254
- super({ displayName, id, stream, isAudioEnabled, isVideoEnabled });
3575
+ constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled, stickyReaction }) {
3576
+ super({ displayName, id, stream, isAudioEnabled, isVideoEnabled, stickyReaction });
3255
3577
  this.isLocalParticipant = true;
3256
3578
  }
3257
3579
  }
@@ -3309,6 +3631,7 @@ exports.deviceIdentifying = deviceIdentifying;
3309
3631
  exports.doAcceptWaitingParticipant = doAcceptWaitingParticipant;
3310
3632
  exports.doAppStart = doAppStart;
3311
3633
  exports.doAppStop = doAppStop;
3634
+ exports.doClearNotifications = doClearNotifications;
3312
3635
  exports.doConnectRoom = doConnectRoom;
3313
3636
  exports.doConnectRtc = doConnectRtc;
3314
3637
  exports.doDisconnectRtc = doDisconnectRtc;
@@ -3324,18 +3647,22 @@ exports.doKnockRoom = doKnockRoom;
3324
3647
  exports.doLockRoom = doLockRoom;
3325
3648
  exports.doOrganizationFetch = doOrganizationFetch;
3326
3649
  exports.doRejectWaitingParticipant = doRejectWaitingParticipant;
3650
+ exports.doRemoveSpotlight = doRemoveSpotlight;
3327
3651
  exports.doRequestAudioEnable = doRequestAudioEnable;
3328
3652
  exports.doRtcAnalyticsCustomEventsInitialize = doRtcAnalyticsCustomEventsInitialize;
3329
3653
  exports.doRtcManagerCreated = doRtcManagerCreated;
3330
3654
  exports.doRtcManagerInitialize = doRtcManagerInitialize;
3331
3655
  exports.doRtcReportStreamResolution = doRtcReportStreamResolution;
3332
3656
  exports.doSendChatMessage = doSendChatMessage;
3657
+ exports.doSendClientMetadata = doSendClientMetadata;
3333
3658
  exports.doSetDevice = doSetDevice;
3334
3659
  exports.doSetDisplayName = doSetDisplayName;
3335
- exports.doSetLocalParticipant = doSetLocalParticipant;
3660
+ exports.doSetLocalStickyReaction = doSetLocalStickyReaction;
3661
+ exports.doSetNotification = doSetNotification;
3336
3662
  exports.doSignalConnect = doSignalConnect;
3337
3663
  exports.doSignalDisconnect = doSignalDisconnect;
3338
3664
  exports.doSignalIdentifyDevice = doSignalIdentifyDevice;
3665
+ exports.doSpotlightParticipant = doSpotlightParticipant;
3339
3666
  exports.doStartCloudRecording = doStartCloudRecording;
3340
3667
  exports.doStartLocalMedia = doStartLocalMedia;
3341
3668
  exports.doStartScreenshare = doStartScreenshare;
@@ -3349,15 +3676,19 @@ exports.doUpdateDeviceList = doUpdateDeviceList;
3349
3676
  exports.getAudioTrack = getAudioTrack;
3350
3677
  exports.getFakeMediaStream = getFakeMediaStream;
3351
3678
  exports.getVideoTrack = getVideoTrack;
3679
+ exports.hasValue = hasValue;
3352
3680
  exports.initialCloudRecordingState = initialCloudRecordingState;
3353
3681
  exports.initialLocalMediaState = initialLocalMediaState;
3682
+ exports.initialNotificationsState = initialNotificationsState;
3354
3683
  exports.isAcceptingStreams = isAcceptingStreams;
3684
+ exports.isClientSpotlighted = isClientSpotlighted;
3355
3685
  exports.listenerMiddleware = listenerMiddleware;
3356
3686
  exports.localMediaSlice = localMediaSlice;
3357
3687
  exports.localMediaStopped = localMediaStopped;
3358
3688
  exports.localParticipantSlice = localParticipantSlice;
3359
3689
  exports.localScreenshareSlice = localScreenshareSlice;
3360
3690
  exports.localStreamMetadataUpdated = localStreamMetadataUpdated;
3691
+ exports.notificationsSlice = notificationsSlice;
3361
3692
  exports.observeStore = observeStore;
3362
3693
  exports.organizationSlice = organizationSlice;
3363
3694
  exports.parseRoomUrlAndSubdomain = parseRoomUrlAndSubdomain;
@@ -3378,6 +3709,7 @@ exports.rtcDispatcherCreated = rtcDispatcherCreated;
3378
3709
  exports.rtcManagerCreated = rtcManagerCreated;
3379
3710
  exports.rtcManagerDestroyed = rtcManagerDestroyed;
3380
3711
  exports.rtcManagerInitialized = rtcManagerInitialized;
3712
+ exports.selectAllClientViews = selectAllClientViews;
3381
3713
  exports.selectAppDisplayName = selectAppDisplayName;
3382
3714
  exports.selectAppExternalId = selectAppExternalId;
3383
3715
  exports.selectAppInitialConfig = selectAppInitialConfig;
@@ -3399,17 +3731,21 @@ exports.selectCloudRecordingStartedAt = selectCloudRecordingStartedAt;
3399
3731
  exports.selectCloudRecordingStatus = selectCloudRecordingStatus;
3400
3732
  exports.selectCurrentCameraDeviceId = selectCurrentCameraDeviceId;
3401
3733
  exports.selectCurrentMicrophoneDeviceId = selectCurrentMicrophoneDeviceId;
3734
+ exports.selectCurrentSpeakerDeviceId = selectCurrentSpeakerDeviceId;
3402
3735
  exports.selectDeviceCredentialsRaw = selectDeviceCredentialsRaw;
3403
3736
  exports.selectDeviceId = selectDeviceId;
3404
3737
  exports.selectHasFetchedDeviceCredentials = selectHasFetchedDeviceCredentials;
3405
3738
  exports.selectIsAcceptingStreams = selectIsAcceptingStreams;
3739
+ exports.selectIsAuthorizedToAskToSpeak = selectIsAuthorizedToAskToSpeak;
3406
3740
  exports.selectIsAuthorizedToEndMeeting = selectIsAuthorizedToEndMeeting;
3407
3741
  exports.selectIsAuthorizedToKickClient = selectIsAuthorizedToKickClient;
3408
3742
  exports.selectIsAuthorizedToLockRoom = selectIsAuthorizedToLockRoom;
3409
3743
  exports.selectIsAuthorizedToRequestAudioEnable = selectIsAuthorizedToRequestAudioEnable;
3744
+ exports.selectIsAuthorizedToSpotlight = selectIsAuthorizedToSpotlight;
3410
3745
  exports.selectIsCameraEnabled = selectIsCameraEnabled;
3411
3746
  exports.selectIsCloudRecording = selectIsCloudRecording;
3412
3747
  exports.selectIsLocalMediaStarting = selectIsLocalMediaStarting;
3748
+ exports.selectIsLocalParticipantSpotlighted = selectIsLocalParticipantSpotlighted;
3413
3749
  exports.selectIsLowDataModeEnabled = selectIsLowDataModeEnabled;
3414
3750
  exports.selectIsMicrophoneEnabled = selectIsMicrophoneEnabled;
3415
3751
  exports.selectIsSettingCameraDevice = selectIsSettingCameraDevice;
@@ -3427,15 +3763,23 @@ exports.selectLocalMediaStartError = selectLocalMediaStartError;
3427
3763
  exports.selectLocalMediaStatus = selectLocalMediaStatus;
3428
3764
  exports.selectLocalMediaStream = selectLocalMediaStream;
3429
3765
  exports.selectLocalParticipantClientClaim = selectLocalParticipantClientClaim;
3766
+ exports.selectLocalParticipantDisplayName = selectLocalParticipantDisplayName;
3430
3767
  exports.selectLocalParticipantIsScreenSharing = selectLocalParticipantIsScreenSharing;
3431
3768
  exports.selectLocalParticipantRaw = selectLocalParticipantRaw;
3769
+ exports.selectLocalParticipantStickyReaction = selectLocalParticipantStickyReaction;
3770
+ exports.selectLocalParticipantView = selectLocalParticipantView;
3432
3771
  exports.selectLocalScreenshareRaw = selectLocalScreenshareRaw;
3433
3772
  exports.selectLocalScreenshareStatus = selectLocalScreenshareStatus;
3434
3773
  exports.selectLocalScreenshareStream = selectLocalScreenshareStream;
3435
3774
  exports.selectMicrophoneDeviceError = selectMicrophoneDeviceError;
3436
3775
  exports.selectMicrophoneDevices = selectMicrophoneDevices;
3776
+ exports.selectNotificationsEmitter = selectNotificationsEmitter;
3777
+ exports.selectNotificationsEvents = selectNotificationsEvents;
3778
+ exports.selectNotificationsRaw = selectNotificationsRaw;
3779
+ exports.selectNumParticipants = selectNumParticipants;
3437
3780
  exports.selectOrganizationId = selectOrganizationId;
3438
3781
  exports.selectOrganizationRaw = selectOrganizationRaw;
3782
+ exports.selectRemoteClientViews = selectRemoteClientViews;
3439
3783
  exports.selectRemoteParticipants = selectRemoteParticipants;
3440
3784
  exports.selectRemoteParticipantsRaw = selectRemoteParticipantsRaw;
3441
3785
  exports.selectRoomConnectionError = selectRoomConnectionError;
@@ -3467,12 +3811,16 @@ exports.selectSignalConnectionSocket = selectSignalConnectionSocket;
3467
3811
  exports.selectSignalIsIdentifyingDevice = selectSignalIsIdentifyingDevice;
3468
3812
  exports.selectSignalStatus = selectSignalStatus;
3469
3813
  exports.selectSpeakerDevices = selectSpeakerDevices;
3814
+ exports.selectSpotlightedClientViews = selectSpotlightedClientViews;
3815
+ exports.selectSpotlights = selectSpotlights;
3816
+ exports.selectSpotlightsRaw = selectSpotlightsRaw;
3470
3817
  exports.selectStreamingRaw = selectStreamingRaw;
3471
3818
  exports.selectStreamsToAccept = selectStreamsToAccept;
3472
3819
  exports.selectWaitingParticipants = selectWaitingParticipants;
3473
3820
  exports.selectWaitingParticipantsRaw = selectWaitingParticipantsRaw;
3474
3821
  exports.setCurrentCameraDeviceId = setCurrentCameraDeviceId;
3475
3822
  exports.setCurrentMicrophoneDeviceId = setCurrentMicrophoneDeviceId;
3823
+ exports.setCurrentSpeakerDeviceId = setCurrentSpeakerDeviceId;
3476
3824
  exports.setLocalMediaOptions = setLocalMediaOptions;
3477
3825
  exports.setLocalMediaStream = setLocalMediaStream;
3478
3826
  exports.setRoomKey = setRoomKey;
@@ -3482,8 +3830,10 @@ exports.socketConnected = socketConnected;
3482
3830
  exports.socketConnecting = socketConnecting;
3483
3831
  exports.socketDisconnected = socketDisconnected;
3484
3832
  exports.socketReconnecting = socketReconnecting;
3833
+ exports.spotlightsSlice = spotlightsSlice;
3485
3834
  exports.startAppListening = startAppListening;
3486
3835
  exports.stopScreenshare = stopScreenshare;
3836
+ exports.streamIdForClient = streamIdForClient;
3487
3837
  exports.streamStatusUpdated = streamStatusUpdated;
3488
3838
  exports.streamingSlice = streamingSlice;
3489
3839
  exports.toggleCameraEnabled = toggleCameraEnabled;