@stream-io/video-client 1.61.0 → 2.0.0-beta.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +10 -10
  2. package/dist/index.browser.es.js +358 -611
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +357 -611
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +358 -611
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +3 -3
  9. package/dist/src/StreamVideoClient.d.ts +15 -21
  10. package/dist/src/store/CallState.d.ts +108 -266
  11. package/dist/src/store/ClientState.d.ts +62 -0
  12. package/dist/src/store/index.d.ts +1 -1
  13. package/dist/src/store/subjects.d.ts +15 -0
  14. package/dist/src/store/types.d.ts +22 -0
  15. package/dist/src/types.d.ts +3 -3
  16. package/package.json +2 -2
  17. package/src/Call.ts +14 -18
  18. package/src/StreamVideoClient.ts +40 -47
  19. package/src/__tests__/Call.autodrop.test.ts +4 -4
  20. package/src/__tests__/Call.getRingState.test.ts +2 -2
  21. package/src/__tests__/Call.lifecycle.test.ts +8 -8
  22. package/src/__tests__/Call.publishing.test.ts +2 -2
  23. package/src/__tests__/Call.ringSettled.test.ts +4 -4
  24. package/src/__tests__/Call.ringingLifecycle.test.ts +2 -2
  25. package/src/__tests__/StreamVideoClient.disconnect.test.ts +62 -0
  26. package/src/devices/__tests__/CameraManager.test.ts +2 -2
  27. package/src/devices/__tests__/DeviceManager.test.ts +2 -2
  28. package/src/devices/__tests__/DeviceManagerFilters.test.ts +2 -2
  29. package/src/devices/__tests__/MicrophoneManager.test.ts +2 -2
  30. package/src/devices/__tests__/MicrophoneManagerRN.test.ts +2 -2
  31. package/src/devices/__tests__/ScreenShareManager.test.ts +3 -3
  32. package/src/devices/__tests__/SpeakerManager.test.ts +4 -4
  33. package/src/events/__tests__/call.test.ts +3 -3
  34. package/src/helpers/__tests__/AudioBindingsWatchdog.test.ts +2 -2
  35. package/src/helpers/__tests__/DynascaleManager.test.ts +2 -2
  36. package/src/helpers/__tests__/ViewportTracker.test.ts +2 -2
  37. package/src/ringing/__tests__/RingStatePoller.test.ts +7 -7
  38. package/src/ringing/__tests__/RingTimeout.test.ts +4 -4
  39. package/src/ringing/__tests__/reconcileRingState.test.ts +3 -3
  40. package/src/rtc/__tests__/Call.reconnect.test.ts +5 -5
  41. package/src/store/CallState.ts +281 -551
  42. package/src/store/ClientState.ts +101 -0
  43. package/src/store/__tests__/CallState.test.ts +1 -1
  44. package/src/store/__tests__/ClientState.test.ts +35 -0
  45. package/src/store/__tests__/rxUtils.test.ts +67 -1
  46. package/src/store/index.ts +1 -1
  47. package/src/store/rxUtils.ts +8 -4
  48. package/src/store/subjects.ts +30 -0
  49. package/src/store/types.ts +45 -0
  50. package/src/types.ts +3 -3
  51. package/dist/src/store/stateStore.d.ts +0 -84
  52. package/src/store/stateStore.ts +0 -156
@@ -0,0 +1,62 @@
1
+ import { type Patch } from './rxUtils';
2
+ import type { Call } from '../Call';
3
+ import type { OwnUserResponse } from '../gen/coordinator';
4
+ /**
5
+ * Holds the state of the client, and the calls it created or tracks.
6
+ * You can subscribe to the exposed observables to get notified about changes.
7
+ */
8
+ export declare class ClientState {
9
+ readonly logger: import("@stream-io/logger").Logger<string & {}>;
10
+ private connectedUserSubject;
11
+ private callsSubject;
12
+ /** Data describing a user successfully connected over WS to the coordinator. */
13
+ connectedUser$: import("rxjs").Observable<OwnUserResponse | undefined>;
14
+ /** A list of {@link Call} objects created/tracked by this client. */
15
+ calls$: import("rxjs").Observable<Call[]>;
16
+ /** The currently connected user. */
17
+ get connectedUser(): OwnUserResponse | undefined;
18
+ /** A list of {@link Call} objects created/tracked by this client. */
19
+ get calls(): Call[];
20
+ /**
21
+ * Sets the currently connected user.
22
+ *
23
+ * @internal
24
+ * @param user the user to set as connected.
25
+ */
26
+ setConnectedUser: (user: Patch<OwnUserResponse | undefined>) => OwnUserResponse | undefined;
27
+ /**
28
+ * Sets the list of {@link Call} objects created/tracked by this client.
29
+ *
30
+ * @internal
31
+ * @param calls the calls to set.
32
+ */
33
+ setCalls: (calls: Patch<Call[]>) => Call[];
34
+ /**
35
+ * Adds a {@link Call} object to the list of calls tracked by this client.
36
+ *
37
+ * @internal
38
+ * @param call the call to add.
39
+ */
40
+ registerCall: (call: Call) => void;
41
+ /**
42
+ * Registers a {@link Call} object if it doesn't exist, otherwise updates it.
43
+ *
44
+ * @internal
45
+ * @param call the call to register or update.
46
+ */
47
+ registerOrUpdateCall: (call: Call) => void | Call[];
48
+ /**
49
+ * Removes a {@link Call} object from the list of calls tracked by this client.
50
+ *
51
+ * @internal
52
+ * @param call the call to remove.
53
+ */
54
+ unregisterCall: (call: Call) => Call[];
55
+ /**
56
+ * Finds a {@link Call} object in the list of calls tracked by this client.
57
+ *
58
+ * @param type the type of call to find.
59
+ * @param id the id of the call to find.
60
+ */
61
+ findCall: (type: string, id: string) => Call | undefined;
62
+ }
@@ -1,4 +1,4 @@
1
1
  export * as RxUtils from './rxUtils';
2
2
  export * from './CallingState';
3
- export * from './stateStore';
3
+ export * from './ClientState';
4
4
  export * from './CallState';
@@ -0,0 +1,15 @@
1
+ import { BehaviorSubject, Observable } from 'rxjs';
2
+ /** Creates a BehaviorSubject seeded with the given value. */
3
+ export declare function subject<T>(initialValue: T): BehaviorSubject<T>;
4
+ /** Creates a BehaviorSubject which starts out holding `undefined`. */
5
+ export declare function subject<T>(): BehaviorSubject<T | undefined>;
6
+ /**
7
+ * Creates an Observable from the given subject by piping it to the
8
+ * `distinctUntilChanged()` operator.
9
+ */
10
+ export declare const duc: <T>(source: BehaviorSubject<T>, comparator?: (a: T, b: T) => boolean) => Observable<T>;
11
+ /**
12
+ * Multicasts the given Observable, replaying the latest computed value to
13
+ * every new subscriber instead of re-running the pipeline for each of them.
14
+ */
15
+ export declare const shared: <T>(source: Observable<T>) => Observable<T>;
@@ -0,0 +1,22 @@
1
+ import type { VideoEvent } from '../gen/coordinator';
2
+ /** Handles a single video event of the given type. */
3
+ export type EventHandler<T extends VideoEvent['type']> = (event: Extract<VideoEvent, {
4
+ type: T;
5
+ }>) => void;
6
+ /**
7
+ * Identity type constrained to real event names, so that a name which no
8
+ * longer exists in `VideoEvent` fails to compile instead of being ignored.
9
+ */
10
+ type EventTypes<T extends VideoEvent['type']> = T;
11
+ /**
12
+ * Events that intentionally leave the call state untouched. Listing a name
13
+ * here excuses it from `CallStateEventHandlers`, which is what makes a newly
14
+ * introduced event fail to compile until it has been triaged.
15
+ */
16
+ type UnhandledEventType = EventTypes<'call.frame_recording_ready' | 'call.kicked_user' | 'call.moderation_blur' | 'call.moderation_warning' | 'call.permission_request' | 'call.recording_ready' | 'call.rtmp_broadcast_failed' | 'call.rtmp_broadcast_started' | 'call.rtmp_broadcast_stopped' | 'call.stats_report_ready' | 'call.transcription_ready' | 'call.user_feedback_submitted' | 'call.user_muted' | 'connection.error' | 'connection.ok' | 'health.check' | 'user.updated' | 'custom'>;
17
+ export type AllEventHandlers = {
18
+ [T in VideoEvent['type']]: EventHandler<T>;
19
+ };
20
+ /** A handler for every event that does update the call state. */
21
+ export type CallStateEventHandlers = Omit<AllEventHandlers, UnhandledEventType>;
22
+ export {};
@@ -4,7 +4,7 @@ import type { StreamClient } from './coordinator/connection/client';
4
4
  import type { ClientEventReporter } from './reporting';
5
5
  import type { RejectReason, StreamClientOptions, TokenProvider, User } from './coordinator/connection/types';
6
6
  import type { Comparator } from './sorting';
7
- import type { StreamVideoWriteableStateStore } from './store';
7
+ import type { ClientState } from './store';
8
8
  import { AxiosError } from 'axios';
9
9
  import type { Call } from './Call';
10
10
  export type StreamReaction = Pick<VideoReactionResponse, 'type' | 'emoji_code' | 'custom'>;
@@ -293,9 +293,9 @@ export type CallConstructor = {
293
293
  */
294
294
  sortParticipantsBy?: Comparator<StreamVideoParticipant>;
295
295
  /**
296
- * The state store of the client
296
+ * The state of the client.
297
297
  */
298
- clientStore: StreamVideoWriteableStateStore;
298
+ clientState: ClientState;
299
299
  };
300
300
  type StreamVideoClientBaseOptions = {
301
301
  apiKey: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "1.61.0",
3
+ "version": "2.0.0-beta.1",
4
4
  "main": "dist/index.cjs.js",
5
5
  "module": "dist/index.es.js",
6
6
  "browser": "dist/index.browser.es.js",
@@ -46,7 +46,7 @@
46
46
  "@openapitools/openapi-generator-cli": "^2.40.1",
47
47
  "@rollup/plugin-replace": "^6.0.3",
48
48
  "@rollup/plugin-typescript": "^12.3.0",
49
- "@stream-io/audio-filters-web": "^0.10.4",
49
+ "@stream-io/audio-filters-web": "^1.0.0-beta.0",
50
50
  "@stream-io/node-sdk": "^0.7.63",
51
51
  "@stream-io/typescript-config": "^0.0.0",
52
52
  "@total-typescript/shoehorn": "^0.1.2",
package/src/Call.ts CHANGED
@@ -22,11 +22,7 @@ import {
22
22
  registerEventHandlers,
23
23
  registerRingingCallEventHandlers,
24
24
  } from './events/callEventHandlers';
25
- import {
26
- CallingState,
27
- CallState,
28
- StreamVideoWriteableStateStore,
29
- } from './store';
25
+ import { CallingState, CallState, ClientState } from './store';
30
26
  import {
31
27
  createSafeAsyncSubscription,
32
28
  createSubscription,
@@ -307,7 +303,7 @@ export class Call {
307
303
  private ringTimeout: RingTimeout | undefined;
308
304
  private ringStatePoller: RingStatePoller | undefined;
309
305
 
310
- private readonly clientStore: StreamVideoWriteableStateStore;
306
+ private readonly clientState: ClientState;
311
307
  public readonly streamClient: StreamClient;
312
308
  public readonly clientEventReporter: ClientEventReporter;
313
309
  private sfuClient?: StreamSfuClient;
@@ -390,7 +386,7 @@ export class Call {
390
386
  members,
391
387
  ownCapabilities,
392
388
  sortParticipantsBy,
393
- clientStore,
389
+ clientState,
394
390
  ringing = false,
395
391
  watching = false,
396
392
  }: CallConstructor) {
@@ -401,7 +397,7 @@ export class Call {
401
397
  this.watching = watching;
402
398
  this.streamClient = streamClient;
403
399
  this.clientEventReporter = clientEventReporter;
404
- this.clientStore = clientStore;
400
+ this.clientState = clientState;
405
401
  this.streamClientBasePath = `/call/${this.type}/${this.id}`;
406
402
  this.logger = videoLoggerSystem.getLogger('Call');
407
403
 
@@ -560,7 +556,7 @@ export class Call {
560
556
 
561
557
  private handleRingingCall = () => {
562
558
  const callSession = this.state.session;
563
- const receiver_id = this.clientStore.connectedUser?.id;
559
+ const receiver_id = this.clientState.connectedUser?.id;
564
560
  const ended_at = callSession?.ended_at;
565
561
  const created_by_id = this.state.createdBy?.id;
566
562
 
@@ -825,7 +821,7 @@ export class Call {
825
821
  this.ringingSubject.next(false);
826
822
  this.cancelAutoDrop();
827
823
  this.cancelRingStatePolling();
828
- this.clientStore.unregisterCall(this);
824
+ this.clientState.unregisterCall(this);
829
825
 
830
826
  globalThis.streamRNVideoSDK?.callManager.stop({
831
827
  isRingingTypeCall: this.ringing,
@@ -892,7 +888,7 @@ export class Call {
892
888
  * Retrieves the current user ID.
893
889
  */
894
890
  get currentUserId() {
895
- return this.clientStore.connectedUser?.id;
891
+ return this.clientState.connectedUser?.id;
896
892
  }
897
893
 
898
894
  /**
@@ -957,8 +953,8 @@ export class Call {
957
953
  this.ringingSubject.next(true);
958
954
  // we remove the instance from the calls list to enable the following filter in useCalls hook
959
955
  // const calls = useCalls().filter((c) => c.ringing);
960
- const calls = this.clientStore.calls.filter((c) => c.cid !== this.cid);
961
- this.clientStore.setCalls([this, ...calls]);
956
+ const calls = this.clientState.calls.filter((c) => c.cid !== this.cid);
957
+ this.clientState.setCalls([this, ...calls]);
962
958
  await this.applyDeviceConfig(settings, { publish: false });
963
959
  };
964
960
 
@@ -1005,7 +1001,7 @@ export class Call {
1005
1001
 
1006
1002
  if (this.streamClient._hasConnectionID()) {
1007
1003
  this.watching = true;
1008
- this.clientStore.registerOrUpdateCall(this);
1004
+ this.clientState.registerOrUpdateCall(this);
1009
1005
  }
1010
1006
  await this.applyDeviceConfig(response.call.settings, { publish: false });
1011
1007
 
@@ -1033,7 +1029,7 @@ export class Call {
1033
1029
 
1034
1030
  if (this.streamClient._hasConnectionID()) {
1035
1031
  this.watching = true;
1036
- this.clientStore.registerOrUpdateCall(this);
1032
+ this.clientState.registerOrUpdateCall(this);
1037
1033
  }
1038
1034
 
1039
1035
  await this.applyDeviceConfig(response.call.settings, { publish: false });
@@ -1207,7 +1203,7 @@ export class Call {
1207
1203
  // for Android/iOS, we need to start the call in the callingx library as soon as possible
1208
1204
  await callingX.joinCall(
1209
1205
  this,
1210
- this.clientStore.calls,
1206
+ this.clientState.calls,
1211
1207
  supersededByLeave,
1212
1208
  );
1213
1209
  if (supersededByLeave()) {
@@ -1873,7 +1869,7 @@ export class Call {
1873
1869
 
1874
1870
  if (this.streamClient._hasConnectionID()) {
1875
1871
  this.watching = true;
1876
- this.clientStore.registerOrUpdateCall(this);
1872
+ this.clientState.registerOrUpdateCall(this);
1877
1873
  }
1878
1874
 
1879
1875
  return joinResponse;
@@ -2696,7 +2692,7 @@ export class Call {
2696
2692
  };
2697
2693
 
2698
2694
  /**
2699
- * Will enhance the reported stats with additional participant-specific information (`callStatsReport$` state [store variable](./StreamVideoClient.md/#readonlystatestore)).
2695
+ * Will enhance the reported stats with additional participant-specific information (the `callStatsReport$` state variable).
2700
2696
  * This is usually helpful when detailed stats for a specific participant are needed.
2701
2697
  *
2702
2698
  * @param sessionId the sessionId to start reporting for.
@@ -1,10 +1,6 @@
1
1
  import { Call } from './Call';
2
2
  import { StreamClient } from './coordinator/connection/client';
3
- import {
4
- CallingState,
5
- StreamVideoReadOnlyStateStore,
6
- StreamVideoWriteableStateStore,
7
- } from './store';
3
+ import { CallingState, ClientState } from './store';
8
4
  import type {
9
5
  CallCreatedEvent,
10
6
  CallRingEvent,
@@ -48,19 +44,14 @@ import { ClientEventReporter } from './reporting';
48
44
  */
49
45
  export class StreamVideoClient {
50
46
  /**
51
- * A reactive store that exposes all the state variables reactively.
47
+ * The reactive state of this client.
52
48
  * You can subscribe to changes of the different state variables.
53
- * Our library is built in a way that all state changes are exposed in this store,
54
- * o all UI changes in your application should be handled by subscribing to these variables.
55
- *
56
- * @deprecated use the `client.state` getter.
57
49
  */
58
- readonly readOnlyStateStore: StreamVideoReadOnlyStateStore;
50
+ readonly state = new ClientState();
59
51
  readonly logger: ScopedLogger;
60
52
 
61
- protected readonly writeableStateStore: StreamVideoWriteableStateStore;
62
- streamClient: StreamClient;
63
- readonly clientEventReporter: ClientEventReporter;
53
+ readonly streamClient: StreamClient;
54
+ private readonly clientEventReporter: ClientEventReporter;
64
55
 
65
56
  private effectsRegistered = false;
66
57
  private eventHandlersToUnregister: Array<() => void> = [];
@@ -103,11 +94,6 @@ export class StreamVideoClient {
103
94
  enabled: clientOptions?.clientEventsReportingEnabled ?? true,
104
95
  });
105
96
 
106
- this.writeableStateStore = new StreamVideoWriteableStateStore();
107
- this.readOnlyStateStore = new StreamVideoReadOnlyStateStore(
108
- this.writeableStateStore,
109
- );
110
-
111
97
  if (typeof apiKeyOrArgs !== 'string' && apiKeyOrArgs.user) {
112
98
  const user = apiKeyOrArgs.user;
113
99
  if (user.type === 'anonymous') user.id = '!anon';
@@ -158,13 +144,6 @@ export class StreamVideoClient {
158
144
  StreamVideoClient._instances.set(instanceKey, this);
159
145
  };
160
146
 
161
- /**
162
- * Return the reactive state store, use this if you want to be notified about changes to the client state
163
- */
164
- get state() {
165
- return this.readOnlyStateStore;
166
- }
167
-
168
147
  private registerEffects = () => {
169
148
  if (this.effectsRegistered) return;
170
149
 
@@ -174,7 +153,7 @@ export class StreamVideoClient {
174
153
  this.on('connection.changed', (event) => {
175
154
  if (!event.online) return;
176
155
 
177
- const callsToReWatch = this.writeableStateStore.calls
156
+ const callsToReWatch = this.state.calls
178
157
  .filter((call) => call.watching)
179
158
  .map((call) => call.cid);
180
159
  if (callsToReWatch.length <= 0) return;
@@ -197,7 +176,7 @@ export class StreamVideoClient {
197
176
  const concurrencyTag = getCallInitConcurrencyTag(e.call_cid);
198
177
  await withoutConcurrency(concurrencyTag, async () => {
199
178
  const ringing = e.type === 'call.ring';
200
- let call = this.writeableStateStore.findCall(e.call.type, e.call.id);
179
+ let call = this.state.findCall(e.call.type, e.call.id);
201
180
  if (call) {
202
181
  if (ringing) {
203
182
  if (this.shouldRejectCall(call.cid)) {
@@ -224,7 +203,7 @@ export class StreamVideoClient {
224
203
  type: e.call.type,
225
204
  id: e.call.id,
226
205
  members: e.members,
227
- clientStore: this.writeableStateStore,
206
+ clientState: this.state,
228
207
  ringing,
229
208
  });
230
209
 
@@ -239,7 +218,7 @@ export class StreamVideoClient {
239
218
  }
240
219
  } else {
241
220
  call.state.updateFromCallResponse(e.call);
242
- this.writeableStateStore.registerCall(call);
221
+ this.state.registerCall(call);
243
222
  this.logger.info(`New call created and registered: ${call.cid}`);
244
223
  }
245
224
  });
@@ -278,10 +257,7 @@ export class StreamVideoClient {
278
257
  });
279
258
 
280
259
  for (const c of response.calls) {
281
- const call = this.writeableStateStore.findCall(
282
- c.call.type,
283
- c.call.id,
284
- );
260
+ const call = this.state.findCall(c.call.type, c.call.id);
285
261
 
286
262
  if (call) {
287
263
  call.updateFromCallStateResponse(c);
@@ -310,8 +286,6 @@ export class StreamVideoClient {
310
286
 
311
287
  /**
312
288
  * Connects the given user to the client.
313
- * Only one user can connect at a time, if you want to change users, call `disconnectUser` before connecting a new user.
314
- * If the connection is successful, the connected user [state variable](#readonlystatestore) will be updated accordingly.
315
289
  *
316
290
  * @param user the user to connect.
317
291
  * @param tokenOrProvider a token or a function that returns a token.
@@ -369,7 +343,7 @@ export class StreamVideoClient {
369
343
 
370
344
  // connectUserResponse will be void if connectUser called twice for the same user
371
345
  if (connectUserResponse?.me) {
372
- this.writeableStateStore.setConnectedUser(connectUserResponse.me);
346
+ this.state.setConnectedUser(connectUserResponse.me);
373
347
  }
374
348
 
375
349
  this.registerEffects();
@@ -377,19 +351,36 @@ export class StreamVideoClient {
377
351
  return connectUserResponse;
378
352
  };
379
353
 
354
+ /**
355
+ * Leaves every call this client still tracks. Runs while the coordinator
356
+ * connection is alive, so that the leave requests each call sends reach the
357
+ * backend.
358
+ */
359
+ private leaveAllCalls = async () => {
360
+ for (const call of this.state.calls) {
361
+ if (call.state.callingState === CallingState.LEFT) continue;
362
+
363
+ this.logger.info(`User disconnected, leaving call: ${call.cid}`);
364
+ await call
365
+ .leave({ message: 'client.disconnectUser() called' })
366
+ .catch((err) => {
367
+ this.logger.error(`Error leaving call: ${call.cid}`, err);
368
+ });
369
+ }
370
+ };
371
+
380
372
  /**
381
373
  * Disconnects the currently connected user from the client.
382
- *
383
- * If the connection is successfully disconnected, the connected user [state variable](#readonlystatestore) will be updated accordingly
374
+ * Leaves every call the user is still in, and updates `client.state`accordingly.
384
375
  *
385
376
  * @param timeout Max number of ms, to wait for close event of websocket, before forcefully assuming successful disconnection.
386
- * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
387
377
  */
388
378
  disconnectUser = async (timeout?: number) => {
389
379
  await withoutConcurrency(this.connectionConcurrencyTag, async () => {
390
380
  const { user, key } = this.streamClient;
391
381
  if (!user) return;
392
382
 
383
+ await this.leaveAllCalls();
393
384
  await this.streamClient.disconnectUser(timeout);
394
385
 
395
386
  if (user.id) {
@@ -398,14 +389,16 @@ export class StreamVideoClient {
398
389
  this.eventHandlersToUnregister.forEach((unregister) => unregister());
399
390
  this.eventHandlersToUnregister = [];
400
391
  this.effectsRegistered = false;
401
- this.writeableStateStore.setConnectedUser(undefined);
392
+ this.state.setConnectedUser(undefined);
402
393
  });
403
394
  };
404
395
 
405
396
  /**
406
397
  * You can subscribe to WebSocket events provided by the API.
407
398
  * To remove a subscription, call the `off` method or, execute the returned unsubscribe function.
408
- * Please note that subscribing to WebSocket events is an advanced use-case, for most use-cases it should be enough to watch for changes in the reactive [state store](#readonlystatestore).
399
+ * Please note that subscribing to WebSocket events is an advanced use-case,
400
+ * for most use-cases it should be enough to watch for changes in the reactive
401
+ * `client.state`.
409
402
  *
410
403
  * @param eventName the event name or 'all'.
411
404
  * @param callback the callback which will be called when the event is emitted.
@@ -444,7 +437,7 @@ export class StreamVideoClient {
444
437
  options: { reuseInstance?: boolean } = {},
445
438
  ) => {
446
439
  const call = options.reuseInstance
447
- ? this.writeableStateStore.findCall(type, id)
440
+ ? this.state.findCall(type, id)
448
441
  : undefined;
449
442
  return (
450
443
  call ??
@@ -453,7 +446,7 @@ export class StreamVideoClient {
453
446
  clientEventReporter: this.clientEventReporter,
454
447
  id: id,
455
448
  type: type,
456
- clientStore: this.writeableStateStore,
449
+ clientState: this.state,
457
450
  })
458
451
  );
459
452
  };
@@ -492,7 +485,7 @@ export class StreamVideoClient {
492
485
  members: c.members,
493
486
  ownCapabilities: c.own_capabilities,
494
487
  watching: data.watch,
495
- clientStore: this.writeableStateStore,
488
+ clientState: this.state,
496
489
  });
497
490
  call.state.updateFromCallResponse(c.call);
498
491
  await call.applyDeviceConfig(c.call.settings, {
@@ -501,7 +494,7 @@ export class StreamVideoClient {
501
494
  });
502
495
  if (data.watch) {
503
496
  await call.setup();
504
- this.writeableStateStore.registerCall(call);
497
+ this.state.registerCall(call);
505
498
  }
506
499
  calls.push(call);
507
500
  }
@@ -636,7 +629,7 @@ export class StreamVideoClient {
636
629
  clientEventReporter: this.clientEventReporter,
637
630
  type: callType,
638
631
  id: callId,
639
- clientStore: this.writeableStateStore,
632
+ clientState: this.state,
640
633
  ringing: true,
641
634
  });
642
635
  await call.get();
@@ -6,7 +6,7 @@ import { Call } from '../Call';
6
6
  import { StreamClient } from '../coordinator/connection/client';
7
7
  import { ClientEventReporter } from '../reporting';
8
8
  import { generateUUIDv4 } from '../coordinator/connection/utils';
9
- import { CallingState, StreamVideoWriteableStateStore } from '../store';
9
+ import { CallingState, ClientState } from '../store';
10
10
  import { CallSettingsResponse } from '../gen/coordinator';
11
11
 
12
12
  const TIMEOUT_MS = 30_000;
@@ -19,18 +19,18 @@ describe('Auto drop ringing calls', () => {
19
19
  let call: Call;
20
20
 
21
21
  const ringingCall = () => {
22
- const clientStore = new StreamVideoWriteableStateStore();
22
+ const clientState = new ClientState();
23
23
  const streamClient = new StreamClient('abc');
24
24
  const newCall = new Call({
25
25
  type: 'test',
26
26
  id: generateUUIDv4(),
27
27
  streamClient,
28
28
  clientEventReporter: new ClientEventReporter({ streamClient }),
29
- clientStore,
29
+ clientState,
30
30
  ringing: true,
31
31
  });
32
32
 
33
- clientStore.setConnectedUser(fromPartial({ id: userId }));
33
+ clientState.setConnectedUser(fromPartial({ id: userId }));
34
34
  newCall.state['createdBySubject'].next(fromPartial({ id: userId }));
35
35
  newCall.state['settingsSubject'].next(
36
36
  fromPartial<CallSettingsResponse>({
@@ -6,7 +6,7 @@ import { Call } from '../Call';
6
6
  import { StreamClient } from '../coordinator/connection/client';
7
7
  import { ClientEventReporter } from '../reporting';
8
8
  import { generateUUIDv4 } from '../coordinator/connection/utils';
9
- import { StreamVideoWriteableStateStore } from '../store';
9
+ import { ClientState } from '../store';
10
10
  import { CallSessionResponse } from '../gen/coordinator';
11
11
 
12
12
  describe('Call.getRingState', () => {
@@ -19,7 +19,7 @@ describe('Call.getRingState', () => {
19
19
  id: callId,
20
20
  streamClient,
21
21
  clientEventReporter: new ClientEventReporter({ streamClient }),
22
- clientStore: new StreamVideoWriteableStateStore(),
22
+ clientState: new ClientState(),
23
23
  });
24
24
 
25
25
  if (sessionId) {
@@ -15,7 +15,7 @@ import { ClientEventReporter } from '../reporting';
15
15
  import type { GetCallResponse, JoinCallResponse } from '../gen/coordinator';
16
16
  import { WebsocketReconnectStrategy } from '../gen/video/sfu/models/models';
17
17
  import { generateUUIDv4 } from '../coordinator/connection/utils';
18
- import { CallingState, StreamVideoWriteableStateStore } from '../store';
18
+ import { CallingState, ClientState } from '../store';
19
19
  import { promiseWithResolvers } from '../helpers/promise';
20
20
 
21
21
  // A controlled stand-in for the retry backoff. Unless a test installs a hook,
@@ -74,7 +74,7 @@ describe('Call lifecycle wiring', () => {
74
74
  streamClient,
75
75
  enabled: false,
76
76
  }),
77
- clientStore: new StreamVideoWriteableStateStore(),
77
+ clientState: new ClientState(),
78
78
  });
79
79
  internalCall = call as unknown as typeof internalCall;
80
80
  });
@@ -283,7 +283,7 @@ describe('Call lifecycle wiring', () => {
283
283
  const accept = vi
284
284
  .spyOn(call, 'accept')
285
285
  .mockImplementation(() => responseAt('acceptance', { duration: '0ms' }));
286
- const registerCall = vi.spyOn(call.clientStore, 'registerOrUpdateCall');
286
+ const registerCall = vi.spyOn(call.clientState, 'registerOrUpdateCall');
287
287
  const request = vi.spyOn(call.streamClient, 'post').mockImplementation(() =>
288
288
  responseAt(
289
289
  'coordinator request',
@@ -361,7 +361,7 @@ describe('Call lifecycle wiring', () => {
361
361
  expect(call['currentPublishOptions']).toBe(publishOptions);
362
362
  expect(call['fastReconnectDeadlineSeconds']).toBe(reconnectDeadline);
363
363
  expect(call['sfuClient']).toBeUndefined();
364
- expect(call.clientStore.calls).not.toContain(call);
364
+ expect(call.clientState.calls).not.toContain(call);
365
365
  expect(call.ringing).toBe(false);
366
366
  expect(call.state.callingState).toBe(CallingState.LEFT);
367
367
  if (phase === 'SFU rejection') {
@@ -401,7 +401,7 @@ describe('Call lifecycle wiring', () => {
401
401
  call['sfuClient'] = oldSfu;
402
402
  call['subscriber'] = oldSubscriber;
403
403
  call['publisher'] = oldPublisher;
404
- call.clientStore.registerOrUpdateCall(call);
404
+ call.clientState.registerOrUpdateCall(call);
405
405
  const task = call['reconnect'](
406
406
  WebsocketReconnectStrategy[strategy],
407
407
  'test',
@@ -419,7 +419,7 @@ describe('Call lifecycle wiring', () => {
419
419
  await task;
420
420
 
421
421
  expect(call.state.callingState).toBe(CallingState.LEFT);
422
- expect(call.clientStore.calls).not.toContain(call);
422
+ expect(call.clientState.calls).not.toContain(call);
423
423
  expect(get).not.toHaveBeenCalled();
424
424
  expect(restoreSubscribed).not.toHaveBeenCalled();
425
425
  if (phase === 'join') expect(restorePublished).not.toHaveBeenCalled();
@@ -461,7 +461,7 @@ describe('Call lifecycle wiring', () => {
461
461
  await task;
462
462
 
463
463
  expect(call.state.callingState).toBe(CallingState.LEFT);
464
- expect(call.clientStore.calls).not.toContain(call);
464
+ expect(call.clientState.calls).not.toContain(call);
465
465
  expect(get).toHaveBeenCalledTimes(phase === 'failure refresh' ? 1 : 0);
466
466
  expect(reconnect).toHaveBeenCalledOnce();
467
467
  expect(call['reconnectStrategy']).toBe(
@@ -492,7 +492,7 @@ describe('Call lifecycle wiring', () => {
492
492
  pending.resolve(response);
493
493
  await expect(task).resolves.toBe(response);
494
494
 
495
- expect(call.clientStore.calls.includes(call)).toBe(!leaveDuringFetch);
495
+ expect(call.clientState.calls.includes(call)).toBe(!leaveDuringFetch);
496
496
  expect(update).toHaveBeenCalledTimes(leaveDuringFetch ? 0 : 1);
497
497
  expect(configure).toHaveBeenCalledTimes(leaveDuringFetch ? 0 : 1);
498
498
  expect(call.state.callingState).toBe(
@@ -8,7 +8,7 @@ import { ClientEventReporter } from '../reporting';
8
8
  import { generateUUIDv4 } from '../coordinator/connection/utils';
9
9
  import { PermissionsContext } from '../permissions';
10
10
  import { OwnCapability } from '../gen/coordinator';
11
- import { StreamVideoWriteableStateStore } from '../store';
11
+ import { ClientState } from '../store';
12
12
  import { TrackType } from '../gen/video/sfu/models/models';
13
13
  import { StreamSfuClient } from '../StreamSfuClient';
14
14
 
@@ -22,7 +22,7 @@ describe('Publishing and Unpublishing tracks', () => {
22
22
  id: generateUUIDv4(),
23
23
  streamClient,
24
24
  clientEventReporter: new ClientEventReporter({ streamClient }),
25
- clientStore: new StreamVideoWriteableStateStore(),
25
+ clientState: new ClientState(),
26
26
  });
27
27
 
28
28
  const ctx = new PermissionsContext();
@@ -6,7 +6,7 @@ import { Call } from '../Call';
6
6
  import { StreamClient } from '../coordinator/connection/client';
7
7
  import { ClientEventReporter } from '../reporting';
8
8
  import { generateUUIDv4 } from '../coordinator/connection/utils';
9
- import { CallingState, StreamVideoWriteableStateStore } from '../store';
9
+ import { CallingState, ClientState } from '../store';
10
10
  import { CallSessionResponse } from '../gen/coordinator';
11
11
 
12
12
  const ME = 'jane';
@@ -18,18 +18,18 @@ describe('Leaving a call settled by the current user', () => {
18
18
  let call: Call;
19
19
 
20
20
  const createCall = async (ringing: boolean) => {
21
- const clientStore = new StreamVideoWriteableStateStore();
21
+ const clientState = new ClientState();
22
22
  const streamClient = new StreamClient('abc');
23
23
  call = new Call({
24
24
  type: 'test',
25
25
  id: generateUUIDv4(),
26
26
  streamClient,
27
27
  clientEventReporter: new ClientEventReporter({ streamClient }),
28
- clientStore,
28
+ clientState,
29
29
  ringing,
30
30
  });
31
31
 
32
- clientStore.setConnectedUser(fromPartial({ id: ME }));
32
+ clientState.setConnectedUser(fromPartial({ id: ME }));
33
33
  vi.spyOn(call, 'leave').mockResolvedValue(undefined);
34
34
  await call.setup();
35
35
  return call;