@stream-io/video-client 1.28.0 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/index.browser.es.js +109 -74
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +108 -73
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +109 -74
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +1 -0
- package/dist/src/devices/InputMediaDeviceManager.d.ts +3 -0
- package/dist/src/store/CallState.d.ts +9 -1
- package/package.json +1 -1
- package/src/Call.ts +54 -43
- package/src/coordinator/connection/client.ts +9 -1
- package/src/devices/InputMediaDeviceManager.ts +8 -1
- package/src/events/call-permissions.ts +2 -20
- package/src/events/callEventHandlers.ts +0 -5
- package/src/store/CallState.ts +59 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.29.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.28.1...@stream-io/video-client-1.29.0) (2025-09-09)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- opt-out from optimistic updates ([#1904](https://github.com/GetStream/stream-video-js/issues/1904)) ([45dba34](https://github.com/GetStream/stream-video-js/commit/45dba34d38dc64f456e37b593e38e420426529f5))
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- capabilities and call grants ([#1899](https://github.com/GetStream/stream-video-js/issues/1899)) ([5725dfa](https://github.com/GetStream/stream-video-js/commit/5725dfa29b1e5fdb6fe4e26825ce7b268664d2fa))
|
|
14
|
+
- graceful Axios request config overrides ([#1913](https://github.com/GetStream/stream-video-js/issues/1913)) ([a124099](https://github.com/GetStream/stream-video-js/commit/a124099f984a592750d66ac440ef6c27ae7a02d9))
|
|
15
|
+
|
|
16
|
+
## [1.28.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.28.0...@stream-io/video-client-1.28.1) (2025-08-22)
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- handle pre ended calls on ringing push arrival ([#1897](https://github.com/GetStream/stream-video-js/issues/1897)) ([935e375](https://github.com/GetStream/stream-video-js/commit/935e3756035639c651b3ac4469321a64b8576a0e))
|
|
21
|
+
|
|
5
22
|
## [1.28.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.27.5...@stream-io/video-client-1.28.0) (2025-08-21)
|
|
6
23
|
|
|
7
24
|
### Features
|
package/dist/index.browser.es.js
CHANGED
|
@@ -4,7 +4,7 @@ import { ServiceType, stackIntercept, RpcError } from '@protobuf-ts/runtime-rpc'
|
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
export { AxiosError } from 'axios';
|
|
6
6
|
import { TwirpFetchTransport, TwirpErrorCode } from '@protobuf-ts/twirp-transport';
|
|
7
|
-
import { ReplaySubject, combineLatest, BehaviorSubject, shareReplay, map, distinctUntilChanged, takeWhile, distinctUntilKeyChanged, fromEventPattern,
|
|
7
|
+
import { ReplaySubject, combineLatest, BehaviorSubject, shareReplay, map, distinctUntilChanged, startWith, takeWhile, distinctUntilKeyChanged, fromEventPattern, concatMap, merge, from, fromEvent, tap, debounceTime, pairwise, of } from 'rxjs';
|
|
8
8
|
import { UAParser } from 'ua-parser-js';
|
|
9
9
|
import { parse, write } from 'sdp-transform';
|
|
10
10
|
|
|
@@ -4649,6 +4649,7 @@ class CallState {
|
|
|
4649
4649
|
// This happens when the participantJoined event hasn't been received yet.
|
|
4650
4650
|
// We keep these tracks around until we can associate them with a participant.
|
|
4651
4651
|
this.orphanedTracks = [];
|
|
4652
|
+
this.callGrantsSubject = new ReplaySubject(1);
|
|
4652
4653
|
this.logger = getLogger(['CallState']);
|
|
4653
4654
|
/**
|
|
4654
4655
|
* A list of comparators that are used to sort the participants.
|
|
@@ -4776,6 +4777,15 @@ class CallState {
|
|
|
4776
4777
|
this.setOwnCapabilities = (capabilities) => {
|
|
4777
4778
|
return this.setCurrentValue(this.ownCapabilitiesSubject, capabilities);
|
|
4778
4779
|
};
|
|
4780
|
+
/**
|
|
4781
|
+
* Sets the call grants (used for own capabilities).
|
|
4782
|
+
*
|
|
4783
|
+
* @internal
|
|
4784
|
+
* @param grants the grants to set.
|
|
4785
|
+
*/
|
|
4786
|
+
this.setCallGrants = (grants) => {
|
|
4787
|
+
return this.setCurrentValue(this.callGrantsSubject, grants);
|
|
4788
|
+
};
|
|
4779
4789
|
/**
|
|
4780
4790
|
* Sets the backstage state.
|
|
4781
4791
|
* @param backstage the backstage state.
|
|
@@ -5207,7 +5217,7 @@ class CallState {
|
|
|
5207
5217
|
};
|
|
5208
5218
|
this.updateOwnCapabilities = (event) => {
|
|
5209
5219
|
if (event.user.id === this.localParticipant?.userId) {
|
|
5210
|
-
this.
|
|
5220
|
+
this.setOwnCapabilities(event.own_capabilities);
|
|
5211
5221
|
}
|
|
5212
5222
|
};
|
|
5213
5223
|
this.updateFromClosedCaptions = (event) => {
|
|
@@ -5276,25 +5286,53 @@ class CallState {
|
|
|
5276
5286
|
const isShallowEqual = (a, b) => {
|
|
5277
5287
|
if (a.length !== b.length)
|
|
5278
5288
|
return false;
|
|
5279
|
-
for (const item of a)
|
|
5289
|
+
for (const item of a) {
|
|
5280
5290
|
if (!b.includes(item))
|
|
5281
5291
|
return false;
|
|
5282
|
-
|
|
5292
|
+
}
|
|
5293
|
+
for (const item of b) {
|
|
5283
5294
|
if (!a.includes(item))
|
|
5284
5295
|
return false;
|
|
5296
|
+
}
|
|
5285
5297
|
return true;
|
|
5286
5298
|
};
|
|
5287
5299
|
/**
|
|
5288
5300
|
* Creates an Observable from the given subject by piping to the
|
|
5289
5301
|
* `distinctUntilChanged()` operator.
|
|
5290
5302
|
*/
|
|
5291
|
-
const duc = (subject, comparator) => subject.
|
|
5303
|
+
const duc = (subject, comparator) => subject.pipe(distinctUntilChanged(comparator));
|
|
5292
5304
|
// primitive values should only emit once the value they hold changes
|
|
5293
5305
|
this.anonymousParticipantCount$ = duc(this.anonymousParticipantCountSubject);
|
|
5294
5306
|
this.blockedUserIds$ = duc(this.blockedUserIdsSubject, isShallowEqual);
|
|
5295
5307
|
this.backstage$ = duc(this.backstageSubject);
|
|
5296
5308
|
this.callingState$ = duc(this.callingStateSubject);
|
|
5297
|
-
this.ownCapabilities$ =
|
|
5309
|
+
this.ownCapabilities$ = combineLatest([
|
|
5310
|
+
this.ownCapabilitiesSubject,
|
|
5311
|
+
this.callGrantsSubject.pipe(startWith(undefined)),
|
|
5312
|
+
]).pipe(map(([capabilities, grants]) => {
|
|
5313
|
+
if (!grants)
|
|
5314
|
+
return capabilities;
|
|
5315
|
+
const { canPublishAudio, canPublishVideo, canScreenshare } = grants;
|
|
5316
|
+
const update = {
|
|
5317
|
+
[OwnCapability.SEND_AUDIO]: canPublishAudio,
|
|
5318
|
+
[OwnCapability.SEND_VIDEO]: canPublishVideo,
|
|
5319
|
+
[OwnCapability.SCREENSHARE]: canScreenshare,
|
|
5320
|
+
};
|
|
5321
|
+
const nextCapabilities = [...capabilities];
|
|
5322
|
+
for (const _capability in update) {
|
|
5323
|
+
const capability = _capability;
|
|
5324
|
+
const allowed = update[capability];
|
|
5325
|
+
// grants take precedence over capabilities, reconstruct the capabilities
|
|
5326
|
+
if (allowed && !nextCapabilities.includes(capability)) {
|
|
5327
|
+
nextCapabilities.push(capability);
|
|
5328
|
+
}
|
|
5329
|
+
else if (!allowed && nextCapabilities.includes(capability)) {
|
|
5330
|
+
const index = nextCapabilities.indexOf(capability);
|
|
5331
|
+
nextCapabilities.splice(index, 1);
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5334
|
+
return nextCapabilities;
|
|
5335
|
+
}), distinctUntilChanged(isShallowEqual), shareReplay({ bufferSize: 1, refCount: true }));
|
|
5298
5336
|
this.participantCount$ = duc(this.participantCountSubject);
|
|
5299
5337
|
this.recording$ = duc(this.recordingSubject);
|
|
5300
5338
|
this.transcribing$ = duc(this.transcribingSubject);
|
|
@@ -5653,7 +5691,7 @@ const getSdkVersion = (sdk) => {
|
|
|
5653
5691
|
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
5654
5692
|
};
|
|
5655
5693
|
|
|
5656
|
-
const version = "1.
|
|
5694
|
+
const version = "1.29.0";
|
|
5657
5695
|
const [major, minor, patch] = version.split('.');
|
|
5658
5696
|
let sdkInfo = {
|
|
5659
5697
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -8387,21 +8425,9 @@ const watchSfuCallEnded = (call) => {
|
|
|
8387
8425
|
const watchCallGrantsUpdated = (state) => {
|
|
8388
8426
|
return function onCallGrantsUpdated(event) {
|
|
8389
8427
|
const { currentGrants } = event;
|
|
8390
|
-
if (currentGrants)
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
[OwnCapability.SEND_AUDIO]: canPublishAudio,
|
|
8394
|
-
[OwnCapability.SEND_VIDEO]: canPublishVideo,
|
|
8395
|
-
[OwnCapability.SCREENSHARE]: canScreenshare,
|
|
8396
|
-
};
|
|
8397
|
-
const nextCapabilities = state.ownCapabilities.filter((capability) => update[capability] !== false);
|
|
8398
|
-
Object.entries(update).forEach(([capability, value]) => {
|
|
8399
|
-
if (value && !nextCapabilities.includes(capability)) {
|
|
8400
|
-
nextCapabilities.push(capability);
|
|
8401
|
-
}
|
|
8402
|
-
});
|
|
8403
|
-
state.setOwnCapabilities(nextCapabilities);
|
|
8404
|
-
}
|
|
8428
|
+
if (!currentGrants)
|
|
8429
|
+
return;
|
|
8430
|
+
state.setCallGrants(currentGrants);
|
|
8405
8431
|
};
|
|
8406
8432
|
};
|
|
8407
8433
|
|
|
@@ -8743,10 +8769,6 @@ const registerEventHandlers = (call, dispatcher) => {
|
|
|
8743
8769
|
call.on('inboundStateNotification', watchInboundStateNotification(state)),
|
|
8744
8770
|
handleRemoteSoftMute(call),
|
|
8745
8771
|
];
|
|
8746
|
-
if (call.ringing) {
|
|
8747
|
-
// these events are only relevant when the call is ringing
|
|
8748
|
-
eventHandlers.push(registerRingingCallEventHandlers(call));
|
|
8749
|
-
}
|
|
8750
8772
|
return () => {
|
|
8751
8773
|
eventHandlers.forEach((unsubscribe) => unsubscribe());
|
|
8752
8774
|
};
|
|
@@ -10000,11 +10022,10 @@ class InputMediaDeviceManager {
|
|
|
10000
10022
|
}
|
|
10001
10023
|
});
|
|
10002
10024
|
}
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
async disable(forceStop = false) {
|
|
10025
|
+
async disable(forceStopOrOptions) {
|
|
10026
|
+
const forceStop = typeof forceStopOrOptions === 'boolean'
|
|
10027
|
+
? forceStopOrOptions
|
|
10028
|
+
: (forceStopOrOptions?.forceStop ?? false);
|
|
10008
10029
|
this.state.prevStatus = this.state.optimisticStatus;
|
|
10009
10030
|
if (!forceStop && this.state.optimisticStatus === 'disabled') {
|
|
10010
10031
|
return;
|
|
@@ -11538,6 +11559,21 @@ class Call {
|
|
|
11538
11559
|
});
|
|
11539
11560
|
}
|
|
11540
11561
|
}));
|
|
11562
|
+
if (this.ringing) {
|
|
11563
|
+
// if the call is ringing, we need to register the ringing call effects
|
|
11564
|
+
this.handleRingingCall();
|
|
11565
|
+
}
|
|
11566
|
+
else {
|
|
11567
|
+
// if the call is not ringing, we need to register the ringing call subscriptions
|
|
11568
|
+
// to handle the case when the call gets ringing flag after creation event
|
|
11569
|
+
this.leaveCallHooks.add(
|
|
11570
|
+
// "ringing" mode effects and event handlers
|
|
11571
|
+
createSubscription(this.ringingSubject, (isRinging) => {
|
|
11572
|
+
if (!isRinging)
|
|
11573
|
+
return;
|
|
11574
|
+
this.handleRingingCall();
|
|
11575
|
+
}));
|
|
11576
|
+
}
|
|
11541
11577
|
this.leaveCallHooks.add(
|
|
11542
11578
|
// cancel auto-drop when call is accepted or rejected
|
|
11543
11579
|
createSubscription(this.state.session$, (session) => {
|
|
@@ -11559,53 +11595,49 @@ class Call {
|
|
|
11559
11595
|
});
|
|
11560
11596
|
}
|
|
11561
11597
|
}));
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11598
|
+
};
|
|
11599
|
+
this.handleRingingCall = () => {
|
|
11600
|
+
const callSession = this.state.session;
|
|
11601
|
+
const receiver_id = this.clientStore.connectedUser?.id;
|
|
11602
|
+
const ended_at = callSession?.ended_at;
|
|
11603
|
+
const created_by_id = this.state.createdBy?.id;
|
|
11604
|
+
const rejected_by = callSession?.rejected_by;
|
|
11605
|
+
const accepted_by = callSession?.accepted_by;
|
|
11606
|
+
let leaveCallIdle = false;
|
|
11607
|
+
if (ended_at) {
|
|
11608
|
+
// call was ended before it was accepted or rejected so we should leave it to idle
|
|
11609
|
+
leaveCallIdle = true;
|
|
11610
|
+
}
|
|
11611
|
+
else if (created_by_id && rejected_by) {
|
|
11612
|
+
if (rejected_by[created_by_id]) {
|
|
11613
|
+
// call was cancelled by the caller
|
|
11576
11614
|
leaveCallIdle = true;
|
|
11577
11615
|
}
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
}
|
|
11584
|
-
else if (receiver_id && rejected_by) {
|
|
11585
|
-
if (rejected_by[receiver_id]) {
|
|
11586
|
-
// call was rejected by the receiver in some other device
|
|
11587
|
-
leaveCallIdle = true;
|
|
11588
|
-
}
|
|
11616
|
+
}
|
|
11617
|
+
else if (receiver_id && rejected_by) {
|
|
11618
|
+
if (rejected_by[receiver_id]) {
|
|
11619
|
+
// call was rejected by the receiver in some other device
|
|
11620
|
+
leaveCallIdle = true;
|
|
11589
11621
|
}
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11622
|
+
}
|
|
11623
|
+
else if (receiver_id && accepted_by) {
|
|
11624
|
+
if (accepted_by[receiver_id]) {
|
|
11625
|
+
// call was accepted by the receiver in some other device
|
|
11626
|
+
leaveCallIdle = true;
|
|
11595
11627
|
}
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11628
|
+
}
|
|
11629
|
+
if (leaveCallIdle) {
|
|
11630
|
+
if (this.state.callingState !== CallingState.IDLE) {
|
|
11631
|
+
this.state.setCallingState(CallingState.IDLE);
|
|
11600
11632
|
}
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
this.scheduleAutoDrop();
|
|
11606
|
-
this.leaveCallHooks.add(registerRingingCallEventHandlers(this));
|
|
11633
|
+
}
|
|
11634
|
+
else {
|
|
11635
|
+
if (this.state.callingState === CallingState.IDLE) {
|
|
11636
|
+
this.state.setCallingState(CallingState.RINGING);
|
|
11607
11637
|
}
|
|
11608
|
-
|
|
11638
|
+
this.scheduleAutoDrop();
|
|
11639
|
+
this.leaveCallHooks.add(registerRingingCallEventHandlers(this));
|
|
11640
|
+
}
|
|
11609
11641
|
};
|
|
11610
11642
|
this.handleOwnCapabilitiesUpdated = async (ownCapabilities) => {
|
|
11611
11643
|
// update the permission context.
|
|
@@ -14562,7 +14594,7 @@ class StreamClient {
|
|
|
14562
14594
|
this.getUserAgent = () => {
|
|
14563
14595
|
if (!this.cachedUserAgent) {
|
|
14564
14596
|
const { clientAppIdentifier = {} } = this.options;
|
|
14565
|
-
const { sdkName = 'js', sdkVersion = "1.
|
|
14597
|
+
const { sdkName = 'js', sdkVersion = "1.29.0", ...extras } = clientAppIdentifier;
|
|
14566
14598
|
this.cachedUserAgent = [
|
|
14567
14599
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
14568
14600
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|
|
@@ -14584,12 +14616,14 @@ class StreamClient {
|
|
|
14584
14616
|
'x-client-request-id': generateUUIDv4(),
|
|
14585
14617
|
};
|
|
14586
14618
|
}
|
|
14619
|
+
const { params: axiosConfigParams, headers: axiosConfigHeaders, ...axiosRequestConfig } = this.options.axiosRequestConfig || {};
|
|
14587
14620
|
return {
|
|
14588
14621
|
params: {
|
|
14589
14622
|
user_id: this.userID,
|
|
14590
14623
|
connection_id: this._getConnectionID(),
|
|
14591
14624
|
api_key: this.key,
|
|
14592
14625
|
...options.params,
|
|
14626
|
+
...axiosConfigParams,
|
|
14593
14627
|
},
|
|
14594
14628
|
headers: {
|
|
14595
14629
|
...authorization,
|
|
@@ -14598,9 +14632,10 @@ class StreamClient {
|
|
|
14598
14632
|
: this.getAuthType(),
|
|
14599
14633
|
'X-Stream-Client': this.getUserAgent(),
|
|
14600
14634
|
...options.headers,
|
|
14635
|
+
...axiosConfigHeaders,
|
|
14601
14636
|
},
|
|
14602
14637
|
...options.config,
|
|
14603
|
-
...
|
|
14638
|
+
...axiosRequestConfig,
|
|
14604
14639
|
};
|
|
14605
14640
|
};
|
|
14606
14641
|
this._getToken = () => {
|