Skip to content

Commit 96884a3

Browse files
authored
feat: implement delete call endpoint (#45)
1 parent 2d81816 commit 96884a3

File tree

6 files changed

+333
-108
lines changed

6 files changed

+333
-108
lines changed

__tests__/call.test.ts

Lines changed: 108 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createTestClient } from './create-test-client';
44
import { StreamCall } from '../src/StreamCall';
55
import { StreamClient } from '../src/StreamClient';
66
import {
7+
VideoDeleteCallResponse,
78
VideoRecordSettingsRequestModeEnum,
89
VideoRecordSettingsRequestQualityEnum,
910
} from '../src/gen/video';
@@ -158,127 +159,136 @@ describe('call API', () => {
158159
);
159160
});
160161

161-
describe('recording', () => {
162-
it('enable call recording', async () => {
163-
let response = await call.update({
164-
settings_override: {
165-
recording: {
166-
mode: VideoRecordSettingsRequestModeEnum.DISABLED,
167-
audio_only: true,
168-
},
162+
it('enable call recording', async () => {
163+
let response = await call.update({
164+
settings_override: {
165+
recording: {
166+
mode: VideoRecordSettingsRequestModeEnum.DISABLED,
167+
audio_only: true,
169168
},
170-
});
171-
let settings = response.call.settings.recording;
169+
},
170+
});
171+
let settings = response.call.settings.recording;
172172

173-
expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.DISABLED);
173+
expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.DISABLED);
174174

175-
response = await call.update({
176-
settings_override: {
177-
recording: {
178-
mode: VideoRecordSettingsRequestModeEnum.AVAILABLE,
179-
},
175+
response = await call.update({
176+
settings_override: {
177+
recording: {
178+
mode: VideoRecordSettingsRequestModeEnum.AVAILABLE,
180179
},
181-
});
180+
},
181+
});
182182

183-
settings = response.call.settings.recording;
184-
expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.AVAILABLE);
183+
settings = response.call.settings.recording;
184+
expect(settings.mode).toBe(VideoRecordSettingsRequestModeEnum.AVAILABLE);
185185

186-
response = await call.update({
187-
settings_override: {
188-
recording: {
189-
audio_only: false,
190-
quality: VideoRecordSettingsRequestQualityEnum._1080P,
191-
mode: VideoRecordSettingsRequestModeEnum.AUTO_ON,
192-
},
186+
response = await call.update({
187+
settings_override: {
188+
recording: {
189+
audio_only: false,
190+
quality: VideoRecordSettingsRequestQualityEnum._1080P,
191+
mode: VideoRecordSettingsRequestModeEnum.AUTO_ON,
193192
},
194-
});
195-
196-
settings = response.call.settings.recording;
197-
expect(settings.audio_only).toBe(false);
198-
expect(settings.quality).toBe(
199-
VideoRecordSettingsRequestQualityEnum._1080P,
200-
);
193+
},
201194
});
202195

203-
it('start recording', async () => {
204-
// somewhat dummy test, we should do a proper test in the future where we join a call and start recording
205-
await expect(() => call.startRecording()).rejects.toThrowError(
206-
'Stream error code 4: StartRecording failed with error: "cannot record inactive call"',
207-
);
208-
});
196+
settings = response.call.settings.recording;
197+
expect(settings.audio_only).toBe(false);
198+
expect(settings.quality).toBe(VideoRecordSettingsRequestQualityEnum._1080P);
199+
});
209200

210-
it('stop recording', async () => {
211-
// somewhat dummy test, we should do a proper test in the future
212-
await expect(() => call.stopRecording()).rejects.toThrowError(
213-
'Stream error code 4: StopRecording failed with error: "call is not being recorded"',
214-
);
215-
});
201+
it('start recording', async () => {
202+
// somewhat dummy test, we should do a proper test in the future where we join a call and start recording
203+
await expect(() => call.startRecording()).rejects.toThrowError(
204+
'Stream error code 4: StartRecording failed with error: "cannot record inactive call"',
205+
);
206+
});
216207

217-
it('delete recording', async () => {
218-
// somewhat dummy test, we should do a proper test in the future
219-
await expect(() =>
220-
call.deleteRecording({ session: 'test', filename: 'test' }),
221-
).rejects.toThrowError(
222-
`Stream error code 16: DeleteRecording failed with error: "recording doesn't exist"`,
223-
);
224-
});
208+
it('stop recording', async () => {
209+
// somewhat dummy test, we should do a proper test in the future
210+
await expect(() => call.stopRecording()).rejects.toThrowError(
211+
'Stream error code 4: StopRecording failed with error: "call is not being recorded"',
212+
);
213+
});
225214

226-
it('query recordings', async () => {
227-
// somewhat dummy test, we should do a proper test in the future
228-
const response = await call.listRecordings();
215+
it('delete recording', async () => {
216+
// somewhat dummy test, we should do a proper test in the future
217+
await expect(() =>
218+
call.deleteRecording({ session: 'test', filename: 'test' }),
219+
).rejects.toThrowError(
220+
`Stream error code 16: DeleteRecording failed with error: "recording doesn't exist"`,
221+
);
222+
});
229223

230-
expect(response.recordings).toBeDefined();
224+
it('query recordings', async () => {
225+
// somewhat dummy test, we should do a proper test in the future
226+
const response = await call.listRecordings();
227+
228+
expect(response.recordings).toBeDefined();
229+
});
230+
231+
it('enable backstage mode', async () => {
232+
const response = await call.update({
233+
settings_override: {
234+
backstage: {
235+
enabled: true,
236+
},
237+
},
231238
});
232239

233-
describe('streaming', () => {
234-
it('enable backstage mode', async () => {
235-
const response = await call.update({
236-
settings_override: {
237-
backstage: {
238-
enabled: true,
239-
},
240-
},
241-
});
240+
expect(response.call.settings.backstage.enabled).toBe(true);
241+
});
242242

243-
expect(response.call.settings.backstage.enabled).toBe(true);
244-
});
243+
it('go live', async () => {
244+
const response = await call.goLive();
245245

246-
it('go live', async () => {
247-
const response = await call.goLive();
246+
expect(response.call.backstage).toBe(false);
247+
});
248248

249-
expect(response.call.backstage).toBe(false);
250-
});
249+
it('stop live', async () => {
250+
const response = await call.stopLive();
251251

252-
it('stop live', async () => {
253-
const response = await call.stopLive();
252+
expect(response.call.backstage).toBe(true);
253+
});
254254

255-
expect(response.call.backstage).toBe(true);
256-
});
257-
});
255+
it('start transcribing', async () => {
256+
// somewhat dummy test, we should do a proper test in the future where we join a call and start recording
257+
await expect(() => call.startTranscription()).rejects.toThrowError(
258+
'Stream error code 4: StartTranscription failed with error: "cannot transcribe inactive call"',
259+
);
260+
});
258261

259-
describe('transcriptions', () => {
260-
it('start transcribing', async () => {
261-
// somewhat dummy test, we should do a proper test in the future where we join a call and start recording
262-
await expect(() => call.startTranscription()).rejects.toThrowError(
263-
'Stream error code 4: StartTranscription failed with error: "cannot transcribe inactive call"',
264-
);
265-
});
262+
it('stop transcribing', async () => {
263+
// somewhat dummy test, we should do a proper test in the future
264+
await expect(() => call.stopTranscription()).rejects.toThrowError(
265+
'Stream error code 4: StopTranscription failed with error: "call is not being transcribed"',
266+
);
267+
});
266268

267-
it('stop transcribing', async () => {
268-
// somewhat dummy test, we should do a proper test in the future
269-
await expect(() => call.stopTranscription()).rejects.toThrowError(
270-
'Stream error code 4: StopTranscription failed with error: "call is not being transcribed"',
271-
);
272-
});
269+
it('delete transcription', async () => {
270+
// somewhat dummy test, we should do a proper test in the future
271+
await expect(() =>
272+
call.deleteTranscription({ session: 'test', filename: 'test' }),
273+
).rejects.toThrowError(
274+
`Stream error code 16: DeleteTranscription failed with error: "transcription doesn't exist"`,
275+
);
276+
});
273277

274-
it('delete transcription', async () => {
275-
// somewhat dummy test, we should do a proper test in the future
276-
await expect(() =>
277-
call.deleteTranscription({ session: 'test', filename: 'test' }),
278-
).rejects.toThrowError(
279-
`Stream error code 16: DeleteTranscription failed with error: "transcription doesn't exist"`,
280-
);
278+
it('delete call', async () => {
279+
let response: VideoDeleteCallResponse;
280+
try {
281+
response = await call.delete({ hard: true });
282+
} catch (e) {
283+
// the first request fails on backend sometimes
284+
// retry it
285+
await new Promise<void>((resolve) => {
286+
setTimeout(() => resolve(), 2000);
281287
});
282-
});
288+
289+
response = await call.delete({ hard: true });
290+
}
291+
292+
expect(response.duration).toBeDefined();
283293
});
284294
});

__tests__/external-recording-storage.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('external storage CRUD API', () => {
1515
const response = await client.video.createExternalStorage({
1616
name: storageName,
1717
bucket: 'test',
18-
storage_type: 'test',
18+
storage_type: 'abs',
1919
});
2020

2121
expect(response).toBeDefined();
@@ -32,7 +32,7 @@ describe('external storage CRUD API', () => {
3232
const newBucket = 'new bucket';
3333
const response = await client.video.updateExternalStorage(storageName, {
3434
bucket: newBucket,
35-
storage_type: 'test',
35+
storage_type: 'abs',
3636
});
3737

3838
expect(response.bucket).toBe('new bucket');

src/StreamCall.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
GetCallStatsRequest,
77
ProductvideoApi,
88
VideoBlockUserRequest,
9+
VideoDeleteCallRequest,
910
VideoGetOrCreateCallRequest,
1011
VideoGoLiveRequest,
1112
VideoMuteUsersRequest,
@@ -28,21 +29,32 @@ export class StreamCall {
2829

2930
constructor(
3031
private readonly streamClient: StreamClient,
31-
private readonly type: string,
32-
private readonly id: string,
32+
public readonly type: string,
33+
public readonly id: string,
3334
) {
3435
this.baseRequest = { id: this.id, type: this.type };
3536
const configuration = this.streamClient.getConfiguration('video');
3637
this.apiClient = new ProductvideoApi(configuration);
3738
}
3839

40+
get cid() {
41+
return `${this.type}:${this.id}`;
42+
}
43+
3944
blockUser = (videoBlockUserRequest: VideoBlockUserRequest) => {
4045
return this.apiClient.blockUser({
4146
...this.baseRequest,
4247
videoBlockUserRequest,
4348
});
4449
};
4550

51+
delete = (videoDeleteCallRequest?: VideoDeleteCallRequest) => {
52+
return this.apiClient.deleteCall({
53+
...this.baseRequest,
54+
videoDeleteCallRequest: videoDeleteCallRequest ?? null,
55+
});
56+
};
57+
4658
endCall = () => {
4759
return this.apiClient.endCall({ ...this.baseRequest });
4860
};

src/gen/video/apis/ProductvideoApi.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Stream API
55
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
66
*
7-
* The version of the OpenAPI document: v116.0.0
7+
* The version of the OpenAPI document: v120.0.0
88
*
99
*
1010
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -28,6 +28,8 @@ import type {
2828
VideoCreateExternalStorageResponse,
2929
VideoCreateGuestRequest,
3030
VideoCreateGuestResponse,
31+
VideoDeleteCallRequest,
32+
VideoDeleteCallResponse,
3133
VideoDeleteExternalStorageResponse,
3234
VideoDeleteRecordingResponse,
3335
VideoDeleteTranscriptionResponse,
@@ -116,6 +118,12 @@ export interface CreateGuestRequest {
116118
videoCreateGuestRequest: VideoCreateGuestRequest | null;
117119
}
118120

121+
export interface DeleteCallRequest {
122+
type: string;
123+
id: string;
124+
videoDeleteCallRequest: VideoDeleteCallRequest | null;
125+
}
126+
119127
export interface DeleteCallTypeRequest {
120128
name: string;
121129
}
@@ -650,6 +658,61 @@ export class ProductvideoApi extends runtime.BaseAPI {
650658
return await response.value();
651659
}
652660

661+
/**
662+
* Sends events: - call.deleted Required permissions: - DeleteCall
663+
* Delete Call
664+
*/
665+
async deleteCallRaw(requestParameters: DeleteCallRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<VideoDeleteCallResponse>> {
666+
if (requestParameters.type === null || requestParameters.type === undefined) {
667+
throw new runtime.RequiredError('type','Required parameter requestParameters.type was null or undefined when calling deleteCall.');
668+
}
669+
670+
if (requestParameters.id === null || requestParameters.id === undefined) {
671+
throw new runtime.RequiredError('id','Required parameter requestParameters.id was null or undefined when calling deleteCall.');
672+
}
673+
674+
if (requestParameters.videoDeleteCallRequest === null || requestParameters.videoDeleteCallRequest === undefined) {
675+
throw new runtime.RequiredError('videoDeleteCallRequest','Required parameter requestParameters.videoDeleteCallRequest was null or undefined when calling deleteCall.');
676+
}
677+
678+
const queryParameters: any = {};
679+
680+
const headerParameters: runtime.HTTPHeaders = {};
681+
682+
headerParameters['Content-Type'] = 'application/json';
683+
684+
if (this.configuration && this.configuration.apiKey) {
685+
headerParameters["Stream-Auth-Type"] = this.configuration.apiKey("Stream-Auth-Type"); // stream-auth-type authentication
686+
}
687+
688+
if (this.configuration && this.configuration.apiKey) {
689+
queryParameters["api_key"] = this.configuration.apiKey("api_key"); // api_key authentication
690+
}
691+
692+
if (this.configuration && this.configuration.apiKey) {
693+
headerParameters["Authorization"] = this.configuration.apiKey("Authorization"); // JWT authentication
694+
}
695+
696+
const response = await this.request({
697+
path: `/video/call/{type}/{id}/delete`.replace(`{${"type"}}`, encodeURIComponent(String(requestParameters.type))).replace(`{${"id"}}`, encodeURIComponent(String(requestParameters.id))),
698+
method: 'POST',
699+
headers: headerParameters,
700+
query: queryParameters,
701+
body: requestParameters.videoDeleteCallRequest,
702+
}, initOverrides);
703+
704+
return new runtime.JSONApiResponse(response);
705+
}
706+
707+
/**
708+
* Sends events: - call.deleted Required permissions: - DeleteCall
709+
* Delete Call
710+
*/
711+
async deleteCall(requestParameters: DeleteCallRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<VideoDeleteCallResponse> {
712+
const response = await this.deleteCallRaw(requestParameters, initOverrides);
713+
return await response.value();
714+
}
715+
653716
/**
654717
*
655718
* Delete Call Type

0 commit comments

Comments
 (0)