From 57c928358eebf8b5ca4b21f0653cc05cc3af6369 Mon Sep 17 00:00:00 2001 From: Zita Szupera Date: Thu, 20 Jun 2024 12:59:16 +0200 Subject: [PATCH] feat: implement delete call endpoint --- __tests__/call.test.ts | 200 +++++++++---------- __tests__/external-recording-storage.test.ts | 4 +- src/StreamCall.ts | 16 +- src/gen/video/apis/ProductvideoApi.ts | 65 +++++- src/gen/video/models/index.ts | 148 +++++++++++++- src/gen/video/runtime.ts | 2 +- 6 files changed, 323 insertions(+), 112 deletions(-) diff --git a/__tests__/call.test.ts b/__tests__/call.test.ts index 9d7593f..dd4b6f9 100644 --- a/__tests__/call.test.ts +++ b/__tests__/call.test.ts @@ -1,4 +1,4 @@ -import { beforeAll, describe, expect, it } from 'vitest'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { v4 as uuidv4 } from 'uuid'; import { createTestClient } from './create-test-client'; import { StreamCall } from '../src/StreamCall'; @@ -158,127 +158,123 @@ describe('call API', () => { ); }); - describe('recording', () => { - it('enable call recording', async () => { - let response = await call.update({ - settings_override: { - recording: { - mode: VideoRecordSettingsRequestModeEnum.DISABLED, - audio_only: true, - }, + it('enable call recording', async () => { + let response = await call.update({ + settings_override: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.DISABLED, + audio_only: true, }, - }); - let settings = response.call.settings.recording; + }, + }); + let settings = response.call.settings.recording; - expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.DISABLED); + expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.DISABLED); - response = await call.update({ - settings_override: { - recording: { - mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, - }, + response = await call.update({ + settings_override: { + recording: { + mode: VideoRecordSettingsRequestModeEnum.AVAILABLE, }, - }); + }, + }); - settings = response.call.settings.recording; - expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.AVAILABLE); + settings = response.call.settings.recording; + expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.AVAILABLE); - response = await call.update({ - settings_override: { - recording: { - audio_only: false, - quality: VideoRecordSettingsRequestQualityEnum._1080P, - mode: VideoRecordSettingsRequestModeEnum.AUTO_ON, - }, + response = await call.update({ + settings_override: { + recording: { + audio_only: false, + quality: VideoRecordSettingsRequestQualityEnum._1080P, + mode: VideoRecordSettingsRequestModeEnum.AUTO_ON, }, - }); - - settings = response.call.settings.recording; - expect(settings.audio_only).toBe(false); - expect(settings.quality).toBe( - VideoRecordSettingsRequestQualityEnum._1080P, - ); + }, }); - it('start recording', async () => { - // somewhat dummy test, we should do a proper test in the future where we join a call and start recording - await expect(() => call.startRecording()).rejects.toThrowError( - 'Stream error code 4: StartRecording failed with error: "cannot record inactive call"', - ); - }); + settings = response.call.settings.recording; + expect(settings.audio_only).toBe(false); + expect(settings.quality).toBe(VideoRecordSettingsRequestQualityEnum._1080P); + }); - it('stop recording', async () => { - // somewhat dummy test, we should do a proper test in the future - await expect(() => call.stopRecording()).rejects.toThrowError( - 'Stream error code 4: StopRecording failed with error: "call is not being recorded"', - ); - }); + it('start recording', async () => { + // somewhat dummy test, we should do a proper test in the future where we join a call and start recording + await expect(() => call.startRecording()).rejects.toThrowError( + 'Stream error code 4: StartRecording failed with error: "cannot record inactive call"', + ); + }); - it('delete recording', async () => { - // somewhat dummy test, we should do a proper test in the future - await expect(() => - call.deleteRecording({ session: 'test', filename: 'test' }), - ).rejects.toThrowError( - `Stream error code 16: DeleteRecording failed with error: "recording doesn't exist"`, - ); - }); + it('stop recording', async () => { + // somewhat dummy test, we should do a proper test in the future + await expect(() => call.stopRecording()).rejects.toThrowError( + 'Stream error code 4: StopRecording failed with error: "call is not being recorded"', + ); + }); + + it('delete recording', async () => { + // somewhat dummy test, we should do a proper test in the future + await expect(() => + call.deleteRecording({ session: 'test', filename: 'test' }), + ).rejects.toThrowError( + `Stream error code 16: DeleteRecording failed with error: "recording doesn't exist"`, + ); + }); - it('query recordings', async () => { - // somewhat dummy test, we should do a proper test in the future - const response = await call.listRecordings(); + it('query recordings', async () => { + // somewhat dummy test, we should do a proper test in the future + const response = await call.listRecordings(); - expect(response.recordings).toBeDefined(); + expect(response.recordings).toBeDefined(); + }); + + it('enable backstage mode', async () => { + const response = await call.update({ + settings_override: { + backstage: { + enabled: true, + }, + }, }); - describe('streaming', () => { - it('enable backstage mode', async () => { - const response = await call.update({ - settings_override: { - backstage: { - enabled: true, - }, - }, - }); + expect(response.call.settings.backstage.enabled).toBe(true); + }); - expect(response.call.settings.backstage.enabled).toBe(true); - }); + it('go live', async () => { + const response = await call.goLive(); - it('go live', async () => { - const response = await call.goLive(); + expect(response.call.backstage).toBe(false); + }); - expect(response.call.backstage).toBe(false); - }); + it('stop live', async () => { + const response = await call.stopLive(); - it('stop live', async () => { - const response = await call.stopLive(); + expect(response.call.backstage).toBe(true); + }); - expect(response.call.backstage).toBe(true); - }); - }); + it('start transcribing', async () => { + // somewhat dummy test, we should do a proper test in the future where we join a call and start recording + await expect(() => call.startTranscription()).rejects.toThrowError( + 'Stream error code 4: StartTranscription failed with error: "cannot transcribe inactive call"', + ); + }); - describe('transcriptions', () => { - it('start transcribing', async () => { - // somewhat dummy test, we should do a proper test in the future where we join a call and start recording - await expect(() => call.startTranscription()).rejects.toThrowError( - 'Stream error code 4: StartTranscription failed with error: "cannot transcribe inactive call"', - ); - }); - - it('stop transcribing', async () => { - // somewhat dummy test, we should do a proper test in the future - await expect(() => call.stopTranscription()).rejects.toThrowError( - 'Stream error code 4: StopTranscription failed with error: "call is not being transcribed"', - ); - }); - - it('delete transcription', async () => { - // somewhat dummy test, we should do a proper test in the future - await expect(() => - call.deleteTranscription({ session: 'test', filename: 'test' }), - ).rejects.toThrowError( - `Stream error code 16: DeleteTranscription failed with error: "transcription doesn't exist"`, - ); - }); - }); + it('stop transcribing', async () => { + // somewhat dummy test, we should do a proper test in the future + await expect(() => call.stopTranscription()).rejects.toThrowError( + 'Stream error code 4: StopTranscription failed with error: "call is not being transcribed"', + ); + }); + + it('delete transcription', async () => { + // somewhat dummy test, we should do a proper test in the future + await expect(() => + call.deleteTranscription({ session: 'test', filename: 'test' }), + ).rejects.toThrowError( + `Stream error code 16: DeleteTranscription failed with error: "transcription doesn't exist"`, + ); + }); + + afterAll(async () => { + await call.delete({ hard: true }); }); }); diff --git a/__tests__/external-recording-storage.test.ts b/__tests__/external-recording-storage.test.ts index 8fc5163..0551180 100644 --- a/__tests__/external-recording-storage.test.ts +++ b/__tests__/external-recording-storage.test.ts @@ -15,7 +15,7 @@ describe('external storage CRUD API', () => { const response = await client.video.createExternalStorage({ name: storageName, bucket: 'test', - storage_type: 'test', + storage_type: 'abs', }); expect(response).toBeDefined(); @@ -32,7 +32,7 @@ describe('external storage CRUD API', () => { const newBucket = 'new bucket'; const response = await client.video.updateExternalStorage(storageName, { bucket: newBucket, - storage_type: 'test', + storage_type: 'abs', }); expect(response.bucket).toBe('new bucket'); diff --git a/src/StreamCall.ts b/src/StreamCall.ts index 8bcbbde..ad5e6df 100644 --- a/src/StreamCall.ts +++ b/src/StreamCall.ts @@ -6,6 +6,7 @@ import { GetCallStatsRequest, ProductvideoApi, VideoBlockUserRequest, + VideoDeleteCallRequest, VideoGetOrCreateCallRequest, VideoGoLiveRequest, VideoMuteUsersRequest, @@ -28,14 +29,18 @@ export class StreamCall { constructor( private readonly streamClient: StreamClient, - private readonly type: string, - private readonly id: string, + public readonly type: string, + public readonly id: string, ) { this.baseRequest = { id: this.id, type: this.type }; const configuration = this.streamClient.getConfiguration('video'); this.apiClient = new ProductvideoApi(configuration); } + get cid() { + return `${this.type}:${this.id}`; + } + blockUser = (videoBlockUserRequest: VideoBlockUserRequest) => { return this.apiClient.blockUser({ ...this.baseRequest, @@ -43,6 +48,13 @@ export class StreamCall { }); }; + delete = (videoDeleteCallRequest?: VideoDeleteCallRequest) => { + return this.apiClient.deleteCall({ + ...this.baseRequest, + videoDeleteCallRequest: videoDeleteCallRequest ?? null, + }); + }; + endCall = () => { return this.apiClient.endCall({ ...this.baseRequest }); }; diff --git a/src/gen/video/apis/ProductvideoApi.ts b/src/gen/video/apis/ProductvideoApi.ts index 800d503..81606be 100644 --- a/src/gen/video/apis/ProductvideoApi.ts +++ b/src/gen/video/apis/ProductvideoApi.ts @@ -4,7 +4,7 @@ * Stream API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: v116.0.0 + * The version of the OpenAPI document: v120.0.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -28,6 +28,8 @@ import type { VideoCreateExternalStorageResponse, VideoCreateGuestRequest, VideoCreateGuestResponse, + VideoDeleteCallRequest, + VideoDeleteCallResponse, VideoDeleteExternalStorageResponse, VideoDeleteRecordingResponse, VideoDeleteTranscriptionResponse, @@ -116,6 +118,12 @@ export interface CreateGuestRequest { videoCreateGuestRequest: VideoCreateGuestRequest | null; } +export interface DeleteCallRequest { + type: string; + id: string; + videoDeleteCallRequest: VideoDeleteCallRequest | null; +} + export interface DeleteCallTypeRequest { name: string; } @@ -650,6 +658,61 @@ export class ProductvideoApi extends runtime.BaseAPI { return await response.value(); } + /** + * Sends events: - call.deleted Required permissions: - DeleteCall + * Delete Call + */ + async deleteCallRaw(requestParameters: DeleteCallRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.type === null || requestParameters.type === undefined) { + throw new runtime.RequiredError('type','Required parameter requestParameters.type was null or undefined when calling deleteCall.'); + } + + if (requestParameters.id === null || requestParameters.id === undefined) { + throw new runtime.RequiredError('id','Required parameter requestParameters.id was null or undefined when calling deleteCall.'); + } + + if (requestParameters.videoDeleteCallRequest === null || requestParameters.videoDeleteCallRequest === undefined) { + throw new runtime.RequiredError('videoDeleteCallRequest','Required parameter requestParameters.videoDeleteCallRequest was null or undefined when calling deleteCall.'); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Stream-Auth-Type"] = this.configuration.apiKey("Stream-Auth-Type"); // stream-auth-type authentication + } + + if (this.configuration && this.configuration.apiKey) { + queryParameters["api_key"] = this.configuration.apiKey("api_key"); // api_key authentication + } + + if (this.configuration && this.configuration.apiKey) { + headerParameters["Authorization"] = this.configuration.apiKey("Authorization"); // JWT authentication + } + + const response = await this.request({ + path: `/video/call/{type}/{id}/delete`.replace(`{${"type"}}`, encodeURIComponent(String(requestParameters.type))).replace(`{${"id"}}`, encodeURIComponent(String(requestParameters.id))), + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: requestParameters.videoDeleteCallRequest, + }, initOverrides); + + return new runtime.JSONApiResponse(response); + } + + /** + * Sends events: - call.deleted Required permissions: - DeleteCall + * Delete Call + */ + async deleteCall(requestParameters: DeleteCallRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.deleteCallRaw(requestParameters, initOverrides); + return await response.value(); + } + /** * * Delete Call Type diff --git a/src/gen/video/models/index.ts b/src/gen/video/models/index.ts index ded7e70..f3568c8 100644 --- a/src/gen/video/models/index.ts +++ b/src/gen/video/models/index.ts @@ -231,6 +231,12 @@ export interface VideoBackstageSettingsRequest { * @memberof VideoBackstageSettingsRequest */ enabled?: boolean; + /** + * + * @type {number} + * @memberof VideoBackstageSettingsRequest + */ + join_ahead_time_seconds?: number; } /** * @@ -244,6 +250,12 @@ export interface VideoBackstageSettingsResponse { * @memberof VideoBackstageSettingsResponse */ enabled: boolean; + /** + * + * @type {number} + * @memberof VideoBackstageSettingsResponse + */ + join_ahead_time_seconds?: number; } /** * @@ -542,6 +554,12 @@ export interface VideoCallResponse { * @memberof VideoCallResponse */ ingress: VideoCallIngressResponse; + /** + * + * @type {number} + * @memberof VideoCallResponse + */ + join_ahead_time_seconds?: number; /** * * @type {boolean} @@ -633,6 +651,12 @@ export interface VideoCallSessionResponse { * @memberof VideoCallSessionResponse */ live_started_at?: string; + /** + * + * @type {{ [key: string]: string; }} + * @memberof VideoCallSessionResponse + */ + missed_by: { [key: string]: string; }; /** * * @type {Array} @@ -989,6 +1013,12 @@ export interface VideoCheckExternalStorageResponse { * @memberof VideoCheckExternalStorageResponse */ duration: string; + /** + * + * @type {string} + * @memberof VideoCheckExternalStorageResponse + */ + file_url: string; } /** * @@ -1260,8 +1290,20 @@ export interface VideoCreateExternalStorageRequest { * @type {string} * @memberof VideoCreateExternalStorageRequest */ - storage_type: string; + storage_type: VideoCreateExternalStorageRequestStorageTypeEnum; } + + +/** + * @export + */ +export const VideoCreateExternalStorageRequestStorageTypeEnum = { + S3: 's3', + GCS: 'gcs', + ABS: 'abs' +} as const; +export type VideoCreateExternalStorageRequestStorageTypeEnum = typeof VideoCreateExternalStorageRequestStorageTypeEnum[keyof typeof VideoCreateExternalStorageRequestStorageTypeEnum]; + /** * * @export @@ -1313,6 +1355,44 @@ export interface VideoCreateGuestResponse { */ user: VideoUserResponse; } +/** + * + * @export + * @interface VideoDeleteCallRequest + */ +export interface VideoDeleteCallRequest { + /** + * if true the call will be hard deleted along with all related data + * @type {boolean} + * @memberof VideoDeleteCallRequest + */ + hard?: boolean; +} +/** + * + * @export + * @interface VideoDeleteCallResponse + */ +export interface VideoDeleteCallResponse { + /** + * + * @type {VideoCallResponse} + * @memberof VideoDeleteCallResponse + */ + call: VideoCallResponse; + /** + * Duration of the request in human-readable format + * @type {string} + * @memberof VideoDeleteCallResponse + */ + duration: string; + /** + * + * @type {string} + * @memberof VideoDeleteCallResponse + */ + task_id?: string; +} /** * * @export @@ -1611,8 +1691,20 @@ export interface VideoExternalStorageResponse { * @type {string} * @memberof VideoExternalStorageResponse */ - type: string; + type: VideoExternalStorageResponseTypeEnum; } + + +/** + * @export + */ +export const VideoExternalStorageResponseTypeEnum = { + S3: 's3', + GCS: 'gcs', + ABS: 'abs' +} as const; +export type VideoExternalStorageResponseTypeEnum = typeof VideoExternalStorageResponseTypeEnum[keyof typeof VideoExternalStorageResponseTypeEnum]; + /** * * @export @@ -2577,6 +2669,12 @@ export interface VideoNotificationSettings { * @memberof VideoNotificationSettings */ call_live_started?: VideoEventNotificationSettings; + /** + * + * @type {VideoEventNotificationSettings} + * @memberof VideoNotificationSettings + */ + call_missed?: VideoEventNotificationSettings; /** * * @type {VideoEventNotificationSettings} @@ -3148,6 +3246,12 @@ export interface VideoRingSettingsRequest { * @memberof VideoRingSettingsRequest */ incoming_call_timeout_ms: number; + /** + * + * @type {number} + * @memberof VideoRingSettingsRequest + */ + missed_call_timeout_ms?: number; } /** * @@ -3167,6 +3271,12 @@ export interface VideoRingSettingsResponse { * @memberof VideoRingSettingsResponse */ incoming_call_timeout_ms: number; + /** + * + * @type {number} + * @memberof VideoRingSettingsResponse + */ + missed_call_timeout_ms: number; } /** * @@ -3940,8 +4050,20 @@ export interface VideoUpdateExternalStorageRequest { * @type {string} * @memberof VideoUpdateExternalStorageRequest */ - storage_type: string; + storage_type: VideoUpdateExternalStorageRequestStorageTypeEnum; } + + +/** + * @export + */ +export const VideoUpdateExternalStorageRequestStorageTypeEnum = { + S3: 's3', + GCS: 'gcs', + ABS: 'abs' +} as const; +export type VideoUpdateExternalStorageRequestStorageTypeEnum = typeof VideoUpdateExternalStorageRequestStorageTypeEnum[keyof typeof VideoUpdateExternalStorageRequestStorageTypeEnum]; + /** * * @export @@ -3977,8 +4099,20 @@ export interface VideoUpdateExternalStorageResponse { * @type {string} * @memberof VideoUpdateExternalStorageResponse */ - type: string; + type: VideoUpdateExternalStorageResponseTypeEnum; } + + +/** + * @export + */ +export const VideoUpdateExternalStorageResponseTypeEnum = { + S3: 's3', + GCS: 'gcs', + ABS: 'abs' +} as const; +export type VideoUpdateExternalStorageResponseTypeEnum = typeof VideoUpdateExternalStorageResponseTypeEnum[keyof typeof VideoUpdateExternalStorageResponseTypeEnum]; + /** * * @export @@ -4127,6 +4261,12 @@ export interface VideoUserResponse { * @memberof VideoUserResponse */ banned: boolean; + /** + * + * @type {Array} + * @memberof VideoUserResponse + */ + blocked_user_ids: Array; /** * Date/time of creation * @type {string} diff --git a/src/gen/video/runtime.ts b/src/gen/video/runtime.ts index 2465100..8ae6774 100644 --- a/src/gen/video/runtime.ts +++ b/src/gen/video/runtime.ts @@ -4,7 +4,7 @@ * Stream API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: v116.0.0 + * The version of the OpenAPI document: v120.0.0 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).