diff --git a/docusaurus/video/docusaurus/docs/api/_common_/async-tasks.mdx b/docusaurus/video/docusaurus/docs/api/_common_/async-tasks.mdx index 65a97825..a0257ea4 100644 --- a/docusaurus/video/docusaurus/docs/api/_common_/async-tasks.mdx +++ b/docusaurus/video/docusaurus/docs/api/_common_/async-tasks.mdx @@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem'; const response = await client.(); // you need to poll this endpoint -const taskResponse = await client.getTaskStatus({id: response.task_id}) +const taskResponse = await client.getTask({id: response.task_id}) console.log(taskResponse.status === 'completed'); ``` @@ -45,5 +45,19 @@ curl -X GET https://video.stream-io-api.com/api/v2/tasks/${TASK_ID}?api_key=${AP -H "stream-auth-type: jwt" ``` + + + +```js +// Example of monitoring the status of an async task +// The logic is same for all async tasks +const response = await client.(); + +// you need to poll this endpoint +const taskResponse = await client.getTaskStatus({id: response.task_id}) + +console.log(taskResponse.status === 'completed'); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/_common_/custom-events.mdx b/docusaurus/video/docusaurus/docs/api/_common_/custom-events.mdx index 39181e04..c996fb0a 100644 --- a/docusaurus/video/docusaurus/docs/api/_common_/custom-events.mdx +++ b/docusaurus/video/docusaurus/docs/api/_common_/custom-events.mdx @@ -6,7 +6,7 @@ import TabItem from '@theme/TabItem'; ```js // send a custom event to all users watching the call -call.sendCustomEvent({ +call.sendCallEvent({ custom: { 'render-animation': 'balloons', }, @@ -36,5 +36,18 @@ curl -X POST https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${CA }' ``` + + + +```js +// send a custom event to all users watching the call +call.sendCustomEvent({ + custom: { + 'render-animation': 'balloons', + }, + user_id: 'john', +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/_common_/rtmp.mdx b/docusaurus/video/docusaurus/docs/api/_common_/rtmp.mdx index aba0b793..0f4dd543 100644 --- a/docusaurus/video/docusaurus/docs/api/_common_/rtmp.mdx +++ b/docusaurus/video/docusaurus/docs/api/_common_/rtmp.mdx @@ -9,13 +9,7 @@ const resp = await call.get(); // userId of existing user const userId = 'jane'; -await client.upsertUsers({ - users: { - [userId]: { - id: userId, - }, - }, -}); +await client.upsertUsers([{ id: userId }]); const token = client.createToken(userId); const rtmpURL = resp.call.ingress.rtmp.address; const streamKey = token; @@ -57,5 +51,27 @@ curl -X GET "https://video.stream-io-api.com/api/v2/video/call/livestream/${CALL # Stream key: create a user token ``` + + + +```js +const resp = await call.get(); + +// userId of existing user +const userId = 'jane'; +await client.upsertUsers({ + users: { + [userId]: { + id: userId, + }, + }, +}); +const token = client.createToken(userId); +const rtmpURL = resp.call.ingress.rtmp.address; +const streamKey = token; + +console.log(rtmpURL, streamKey); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/_common_/storage.mdx b/docusaurus/video/docusaurus/docs/api/_common_/storage.mdx index a01a9a7b..e0eaac43 100644 --- a/docusaurus/video/docusaurus/docs/api/_common_/storage.mdx +++ b/docusaurus/video/docusaurus/docs/api/_common_/storage.mdx @@ -15,8 +15,8 @@ To use your own storage you need to: 1. Configure a new storage for your Stream application 2. (Optional) Check storage configuration for correctness. - Calling check endpoint will create a test markdown file in the storage to verify the configuration. It will return an error if the file is not created. - In case of success, the file with`stream-.md` will be uploaded to the storage. Every time you call this endpoint, a new file will be created. + Calling check endpoint will create a test markdown file in the storage to verify the configuration. It will return an error if the file is not created. + In case of success, the file with`stream-.md` will be uploaded to the storage. Every time you call this endpoint, a new file will be created. 3. Configure your call type(s) to use the new storage Once the setup is complete, call recordings and transcription files will be automatically stored in your own storage. @@ -27,28 +27,30 @@ Once the setup is complete, call recordings and transcription files will be auto ```js // 1. create a new storage with all the required parameters await serverSideClient.createExternalStorage({ - bucket: 'my-bucket', - name: 'my-s3', - storage_type: 's3', - path: 'directory_name/', - aws_s3: { - s3_region: 'us-east-1', - s3_api_key: 'my-access-key', - s3_secret: 'my-secret', - }, + bucket: 'my-bucket', + name: 'my-s3', + storage_type: 's3', + path: 'directory_name/', + aws_s3: { + s3_region: 'us-east-1', + s3_api_key: 'my-access-key', + s3_secret: 'my-secret', + }, }); // 2. (Optional) Check storage configuration for correctness // In case of any errors, this will throw a ResponseError. await serverSideClient.checkExternalStorage({ - name: 'my-s3' + name: 'my-s3', }); // 3. update the call type to use the new storage -await serverSideClient.updateCallType('my-call-type', { - external_storage: "my-s3", +await serverSideClient.updateCallType({ + name: 'my-call-type', + external_storage: 'my-s3', }); ``` + @@ -69,12 +71,13 @@ client.video.create_external_storage( ) # 2. (Optional) Check storage configuration for correctness -# In case of any errors, this will throw a StreamAPIException. +# In case of any errors, this will throw a StreamAPIException. response = client.video.check_external_storage(name='my-s3') # 3. update the call type to use the new storage client.video.update_call_type(name='allhands', external_storage='my-s3') ``` + @@ -112,6 +115,35 @@ curl -X PUT https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE}? }' ``` + + + +```js +// 1. create a new storage with all the required parameters +await serverSideClient.video.createExternalStorage({ + bucket: 'my-bucket', + name: 'my-s3', + storage_type: 's3', + path: 'directory_name/', + aws_s3: { + s3_region: 'us-east-1', + s3_api_key: 'my-access-key', + s3_secret: 'my-secret', + }, +}); + +// 2. (Optional) Check storage configuration for correctness +// In case of any errors, this will throw a ResponseError. +await serverSideClient.video.checkExternalStorage({ + name: 'my-s3', +}); + +// 3. update the call type to use the new storage +await serverSideClient.updateCallType('my-call-type', { + external_storage: 'my-s3', +}); +``` + @@ -125,20 +157,21 @@ When transcribing or recording a call, the storage provider is selected in this 2. If specified at the call type level, the storage provider designated for that call type will be used. 3. If neither applies, Stream S3 storage will be used. -> **Note:** All Stream applications have Stream S3 storage enabled by default, which you can refer to as `"stream-s3"` in the configuration. +> **Note:** All Stream applications have Stream S3 storage enabled by default, which you can refer to as `"stream-s3"` in the configuration. ```js // update the call type to use Stream S3 storage for recordings -await serverSideClient.updateCallType('my-call-type', { - external_storage: "stream-s3", +await serverSideClient.updateCallType({ + name: 'my-call-type', + external_storage: 'stream-s3', }); // specify Stream S3 storage when starting call transcribing await call.startTranscription({ - transcription_external_storage: "my-storage", + transcription_external_storage: 'my-storage', }); ``` @@ -179,6 +212,21 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${C }' ``` + + + +```js +// update the call type to use Stream S3 storage for recordings +await serverSideClient.updateCallType('my-call-type', { + external_storage: 'stream-s3', +}); + +// specify Stream S3 storage when starting call transcribing +await call.startTranscription({ + transcription_external_storage: 'my-storage', +}); +``` + @@ -187,7 +235,7 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${C All storage providers have these 4 shared parameters: | Name | Description | Required | -|--------------|-----------------------------------------------------------------------|----------| +| ------------ | --------------------------------------------------------------------- | -------- | | name | The name of the provider, this must be unique | yes | | storage_type | The type of storage to use, allowed values are: `s3`, `gcs` and `abs` | yes | | bucket | The name of the bucket on the service provider | yes | @@ -200,12 +248,11 @@ To use Amazon S3 as your storage provider, you have two authentication options: If you do not specify the `s3_api_key` parameter, Stream will use IAM role authentication. In that case make sure to have the correct IAM role configured for your application. | Name | Description | Required | -|------------|-------------------------------------------|----------| +| ---------- | ----------------------------------------- | -------- | | s3_region | The AWS region where the bucket is hosted | yes | | s3_api_key | The AWS API key | no | | s3_secret | The AWS API Secret | no | - ### Example S3 policy With this option you omit the key and secret, but instead you set up a resource-based policy to grant Stream SendMessage permission on your S3 bucket. @@ -213,24 +260,19 @@ The following policy needs to be attached to your queue (replace the value of Re ```json { - "Version": "2012-10-17", - "Id": "StreamExternalStoragePolicy", - "Statement": [ - { - "Sid": "ExampleStatement01", - "Effect": "Allow", - "Principal": { - "AWS": "arn:aws:iam::185583345998:root" - }, - "Action": [ - "s3:PutObject" - ], - "Resource": [ - "arn:aws:s3:::bucket_name/*", - "arn:aws:s3:::bucket_name" - ] - } - ] + "Version": "2012-10-17", + "Id": "StreamExternalStoragePolicy", + "Statement": [ + { + "Sid": "ExampleStatement01", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::185583345998:root" + }, + "Action": ["s3:PutObject"], + "Resource": ["arn:aws:s3:::bucket_name/*", "arn:aws:s3:::bucket_name"] + } + ] } ``` @@ -246,11 +288,11 @@ Stream only needs permission to write new files, it is not necessary to grant an ```js await serverSideClient.createExternalStorage({ - bucket: 'my-bucket', - name: 'my-gcs', - storage_type: 'gcs', - path: 'directory_name/', - gcs_credentials: "content of the service account file", + bucket: 'my-bucket', + name: 'my-gcs', + storage_type: 'gcs', + path: 'directory_name/', + gcs_credentials: 'content of the service account file', }); ``` @@ -261,7 +303,7 @@ await serverSideClient.createExternalStorage({ ```py with open("/path/to/your/service-account-file.json") as service_account_file: creds = service_account_file.read() - + client.create_external_storage( name='my-gcs', storage_type='gcs', @@ -270,6 +312,7 @@ client.create_external_storage( gcs_credentials=creds ) ``` + @@ -289,6 +332,19 @@ curl -X POST https://video.stream-io-api.com/video/external_storage?api_key=${AP ``` + + + +```js +await serverSideClient.video.createExternalStorage({ + bucket: 'my-bucket', + name: 'my-gcs', + storage_type: 'gcs', + path: 'directory_name/', + gcs_credentials: 'content of the service account file', +}); +``` + @@ -296,12 +352,12 @@ curl -X POST https://video.stream-io-api.com/video/external_storage?api_key=${AP ```json { - "bindings": [ - { - "role": "roles/storage.objectCreator", - "members": ["service_account_principal_identifier"] - } - ] + "bindings": [ + { + "role": "roles/storage.objectCreator", + "members": ["service_account_principal_identifier"] + } + ] } ``` @@ -310,7 +366,7 @@ curl -X POST https://video.stream-io-api.com/video/external_storage?api_key=${AP To use Azure Blob Storage as your storage provider, you need to create a container and a service principal with the following parameters: | Name | Description | Required | -|-------------------|-------------------|----------| +| ----------------- | ----------------- | -------- | | abs_account_name | The account name | yes | | abs_account_key | The account key | yes | | abs_client_secret | The client secret | yes | @@ -323,12 +379,12 @@ Stream only needs permission to write new files, it is not necessary to grant an ```js await serverSideClient.createExternalStorage({ - name: 'my-abs', - storage_type: 'abs', - bucket: 'my-bucket', - path: 'directory_name/', - abs_account_name: "...", - abs_account_key: "...", + name: 'my-abs', + storage_type: 'abs', + bucket: 'my-bucket', + path: 'directory_name/', + abs_account_name: '...', + abs_account_key: '...', }); ``` @@ -352,6 +408,7 @@ client.create_external_storage( ), ) ``` + @@ -370,5 +427,19 @@ curl -X POST https://video.stream-io-api.com/video/external_storage?api_key=${AP }' ``` + + + +```js +await serverSideClient.video.createExternalStorage({ + name: 'my-abs', + storage_type: 'abs', + bucket: 'my-bucket', + path: 'directory_name/', + abs_account_name: '...', + abs_account_key: '...', +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/basics/authentication.mdx b/docusaurus/video/docusaurus/docs/api/basics/authentication.mdx index 2a50d84f..48bfc10e 100644 --- a/docusaurus/video/docusaurus/docs/api/basics/authentication.mdx +++ b/docusaurus/video/docusaurus/docs/api/basics/authentication.mdx @@ -31,11 +31,7 @@ const newUser: UserRequest = { name: 'This is a test user', image: 'link/to/profile/image', }; -await client.upsertUsers({ - users: { - [newUser.id]: newUser, - }, -}); +await client.upsertUsers([newUser]); ``` @@ -78,6 +74,32 @@ curl -X POST https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \ }' ``` + + + +```js +const userId = 'john'; +const newUser: UserRequest = { + id: userId, + role: 'user', + custom: { + color: 'red', + }, + name: 'John', + image: 'link/to/profile/image', +}; +await client.upsertUsers({ + users: { + [newUser.id]: newUser, + }, +}); + +// exp is optional (by default the token is valid for an hour) +const exp = Math.round(new Date().getTime() / 1000) + 60 * 60; + +client.createToken(userId, exp); +``` + @@ -101,11 +123,7 @@ const user: UserRequest = { name: 'This is a test user', image: 'link/to/profile/image', }; -client.upsertUsers({ - users: { - [user.id]: user, - }, -}); +client.upsertUsers([user]); // or client.updateUsersPartial({ @@ -190,6 +208,39 @@ curl -X PATCH https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \ }' ``` + + + +```js +const user: UserRequest = { + id: 'userid', + role: 'user', + custom: { + color: 'red', + }, + name: 'This is a test user', + image: 'link/to/profile/image', +}; +client.upsertUsers({ + users: { + [user.id]: user, + }, +}); + +// or +client.updateUsersPartial({ + users: [ + { + id: user.id, + set: { + color: 'blue', + }, + unset: ['name'], + }, + ], +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/basics/calls.mdx b/docusaurus/video/docusaurus/docs/api/basics/calls.mdx index b8cfcba3..959e39e9 100644 --- a/docusaurus/video/docusaurus/docs/api/basics/calls.mdx +++ b/docusaurus/video/docusaurus/docs/api/basics/calls.mdx @@ -168,27 +168,25 @@ Once this is set, we can proceed with setting up a `call` instance and providing ```js +const callTypeName = 'default'; + const callType = (await client.video.listCallTypes()).call_types[callTypeName]; // Remove JOIN_CALL permission from user role const userGrants = callType.grants['user'].filter( - (c) => c !== VideoOwnCapability.JOIN_CALL, + (c) => c !== OwnCapability.JOIN_CALL, ); // Make sure JOIN_CALL permission is set for call_member role const callMemberGrants = callType.grants['call_member']; -if (!callMemberGrants.includes(VideoOwnCapability.JOIN_CALL)) { - callMemberGrants.push(VideoOwnCapability.JOIN_CALL); +if (!callMemberGrants.includes(OwnCapability.JOIN_CALL)) { + callMemberGrants.push(OwnCapability.JOIN_CALL); } // Update the call type with the changes -await client.video.updateCallType(callTypeName, { +await client.video.updateCallType({ + name: callTypeName, grants: { - user: [], - call_member: [ - VideoOwnCapability.JOIN_CALL, - VideoOwnCapability.GET_CALL, - VideoOwnCapability.SEND_AUDIO, - VideoOwnCapability.JOIN_CALL, - ], + user: userGrants, + call_member: callMemberGrants, }, }); ``` @@ -228,6 +226,35 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +const callType = (await client.video.listCallTypes()).call_types[callTypeName]; +// Remove JOIN_CALL permission from user role +const userGrants = callType.grants['user'].filter( + (c) => c !== VideoOwnCapability.JOIN_CALL, +); +// Make sure JOIN_CALL permission is set for call_member role +const callMemberGrants = callType.grants['call_member']; +if (!callMemberGrants.includes(VideoOwnCapability.JOIN_CALL)) { + callMemberGrants.push(VideoOwnCapability.JOIN_CALL); +} + +// Update the call type with the changes +await client.video.updateCallType(callTypeName, { + grants: { + user: [], + call_member: [ + VideoOwnCapability.JOIN_CALL, + VideoOwnCapability.GET_CALL, + VideoOwnCapability.SEND_AUDIO, + VideoOwnCapability.JOIN_CALL, + ], + }, +}); +``` + @@ -247,7 +274,7 @@ This action terminates the call for everyone. Ending a call requires the `end-ca ```js -await call.endCall(); +await call.end(); ``` @@ -266,6 +293,13 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${C -H "stream-auth-type: jwt" ``` + + + +```js +await call.endCall(); +``` + @@ -494,17 +528,19 @@ const queryMembersReq = { sort: [{ field: 'user_id', direction: 1 }], limit: 2, }; -const response = await call.queryMembers(queryMembersReq); +const response = await call.queryMembers({ payload: queryMembersReq }); // loading next page call.queryMembers({ - ...queryMembersReq, - next: response.next, + payload: { + ...queryMembersReq, + next: response.next, + }, }); // filtering call.queryMembers({ - filter_conditions: { role: { $eq: 'admin' } }, + payload: { filter_conditions: { role: { $eq: 'admin' } } }, }); ``` @@ -586,6 +622,32 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/call/members?api_key= }' ``` + + + +```js +// default sorting +call.queryMembers(); + +// sorting and pagination +const queryMembersReq = { + sort: [{ field: 'user_id', direction: 1 }], + limit: 2, +}; +const response = await call.queryMembers(queryMembersReq); + +// loading next page +call.queryMembers({ + ...queryMembersReq, + next: response.next, +}); + +// filtering +call.queryMembers({ + filter_conditions: { role: { $eq: 'admin' } }, +}); +``` + @@ -615,12 +677,12 @@ You can pin the video of a participant in a call session. The SDKs will make sur ```js -await call.pinVideo({ +await call.videoPin({ session_id: 'session-id', user_id: 'user-id-to-pin', }); -await call.unpinVideo({ +await call.videoUnpin({ session_id: 'session-id', user_id: 'user-id-to-unpin', }); @@ -662,6 +724,21 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${C }' ``` + + + +```js +await call.pinVideo({ + session_id: 'session-id', + user_id: 'user-id-to-pin', +}); + +await call.unpinVideo({ + session_id: 'session-id', + user_id: 'user-id-to-unpin', +}); +``` + @@ -757,6 +834,29 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +await client.video.updateCallType('default', { + settings: { + limits: { + max_duration_seconds: 3600, + }, + }, +}); + +// Disable the default session timer +await client.video.updateCallType('default', { + name: 'default', + settings: { + limits: { + max_duration_seconds: 0, + }, + }, +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/basics/get_started.mdx b/docusaurus/video/docusaurus/docs/api/basics/get_started.mdx index 6f44045f..cf68ef42 100644 --- a/docusaurus/video/docusaurus/docs/api/basics/get_started.mdx +++ b/docusaurus/video/docusaurus/docs/api/basics/get_started.mdx @@ -124,11 +124,7 @@ const newUser: UserRequest = { name: 'John', image: 'link/to/profile/image', }; -await client.upsertUsers({ - users: { - [newUser.id]: newUser, - }, -}); +await client.upsertUsers([newUser]); // exp is optional (by default the token is valid for an hour) const exp = Math.round(new Date().getTime() / 1000) + 60 * 60; @@ -178,6 +174,32 @@ curl -X POST https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \ }' ``` + + + +```js +const userId = 'john'; +const newUser: UserRequest = { + id: userId, + role: 'user', + custom: { + color: 'red', + }, + name: 'John', + image: 'link/to/profile/image', +}; +await client.upsertUsers({ + users: { + [newUser.id]: newUser, + }, +}); + +// exp is optional (by default the token is valid for an hour) +const exp = Math.round(new Date().getTime() / 1000) + 60 * 60; + +client.createToken(userId, exp); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/basics/multi-tenant.mdx b/docusaurus/video/docusaurus/docs/api/basics/multi-tenant.mdx index 13e6c0e7..bc62664f 100644 --- a/docusaurus/video/docusaurus/docs/api/basics/multi-tenant.mdx +++ b/docusaurus/video/docusaurus/docs/api/basics/multi-tenant.mdx @@ -27,11 +27,11 @@ In order to use Teams, your application must have multi-tenant mode enabled. You ```js // shows the current status -const appSettings = await client.getAppSettings(); +const appSettings = await client.getApp(); console.log(appSettings.app.multi_tenant_enabled); // enables teams -client.updateAppSettings({ +client.updateApp({ multi_tenant_enabled: true, }); ``` @@ -66,6 +66,20 @@ curl -X PATCH "https://video.stream-io-api.com/api/v2/app?api_key=${API_KEY}" \ }' ``` + + + +```js +// shows the current status +const appSettings = await client.getAppSettings(); +console.log(appSettings.app.multi_tenant_enabled); + +// enables teams +client.updateAppSettings({ + multi_tenant_enabled: true, +}); +``` + @@ -79,15 +93,13 @@ When multi-tenant is enabled, users can only be created from your back-end. This ```js -client.upsertUsers({ - users: { - ['']: { - id: '', - name: 'Sara', - teams: ['red', 'blue'], - }, +client.upsertUsers([ + { + id: '', + name: 'Sara', + teams: ['red', 'blue'], }, -}); +]); ``` @@ -118,6 +130,21 @@ curl -X POST https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY} \ }' ``` + + + +```js +client.upsertUsers({ + users: { + ['']: { + id: '', + name: 'Sara', + teams: ['red', 'blue'], + }, + }, +}); +``` + @@ -186,17 +213,21 @@ For server-side requests, this filter does not apply and you can search as usual ```js // search for users by name and team client.queryUsers({ - filter_conditions: { - name: 'Nick', - teams: { $in: ['red', 'blue'] }, + payload: { + filter_conditions: { + name: 'Nick', + teams: { $in: ['red', 'blue'] }, + }, }, }); // search for users that are not part of any team client.queryUsers({ - filter_conditions: { - name: 'Tom', - teams: null, + payload: { + filter_conditions: { + name: 'Tom', + teams: null, + }, }, }); ``` @@ -247,6 +278,27 @@ curl -X GET "https://video.stream-io-api.com/api/v2/users?api_key=${API_KEY}&pay -H "stream-auth-type: jwt" ``` + + + +```js +// search for users by name and team +client.queryUsers({ + filter_conditions: { + name: 'Nick', + teams: { $in: ['red', 'blue'] }, + }, +}); + +// search for users that are not part of any team +client.queryUsers({ + filter_conditions: { + name: 'Tom', + teams: null, + }, +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/call_types/manage-types.mdx b/docusaurus/video/docusaurus/docs/api/call_types/manage-types.mdx index 74c4007f..a1a9af25 100644 --- a/docusaurus/video/docusaurus/docs/api/call_types/manage-types.mdx +++ b/docusaurus/video/docusaurus/docs/api/call_types/manage-types.mdx @@ -123,7 +123,8 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/calltypes?api_key=${A ```js -client.video.updateCallType('allhands', { +client.video.updateCallType({ + name: 'allhands', settings: { audio: { mic_default_on: false, default_device: 'earpiece' }, }, @@ -157,6 +158,17 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +client.video.updateCallType('allhands', { + settings: { + audio: { mic_default_on: false, default_device: 'earpiece' }, + }, +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/call_types/permissions.mdx b/docusaurus/video/docusaurus/docs/api/call_types/permissions.mdx index 62de8915..2148ce20 100644 --- a/docusaurus/video/docusaurus/docs/api/call_types/permissions.mdx +++ b/docusaurus/video/docusaurus/docs/api/call_types/permissions.mdx @@ -46,7 +46,8 @@ client.video.createCallType({ }); // or edit a built-in call type -client.video.updateCallType('default', { +client.video.updateCallType({ + name: 'default', grants: { /* ... */ }, @@ -112,6 +113,34 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/default?api_ + + +```js +client.video.createCallType({ + name: '', + grants: { + admin: [ + VideoOwnCapability.SEND_AUDIO, + VideoOwnCapability.SEND_VIDEO, + VideoOwnCapability.MUTE_USERS, + ], + ['customrole']: [ + VideoOwnCapability.SEND_AUDIO, + VideoOwnCapability.SEND_VIDEO, + ], + }, +}); + +// or edit a built-in call type +client.video.updateCallType('default', { + grants: { + /* ... */ + }, +}); +``` + + + ### Built-in roles diff --git a/docusaurus/video/docusaurus/docs/api/misc/rate_limits.mdx b/docusaurus/video/docusaurus/docs/api/misc/rate_limits.mdx new file mode 100644 index 00000000..bb86d28c --- /dev/null +++ b/docusaurus/video/docusaurus/docs/api/misc/rate_limits.mdx @@ -0,0 +1,147 @@ +--- +id: rate_limits +sidebar_position: 2 +title: Rate limits +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Stream powers video, chat and activity feeds for a billion end users. That being said, Stream does have rate limits to protect your applications (making many API requests can trigger client-side events causing degraded app performance) and Stream's infrastructure (using more capacity than is provisioned for your plan). + +Every Application has rate limits applied based on a combination of API endpoint and platform: these limits are set on a 1-minute time window. For example, creating a call has a different limit than querying calls. Likewise, different platforms such as iOS, Android or your server-side infrastructure have independent counters for each API endpoint's rate limit. + +## Types of rate limits + +There are two kinds of rate limits: + +- **User Rate Limits**: Apply to each user and platform combination and help to prevent a single user from consuming your Application rate limits. +- **App rate limits**: App rate limits are calculated per endpoint and platform combination for your application. + +## User Rate Limits + +To avoid individual users consuming your entire quota, every single user is limited to at most 60 requests per minute (per API endpoint and platform). When the limit is exceeded, requests from that user and platform will be rejected. + +## App Rate Limits + +Stream supports four different platforms via our official SDKs: + +- **Server**: SDKs that execute on the server including Node, Python, Ruby, Go, C#, PHP, and Java. +- **Android**: SDKs that execute on an Android device including Kotlin, Java, Flutter, and React Native for Android clients. +- **iOS**: SDKs that execute on an iOS device including Swift, Flutter, and React Native for iOS clients. +- **Web**: SDKs that execute in a browser including React, Angular, or vanilla JavaScript clients. + +Rate limits quotas are not shared across different platforms. This way if by accident a server-side script hits a rate limit, you will not have any impact on your mobile and web applications. When the limit is hit, all calls from the same app, platform, and endpoint will result in an error with a 429 HTTP status code. + +App rate limits are administered both per minute and per second. The per-second limit is equal to the per-minute limit divided by 30 to allow for bursts. + +## What To Do When You've Hit a Rate Limit + +You should always review responses from Stream to watch for error conditions. If you receive 429 status, this means your API request was rate-limited and you will need to retry. We recommend implementing an exponential back-off retry mechanism. + +Here are a few things to keep in mind to avoid rate limits on server-side: + +1. **Slow down your scripts**: This is the most common cause of rate limits. You're running a cronjob or script that runs many API calls in succession. Adding a small timeout in between API calls typically solves the issue. + +2. **Use batch endpoints**: Batch update endpoints exist for many operations. So instead of doing 100 calls to update 1 user each, call the batch endpoint for updating many users. + +3. **Query only when needed**: Sometimes apps will call a query endpoint to see if an entity exists before creating it. Many of Stream's endpoints have an upsert behaviour, so this isn't necessary in most cases. + +4. If rate limits are still a problem, Stream can set higher limits for certain pricing plans: + +- For Standard plans, Stream may also raise rate limits in certain instances, an integration review is required to ensure your integration is making optimal use of the default rate limits before any increase will be applied. +- For Enterprise plans, Stream will review your architecture, and set higher rate limits for your production application. + +## Rate limit headers + +| Header | Description | +| --------------------- | -------------------------------------------------------------- | +| X-RateLimit-Limit | the total limit allowed for the resource requested (i.e. 5000) | +| X-RateLimit-Remaining | the remaining limit (i.e. 4999) | +| X-RateLimit-Reset | when the current limit will reset (Unix timestamp) | + +This is how you can access rate limit information on server-side SDKs: + + + + +```js +const response = client.....; +const rateLimit = response.metadata.rateLimit; + +// the total limit allowed for the resource requested +console.log(rateLimit.rateLimit); +// the remaining limit +console.log(rateLimit.rateLimitRemaining); +// when the current limit will reset - Date +console.log(rateLimit.rateLimitReset); + +// or + +try { + client.... +} catch (error) { + const rateLimit = response.metadata.rateLimit; + if (error.metadata.responseCode === 429) { + // Wait until rate limit resets and then retry + } +} +``` + + + + +## Inspecting rate limits + +Stream offers the ability to inspect an App's current rate limit quotas and usage in your App's dashboard. Alternatively you can also retrieve the API Limits for your application using the API directly. + + + + +```js +// 1. Get Rate limits, server-side platform +limits = await client.getRateLimits({ server_side: true }); + +// 2. Get Rate limits, all platforms +limits = await client.getRateLimits(); + +// 3. Get Rate limits, iOS and Android +limits = await client.getRateLimits({ ios: true, android: true }); + +// 4. Get Rate limits for specific endpoints +limits = await client.getRateLimits({ + endpoints: 'QueryCalls,GetOrCreateCall', +}); +``` + + + + +```bash +# 1. Get Rate limits, server-side platform +curl -X GET "https://video.stream-io-api.com/api/v2/rate_limits?api_key=${API_KEY}&server_side=true" \ + -H "Authorization: ${TOKEN}" \ + -H "stream-auth-type: jwt" + +# 2. Get Rate limits, all platforms +curl -X GET https://video.stream-io-api.com/api/v2/rate_limits?api_key=${API_KEY} \ + -H "Authorization: ${TOKEN}" \ + -H "stream-auth-type: jwt" + +# 3. Get Rate limits, iOS and Android +curl -X GET "https://video.stream-io-api.com/api/v2/rate_limits?api_key=${API_KEY}&ios=true&android=true" \ + -H "Authorization: ${TOKEN}" \ + -H "stream-auth-type: jwt" + +# 4. Get Rate limits for specific endpoints +PAYLOAD='QueryCalls,GetOrCreateCall'; +ENCODED_PAYLOAD=$(echo ${PAYLOAD} | perl -MURI::Escape -lne 'print uri_escape($_)') + +curl -X GET "https://video.stream-io-api.com/api/v2/rate_limits?api_key=${API_KEY}&endpoints=${ENCODED_PAYLOAD}" \ + -H "Authorization: ${TOKEN}" \ + -H "stream-auth-type: jwt" + +``` + + + diff --git a/docusaurus/video/docusaurus/docs/api/moderation/overview.mdx b/docusaurus/video/docusaurus/docs/api/moderation/overview.mdx index 13872d08..55a3fefd 100644 --- a/docusaurus/video/docusaurus/docs/api/moderation/overview.mdx +++ b/docusaurus/video/docusaurus/docs/api/moderation/overview.mdx @@ -323,28 +323,28 @@ Users can be banned, when doing that they are not allowed to join or create call ```js -client.banUser({ +client.moderation.ban({ target_user_id: '', - user_id: '', + banned_by_id: '', reason: '', }); // remove the ban for a user -client.unbanUser({ - targetUserId: '', +client.moderation.unban({ + target_user_id: '', }); // ban a user for 30 minutes -client.banUser({ +client.moderation.ban({ target_user_id: '', - user_id: '', + banned_by_id: '', timeout: 30, }); // ban a user and all users sharing the same IP -client.banUser({ +client.moderation.ban({ target_user_id: '', - user_id: '', + banned_by_id: '', reason: '', ip_ban: true, }); @@ -428,6 +428,37 @@ curl -X POST https://video.stream-io-api.com/api/v2/moderation/ban?api_key=${API }' ``` + + + +```js +client.banUser({ + target_user_id: '', + user_id: '', + reason: '', +}); + +// remove the ban for a user +client.unbanUser({ + targetUserId: '', +}); + +// ban a user for 30 minutes +client.banUser({ + target_user_id: '', + user_id: '', + timeout: 30, +}); + +// ban a user and all users sharing the same IP +client.banUser({ + target_user_id: '', + user_id: '', + reason: '', + ip_ban: true, +}); +``` + @@ -450,7 +481,7 @@ client.blockUsers({ user_id: 'alice', }); -client.getBlockedUsers({ userId: 'alice' }); +client.getBlockedUsers({ user_id: 'alice' }); client.unblockUsers({ blocked_user_id: 'bob', @@ -503,5 +534,22 @@ curl -X POST https://video.stream-io-api.com/api/v2/users/unblock?api_key=${API_ }' ``` + + + +```js +client.blockUsers({ + blocked_user_id: 'bob', + user_id: 'alice', +}); + +client.getBlockedUsers({ userId: 'alice' }); + +client.unblockUsers({ + blocked_user_id: 'bob', + user_id: 'alice', +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/recording/recording_calls.mdx b/docusaurus/video/docusaurus/docs/api/recording/recording_calls.mdx index 81c3b896..eedfef7c 100644 --- a/docusaurus/video/docusaurus/docs/api/recording/recording_calls.mdx +++ b/docusaurus/video/docusaurus/docs/api/recording/recording_calls.mdx @@ -5,8 +5,6 @@ slug: /recording/calls title: Recording calls --- - - import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -150,16 +148,17 @@ Recording can be configured from the Dashboard (see call type screen) or directl call.update({ settings_override: { recording: { - mode: VideoRecordSettingsRequestModeEnum.DISABLED, + mode: 'disabled', }, }, }); // Disable on call type level -client.video.updateCallType('', { +client.video.updateCallType({ + name: '', settings: { recording: { - mode: VideoRecordSettingsModeEnum.DISABLED, + mode: 'disabled', }, }, }); @@ -168,7 +167,7 @@ client.video.updateCallType('', { call.update({ settings_override: { recording: { - mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + mode: 'available', }, }, }); @@ -177,9 +176,9 @@ call.update({ call.update({ settings_override: { recording: { - mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + mode: 'available', audio_only: false, - quality: VideoRecordSettingsRequestQualityEnum._1080P, + quality: '1080p', }, }, }); @@ -301,6 +300,49 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +// Disable on call level +call.update({ + settings_override: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.DISABLED, + }, + }, +}); + +// Disable on call type level +client.video.updateCallType('', { + settings: { + recording: { + mode: VideoRecordSettingsModeEnum.DISABLED, + }, + }, +}); + +// Enable +call.update({ + settings_override: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + }, + }, +}); + +// Other settings +call.update({ + settings_override: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + audio_only: false, + quality: VideoRecordSettingsRequestQualityEnum._1080P, + }, + }, +}); +``` + @@ -316,7 +358,7 @@ You can configure your calls to only record the audio tracks and exclude the vid call.update({ settings_override: { recording: { - mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + mode: 'available', audio_only: true, }, }, @@ -357,6 +399,21 @@ curl -X PATCH "https://video.stream-io-api.com/api/v2/video/call/default/${CALL_ }' ``` + + + +```js +// Enable +call.update({ + settings_override: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + audio_only: true, + }, + }, +}); +``` + @@ -434,7 +491,8 @@ const layoutOptions = { 'participant_label.background_color': 'transparent', }; -client.video.updateCallType(callTypeName, { +client.video.updateCallType({ + name: callTypeName, settings: { recording: { mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, @@ -523,6 +581,41 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +const layoutOptions = { + 'logo.image_url': + 'https://theme.zdassets.com/theme_assets/9442057/efc3820e436f9150bc8cf34267fff4df052a1f9c.png', + 'logo.horizontal_position': 'center', + 'title.text': 'Building Stream Video Q&A', + 'title.horizontal_position': 'center', + 'title.color': 'black', + 'participant_label.border_radius': '0px', + 'participant.border_radius': '0px', + 'layout.spotlight.participants_bar_position': 'top', + 'layout.background_color': '#f2f2f2', + 'participant.placeholder_background_color': '#1f1f1f', + 'layout.single-participant.padding_inline': '20%', + 'participant_label.background_color': 'transparent', +}; + +client.video.updateCallType(callTypeName, { + settings: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + audio_only: false, + quality: VideoRecordSettingsRequestQualityEnum._1080P, + layout: { + name: VideoLayoutSettingsNameEnum.SPOTLIGHT, + options: layoutOptions, + }, + }, + }, +}); +``` + @@ -631,7 +724,8 @@ The best way to find the right CSS setup is by running the layout app directly. ```js -client.video.updateCallType(callTypeName, { +client.video.updateCallType({ + name: callTypeName, settings: { recording: { mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, @@ -692,6 +786,25 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +client.video.updateCallType(callTypeName, { + settings: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + audio_only: false, + quality: VideoRecordSettingsRequestQualityEnum._1080P, + layout: { + name: VideoLayoutSettingsNameEnum.SPOTLIGHT, + external_css_url: 'https://path/to/custom.css', + }, + }, + }, +}); +``` + @@ -705,7 +818,8 @@ The layout app used to record calls is available on [GitHub](https://github.com/ ```js -client.video.updateCallType(callTypeName, { +client.video.updateCallType({ + name: callTypeName, settings: { recording: { mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, @@ -765,6 +879,25 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +client.video.updateCallType(callTypeName, { + settings: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, + audio_only: false, + quality: VideoRecordSettingsRequestQualityEnum._1080P, + layout: { + name: VideoLayoutSettingsNameEnum.CUSTOM, + external_app_url: 'https://path/to/layout/app', + }, + }, + }, +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/streaming/backstage.mdx b/docusaurus/video/docusaurus/docs/api/streaming/backstage.mdx index 7ea1bc6f..b57d4dad 100644 --- a/docusaurus/video/docusaurus/docs/api/streaming/backstage.mdx +++ b/docusaurus/video/docusaurus/docs/api/streaming/backstage.mdx @@ -26,16 +26,16 @@ To create a call in backstage mode and allow users to join ahead of the schedule ```js startsAt = new Date(Date.now() + 30 * 60 * 1000); client.call('livestream', 'test-outgoing-call').getOrCreate({ - data: { - starts_at: startsAt.toISOString(), - created_by_id: 'john', - settings_override: { - backstage: { - enabled: true, - join_ahead_time_seconds: 300, - }, - }, + data: { + starts_at: startsAt, + created_by_id: 'john', + settings_override: { + backstage: { + enabled: true, + join_ahead_time_seconds: 300, + }, }, + }, }); ``` @@ -87,6 +87,25 @@ curl -X POST "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE}/${C }' ``` + + + +```js +startsAt = new Date(Date.now() + 30 * 60 * 1000); +client.call('livestream', 'test-outgoing-call').getOrCreate({ + data: { + starts_at: startsAt.toISOString(), + created_by_id: 'john', + settings_override: { + backstage: { + enabled: true, + join_ahead_time_seconds: 300, + }, + }, + }, +}); +``` + @@ -107,7 +126,8 @@ call.update({ }); // or call type level -client.video.updateCallType('', { +client.video.updateCallType({ + name: '', settings: { backstage: { enabled: true, @@ -176,6 +196,31 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +// call level +call.update({ + settings_override: { + backstage: { + enabled: true, + join_ahead_time_seconds: 300, + }, + }, +}); + +// or call type level +client.video.updateCallType('', { + settings: { + backstage: { + enabled: true, + join_ahead_time_seconds: 300, + }, + }, +}); +``` + @@ -189,9 +234,10 @@ When a call is in backstage mode, only users with the `join-backstage` capabilit ```js -client.video.updateCallType('', { +client.video.updateCallType({ + name: '', grants: { - host: [VideoOwnCapability.JOIN_BACKSTAGE], + host: [OwnCapability.JOIN_BACKSTAGE], }, }); ``` @@ -221,6 +267,17 @@ curl -X PUT "https://video.stream-io-api.com/api/v2/video/calltypes/${CALL_TYPE_ }' ``` + + + +```js +client.video.updateCallType('', { + grants: { + host: [VideoOwnCapability.JOIN_BACKSTAGE], + }, +}); +``` + diff --git a/docusaurus/video/docusaurus/docs/api/transcription/transcribing_calls.mdx b/docusaurus/video/docusaurus/docs/api/transcription/transcribing_calls.mdx index f2f0f276..fd999ff6 100644 --- a/docusaurus/video/docusaurus/docs/api/transcription/transcribing_calls.mdx +++ b/docusaurus/video/docusaurus/docs/api/transcription/transcribing_calls.mdx @@ -101,7 +101,7 @@ An error will be returned if the transcription doesn't exist. ```js -call.deleteTranscription({ session: '', filename: '' }) +call.deleteTranscription({ session: '', filename: '' }); ``` @@ -181,16 +181,17 @@ Transcription can be configured from the Dashboard (see call type screen) or dir call.update({ settings_override: { transcription: { - mode: VideoTranscriptionSettingsRequestModeEnum.DISABLED, + mode: 'disabled', }, }, }); // Disable on call type level -client.video.updateCallType('', { +client.video.updateCallType({ + name: '', settings: { transcription: { - mode: VideoTranscriptionSettingsModeEnum.DISABLED, + mode: 'disabled', }, }, }); @@ -199,7 +200,7 @@ client.video.updateCallType('', { call.update({ settings_override: { transcription: { - mode: VideoTranscriptionSettingsRequestModeEnum.AVAILABLE, + mode: 'available', }, }, }); @@ -209,7 +210,7 @@ call.update({ settings_override: { transcription: { audio_only: false, - quality: VideoTranscriptionSettingsRequestQualityEnum.AUTO_ON, + quality: 'auto-on', }, }, }); @@ -318,6 +319,48 @@ curl -X PATCH "https://video.stream-io-api.com/api/v2/video/call/${CALL_TYPE_NAM By default the transcriptions are stored on Stream’s S3 bucket and retained for 2-weeks. You can also configure your application to have transcriptions stored on your own external storage, see the storage section of tis document for more detail. + + + +```js +// Disable on call level +call.update({ + settings_override: { + transcription: { + mode: VideoTranscriptionSettingsRequestModeEnum.DISABLED, + }, + }, +}); + +// Disable on call type level +client.video.updateCallType('', { + settings: { + transcription: { + mode: VideoTranscriptionSettingsModeEnum.DISABLED, + }, + }, +}); + +// Enable +call.update({ + settings_override: { + transcription: { + mode: VideoTranscriptionSettingsRequestModeEnum.AVAILABLE, + }, + }, +}); + +// Other settings +call.update({ + settings_override: { + transcription: { + audio_only: false, + quality: VideoTranscriptionSettingsRequestQualityEnum.AUTO_ON, + }, + }, +}); +``` +