@stream-io/video-client 0.0.1-alpha.87 → 0.0.1-alpha.89
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.browser.es.js +394 -150
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +394 -150
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +394 -150
- package/dist/index.es.js.map +1 -1
- package/dist/src/CallDropScheduler.d.ts +0 -2
- package/dist/src/coordinator/connection/client.d.ts +5 -5
- package/dist/src/coordinator/connection/connection.d.ts +8 -7
- package/dist/src/coordinator/connection/connection_fallback.d.ts +3 -2
- package/dist/src/coordinator/connection/types.d.ts +4 -11
- package/dist/src/coordinator/connection/utils.d.ts +4 -1
- package/dist/src/events/internal.d.ts +1 -1
- package/dist/src/events/participant.d.ts +4 -4
- package/dist/src/events/speaker.d.ts +2 -2
- package/dist/src/gen/coordinator/index.d.ts +75 -75
- package/dist/src/stats/state-store-stats-reporter.d.ts +2 -2
- package/dist/src/store/CallState.d.ts +124 -18
- package/dist/src/store/rxUtils.d.ts +3 -0
- package/dist/src/store/stateStore.d.ts +83 -4
- package/package.json +1 -1
- package/src/CallDropScheduler.ts +2 -9
- package/src/StreamVideoClient.ts +2 -8
- package/src/coordinator/connection/client.ts +3 -3
- package/src/coordinator/connection/connection.ts +14 -11
- package/src/coordinator/connection/connection_fallback.ts +3 -2
- package/src/coordinator/connection/types.ts +5 -14
- package/src/coordinator/connection/utils.ts +4 -2
- package/src/events/call-permissions.ts +5 -6
- package/src/events/call.ts +23 -24
- package/src/events/internal.ts +2 -2
- package/src/events/moderation.ts +5 -11
- package/src/events/participant.ts +9 -11
- package/src/events/reactions.ts +3 -3
- package/src/events/recording.ts +4 -4
- package/src/events/speaker.ts +6 -6
- package/src/gen/coordinator/index.ts +56 -56
- package/src/rtc/Call.ts +54 -111
- package/src/stats/state-store-stats-reporter.ts +5 -9
- package/src/store/CallState.ts +198 -36
- package/src/store/__tests__/CallState.test.ts +16 -17
- package/src/store/rxUtils.ts +5 -3
- package/src/store/stateStore.ts +132 -9
package/dist/index.browser.es.js
CHANGED
|
@@ -3873,8 +3873,10 @@ function isFunction(value) {
|
|
|
3873
3873
|
'function' === typeof value ||
|
|
3874
3874
|
value instanceof Function));
|
|
3875
3875
|
}
|
|
3876
|
-
|
|
3877
|
-
|
|
3876
|
+
/**
|
|
3877
|
+
* A map of known error codes.
|
|
3878
|
+
*/
|
|
3879
|
+
const KnownCodes = {
|
|
3878
3880
|
TOKEN_EXPIRED: 40,
|
|
3879
3881
|
WS_CLOSED_SUCCESS: 1000,
|
|
3880
3882
|
};
|
|
@@ -4678,7 +4680,7 @@ const watchChangePublishQuality = (dispatcher, call) => {
|
|
|
4678
4680
|
});
|
|
4679
4681
|
});
|
|
4680
4682
|
};
|
|
4681
|
-
const watchConnectionQualityChanged = (dispatcher,
|
|
4683
|
+
const watchConnectionQualityChanged = (dispatcher, state) => {
|
|
4682
4684
|
return dispatcher.on('connectionQualityChanged', (e) => {
|
|
4683
4685
|
if (e.eventPayload.oneofKind !== 'connectionQualityChanged')
|
|
4684
4686
|
return;
|
|
@@ -4686,7 +4688,7 @@ const watchConnectionQualityChanged = (dispatcher, store) => {
|
|
|
4686
4688
|
const { connectionQualityUpdates } = connectionQualityChanged;
|
|
4687
4689
|
if (!connectionQualityUpdates)
|
|
4688
4690
|
return;
|
|
4689
|
-
|
|
4691
|
+
state.updateParticipants(connectionQualityUpdates.reduce((patches, update) => {
|
|
4690
4692
|
const { sessionId, connectionQuality } = update;
|
|
4691
4693
|
patches[sessionId] = {
|
|
4692
4694
|
connectionQuality,
|
|
@@ -4699,15 +4701,15 @@ const watchConnectionQualityChanged = (dispatcher, store) => {
|
|
|
4699
4701
|
/**
|
|
4700
4702
|
* An event responder which handles the `participantJoined` event.
|
|
4701
4703
|
*/
|
|
4702
|
-
const watchParticipantJoined = (dispatcher,
|
|
4704
|
+
const watchParticipantJoined = (dispatcher, state) => {
|
|
4703
4705
|
return dispatcher.on('participantJoined', (e) => {
|
|
4704
4706
|
if (e.eventPayload.oneofKind !== 'participantJoined')
|
|
4705
4707
|
return;
|
|
4706
4708
|
const { participant } = e.eventPayload.participantJoined;
|
|
4707
4709
|
if (!participant)
|
|
4708
4710
|
return;
|
|
4709
|
-
|
|
4710
|
-
...
|
|
4711
|
+
state.setParticipants((participants) => [
|
|
4712
|
+
...participants,
|
|
4711
4713
|
Object.assign(Object.assign({}, participant), { viewportVisibilityState: VisibilityState.UNKNOWN }),
|
|
4712
4714
|
]);
|
|
4713
4715
|
});
|
|
@@ -4715,7 +4717,7 @@ const watchParticipantJoined = (dispatcher, store) => {
|
|
|
4715
4717
|
/**
|
|
4716
4718
|
* An event responder which handles the `participantLeft` event.
|
|
4717
4719
|
*/
|
|
4718
|
-
const watchParticipantLeft = (dispatcher,
|
|
4720
|
+
const watchParticipantLeft = (dispatcher, state) => {
|
|
4719
4721
|
return dispatcher.on('participantLeft', (e) => {
|
|
4720
4722
|
if (e.eventPayload.oneofKind !== 'participantLeft')
|
|
4721
4723
|
return;
|
|
@@ -4728,19 +4730,19 @@ const watchParticipantLeft = (dispatcher, store) => {
|
|
|
4728
4730
|
// console.warn('Received participantLeft notification for a unknown call');
|
|
4729
4731
|
// return;
|
|
4730
4732
|
// }
|
|
4731
|
-
|
|
4733
|
+
state.setParticipants((participants) => participants.filter((p) => p.sessionId !== participant.sessionId));
|
|
4732
4734
|
});
|
|
4733
4735
|
};
|
|
4734
4736
|
/**
|
|
4735
4737
|
* An event responder which handles the `trackPublished` event.
|
|
4736
4738
|
* The SFU will send this event when a participant publishes a track.
|
|
4737
4739
|
*/
|
|
4738
|
-
const watchTrackPublished = (dispatcher,
|
|
4740
|
+
const watchTrackPublished = (dispatcher, state) => {
|
|
4739
4741
|
return dispatcher.on('trackPublished', (e) => {
|
|
4740
4742
|
if (e.eventPayload.oneofKind !== 'trackPublished')
|
|
4741
4743
|
return;
|
|
4742
4744
|
const { trackPublished: { type, sessionId }, } = e.eventPayload;
|
|
4743
|
-
|
|
4745
|
+
state.updateParticipant(sessionId, (p) => ({
|
|
4744
4746
|
publishedTracks: [...p.publishedTracks, type].filter(unique),
|
|
4745
4747
|
}));
|
|
4746
4748
|
});
|
|
@@ -4749,12 +4751,12 @@ const watchTrackPublished = (dispatcher, store) => {
|
|
|
4749
4751
|
* An event responder which handles the `trackUnpublished` event.
|
|
4750
4752
|
* The SFU will send this event when a participant unpublishes a track.
|
|
4751
4753
|
*/
|
|
4752
|
-
const watchTrackUnpublished = (dispatcher,
|
|
4754
|
+
const watchTrackUnpublished = (dispatcher, state) => {
|
|
4753
4755
|
return dispatcher.on('trackUnpublished', (e) => {
|
|
4754
4756
|
if (e.eventPayload.oneofKind !== 'trackUnpublished')
|
|
4755
4757
|
return;
|
|
4756
4758
|
const { trackUnpublished: { type, sessionId }, } = e.eventPayload;
|
|
4757
|
-
|
|
4759
|
+
state.updateParticipant(sessionId, (p) => ({
|
|
4758
4760
|
publishedTracks: p.publishedTracks.filter((t) => t !== type),
|
|
4759
4761
|
}));
|
|
4760
4762
|
});
|
|
@@ -4764,15 +4766,15 @@ const unique = (v, i, arr) => arr.indexOf(v) === i;
|
|
|
4764
4766
|
/**
|
|
4765
4767
|
* Watches for `dominantSpeakerChanged` events.
|
|
4766
4768
|
*/
|
|
4767
|
-
const watchDominantSpeakerChanged = (dispatcher,
|
|
4769
|
+
const watchDominantSpeakerChanged = (dispatcher, state) => {
|
|
4768
4770
|
return dispatcher.on('dominantSpeakerChanged', (e) => {
|
|
4771
|
+
var _a;
|
|
4769
4772
|
if (e.eventPayload.oneofKind !== 'dominantSpeakerChanged')
|
|
4770
4773
|
return;
|
|
4771
4774
|
const { dominantSpeakerChanged: { sessionId }, } = e.eventPayload;
|
|
4772
|
-
|
|
4773
|
-
if (sessionId === (dominantSpeaker === null || dominantSpeaker === void 0 ? void 0 : dominantSpeaker.sessionId))
|
|
4775
|
+
if (sessionId === ((_a = state.dominantSpeaker) === null || _a === void 0 ? void 0 : _a.sessionId))
|
|
4774
4776
|
return;
|
|
4775
|
-
|
|
4777
|
+
state.setParticipants((participants) => participants.map((participant) => {
|
|
4776
4778
|
// mark the new dominant speaker
|
|
4777
4779
|
if (participant.sessionId === sessionId) {
|
|
4778
4780
|
return Object.assign(Object.assign({}, participant), { isDominantSpeaker: true });
|
|
@@ -4788,12 +4790,12 @@ const watchDominantSpeakerChanged = (dispatcher, store) => {
|
|
|
4788
4790
|
/**
|
|
4789
4791
|
* Watches for `audioLevelChanged` events.
|
|
4790
4792
|
*/
|
|
4791
|
-
const watchAudioLevelChanged = (dispatcher,
|
|
4793
|
+
const watchAudioLevelChanged = (dispatcher, state) => {
|
|
4792
4794
|
return dispatcher.on('audioLevelChanged', (e) => {
|
|
4793
4795
|
if (e.eventPayload.oneofKind !== 'audioLevelChanged')
|
|
4794
4796
|
return;
|
|
4795
4797
|
const { audioLevels } = e.eventPayload.audioLevelChanged;
|
|
4796
|
-
|
|
4798
|
+
state.updateParticipants(audioLevels.reduce((patches, current) => {
|
|
4797
4799
|
patches[current.sessionId] = {
|
|
4798
4800
|
audioLevel: current.level,
|
|
4799
4801
|
isSpeaking: current.isSpeaking,
|
|
@@ -4898,14 +4900,13 @@ const getCurrentValue = (observable$) => {
|
|
|
4898
4900
|
* @return the updated value.
|
|
4899
4901
|
*/
|
|
4900
4902
|
const setCurrentValue = (subject, update) => {
|
|
4901
|
-
const currentValue = getCurrentValue(subject);
|
|
4902
4903
|
const next =
|
|
4903
4904
|
// TypeScript needs more context to infer the type of update
|
|
4904
4905
|
typeof update === 'function' && update instanceof Function
|
|
4905
|
-
? update(
|
|
4906
|
+
? update(getCurrentValue(subject))
|
|
4906
4907
|
: update;
|
|
4907
4908
|
subject.next(next);
|
|
4908
|
-
return
|
|
4909
|
+
return next;
|
|
4909
4910
|
};
|
|
4910
4911
|
|
|
4911
4912
|
var rxUtils = /*#__PURE__*/Object.freeze({
|
|
@@ -4951,13 +4952,41 @@ class StreamVideoWriteableStateStore {
|
|
|
4951
4952
|
* @return the updated value.
|
|
4952
4953
|
*/
|
|
4953
4954
|
this.setCurrentValue = setCurrentValue;
|
|
4955
|
+
/**
|
|
4956
|
+
* Sets the currently connected user.
|
|
4957
|
+
*
|
|
4958
|
+
* @internal
|
|
4959
|
+
* @param user the user to set as connected.
|
|
4960
|
+
*/
|
|
4961
|
+
this.setConnectedUser = (user) => {
|
|
4962
|
+
return this.setCurrentValue(this.connectedUserSubject, user);
|
|
4963
|
+
};
|
|
4964
|
+
/**
|
|
4965
|
+
* Sets the list of objects describing all created calls that
|
|
4966
|
+
* have not been yet accepted, rejected nor cancelled.
|
|
4967
|
+
*
|
|
4968
|
+
* @internal
|
|
4969
|
+
* @param calls the calls to set as pending.
|
|
4970
|
+
*/
|
|
4971
|
+
this.setPendingCalls = (calls) => {
|
|
4972
|
+
return this.setCurrentValue(this.pendingCallsSubject, calls);
|
|
4973
|
+
};
|
|
4974
|
+
/**
|
|
4975
|
+
* Sets a call controller instance.
|
|
4976
|
+
*
|
|
4977
|
+
* @internal
|
|
4978
|
+
* @param call the call instance.
|
|
4979
|
+
*/
|
|
4980
|
+
this.setActiveCall = (call) => {
|
|
4981
|
+
return this.setCurrentValue(this.activeCallSubject, call);
|
|
4982
|
+
};
|
|
4954
4983
|
this.incomingCalls$ = this.pendingCallsSubject.pipe(combineLatestWith(this.connectedUserSubject), map$1(([pendingCalls, connectedUser]) => pendingCalls.filter((call) => {
|
|
4955
|
-
|
|
4956
|
-
return (
|
|
4984
|
+
var _a;
|
|
4985
|
+
return ((_a = call.state.metadata) === null || _a === void 0 ? void 0 : _a.created_by.id) !== (connectedUser === null || connectedUser === void 0 ? void 0 : connectedUser.id);
|
|
4957
4986
|
})));
|
|
4958
4987
|
this.outgoingCalls$ = this.pendingCallsSubject.pipe(combineLatestWith(this.connectedUserSubject), map$1(([pendingCalls, connectedUser]) => pendingCalls.filter((call) => {
|
|
4959
|
-
|
|
4960
|
-
return (
|
|
4988
|
+
var _a;
|
|
4989
|
+
return ((_a = call.state.metadata) === null || _a === void 0 ? void 0 : _a.created_by.id) === (connectedUser === null || connectedUser === void 0 ? void 0 : connectedUser.id);
|
|
4961
4990
|
})));
|
|
4962
4991
|
this.activeCallSubject.subscribe((activeCall) => {
|
|
4963
4992
|
if (activeCall) {
|
|
@@ -4967,6 +4996,52 @@ class StreamVideoWriteableStateStore {
|
|
|
4967
4996
|
}
|
|
4968
4997
|
});
|
|
4969
4998
|
}
|
|
4999
|
+
/**
|
|
5000
|
+
* The currently connected user.
|
|
5001
|
+
*/
|
|
5002
|
+
get connectedUser() {
|
|
5003
|
+
return this.getCurrentValue(this.connectedUserSubject);
|
|
5004
|
+
}
|
|
5005
|
+
/**
|
|
5006
|
+
* A list of objects describing all created calls that
|
|
5007
|
+
* have not been yet accepted, rejected nor cancelled.
|
|
5008
|
+
*/
|
|
5009
|
+
get pendingCalls() {
|
|
5010
|
+
return this.getCurrentValue(this.pendingCallsSubject);
|
|
5011
|
+
}
|
|
5012
|
+
/**
|
|
5013
|
+
* A list of objects describing incoming calls.
|
|
5014
|
+
*/
|
|
5015
|
+
get incomingCalls() {
|
|
5016
|
+
return this.getCurrentValue(this.incomingCalls$);
|
|
5017
|
+
}
|
|
5018
|
+
/**
|
|
5019
|
+
* A list of objects describing calls initiated by the current user.
|
|
5020
|
+
*/
|
|
5021
|
+
get outgoingCalls() {
|
|
5022
|
+
return this.getCurrentValue(this.outgoingCalls$);
|
|
5023
|
+
}
|
|
5024
|
+
/**
|
|
5025
|
+
* A notification describing accepted call.
|
|
5026
|
+
*/
|
|
5027
|
+
get acceptedCall() {
|
|
5028
|
+
return this.getCurrentValue(this.acceptedCallSubject);
|
|
5029
|
+
}
|
|
5030
|
+
/**
|
|
5031
|
+
* Sets a notification describing accepted call.
|
|
5032
|
+
*
|
|
5033
|
+
* @internal
|
|
5034
|
+
* @param call the call event.
|
|
5035
|
+
*/
|
|
5036
|
+
setAcceptedCall(call) {
|
|
5037
|
+
return this.setCurrentValue(this.acceptedCallSubject, call);
|
|
5038
|
+
}
|
|
5039
|
+
/**
|
|
5040
|
+
* A call controller instance.
|
|
5041
|
+
*/
|
|
5042
|
+
get activeCall() {
|
|
5043
|
+
return this.getCurrentValue(this.activeCallSubject);
|
|
5044
|
+
}
|
|
4970
5045
|
}
|
|
4971
5046
|
/**
|
|
4972
5047
|
* A reactive store that exposes state variables in a reactive manner.
|
|
@@ -4975,6 +5050,13 @@ class StreamVideoWriteableStateStore {
|
|
|
4975
5050
|
*/
|
|
4976
5051
|
class StreamVideoReadOnlyStateStore {
|
|
4977
5052
|
constructor(store) {
|
|
5053
|
+
/**
|
|
5054
|
+
* This method allows you the get the current value of a state variable.
|
|
5055
|
+
*
|
|
5056
|
+
* @param observable the observable to get the current value of.
|
|
5057
|
+
* @returns the current value of the observable.
|
|
5058
|
+
*/
|
|
5059
|
+
this.getCurrentValue = getCurrentValue;
|
|
4978
5060
|
// convert and expose subjects as observables
|
|
4979
5061
|
this.connectedUser$ = store.connectedUserSubject.asObservable();
|
|
4980
5062
|
this.pendingCalls$ = store.pendingCallsSubject.asObservable();
|
|
@@ -4983,8 +5065,43 @@ class StreamVideoReadOnlyStateStore {
|
|
|
4983
5065
|
// re-expose observables
|
|
4984
5066
|
this.incomingCalls$ = store.incomingCalls$;
|
|
4985
5067
|
this.outgoingCalls$ = store.outgoingCalls$;
|
|
4986
|
-
|
|
4987
|
-
|
|
5068
|
+
}
|
|
5069
|
+
/**
|
|
5070
|
+
* The current user connected over WS to the backend.
|
|
5071
|
+
*/
|
|
5072
|
+
get connectedUser() {
|
|
5073
|
+
return getCurrentValue(this.connectedUser$);
|
|
5074
|
+
}
|
|
5075
|
+
/**
|
|
5076
|
+
* A list of objects describing all created calls that
|
|
5077
|
+
* have not been yet accepted, rejected nor cancelled.
|
|
5078
|
+
*/
|
|
5079
|
+
get pendingCalls() {
|
|
5080
|
+
return getCurrentValue(this.pendingCalls$);
|
|
5081
|
+
}
|
|
5082
|
+
/**
|
|
5083
|
+
* A list of objects describing incoming calls.
|
|
5084
|
+
*/
|
|
5085
|
+
get incomingCalls() {
|
|
5086
|
+
return getCurrentValue(this.incomingCalls$);
|
|
5087
|
+
}
|
|
5088
|
+
/**
|
|
5089
|
+
* A list of objects describing calls initiated by the current user.
|
|
5090
|
+
*/
|
|
5091
|
+
get outgoingCalls() {
|
|
5092
|
+
return getCurrentValue(this.outgoingCalls$);
|
|
5093
|
+
}
|
|
5094
|
+
/**
|
|
5095
|
+
* The call data describing an incoming call accepted by the current user.
|
|
5096
|
+
*/
|
|
5097
|
+
get acceptedCall() {
|
|
5098
|
+
return getCurrentValue(this.acceptedCall$);
|
|
5099
|
+
}
|
|
5100
|
+
/**
|
|
5101
|
+
* The currenlty active call.
|
|
5102
|
+
*/
|
|
5103
|
+
get activeCall() {
|
|
5104
|
+
return getCurrentValue(this.activeCall$);
|
|
4988
5105
|
}
|
|
4989
5106
|
}
|
|
4990
5107
|
|
|
@@ -5315,6 +5432,79 @@ class CallState {
|
|
|
5315
5432
|
* @return the updated value.
|
|
5316
5433
|
*/
|
|
5317
5434
|
this.setCurrentValue = setCurrentValue;
|
|
5435
|
+
/**
|
|
5436
|
+
* Sets the list of participants in the current call.
|
|
5437
|
+
*
|
|
5438
|
+
* @internal
|
|
5439
|
+
*
|
|
5440
|
+
* @param participants the list of participants.
|
|
5441
|
+
*/
|
|
5442
|
+
this.setParticipants = (participants) => {
|
|
5443
|
+
return this.setCurrentValue(this.participantsSubject, participants);
|
|
5444
|
+
};
|
|
5445
|
+
/**
|
|
5446
|
+
* Sets the calling state.
|
|
5447
|
+
*
|
|
5448
|
+
* @internal
|
|
5449
|
+
* @param state the new calling state.
|
|
5450
|
+
*/
|
|
5451
|
+
this.setCallingState = (state) => {
|
|
5452
|
+
return this.setCurrentValue(this.callingStateSubject, state);
|
|
5453
|
+
};
|
|
5454
|
+
/**
|
|
5455
|
+
* Sets the list of call recordings.
|
|
5456
|
+
*
|
|
5457
|
+
* @internal
|
|
5458
|
+
* @param recordings the list of call recordings.
|
|
5459
|
+
*/
|
|
5460
|
+
this.setCallRecordingsList = (recordings) => {
|
|
5461
|
+
return this.setCurrentValue(this.callRecordingListSubject, recordings);
|
|
5462
|
+
};
|
|
5463
|
+
/**
|
|
5464
|
+
* Sets whether a call recording is in progress.
|
|
5465
|
+
*
|
|
5466
|
+
* @param inProgress whether a call recording is in progress.
|
|
5467
|
+
*/
|
|
5468
|
+
this.setCallRecordingInProgress = (inProgress) => {
|
|
5469
|
+
return this.setCurrentValue(this.callRecordingInProgressSubject, inProgress);
|
|
5470
|
+
};
|
|
5471
|
+
/**
|
|
5472
|
+
* Sets the last call permission request.
|
|
5473
|
+
*
|
|
5474
|
+
* @internal
|
|
5475
|
+
* @param request the last call permission request.
|
|
5476
|
+
*/
|
|
5477
|
+
this.setCallPermissionRequest = (request) => {
|
|
5478
|
+
return this.setCurrentValue(this.callPermissionRequestSubject, request);
|
|
5479
|
+
};
|
|
5480
|
+
/**
|
|
5481
|
+
* Sets the call stats report.
|
|
5482
|
+
*
|
|
5483
|
+
* @internal
|
|
5484
|
+
* @param report the report to set.
|
|
5485
|
+
*/
|
|
5486
|
+
this.setCallStatsReport = (report) => {
|
|
5487
|
+
return this.setCurrentValue(this.callStatsReportSubject, report);
|
|
5488
|
+
};
|
|
5489
|
+
/**
|
|
5490
|
+
* Sets the metadata of the current call.
|
|
5491
|
+
*
|
|
5492
|
+
* @internal
|
|
5493
|
+
*
|
|
5494
|
+
* @param metadata the metadata to set.
|
|
5495
|
+
*/
|
|
5496
|
+
this.setMetadata = (metadata) => {
|
|
5497
|
+
return this.setCurrentValue(this.metadataSubject, metadata);
|
|
5498
|
+
};
|
|
5499
|
+
/**
|
|
5500
|
+
* Sets the members of the current call.
|
|
5501
|
+
*
|
|
5502
|
+
* @internal
|
|
5503
|
+
* @param members the members to set.
|
|
5504
|
+
*/
|
|
5505
|
+
this.setMembers = (members) => {
|
|
5506
|
+
this.setCurrentValue(this.membersSubject, members);
|
|
5507
|
+
};
|
|
5318
5508
|
/**
|
|
5319
5509
|
* Will try to find the participant with the given sessionId in the active call.
|
|
5320
5510
|
*
|
|
@@ -5322,8 +5512,7 @@ class CallState {
|
|
|
5322
5512
|
* @returns the participant with the given sessionId or undefined if not found.
|
|
5323
5513
|
*/
|
|
5324
5514
|
this.findParticipantBySessionId = (sessionId) => {
|
|
5325
|
-
|
|
5326
|
-
return participants.find((p) => p.sessionId === sessionId);
|
|
5515
|
+
return this.participants.find((p) => p.sessionId === sessionId);
|
|
5327
5516
|
};
|
|
5328
5517
|
/**
|
|
5329
5518
|
* Updates a participant in the active call identified by the given `sessionId`.
|
|
@@ -5343,7 +5532,7 @@ class CallState {
|
|
|
5343
5532
|
}
|
|
5344
5533
|
const thePatch = typeof patch === 'function' ? patch(participant) : patch;
|
|
5345
5534
|
const updatedParticipant = Object.assign(Object.assign({}, participant), thePatch);
|
|
5346
|
-
return this.
|
|
5535
|
+
return this.setParticipants((participants) => participants.map((p) => p.sessionId === sessionId ? updatedParticipant : p));
|
|
5347
5536
|
};
|
|
5348
5537
|
/**
|
|
5349
5538
|
* Updates all participants in the active call whose session ID is in the given `sessionIds`.
|
|
@@ -5355,10 +5544,9 @@ class CallState {
|
|
|
5355
5544
|
* @returns all participants, with all patch applied.
|
|
5356
5545
|
*/
|
|
5357
5546
|
this.updateParticipants = (patch) => {
|
|
5358
|
-
if (Object.keys(patch).length === 0)
|
|
5547
|
+
if (Object.keys(patch).length === 0)
|
|
5359
5548
|
return;
|
|
5360
|
-
|
|
5361
|
-
return this.setCurrentValue(this.participantsSubject, (participants) => participants.map((p) => {
|
|
5549
|
+
return this.setParticipants((participants) => participants.map((p) => {
|
|
5362
5550
|
const thePatch = patch[p.sessionId];
|
|
5363
5551
|
if (thePatch) {
|
|
5364
5552
|
return Object.assign(Object.assign({}, p), thePatch);
|
|
@@ -5382,16 +5570,87 @@ class CallState {
|
|
|
5382
5570
|
this.callPermissionRequestSubject.asObservable();
|
|
5383
5571
|
this.callRecordingList$ = this.callRecordingListSubject.asObservable();
|
|
5384
5572
|
this.metadata$ = this.metadataSubject.asObservable();
|
|
5385
|
-
|
|
5386
|
-
this.members$ = this.membersSubject.pipe(map$1((members) => {
|
|
5387
|
-
return members.reduce((acc, member) => {
|
|
5388
|
-
const user = member.user;
|
|
5389
|
-
acc[user.id] = user;
|
|
5390
|
-
return acc;
|
|
5391
|
-
}, {});
|
|
5392
|
-
}));
|
|
5573
|
+
this.members$ = this.membersSubject.asObservable();
|
|
5393
5574
|
this.callingState$ = this.callingStateSubject.asObservable();
|
|
5394
5575
|
}
|
|
5576
|
+
/**
|
|
5577
|
+
* The list of participants in the current call.
|
|
5578
|
+
*/
|
|
5579
|
+
get participants() {
|
|
5580
|
+
return this.getCurrentValue(this.participants$);
|
|
5581
|
+
}
|
|
5582
|
+
/**
|
|
5583
|
+
* The local participant in the current call.
|
|
5584
|
+
*/
|
|
5585
|
+
get localParticipant() {
|
|
5586
|
+
return this.getCurrentValue(this.localParticipant$);
|
|
5587
|
+
}
|
|
5588
|
+
/**
|
|
5589
|
+
* The list of remote participants in the current call.
|
|
5590
|
+
*/
|
|
5591
|
+
get remoteParticipants() {
|
|
5592
|
+
return this.getCurrentValue(this.remoteParticipants$);
|
|
5593
|
+
}
|
|
5594
|
+
/**
|
|
5595
|
+
* The dominant speaker in the current call.
|
|
5596
|
+
*/
|
|
5597
|
+
get dominantSpeaker() {
|
|
5598
|
+
return this.getCurrentValue(this.dominantSpeaker$);
|
|
5599
|
+
}
|
|
5600
|
+
/**
|
|
5601
|
+
* The list of pinned participants in the current call.
|
|
5602
|
+
*/
|
|
5603
|
+
get pinnedParticipants() {
|
|
5604
|
+
return this.getCurrentValue(this.pinnedParticipants$);
|
|
5605
|
+
}
|
|
5606
|
+
/**
|
|
5607
|
+
* Tell if there is an ongoing screen share in this call.
|
|
5608
|
+
*/
|
|
5609
|
+
get hasOngoingScreenShare() {
|
|
5610
|
+
return this.getCurrentValue(this.hasOngoingScreenShare$);
|
|
5611
|
+
}
|
|
5612
|
+
/**
|
|
5613
|
+
* The calling state.
|
|
5614
|
+
*/
|
|
5615
|
+
get callingState() {
|
|
5616
|
+
return this.getCurrentValue(this.callingState$);
|
|
5617
|
+
}
|
|
5618
|
+
/**
|
|
5619
|
+
* The list of call recordings.
|
|
5620
|
+
*/
|
|
5621
|
+
get callRecordingsList() {
|
|
5622
|
+
return this.getCurrentValue(this.callRecordingList$);
|
|
5623
|
+
}
|
|
5624
|
+
/**
|
|
5625
|
+
* Tells whether a call recording is in progress.
|
|
5626
|
+
*/
|
|
5627
|
+
get callRecordingInProgress() {
|
|
5628
|
+
return this.getCurrentValue(this.callRecordingInProgress$);
|
|
5629
|
+
}
|
|
5630
|
+
/**
|
|
5631
|
+
* The last call permission request.
|
|
5632
|
+
*/
|
|
5633
|
+
get callPermissionRequest() {
|
|
5634
|
+
return this.getCurrentValue(this.callPermissionRequest$);
|
|
5635
|
+
}
|
|
5636
|
+
/**
|
|
5637
|
+
* The call stats report.
|
|
5638
|
+
*/
|
|
5639
|
+
get callStatsReport() {
|
|
5640
|
+
return this.getCurrentValue(this.callStatsReport$);
|
|
5641
|
+
}
|
|
5642
|
+
/**
|
|
5643
|
+
* The metadata of the current call.
|
|
5644
|
+
*/
|
|
5645
|
+
get metadata() {
|
|
5646
|
+
return this.getCurrentValue(this.metadata$);
|
|
5647
|
+
}
|
|
5648
|
+
/**
|
|
5649
|
+
* The members of the current call.
|
|
5650
|
+
*/
|
|
5651
|
+
get members() {
|
|
5652
|
+
return this.getCurrentValue(this.members$);
|
|
5653
|
+
}
|
|
5395
5654
|
}
|
|
5396
5655
|
|
|
5397
5656
|
const trackTypeToParticipantStreamKey = (trackType) => {
|
|
@@ -5495,7 +5754,7 @@ const toRtcConfiguration = (config) => {
|
|
|
5495
5754
|
/**
|
|
5496
5755
|
* Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
|
|
5497
5756
|
*/
|
|
5498
|
-
const createStatsReporter = ({ subscriber, publisher,
|
|
5757
|
+
const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIntervalInMs = 2000, }) => {
|
|
5499
5758
|
const getRawStatsForTrack = (kind, selector) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5500
5759
|
if (kind === 'subscriber' && subscriber) {
|
|
5501
5760
|
return subscriber.getStats(selector);
|
|
@@ -5536,11 +5795,10 @@ const createStatsReporter = ({ subscriber, publisher, store, edgeName, pollingIn
|
|
|
5536
5795
|
*/
|
|
5537
5796
|
const run = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
5538
5797
|
var _a, _b;
|
|
5539
|
-
const participants = store.getCurrentValue(store.participantsSubject);
|
|
5540
5798
|
const participantStats = {};
|
|
5541
5799
|
const sessionIds = new Set(sessionIdsToTrack);
|
|
5542
5800
|
if (sessionIds.size > 0) {
|
|
5543
|
-
for (let participant of participants) {
|
|
5801
|
+
for (let participant of state.participants) {
|
|
5544
5802
|
if (!sessionIds.has(participant.sessionId))
|
|
5545
5803
|
continue;
|
|
5546
5804
|
const kind = participant.isLoggedInUser ? 'publisher' : 'subscriber';
|
|
@@ -5579,7 +5837,7 @@ const createStatsReporter = ({ subscriber, publisher, store, edgeName, pollingIn
|
|
|
5579
5837
|
getRawStatsForTrack('subscriber'),
|
|
5580
5838
|
getRawStatsForTrack('publisher'),
|
|
5581
5839
|
]);
|
|
5582
|
-
|
|
5840
|
+
state.setCallStatsReport({
|
|
5583
5841
|
datacenter: edgeName || 'N/A',
|
|
5584
5842
|
publisherStats,
|
|
5585
5843
|
subscriberStats,
|
|
@@ -5587,8 +5845,7 @@ const createStatsReporter = ({ subscriber, publisher, store, edgeName, pollingIn
|
|
|
5587
5845
|
publisherRawStats,
|
|
5588
5846
|
participants: participantStats,
|
|
5589
5847
|
timestamp: Date.now(),
|
|
5590
|
-
};
|
|
5591
|
-
store.setCurrentValue(store.callStatsReportSubject, statsReport);
|
|
5848
|
+
});
|
|
5592
5849
|
});
|
|
5593
5850
|
let timeoutId;
|
|
5594
5851
|
if (pollingIntervalInMs > 0) {
|
|
@@ -5946,7 +6203,7 @@ class Call {
|
|
|
5946
6203
|
*/
|
|
5947
6204
|
this.leave = () => {
|
|
5948
6205
|
var _a, _b, _c, _d;
|
|
5949
|
-
if (this.state.
|
|
6206
|
+
if (this.state.callingState === CallingState.LEFT) {
|
|
5950
6207
|
throw new Error('Cannot leave call that has already been left.');
|
|
5951
6208
|
}
|
|
5952
6209
|
(_a = this.statsReporter) === null || _a === void 0 ? void 0 : _a.stop();
|
|
@@ -5960,8 +6217,8 @@ class Call {
|
|
|
5960
6217
|
this.dispatcher.offAll();
|
|
5961
6218
|
// Call all leave call hooks, e.g. to clean up global event handlers
|
|
5962
6219
|
this.leaveCallHooks.forEach((hook) => hook());
|
|
5963
|
-
this.clientStore.
|
|
5964
|
-
this.state.
|
|
6220
|
+
this.clientStore.setActiveCall(undefined);
|
|
6221
|
+
this.state.setCallingState(CallingState.LEFT);
|
|
5965
6222
|
};
|
|
5966
6223
|
this.waitForJoinResponse = (timeout = 5000) => new Promise((resolve, reject) => {
|
|
5967
6224
|
const unsubscribe = this.on('joinResponse', (event) => {
|
|
@@ -5983,8 +6240,8 @@ class Call {
|
|
|
5983
6240
|
*/
|
|
5984
6241
|
this.watch = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
5985
6242
|
const response = yield watch(this.streamClient, this.type, this.id, data);
|
|
5986
|
-
this.state.
|
|
5987
|
-
this.state.
|
|
6243
|
+
this.state.setMetadata(response.call);
|
|
6244
|
+
this.state.setMembers(response.members);
|
|
5988
6245
|
return response;
|
|
5989
6246
|
});
|
|
5990
6247
|
/**
|
|
@@ -5994,15 +6251,15 @@ class Call {
|
|
|
5994
6251
|
*/
|
|
5995
6252
|
this.join = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
5996
6253
|
var _a;
|
|
5997
|
-
if ([CallingState.JOINED, CallingState.JOINING].includes(this.state.
|
|
6254
|
+
if ([CallingState.JOINED, CallingState.JOINING].includes(this.state.callingState)) {
|
|
5998
6255
|
throw new Error(`Illegal State: Already joined.`);
|
|
5999
6256
|
}
|
|
6000
|
-
this.state.
|
|
6257
|
+
this.state.setCallingState(CallingState.JOINING);
|
|
6001
6258
|
const call = yield join(this.streamClient, this.type, this.id, data);
|
|
6002
|
-
this.state.
|
|
6003
|
-
this.state.
|
|
6259
|
+
this.state.setMetadata(call.metadata);
|
|
6260
|
+
this.state.setMembers(call.members);
|
|
6004
6261
|
// FIXME OL: convert to a derived state
|
|
6005
|
-
this.state.
|
|
6262
|
+
this.state.setCallRecordingInProgress(call.metadata.recording);
|
|
6006
6263
|
// FIXME OL: remove once cascading is implemented
|
|
6007
6264
|
let sfuUrl = call.sfuServer.url;
|
|
6008
6265
|
if (typeof window !== 'undefined' &&
|
|
@@ -6020,10 +6277,10 @@ class Call {
|
|
|
6020
6277
|
var _b, _c, _d;
|
|
6021
6278
|
console.log(`Rejoining call ${this.cid} (${this.reconnectAttempts})...`);
|
|
6022
6279
|
this.reconnectAttempts++;
|
|
6023
|
-
this.state.
|
|
6280
|
+
this.state.setCallingState(CallingState.RECONNECTING);
|
|
6024
6281
|
// take a snapshot of the current "local participant" state
|
|
6025
6282
|
// we'll need it for restoring the previous publishing state later
|
|
6026
|
-
const localParticipant = this.state.
|
|
6283
|
+
const localParticipant = this.state.localParticipant;
|
|
6027
6284
|
(_b = this.subscriber) === null || _b === void 0 ? void 0 : _b.close();
|
|
6028
6285
|
(_c = this.publisher) === null || _c === void 0 ? void 0 : _c.stopPublishing({ stopTracks: false });
|
|
6029
6286
|
(_d = this.statsReporter) === null || _d === void 0 ? void 0 : _d.stop();
|
|
@@ -6054,12 +6311,12 @@ class Call {
|
|
|
6054
6311
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
6055
6312
|
rejoin().catch(() => {
|
|
6056
6313
|
console.log(`Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
|
|
6057
|
-
this.state.
|
|
6314
|
+
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
6058
6315
|
});
|
|
6059
6316
|
}
|
|
6060
6317
|
else {
|
|
6061
6318
|
console.log('Reconnect attempts exceeded. Giving up...');
|
|
6062
|
-
this.state.
|
|
6319
|
+
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
6063
6320
|
}
|
|
6064
6321
|
});
|
|
6065
6322
|
});
|
|
@@ -6069,16 +6326,15 @@ class Call {
|
|
|
6069
6326
|
const handleOnOffline = () => {
|
|
6070
6327
|
window.removeEventListener('offline', handleOnOffline);
|
|
6071
6328
|
console.log('Join: Going offline...');
|
|
6072
|
-
this.state.
|
|
6329
|
+
this.state.setCallingState(CallingState.OFFLINE);
|
|
6073
6330
|
};
|
|
6074
6331
|
const handleOnOnline = () => {
|
|
6075
6332
|
window.removeEventListener('online', handleOnOnline);
|
|
6076
|
-
if (this.state.
|
|
6077
|
-
CallingState.OFFLINE) {
|
|
6333
|
+
if (this.state.callingState === CallingState.OFFLINE) {
|
|
6078
6334
|
console.log('Join: Going online...');
|
|
6079
6335
|
rejoin().catch(() => {
|
|
6080
6336
|
console.log(`Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
|
|
6081
|
-
this.state.
|
|
6337
|
+
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
6082
6338
|
});
|
|
6083
6339
|
}
|
|
6084
6340
|
};
|
|
@@ -6113,7 +6369,7 @@ class Call {
|
|
|
6113
6369
|
this.statsReporter = createStatsReporter({
|
|
6114
6370
|
subscriber: this.subscriber,
|
|
6115
6371
|
publisher: this.publisher,
|
|
6116
|
-
|
|
6372
|
+
state: this.state,
|
|
6117
6373
|
edgeName: call.sfuServer.edge_name,
|
|
6118
6374
|
});
|
|
6119
6375
|
try {
|
|
@@ -6133,12 +6389,12 @@ class Call {
|
|
|
6133
6389
|
const ownCapabilities = {
|
|
6134
6390
|
ownCapabilities: call.metadata.own_capabilities,
|
|
6135
6391
|
};
|
|
6136
|
-
this.state.
|
|
6392
|
+
this.state.setParticipants(currentParticipants.map((participant) => (Object.assign(Object.assign(Object.assign({}, participant), { isLoggedInUser: participant.sessionId === sfuClient.sessionId, viewportVisibilityState: VisibilityState.UNKNOWN }), (participant.sessionId === sfuClient.sessionId
|
|
6137
6393
|
? ownCapabilities
|
|
6138
6394
|
: {})))));
|
|
6139
|
-
this.clientStore.
|
|
6395
|
+
this.clientStore.setActiveCall(this);
|
|
6140
6396
|
this.reconnectAttempts = 0; // reset the reconnect attempts counter
|
|
6141
|
-
this.state.
|
|
6397
|
+
this.state.setCallingState(CallingState.JOINED);
|
|
6142
6398
|
console.log(`Joined call ${this.cid}`);
|
|
6143
6399
|
}
|
|
6144
6400
|
catch (err) {
|
|
@@ -6149,7 +6405,7 @@ class Call {
|
|
|
6149
6405
|
}
|
|
6150
6406
|
else {
|
|
6151
6407
|
console.log(`Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
|
|
6152
|
-
this.state.
|
|
6408
|
+
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
6153
6409
|
throw new Error('Join failed');
|
|
6154
6410
|
}
|
|
6155
6411
|
}
|
|
@@ -6466,9 +6722,7 @@ class Call {
|
|
|
6466
6722
|
// example: `e3f6aaf8-b03d-4911-be36-83f47d37a76a:TRACK_TYPE_VIDEO`
|
|
6467
6723
|
const [trackId, trackType] = primaryStream.id.split(':');
|
|
6468
6724
|
console.log(`Got remote ${trackType} track:`, e.track);
|
|
6469
|
-
const participantToUpdate = this.state
|
|
6470
|
-
.getCurrentValue(this.state.participantsSubject)
|
|
6471
|
-
.find((p) => p.trackLookupPrefix === trackId);
|
|
6725
|
+
const participantToUpdate = this.state.participants.find((p) => p.trackLookupPrefix === trackId);
|
|
6472
6726
|
if (!participantToUpdate) {
|
|
6473
6727
|
console.error('Received track for unknown participant', trackId, e);
|
|
6474
6728
|
return;
|
|
@@ -6538,18 +6792,20 @@ class Call {
|
|
|
6538
6792
|
};
|
|
6539
6793
|
this.get = () => __awaiter(this, void 0, void 0, function* () {
|
|
6540
6794
|
const response = yield this.streamClient.get(this.streamClientBasePath);
|
|
6541
|
-
this.state.
|
|
6542
|
-
this.state.
|
|
6795
|
+
this.state.setMetadata(response.call);
|
|
6796
|
+
this.state.setMembers(response.members);
|
|
6543
6797
|
return response;
|
|
6544
6798
|
});
|
|
6545
6799
|
this.getOrCreate = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
6546
6800
|
const response = yield this.streamClient.post(this.streamClientBasePath, data);
|
|
6547
|
-
this.state.
|
|
6548
|
-
this.state.
|
|
6549
|
-
const
|
|
6550
|
-
const callAlreadyRegistered = currentPendingCalls.find((pendingCall) => pendingCall.id === this.id);
|
|
6801
|
+
this.state.setMetadata(response.call);
|
|
6802
|
+
this.state.setMembers(response.members);
|
|
6803
|
+
const callAlreadyRegistered = this.clientStore.pendingCalls.find((pendingCall) => pendingCall.id === this.id);
|
|
6551
6804
|
if (!callAlreadyRegistered) {
|
|
6552
|
-
this.clientStore.
|
|
6805
|
+
this.clientStore.setPendingCalls((pendingCalls) => [
|
|
6806
|
+
...pendingCalls,
|
|
6807
|
+
this,
|
|
6808
|
+
]);
|
|
6553
6809
|
}
|
|
6554
6810
|
return response;
|
|
6555
6811
|
});
|
|
@@ -6627,17 +6883,16 @@ class Call {
|
|
|
6627
6883
|
* @returns
|
|
6628
6884
|
*/
|
|
6629
6885
|
this.accept = () => __awaiter(this, void 0, void 0, function* () {
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
.find((c) => c.id === this.id && c.type === this.type);
|
|
6886
|
+
// FIXME OL: this method should be merged with the join method.
|
|
6887
|
+
const callToAccept = this.clientStore.pendingCalls.find((c) => c.id === this.id && c.type === this.type);
|
|
6633
6888
|
if (callToAccept) {
|
|
6634
6889
|
yield this.streamClient.post(`${this.streamClientBasePath}/event`, {
|
|
6635
6890
|
type: 'call.accepted',
|
|
6636
6891
|
});
|
|
6637
6892
|
// remove the accepted call from the "pending calls" list.
|
|
6638
|
-
this.clientStore.
|
|
6893
|
+
this.clientStore.setPendingCalls((pendingCalls) => pendingCalls.filter((c) => c !== callToAccept));
|
|
6639
6894
|
yield this.join();
|
|
6640
|
-
this.clientStore.
|
|
6895
|
+
this.clientStore.setActiveCall(callToAccept);
|
|
6641
6896
|
}
|
|
6642
6897
|
});
|
|
6643
6898
|
/**
|
|
@@ -6646,7 +6901,7 @@ class Call {
|
|
|
6646
6901
|
* @returns
|
|
6647
6902
|
*/
|
|
6648
6903
|
this.reject = () => __awaiter(this, void 0, void 0, function* () {
|
|
6649
|
-
this.clientStore.
|
|
6904
|
+
this.clientStore.setPendingCalls((pendingCalls) => pendingCalls.filter((c) => c.cid !== this.cid));
|
|
6650
6905
|
yield this.streamClient.post(`${this.streamClientBasePath}/event`, {
|
|
6651
6906
|
type: 'call.rejected',
|
|
6652
6907
|
});
|
|
@@ -6660,18 +6915,19 @@ class Call {
|
|
|
6660
6915
|
*/
|
|
6661
6916
|
this.cancel = () => __awaiter(this, void 0, void 0, function* () {
|
|
6662
6917
|
console.log('call cancelled');
|
|
6918
|
+
// FIXME OL: this method should be merged with the leave method.
|
|
6663
6919
|
const store = this.clientStore;
|
|
6664
|
-
const activeCall = store.
|
|
6665
|
-
const leavingActiveCall = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.
|
|
6920
|
+
const activeCall = store.activeCall;
|
|
6921
|
+
const leavingActiveCall = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.cid) === this.cid;
|
|
6666
6922
|
if (leavingActiveCall) {
|
|
6667
6923
|
activeCall.leave();
|
|
6668
6924
|
}
|
|
6669
6925
|
else {
|
|
6670
|
-
store.
|
|
6926
|
+
store.setPendingCalls((pendingCalls) => pendingCalls.filter((c) => c.cid !== this.cid));
|
|
6671
6927
|
}
|
|
6672
6928
|
if (activeCall) {
|
|
6673
6929
|
const state = activeCall.state;
|
|
6674
|
-
const remoteParticipants = state.
|
|
6930
|
+
const remoteParticipants = state.remoteParticipants;
|
|
6675
6931
|
if (!remoteParticipants.length && !leavingActiveCall) {
|
|
6676
6932
|
yield this.endCall();
|
|
6677
6933
|
}
|
|
@@ -6685,7 +6941,7 @@ class Call {
|
|
|
6685
6941
|
// FIXME: this is a temporary setting to take call ID as session ID
|
|
6686
6942
|
const sessionId = this.id;
|
|
6687
6943
|
const response = yield this.streamClient.get(`${this.streamClientBasePath}/${sessionId}/recordings`);
|
|
6688
|
-
this.state.
|
|
6944
|
+
this.state.setCallRecordingsList(response.recordings);
|
|
6689
6945
|
return response;
|
|
6690
6946
|
});
|
|
6691
6947
|
this.getEdgeServer = (data) => {
|
|
@@ -6702,8 +6958,8 @@ class Call {
|
|
|
6702
6958
|
this.streamClientBasePath = `/call/${this.type}/${this.id}`;
|
|
6703
6959
|
const callTypeConfig = CallTypes.get(type);
|
|
6704
6960
|
this.state = new CallState(sortParticipantsBy || callTypeConfig.options.sortParticipantsBy);
|
|
6705
|
-
this.state.
|
|
6706
|
-
this.state.
|
|
6961
|
+
this.state.setMetadata(metadata);
|
|
6962
|
+
this.state.setMembers(members || []);
|
|
6707
6963
|
registerEventHandlers(this, this.state, this.dispatcher);
|
|
6708
6964
|
this.trackSubscriptionsSubject
|
|
6709
6965
|
.pipe(debounceTime(UPDATE_SUBSCRIPTIONS_DEBOUNCE_DURATION))
|
|
@@ -6726,7 +6982,7 @@ class Call {
|
|
|
6726
6982
|
}
|
|
6727
6983
|
}
|
|
6728
6984
|
get data() {
|
|
6729
|
-
return this.state.
|
|
6985
|
+
return this.state.metadata;
|
|
6730
6986
|
}
|
|
6731
6987
|
}
|
|
6732
6988
|
|
|
@@ -6745,12 +7001,12 @@ const watchCallCreated = (store, streamClient) => {
|
|
|
6745
7001
|
console.warn("Can't find call in CallCreatedEvent");
|
|
6746
7002
|
return;
|
|
6747
7003
|
}
|
|
6748
|
-
const currentUser = store.
|
|
7004
|
+
const currentUser = store.connectedUser;
|
|
6749
7005
|
if ((currentUser === null || currentUser === void 0 ? void 0 : currentUser.id) === call.created_by.id) {
|
|
6750
7006
|
console.warn('Received CallCreatedEvent sent by the current user');
|
|
6751
7007
|
return;
|
|
6752
7008
|
}
|
|
6753
|
-
store.
|
|
7009
|
+
store.setPendingCalls((pendingCalls) => [
|
|
6754
7010
|
...pendingCalls,
|
|
6755
7011
|
new Call({
|
|
6756
7012
|
streamClient,
|
|
@@ -6778,17 +7034,13 @@ const watchCallAccepted = (store) => {
|
|
|
6778
7034
|
console.warn("Can't find call_cid in CallAcceptedEvent");
|
|
6779
7035
|
return;
|
|
6780
7036
|
}
|
|
6781
|
-
const acceptedIncomingCall = store
|
|
6782
|
-
.getCurrentValue(store.incomingCalls$)
|
|
6783
|
-
.find((incomingCall) => incomingCall.cid === call_cid);
|
|
7037
|
+
const acceptedIncomingCall = store.incomingCalls.find((incomingCall) => incomingCall.cid === call_cid);
|
|
6784
7038
|
if (acceptedIncomingCall) {
|
|
6785
7039
|
console.warn('Received CallAcceptedEvent for an incoming call');
|
|
6786
7040
|
return;
|
|
6787
7041
|
}
|
|
6788
|
-
const acceptedOutgoingCall = store
|
|
6789
|
-
|
|
6790
|
-
.find((outgoingCall) => outgoingCall.cid === call_cid);
|
|
6791
|
-
const activeCall = store.getCurrentValue(store.activeCallSubject);
|
|
7042
|
+
const acceptedOutgoingCall = store.outgoingCalls.find((outgoingCall) => outgoingCall.cid === call_cid);
|
|
7043
|
+
const activeCall = store.activeCall;
|
|
6792
7044
|
// FIXME OL: we should revisit this logic, it is hard to follow
|
|
6793
7045
|
const acceptedActiveCall = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.cid) !== undefined && activeCall.cid === call_cid
|
|
6794
7046
|
? activeCall
|
|
@@ -6801,7 +7053,7 @@ const watchCallAccepted = (store) => {
|
|
|
6801
7053
|
if (call_cid === (acceptedActiveCall === null || acceptedActiveCall === void 0 ? void 0 : acceptedActiveCall.cid)) {
|
|
6802
7054
|
return;
|
|
6803
7055
|
}
|
|
6804
|
-
store.
|
|
7056
|
+
store.setAcceptedCall(event);
|
|
6805
7057
|
};
|
|
6806
7058
|
};
|
|
6807
7059
|
/**
|
|
@@ -6819,17 +7071,13 @@ const watchCallRejected = (store) => {
|
|
|
6819
7071
|
console.warn("Can't find call_cid in CallRejectedEvent");
|
|
6820
7072
|
return;
|
|
6821
7073
|
}
|
|
6822
|
-
const rejectedIncomingCall = store
|
|
6823
|
-
.getCurrentValue(store.incomingCalls$)
|
|
6824
|
-
.find((incomingCall) => incomingCall.cid === call_cid);
|
|
7074
|
+
const rejectedIncomingCall = store.incomingCalls.find((incomingCall) => incomingCall.cid === call_cid);
|
|
6825
7075
|
if (rejectedIncomingCall) {
|
|
6826
7076
|
console.warn('Received CallRejectedEvent for an incoming call');
|
|
6827
7077
|
return;
|
|
6828
7078
|
}
|
|
6829
|
-
const rejectedOutgoingCall = store
|
|
6830
|
-
|
|
6831
|
-
.find((outgoingCall) => outgoingCall.cid === call_cid);
|
|
6832
|
-
const activeCall = store.getCurrentValue(store.activeCallSubject);
|
|
7079
|
+
const rejectedOutgoingCall = store.outgoingCalls.find((outgoingCall) => outgoingCall.cid === call_cid);
|
|
7080
|
+
const activeCall = store.activeCall;
|
|
6833
7081
|
const rejectedActiveCall = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.cid) !== undefined && activeCall.cid === call_cid
|
|
6834
7082
|
? activeCall
|
|
6835
7083
|
: undefined;
|
|
@@ -6837,7 +7085,7 @@ const watchCallRejected = (store) => {
|
|
|
6837
7085
|
console.warn(`CallRejectedEvent received for a non-existent outgoing call (CID: ${call_cid}`);
|
|
6838
7086
|
return;
|
|
6839
7087
|
}
|
|
6840
|
-
store.
|
|
7088
|
+
store.setPendingCalls((pendingCalls) => pendingCalls.filter((pendingCall) => pendingCall.cid !== call_cid));
|
|
6841
7089
|
};
|
|
6842
7090
|
};
|
|
6843
7091
|
/**
|
|
@@ -6855,10 +7103,8 @@ const watchCallCancelled = (store) => {
|
|
|
6855
7103
|
console.log("Can't find call in CallEndedEvent");
|
|
6856
7104
|
return;
|
|
6857
7105
|
}
|
|
6858
|
-
const cancelledIncomingCall = store
|
|
6859
|
-
|
|
6860
|
-
.find((incomingCall) => incomingCall.cid === call_cid);
|
|
6861
|
-
const activeCall = store.getCurrentValue(store.activeCallSubject);
|
|
7106
|
+
const cancelledIncomingCall = store.incomingCalls.find((incomingCall) => incomingCall.cid === call_cid);
|
|
7107
|
+
const activeCall = store.activeCall;
|
|
6862
7108
|
const cancelledActiveCall = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.cid) !== undefined && activeCall.cid === call_cid
|
|
6863
7109
|
? activeCall
|
|
6864
7110
|
: undefined;
|
|
@@ -6866,7 +7112,7 @@ const watchCallCancelled = (store) => {
|
|
|
6866
7112
|
console.warn(`CallEndedEvent received for a non-existent incoming call (CID: ${call_cid}`);
|
|
6867
7113
|
return;
|
|
6868
7114
|
}
|
|
6869
|
-
store.
|
|
7115
|
+
store.setPendingCalls((pendingCalls) => pendingCalls.filter((pendingCall) => pendingCall.cid !== call_cid));
|
|
6870
7116
|
};
|
|
6871
7117
|
};
|
|
6872
7118
|
|
|
@@ -6879,7 +7125,7 @@ const watchCallPermissionRequest = (store) => {
|
|
|
6879
7125
|
if (event.type !== 'call.permission_request') {
|
|
6880
7126
|
return;
|
|
6881
7127
|
}
|
|
6882
|
-
const activeCall = store.
|
|
7128
|
+
const activeCall = store.activeCall;
|
|
6883
7129
|
if (!activeCall) {
|
|
6884
7130
|
console.warn(`Ignoring "call.permission_request" as there is no active call`, event);
|
|
6885
7131
|
return;
|
|
@@ -6889,12 +7135,12 @@ const watchCallPermissionRequest = (store) => {
|
|
|
6889
7135
|
return;
|
|
6890
7136
|
}
|
|
6891
7137
|
const state = activeCall.state;
|
|
6892
|
-
const localParticipant = state.
|
|
7138
|
+
const localParticipant = state.localParticipant;
|
|
6893
7139
|
if (!(localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.ownCapabilities.includes('update-call-permissions'))) {
|
|
6894
7140
|
console.warn(`Ignoring "call.permission_request" as the user doesn't have permission to handle it`);
|
|
6895
7141
|
return;
|
|
6896
7142
|
}
|
|
6897
|
-
state.
|
|
7143
|
+
state.setCallPermissionRequest(event);
|
|
6898
7144
|
};
|
|
6899
7145
|
};
|
|
6900
7146
|
/**
|
|
@@ -6906,7 +7152,7 @@ const watchCallPermissionsUpdated = (store) => {
|
|
|
6906
7152
|
if (event.type !== 'call.permissions_updated') {
|
|
6907
7153
|
return;
|
|
6908
7154
|
}
|
|
6909
|
-
const activeCall = store.
|
|
7155
|
+
const activeCall = store.activeCall;
|
|
6910
7156
|
if (!activeCall) {
|
|
6911
7157
|
console.warn(`Ignoring "call.permissions_updated" as there is no active call`, event);
|
|
6912
7158
|
return;
|
|
@@ -6916,7 +7162,7 @@ const watchCallPermissionsUpdated = (store) => {
|
|
|
6916
7162
|
return;
|
|
6917
7163
|
}
|
|
6918
7164
|
const state = activeCall.state;
|
|
6919
|
-
const localParticipant = state.
|
|
7165
|
+
const localParticipant = state.localParticipant;
|
|
6920
7166
|
if (event.user.id === (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.userId)) {
|
|
6921
7167
|
state.updateParticipant(localParticipant.sessionId, {
|
|
6922
7168
|
ownCapabilities: event.own_capabilities,
|
|
@@ -6937,14 +7183,14 @@ const watchNewReactions = (store) => {
|
|
|
6937
7183
|
return;
|
|
6938
7184
|
}
|
|
6939
7185
|
const { call_cid, reaction } = event;
|
|
6940
|
-
const activeCall = store.
|
|
7186
|
+
const activeCall = store.activeCall;
|
|
6941
7187
|
if (!activeCall || activeCall.cid !== call_cid) {
|
|
6942
7188
|
console.warn('Received CallReactionEvent for an inactive or unknown call');
|
|
6943
7189
|
return;
|
|
6944
7190
|
}
|
|
6945
7191
|
const state = activeCall.state;
|
|
6946
|
-
|
|
6947
|
-
|
|
7192
|
+
const { user, custom, type, emoji_code } = reaction;
|
|
7193
|
+
state.setParticipants((participants) => {
|
|
6948
7194
|
return participants.map((p) => {
|
|
6949
7195
|
// skip if the reaction is not for this participant
|
|
6950
7196
|
if (p.userId !== user.id)
|
|
@@ -6972,13 +7218,13 @@ const watchCallRecordingStarted = (store) => {
|
|
|
6972
7218
|
return;
|
|
6973
7219
|
}
|
|
6974
7220
|
const { call_cid } = event;
|
|
6975
|
-
const activeCall = store.
|
|
7221
|
+
const activeCall = store.activeCall;
|
|
6976
7222
|
if (!activeCall || activeCall.cid !== call_cid) {
|
|
6977
7223
|
console.warn('Received CallRecordingStartedEvent for a non-active call');
|
|
6978
7224
|
return;
|
|
6979
7225
|
}
|
|
6980
7226
|
const state = activeCall.state;
|
|
6981
|
-
state.
|
|
7227
|
+
state.setCallRecordingInProgress(true);
|
|
6982
7228
|
};
|
|
6983
7229
|
};
|
|
6984
7230
|
/**
|
|
@@ -6990,13 +7236,13 @@ const watchCallRecordingStopped = (store) => {
|
|
|
6990
7236
|
return;
|
|
6991
7237
|
}
|
|
6992
7238
|
const { call_cid } = event;
|
|
6993
|
-
const activeCall = store.
|
|
7239
|
+
const activeCall = store.activeCall;
|
|
6994
7240
|
if (!activeCall || activeCall.cid !== call_cid) {
|
|
6995
7241
|
console.warn('Received CallRecordingStoppedEvent for a non-active call');
|
|
6996
7242
|
return;
|
|
6997
7243
|
}
|
|
6998
7244
|
const state = activeCall.state;
|
|
6999
|
-
state.
|
|
7245
|
+
state.setCallRecordingInProgress(false);
|
|
7000
7246
|
};
|
|
7001
7247
|
};
|
|
7002
7248
|
|
|
@@ -7006,21 +7252,21 @@ const watchCallRecordingStopped = (store) => {
|
|
|
7006
7252
|
* `event.user_id` to the list
|
|
7007
7253
|
*/
|
|
7008
7254
|
const watchBlockedUser = (store) => (event) => {
|
|
7255
|
+
var _a;
|
|
7009
7256
|
if (event.type !== 'call.blocked_user') {
|
|
7010
7257
|
return;
|
|
7011
7258
|
}
|
|
7012
|
-
const activeCall = store.
|
|
7259
|
+
const activeCall = store.activeCall;
|
|
7013
7260
|
if (!activeCall || activeCall.cid !== event.call_cid) {
|
|
7014
7261
|
console.warn(`Received "call.blocked_user" for an inactive or unknown call`, event);
|
|
7015
7262
|
return;
|
|
7016
7263
|
}
|
|
7017
7264
|
const state = activeCall.state;
|
|
7018
|
-
const localParticipant = state.getCurrentValue(state.localParticipant$);
|
|
7019
7265
|
// FIXME: end call
|
|
7020
|
-
if ((localParticipant === null ||
|
|
7266
|
+
if (((_a = state.localParticipant) === null || _a === void 0 ? void 0 : _a.userId) === event.user.id) {
|
|
7021
7267
|
activeCall.leave();
|
|
7022
7268
|
}
|
|
7023
|
-
state.
|
|
7269
|
+
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { blocked_user_ids: [...metadata.blocked_user_ids, event.user.id] })));
|
|
7024
7270
|
};
|
|
7025
7271
|
/**
|
|
7026
7272
|
* Event handler that watches for `call.unblocked_user` events,
|
|
@@ -7031,13 +7277,13 @@ const watchUnblockedUser = (store) => (event) => {
|
|
|
7031
7277
|
if (event.type !== 'call.unblocked_user') {
|
|
7032
7278
|
return;
|
|
7033
7279
|
}
|
|
7034
|
-
const activeCall = store.
|
|
7280
|
+
const activeCall = store.activeCall;
|
|
7035
7281
|
if (!activeCall || activeCall.cid !== event.call_cid) {
|
|
7036
7282
|
console.warn(`Received "call.unblocked_user" for an inactive or unknown call`, event);
|
|
7037
7283
|
return;
|
|
7038
7284
|
}
|
|
7039
7285
|
const state = activeCall.state;
|
|
7040
|
-
state.
|
|
7286
|
+
state.setMetadata((metadata) => {
|
|
7041
7287
|
const blocked_user_ids = metadata.blocked_user_ids.filter((userId) => event.user.id !== userId);
|
|
7042
7288
|
return Object.assign(Object.assign({}, metadata), { blocked_user_ids });
|
|
7043
7289
|
});
|
|
@@ -7055,7 +7301,7 @@ class CallDropScheduler {
|
|
|
7055
7301
|
const newIncomingCall = CallDropScheduler.getLatestCall(currentCalls, prevCalls);
|
|
7056
7302
|
if (!newIncomingCall)
|
|
7057
7303
|
return;
|
|
7058
|
-
const activeCall = this.store.
|
|
7304
|
+
const activeCall = this.store.activeCall;
|
|
7059
7305
|
if (activeCall) {
|
|
7060
7306
|
yield newIncomingCall.reject();
|
|
7061
7307
|
}
|
|
@@ -7070,7 +7316,7 @@ class CallDropScheduler {
|
|
|
7070
7316
|
const newIncomingCall = CallDropScheduler.getLatestCall(currentCalls, prevCalls);
|
|
7071
7317
|
if (!newIncomingCall)
|
|
7072
7318
|
return;
|
|
7073
|
-
const activeCall = this.store.
|
|
7319
|
+
const activeCall = this.store.activeCall;
|
|
7074
7320
|
const incomingCallRejectedImmediately = activeCall && this.callConfig.autoRejectWhenInCall;
|
|
7075
7321
|
if (incomingCallRejectedImmediately)
|
|
7076
7322
|
return;
|
|
@@ -7121,8 +7367,6 @@ class CallDropScheduler {
|
|
|
7121
7367
|
};
|
|
7122
7368
|
/**
|
|
7123
7369
|
* Schedules automatic call rejection.
|
|
7124
|
-
* @param {string} callId
|
|
7125
|
-
* @param {string} callType
|
|
7126
7370
|
*/
|
|
7127
7371
|
this.scheduleReject = (call) => {
|
|
7128
7372
|
const timeout = this.callConfig.autoRejectTimeoutInMs;
|
|
@@ -7351,7 +7595,7 @@ class StableWSConnection {
|
|
|
7351
7595
|
if (this.wsID !== wsID)
|
|
7352
7596
|
return;
|
|
7353
7597
|
this._log('onclose() - onclose callback - ' + event.code, { event, wsID });
|
|
7354
|
-
if (event.code ===
|
|
7598
|
+
if (event.code === KnownCodes.WS_CLOSED_SUCCESS) {
|
|
7355
7599
|
// this is a permanent error raised by stream..
|
|
7356
7600
|
// usually caused by invalid auth details
|
|
7357
7601
|
const error = new Error(`WS connection reject with error ${event.reason}`);
|
|
@@ -7526,7 +7770,7 @@ class StableWSConnection {
|
|
|
7526
7770
|
/**
|
|
7527
7771
|
* connect - Connect to the WS URL
|
|
7528
7772
|
* the default 15s timeout allows between 2~3 tries
|
|
7529
|
-
* @return {ConnectAPIResponse<
|
|
7773
|
+
* @return {ConnectAPIResponse<ConnectedEvent>} Promise that completes once the first health check message is received
|
|
7530
7774
|
*/
|
|
7531
7775
|
connect(timeout = 15000) {
|
|
7532
7776
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -7544,7 +7788,7 @@ class StableWSConnection {
|
|
|
7544
7788
|
this.consecutiveFailures += 1;
|
|
7545
7789
|
if (
|
|
7546
7790
|
// @ts-ignore
|
|
7547
|
-
error.code ===
|
|
7791
|
+
error.code === KnownCodes.TOKEN_EXPIRED &&
|
|
7548
7792
|
!this.client.tokenManager.isStatic()) {
|
|
7549
7793
|
this._log('connect() - WS failure due to expired token, so going to try to reload token and reconnect');
|
|
7550
7794
|
this._reconnect({ refreshToken: true });
|
|
@@ -7648,7 +7892,7 @@ class StableWSConnection {
|
|
|
7648
7892
|
setTimeout(onclose, timeout != null ? timeout : 1000);
|
|
7649
7893
|
});
|
|
7650
7894
|
this._log(`disconnect() - Manually closed connection by calling client.disconnect()`);
|
|
7651
|
-
ws.close(
|
|
7895
|
+
ws.close(KnownCodes.WS_CLOSED_SUCCESS, 'Manually closed connection by calling client.disconnect()');
|
|
7652
7896
|
}
|
|
7653
7897
|
else {
|
|
7654
7898
|
this._log(`disconnect() - ws connection doesn't exist or it is already closed.`);
|
|
@@ -7660,7 +7904,7 @@ class StableWSConnection {
|
|
|
7660
7904
|
/**
|
|
7661
7905
|
* _connect - Connect to the WS endpoint
|
|
7662
7906
|
*
|
|
7663
|
-
* @return {ConnectAPIResponse<
|
|
7907
|
+
* @return {ConnectAPIResponse<ConnectedEvent>} Promise that completes once the first health check message is received
|
|
7664
7908
|
*/
|
|
7665
7909
|
_connect() {
|
|
7666
7910
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -7773,7 +8017,7 @@ class StableWSConnection {
|
|
|
7773
8017
|
catch (error) {
|
|
7774
8018
|
this.isHealthy = false;
|
|
7775
8019
|
this.consecutiveFailures += 1;
|
|
7776
|
-
if (error.code ===
|
|
8020
|
+
if (error.code === KnownCodes.TOKEN_EXPIRED &&
|
|
7777
8021
|
!this.client.tokenManager.isStatic()) {
|
|
7778
8022
|
this._log('_reconnect() - WS failure due to expired token, so going to try to reload token and reconnect');
|
|
7779
8023
|
return this._reconnect({ refreshToken: true });
|
|
@@ -8465,7 +8709,7 @@ class StreamClient {
|
|
|
8465
8709
|
this.consecutiveFailures += 1;
|
|
8466
8710
|
if (e.response) {
|
|
8467
8711
|
/** connection_fallback depends on this token expiration logic */
|
|
8468
|
-
if (e.response.data.code ===
|
|
8712
|
+
if (e.response.data.code === KnownCodes.TOKEN_EXPIRED &&
|
|
8469
8713
|
!this.tokenManager.isStatic()) {
|
|
8470
8714
|
if (this.consecutiveFailures > 1) {
|
|
8471
8715
|
yield sleep(retryInterval(this.consecutiveFailures));
|
|
@@ -8781,7 +9025,7 @@ class StreamClient {
|
|
|
8781
9025
|
}
|
|
8782
9026
|
getUserAgent() {
|
|
8783
9027
|
return (this.userAgent ||
|
|
8784
|
-
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.1-alpha.
|
|
9028
|
+
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.1-alpha.88"}`);
|
|
8785
9029
|
}
|
|
8786
9030
|
setUserAgent(userAgent) {
|
|
8787
9031
|
this.userAgent = userAgent;
|
|
@@ -8853,7 +9097,7 @@ class StreamVideoClient {
|
|
|
8853
9097
|
this.on('call.recording_started', watchCallRecordingStarted(this.writeableStateStore));
|
|
8854
9098
|
this.on('call.recording_stopped', watchCallRecordingStopped(this.writeableStateStore));
|
|
8855
9099
|
this.on('call.reaction_new', watchNewReactions(this.writeableStateStore));
|
|
8856
|
-
this.writeableStateStore.
|
|
9100
|
+
this.writeableStateStore.setConnectedUser(user);
|
|
8857
9101
|
});
|
|
8858
9102
|
/**
|
|
8859
9103
|
* Disconnects the currently connected user from the client.
|
|
@@ -8867,7 +9111,7 @@ class StreamVideoClient {
|
|
|
8867
9111
|
var _a;
|
|
8868
9112
|
yield this.streamClient.disconnectUser(timeout);
|
|
8869
9113
|
(_a = this.callDropScheduler) === null || _a === void 0 ? void 0 : _a.cleanUp();
|
|
8870
|
-
this.writeableStateStore.
|
|
9114
|
+
this.writeableStateStore.setConnectedUser(undefined);
|
|
8871
9115
|
});
|
|
8872
9116
|
/**
|
|
8873
9117
|
* You can subscribe to WebSocket events provided by the API.
|