@stream-io/video-client 0.0.11 → 0.0.13

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.
@@ -2,7 +2,7 @@ import { Call } from './Call';
2
2
  import { StreamClient } from './coordinator/connection/client';
3
3
  import { StreamVideoReadOnlyStateStore } from './store';
4
4
  import type { ConnectedEvent, CreateCallTypeRequest, CreateCallTypeResponse, CreateDeviceRequest, CreateGuestRequest, CreateGuestResponse, GetCallTypeResponse, GetEdgesResponse, ListCallTypeResponse, ListDevicesResponse, QueryCallsRequest, UpdateCallTypeRequest, UpdateCallTypeResponse } from './gen/coordinator';
5
- import type { EventHandler, EventTypes, StreamClientOptions, TokenOrProvider, User } from './coordinator/connection/types';
5
+ import type { EventHandler, EventTypes, StreamClientOptions, TokenOrProvider, TokenProvider, User } from './coordinator/connection/types';
6
6
  /**
7
7
  * A `StreamVideoClient` instance lets you communicate with our API, and authenticate users.
8
8
  */
@@ -11,6 +11,8 @@ export declare class StreamVideoClient {
11
11
  * A reactive store that exposes all the state variables in a reactive manner - you can subscribe to changes of the different state variables. Our library is built in a way that all state changes are exposed in this store, so all UI changes in your application should be handled by subscribing to these variables.
12
12
  */
13
13
  readonly readOnlyStateStore: StreamVideoReadOnlyStateStore;
14
+ readonly user?: User;
15
+ readonly token?: TokenOrProvider;
14
16
  private readonly writeableStateStore;
15
17
  streamClient: StreamClient;
16
18
  private eventHandlersToUnregister;
@@ -18,19 +20,24 @@ export declare class StreamVideoClient {
18
20
  private disconnectionPromise;
19
21
  /**
20
22
  * You should create only one instance of `StreamVideoClient`.
21
- * @param apiKey your Stream API key
22
- * @param opts the options for the client.
23
23
  */
24
24
  constructor(apiKey: string, opts?: StreamClientOptions);
25
+ constructor(args: {
26
+ apiKey: string;
27
+ options?: StreamClientOptions;
28
+ user?: User;
29
+ token?: string;
30
+ tokenProvider?: TokenProvider;
31
+ });
25
32
  /**
26
33
  * Connects the given user to the client.
27
34
  * Only one user can connect at a time, if you want to change users, call `disconnectUser` before connecting a new user.
28
35
  * If the connection is successful, the connected user [state variable](#readonlystatestore) will be updated accordingly.
29
36
  *
30
37
  * @param user the user to connect.
31
- * @param tokenOrProvider a token or a function that returns a token.
38
+ * @param token a token or a function that returns a token.
32
39
  */
33
- connectUser(user: User, token: TokenOrProvider): Promise<void | ConnectedEvent>;
40
+ connectUser(user?: User, token?: TokenOrProvider): Promise<void | ConnectedEvent>;
34
41
  /**
35
42
  * Disconnects the currently connected user from the client.
36
43
  *
@@ -38,6 +38,8 @@ export declare class StreamClient {
38
38
  rejectConnectionId: Function;
39
39
  connectionIdPromise: Promise<string | undefined>;
40
40
  private nextRequestAbortController;
41
+ private waitForConnectPromise?;
42
+ private resolveConnectPromise?;
41
43
  /**
42
44
  * Initialize a client.
43
45
  *
@@ -56,6 +58,10 @@ export declare class StreamClient {
56
58
  setBaseURL(baseURL: string): void;
57
59
  _getConnectionID: () => string | undefined;
58
60
  _hasConnectionID: () => boolean;
61
+ /**
62
+ * This will start a promise to hold API calls until `connectUser` is called, useful when user is set in `StreamVideoClient constructor`
63
+ */
64
+ startWaitingForConnection: () => void;
59
65
  /**
60
66
  * connectUser - Set the current user and open a WebSocket connection
61
67
  *
@@ -11,16 +11,6 @@ export declare class StreamVideoWriteableStateStore {
11
11
  * A list of {@link Call} objects created/tracked by this client.
12
12
  */
13
13
  callsSubject: BehaviorSubject<Call[]>;
14
- /**
15
- * A list of objects describing incoming calls.
16
- * @deprecated derive from calls$ instead.
17
- */
18
- incomingCalls$: Observable<Call[]>;
19
- /**
20
- * A list of objects describing calls initiated by the current user (connectedUser).
21
- * @deprecated derive from calls$ instead.
22
- */
23
- outgoingCalls$: Observable<Call[]>;
24
14
  constructor();
25
15
  /**
26
16
  * Gets the current value of an observable, or undefined if the observable has
@@ -78,16 +68,6 @@ export declare class StreamVideoWriteableStateStore {
78
68
  * @param id the id of the call to find.
79
69
  */
80
70
  findCall: (type: string, id: string) => Call | undefined;
81
- /**
82
- * A list of objects describing incoming calls.
83
- * @deprecated derive from calls$ instead.
84
- */
85
- get incomingCalls(): Call[];
86
- /**
87
- * A list of objects describing calls initiated by the current user.
88
- * @deprecated derive from calls$ instead.
89
- */
90
- get outgoingCalls(): Call[];
91
71
  }
92
72
  /**
93
73
  * A reactive store that exposes state variables in a reactive manner.
@@ -103,16 +83,6 @@ export declare class StreamVideoReadOnlyStateStore {
103
83
  * A list of {@link Call} objects created/tracked by this client.
104
84
  */
105
85
  calls$: Observable<Call[]>;
106
- /**
107
- * A list of objects describing calls initiated by the current user (connectedUser).
108
- * @deprecated derive from calls$ instead.
109
- */
110
- outgoingCalls$: Observable<Call[]>;
111
- /**
112
- * A list of objects describing incoming calls.
113
- * @deprecated derive from calls$ instead.
114
- */
115
- incomingCalls$: Observable<Call[]>;
116
86
  /**
117
87
  * This method allows you the get the current value of a state variable.
118
88
  *
@@ -129,14 +99,4 @@ export declare class StreamVideoReadOnlyStateStore {
129
99
  * A list of {@link Call} objects created/tracked by this client.
130
100
  */
131
101
  get calls(): Call[];
132
- /**
133
- * A list of objects describing incoming calls.
134
- * @deprecated derive from calls$ instead.
135
- */
136
- get incomingCalls(): Call[];
137
- /**
138
- * A list of objects describing calls initiated by the current user.
139
- * @deprecated derive from calls$ instead.
140
- */
141
- get outgoingCalls(): Call[];
142
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -26,6 +26,7 @@ import type {
26
26
  EventTypes,
27
27
  StreamClientOptions,
28
28
  TokenOrProvider,
29
+ TokenProvider,
29
30
  User,
30
31
  UserWithId,
31
32
  } from './coordinator/connection/types';
@@ -38,6 +39,8 @@ export class StreamVideoClient {
38
39
  * A reactive store that exposes all the state variables in a reactive manner - you can subscribe to changes of the different state variables. Our library is built in a way that all state changes are exposed in this store, so all UI changes in your application should be handled by subscribing to these variables.
39
40
  */
40
41
  readonly readOnlyStateStore: StreamVideoReadOnlyStateStore;
42
+ readonly user?: User;
43
+ readonly token?: TokenOrProvider;
41
44
  private readonly writeableStateStore: StreamVideoWriteableStateStore;
42
45
  streamClient: StreamClient;
43
46
 
@@ -47,14 +50,44 @@ export class StreamVideoClient {
47
50
 
48
51
  /**
49
52
  * You should create only one instance of `StreamVideoClient`.
50
- * @param apiKey your Stream API key
51
- * @param opts the options for the client.
52
53
  */
53
- constructor(apiKey: string, opts?: StreamClientOptions) {
54
- this.streamClient = new StreamClient(apiKey, {
55
- persistUserOnConnectionFailure: true,
56
- ...opts,
57
- });
54
+ constructor(apiKey: string, opts?: StreamClientOptions);
55
+ constructor(args: {
56
+ apiKey: string;
57
+ options?: StreamClientOptions;
58
+ user?: User;
59
+ token?: string;
60
+ tokenProvider?: TokenProvider;
61
+ });
62
+ constructor(
63
+ apiKeyOrArgs:
64
+ | string
65
+ | {
66
+ apiKey: string;
67
+ options?: StreamClientOptions;
68
+ user?: User;
69
+ token?: string;
70
+ tokenProvider?: TokenProvider;
71
+ },
72
+ opts?: StreamClientOptions,
73
+ ) {
74
+ if (typeof apiKeyOrArgs === 'string') {
75
+ this.streamClient = new StreamClient(apiKeyOrArgs, {
76
+ persistUserOnConnectionFailure: true,
77
+ ...opts,
78
+ });
79
+ } else {
80
+ this.streamClient = new StreamClient(apiKeyOrArgs.apiKey, {
81
+ persistUserOnConnectionFailure: true,
82
+ ...apiKeyOrArgs.options,
83
+ });
84
+
85
+ this.user = apiKeyOrArgs.user;
86
+ this.token = apiKeyOrArgs.token || apiKeyOrArgs.tokenProvider;
87
+ if (this.user) {
88
+ this.streamClient.startWaitingForConnection();
89
+ }
90
+ }
58
91
 
59
92
  this.writeableStateStore = new StreamVideoWriteableStateStore();
60
93
  this.readOnlyStateStore = new StreamVideoReadOnlyStateStore(
@@ -68,27 +101,32 @@ export class StreamVideoClient {
68
101
  * If the connection is successful, the connected user [state variable](#readonlystatestore) will be updated accordingly.
69
102
  *
70
103
  * @param user the user to connect.
71
- * @param tokenOrProvider a token or a function that returns a token.
104
+ * @param token a token or a function that returns a token.
72
105
  */
73
106
  async connectUser(
74
- user: User,
75
- token: TokenOrProvider,
107
+ user?: User,
108
+ token?: TokenOrProvider,
76
109
  ): Promise<void | ConnectedEvent> {
77
- if (user.type === 'anonymous') {
78
- user.id = '!anon';
79
- return this.connectAnonymousUser(user as UserWithId, token);
110
+ const userToConnect = user || this.user;
111
+ const tokenToUse = token || this.token;
112
+ if (!userToConnect) {
113
+ throw new Error('Connect user is called without user');
80
114
  }
81
- if (user.type === 'guest') {
115
+ if (userToConnect.type === 'anonymous') {
116
+ userToConnect.id = '!anon';
117
+ return this.connectAnonymousUser(userToConnect as UserWithId, tokenToUse);
118
+ }
119
+ if (userToConnect.type === 'guest') {
82
120
  const response = await this.createGuestUser({
83
121
  user: {
84
- ...user,
122
+ ...userToConnect,
85
123
  role: 'guest',
86
124
  },
87
125
  });
88
126
  return this.connectUser(response.user, response.access_token);
89
127
  }
90
128
  const connectUser = () => {
91
- return this.streamClient.connectUser(user, token);
129
+ return this.streamClient.connectUser(userToConnect, tokenToUse);
92
130
  };
93
131
  this.connectionPromise = this.disconnectionPromise
94
132
  ? this.disconnectionPromise.then(() => connectUser())
@@ -128,7 +166,7 @@ export class StreamVideoClient {
128
166
  this.on('call.created', (event) => {
129
167
  if (event.type !== 'call.created') return;
130
168
  const { call, members } = event;
131
- if (user.id === call.created_by.id) {
169
+ if (userToConnect.id === call.created_by.id) {
132
170
  console.warn('Received `call.created` sent by the current user');
133
171
  return;
134
172
  }
@@ -150,29 +188,27 @@ export class StreamVideoClient {
150
188
  this.on('call.ring', async (event) => {
151
189
  if (event.type !== 'call.ring') return;
152
190
  const { call, members } = event;
153
- if (user.id === call.created_by.id) {
191
+ if (userToConnect.id === call.created_by.id) {
154
192
  console.warn('Received `call.ring` sent by the current user');
155
193
  return;
156
194
  }
157
195
 
158
196
  // The call might already be tracked by the client,
159
197
  // if `call.created` was received before `call.ring`.
160
- // In that case, we just reuse the already tracked call.
161
- let theCall = this.writeableStateStore.findCall(call.type, call.id);
162
- if (!theCall) {
163
- // otherwise, we create a new call
164
- theCall = new Call({
165
- streamClient: this.streamClient,
166
- type: call.type,
167
- id: call.id,
168
- members,
169
- clientStore: this.writeableStateStore,
170
- ringing: true,
171
- });
172
- }
173
-
198
+ // In that case, we cleanup the already tracked call.
199
+ const prevCall = this.writeableStateStore.findCall(call.type, call.id);
200
+ await prevCall?.leave();
201
+ // we create a new call
202
+ const theCall = new Call({
203
+ streamClient: this.streamClient,
204
+ type: call.type,
205
+ id: call.id,
206
+ members,
207
+ clientStore: this.writeableStateStore,
208
+ ringing: true,
209
+ });
174
210
  // we fetch the latest metadata for the call from the server
175
- await theCall.get({ ring: true });
211
+ await theCall.get();
176
212
  this.writeableStateStore.registerCall(theCall);
177
213
  }),
178
214
  );
@@ -189,6 +225,9 @@ export class StreamVideoClient {
189
225
  * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
190
226
  */
191
227
  disconnectUser = async (timeout?: number) => {
228
+ if (!this.streamClient.user) {
229
+ return;
230
+ }
192
231
  const disconnectUser = () => this.streamClient.disconnectUser(timeout);
193
232
  this.disconnectionPromise = this.connectionPromise
194
233
  ? this.connectionPromise.then(() => disconnectUser())
@@ -67,6 +67,8 @@ export class StreamClient {
67
67
  rejectConnectionId!: Function;
68
68
  connectionIdPromise: Promise<string | undefined>;
69
69
  private nextRequestAbortController: AbortController | null = null;
70
+ private waitForConnectPromise?: Promise<void>;
71
+ private resolveConnectPromise?: Function;
70
72
 
71
73
  /**
72
74
  * Initialize a client.
@@ -180,6 +182,15 @@ export class StreamClient {
180
182
 
181
183
  _hasConnectionID = () => Boolean(this._getConnectionID());
182
184
 
185
+ /**
186
+ * This will start a promise to hold API calls until `connectUser` is called, useful when user is set in `StreamVideoClient constructor`
187
+ */
188
+ startWaitingForConnection = () => {
189
+ this.waitForConnectPromise = new Promise((resolve) => {
190
+ this.resolveConnectPromise = resolve;
191
+ });
192
+ };
193
+
183
194
  /**
184
195
  * connectUser - Set the current user and open a WebSocket connection
185
196
  *
@@ -239,6 +250,12 @@ export class StreamClient {
239
250
  (result) => result[1], // We only return connection promise;
240
251
  );
241
252
 
253
+ if (this.resolveConnectPromise) {
254
+ this.resolveConnectPromise();
255
+ this.waitForConnectPromise = undefined;
256
+ this.resolveConnectPromise = undefined;
257
+ }
258
+
242
259
  try {
243
260
  return await this.setUserPromise;
244
261
  } catch (err) {
@@ -387,6 +404,12 @@ export class StreamClient {
387
404
  ) => {
388
405
  this.anonymous = true;
389
406
  await this._setToken(user, tokenOrProvider, this.anonymous);
407
+
408
+ if (this.resolveConnectPromise) {
409
+ this.resolveConnectPromise();
410
+ this.waitForConnectPromise = undefined;
411
+ this.resolveConnectPromise = undefined;
412
+ }
390
413
  this._setUser(user);
391
414
  // some endpoints require a connection_id to be resolved.
392
415
  // as anonymous users aren't allowed to open WS connections, we just
@@ -496,6 +519,9 @@ export class StreamClient {
496
519
  } & { publicEndpoint?: boolean } = {},
497
520
  ): Promise<T> => {
498
521
  if (!options.publicEndpoint || this.user) {
522
+ if (this.waitForConnectPromise) {
523
+ await this.waitForConnectPromise;
524
+ }
499
525
  await this.tokenManager.tokenReady();
500
526
  }
501
527
  const requestConfig = this._enrichAxiosOptions(options);
@@ -1,10 +1,8 @@
1
1
  import { BehaviorSubject, Observable } from 'rxjs';
2
- import { combineLatestWith, map } from 'rxjs/operators';
3
2
  import type { Patch } from './rxUtils';
4
3
  import * as RxUtils from './rxUtils';
5
4
  import { Call } from '../Call';
6
5
  import type { OwnUserResponse } from '../coordinator/connection/types';
7
- import { CallingState } from './CallState';
8
6
 
9
7
  export class StreamVideoWriteableStateStore {
10
8
  /**
@@ -19,18 +17,6 @@ export class StreamVideoWriteableStateStore {
19
17
  */
20
18
  callsSubject = new BehaviorSubject<Call[]>([]);
21
19
 
22
- /**
23
- * A list of objects describing incoming calls.
24
- * @deprecated derive from calls$ instead.
25
- */
26
- incomingCalls$: Observable<Call[]>;
27
-
28
- /**
29
- * A list of objects describing calls initiated by the current user (connectedUser).
30
- * @deprecated derive from calls$ instead.
31
- */
32
- outgoingCalls$: Observable<Call[]>;
33
-
34
20
  constructor() {
35
21
  this.connectedUserSubject.subscribe(async (user) => {
36
22
  // leave all calls when the user disconnects.
@@ -40,32 +26,6 @@ export class StreamVideoWriteableStateStore {
40
26
  }
41
27
  }
42
28
  });
43
-
44
- this.incomingCalls$ = this.callsSubject.pipe(
45
- combineLatestWith(this.connectedUserSubject),
46
- map(([calls, connectedUser]) =>
47
- calls.filter((call) => {
48
- const { metadata, callingState } = call.state;
49
- return (
50
- metadata?.created_by.id !== connectedUser?.id &&
51
- callingState === CallingState.RINGING
52
- );
53
- }),
54
- ),
55
- );
56
-
57
- this.outgoingCalls$ = this.callsSubject.pipe(
58
- combineLatestWith(this.connectedUserSubject),
59
- map(([calls, connectedUser]) =>
60
- calls.filter((call) => {
61
- const { metadata, callingState } = call.state;
62
- return (
63
- metadata?.created_by.id === connectedUser?.id &&
64
- callingState === CallingState.RINGING
65
- );
66
- }),
67
- ),
68
- );
69
29
  }
70
30
 
71
31
  /**
@@ -148,22 +108,6 @@ export class StreamVideoWriteableStateStore {
148
108
  findCall = (type: string, id: string) => {
149
109
  return this.calls.find((c) => c.type === type && c.id === id);
150
110
  };
151
-
152
- /**
153
- * A list of objects describing incoming calls.
154
- * @deprecated derive from calls$ instead.
155
- */
156
- get incomingCalls(): Call[] {
157
- return this.getCurrentValue(this.incomingCalls$);
158
- }
159
-
160
- /**
161
- * A list of objects describing calls initiated by the current user.
162
- * @deprecated derive from calls$ instead.
163
- */
164
- get outgoingCalls(): Call[] {
165
- return this.getCurrentValue(this.outgoingCalls$);
166
- }
167
111
  }
168
112
 
169
113
  /**
@@ -182,18 +126,6 @@ export class StreamVideoReadOnlyStateStore {
182
126
  */
183
127
  calls$: Observable<Call[]>;
184
128
 
185
- /**
186
- * A list of objects describing calls initiated by the current user (connectedUser).
187
- * @deprecated derive from calls$ instead.
188
- */
189
- outgoingCalls$: Observable<Call[]>;
190
-
191
- /**
192
- * A list of objects describing incoming calls.
193
- * @deprecated derive from calls$ instead.
194
- */
195
- incomingCalls$: Observable<Call[]>;
196
-
197
129
  /**
198
130
  * This method allows you the get the current value of a state variable.
199
131
  *
@@ -206,10 +138,6 @@ export class StreamVideoReadOnlyStateStore {
206
138
  // convert and expose subjects as observables
207
139
  this.connectedUser$ = store.connectedUserSubject.asObservable();
208
140
  this.calls$ = store.callsSubject.asObservable();
209
-
210
- // re-expose observables
211
- this.incomingCalls$ = store.incomingCalls$;
212
- this.outgoingCalls$ = store.outgoingCalls$;
213
141
  }
214
142
 
215
143
  /**
@@ -225,20 +153,4 @@ export class StreamVideoReadOnlyStateStore {
225
153
  get calls(): Call[] {
226
154
  return RxUtils.getCurrentValue(this.calls$);
227
155
  }
228
-
229
- /**
230
- * A list of objects describing incoming calls.
231
- * @deprecated derive from calls$ instead.
232
- */
233
- get incomingCalls(): Call[] {
234
- return RxUtils.getCurrentValue(this.incomingCalls$);
235
- }
236
-
237
- /**
238
- * A list of objects describing calls initiated by the current user.
239
- * @deprecated derive from calls$ instead.
240
- */
241
- get outgoingCalls(): Call[] {
242
- return RxUtils.getCurrentValue(this.outgoingCalls$);
243
- }
244
156
  }