whio-api-sdk 1.0.206-beta-staging → 1.0.207-beta-staging

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.
@@ -1,1312 +0,0 @@
1
- // sdk.ts
2
- import {
3
- LoginResponse,
4
- LoginCredentials,
5
- SDKConfig,
6
- User,
7
- AssignTeamRoleDto,
8
- CreateTeamDto,
9
- UpdateTeamDto,
10
- CreateTemplateDto,
11
- UpdateTemplateDto,
12
- GenerateTranscriptionSummaryDto,
13
- UpdateTranscriptionSummaryDto,
14
- CreateTranscriptionSummaryDto,
15
- AssignOrganizationRoleDto,
16
- CreateUserTemplateDto,
17
- UpdateUserTemplateDto,
18
- CreateUserDto,
19
- UpdateUserDto,
20
- CreateOrganizationDto,
21
- UpdateOrganizationDto,
22
- CreateTemplateCategoryDto,
23
- UpdateTemplateCategoryDto,
24
- AssignTeamTemplateDto,
25
- OrganizationRoleType,
26
- RoleType,
27
- Organization,
28
- TemplateCategory,
29
- Template,
30
- Team,
31
- UserTemplate,
32
- TranscriptionSummary,
33
- TranscriptionAudioUploadResponse,
34
- ChangePasswordDto,
35
- AdminChangePasswordDto,
36
- PasswordChangeResponse,
37
- Session,
38
- CreateSessionDto,
39
- UpdateSessionDto,
40
- Agent,
41
- CreateAgentDto,
42
- UpdateAgentDto,
43
- AudioFile,
44
- AudioFileStatus,
45
- CreateAudioFileDto,
46
- UpdateAudioFileDto,
47
- UploadAudioFileDto,
48
- AgentSettings,
49
- CreateAgentSettingsDto,
50
- UpdateAgentSettingsDto,
51
- Workflow,
52
- CreateWorkflowDto,
53
- UpdateWorkflowDto,
54
- Base64AudioFile,
55
- CreateBase64AudioFileDto,
56
- UpdateBase64AudioFileDto,
57
- AddBase64ChunkResponse,
58
- Log,
59
- LogsResponse,
60
- LogStats,
61
- FilterLogsDto,
62
- CreateLogDto,
63
- DebugSessionSummary,
64
- } from './types';
65
- import urls from './urls';
66
- import { jwtDecode } from 'jwt-decode';
67
-
68
- export class ApiSDK {
69
- private baseUrl: string;
70
- private storage: SDKConfig['storage'];
71
- private accessToken: string | null = null;
72
- private refreshToken: string | null = null;
73
- private user: User | null = null;
74
-
75
- constructor(config: SDKConfig = {}) {
76
- this.baseUrl = config.baseUrl || '/api';
77
- this.storage = config.storage;
78
- this.initialize();
79
- }
80
-
81
- public async fetchConfig(url: string): Promise<void> {
82
- const response = await fetch(url);
83
- if (!response.ok) {
84
- throw new Error(`Failed to fetch config from ${url}`);
85
- }
86
- const conf = await response.json();
87
- this.baseUrl = conf.baseUrl || this.baseUrl;
88
- }
89
-
90
- private async getToken() {
91
- const accessToken = await this.storage!.getItem('access_token');
92
- this.accessToken = accessToken ? JSON.parse(accessToken) : null;
93
- if (!this.accessToken) {
94
- throw new Error('Access token not found');
95
- }
96
-
97
- // Check if token is expired or expiring soon
98
- if (this.isTokenExpired(this.accessToken)) {
99
- // Try to refresh the token
100
- if (this.refreshToken) {
101
- await this.refreshAccessToken();
102
- } else {
103
- throw new Error('Access token expired and no refresh token available');
104
- }
105
- }
106
- }
107
-
108
- private async initialize() {
109
- const accessToken = await this.storage!.getItem('access_token');
110
- const refreshToken = await this.storage!.getItem('refresh_token');
111
- const userString = await this.storage!.getItem('user');
112
- this.user = userString ? JSON.parse(userString) : null;
113
- this.accessToken = accessToken ? JSON.parse(accessToken) : null;
114
- this.refreshToken = refreshToken ? JSON.parse(refreshToken) : null;
115
- }
116
-
117
- private async request<T>(
118
- endpoint: string,
119
- method: string = 'GET',
120
- body?: any,
121
- headers: Record<string, string> = {},
122
- noToken: boolean = false,
123
- ): Promise<T> {
124
- const url = `${this.baseUrl}${endpoint}`;
125
- const defaultHeaders: Record<string, string> = {
126
- 'Content-Type': 'application/json',
127
- 'ngrok-skip-browser-warning': 'true'
128
- };
129
-
130
- if (noToken) {
131
- defaultHeaders['Authorization'] = '';
132
- } else {
133
- // If no token is available, try to get it
134
- await this.getToken();
135
- }
136
-
137
-
138
- if (this.accessToken) {
139
- defaultHeaders['Authorization'] = `Bearer ${this.accessToken}`;
140
- }
141
-
142
- const response = await fetch(url, {
143
- method,
144
- headers: { ...defaultHeaders, ...headers },
145
- body: body ? JSON.stringify(body) : undefined,
146
- });
147
-
148
- if (!response.ok) {
149
- const errorData = await response.json().catch(() => ({}));
150
- throw new Error(
151
- errorData.message || `Request failed with status ${response.status}`
152
- );
153
- }
154
-
155
- return response.json();
156
- }
157
-
158
- private async fileUploadRequest<T>(
159
- endpoint: string,
160
- body?: FormData,
161
- headers: Record<string, string> = {}
162
- ): Promise<T> {
163
- const url = `${this.baseUrl}${endpoint}`;
164
- const defaultHeaders: Record<string, string> = {
165
- 'ngrok-skip-browser-warning': 'true'
166
- };
167
-
168
- if (this.accessToken) {
169
- defaultHeaders['Authorization'] = `Bearer ${this.accessToken}`;
170
- }
171
-
172
- // Don't set Content-Type for FormData - let browser set it with boundary
173
- const response = await fetch(url, {
174
- method: 'POST',
175
- headers: { ...defaultHeaders, ...headers },
176
- body,
177
- });
178
-
179
- if (!response.ok) {
180
- const errorData = await response.json().catch(() => ({}));
181
- throw new Error(
182
- errorData.message || `Request failed with status ${response.status}`
183
- );
184
- }
185
-
186
- return response.json();
187
- }
188
-
189
- public async login(credentials: LoginCredentials): Promise<LoginResponse> {
190
- try {
191
- const response = await this.request<LoginResponse>(
192
- '/auth/login',
193
- 'POST',
194
- credentials,
195
- {},
196
- true
197
- );
198
- this.accessToken = response.access_token;
199
- this.refreshToken = response.refresh_token;
200
-
201
- this.user = response.user;
202
-
203
- await this.storage!.setItem('access_token', JSON.stringify(response.access_token));
204
- await this.storage!.setItem('refresh_token', JSON.stringify(response.refresh_token));
205
- await this.storage!.setItem('user', JSON.stringify(response.user));
206
-
207
- return response;
208
- } catch (error) {
209
- await this.clearAuth();
210
- throw error;
211
- }
212
- }
213
-
214
- public async logout(): Promise<void> {
215
- await this.clearAuth();
216
- }
217
-
218
- private async clearAuth(): Promise<void> {
219
- this.accessToken = null;
220
- this.refreshToken = null;
221
- this.user = null;
222
- await this.storage!.removeItem('access_token');
223
- await this.storage!.removeItem('refresh_token');
224
- await this.storage!.removeItem('user');
225
- }
226
-
227
- private isTokenExpired(token: string, bufferMinutes: number = 5): boolean {
228
- try {
229
- const decoded: any = jwtDecode(token);
230
- const currentTime = Date.now() / 1000;
231
- const bufferTime = bufferMinutes * 60;
232
-
233
- return decoded.exp <= (currentTime + bufferTime);
234
- } catch (error) {
235
- // If we can't decode the token, consider it expired
236
- return true;
237
- }
238
- }
239
-
240
- private async refreshAccessToken(): Promise<void> {
241
- if (!this.refreshToken) {
242
- throw new Error('No refresh token available');
243
- }
244
-
245
- try {
246
- const response = await this.request<LoginResponse>(
247
- '/auth/refresh',
248
- 'POST',
249
- { refresh_token: this.refreshToken },
250
- {},
251
- true // Skip token validation for this request
252
- );
253
-
254
- this.accessToken = response.access_token;
255
- this.refreshToken = response.refresh_token;
256
- this.user = response.user;
257
-
258
- await this.storage!.setItem('access_token', JSON.stringify(response.access_token));
259
- await this.storage!.setItem('refresh_token', JSON.stringify(response.refresh_token));
260
- await this.storage!.setItem('user', JSON.stringify(response.user));
261
- } catch (error) {
262
- await this.clearAuth();
263
- throw new Error('Failed to refresh access token');
264
- }
265
- }
266
-
267
- public isAuthenticated(): boolean {
268
- return !!this.accessToken;
269
- }
270
-
271
- public getCurrentUser(): User | null {
272
- return this.user;
273
- }
274
-
275
- public getAccessToken(): string | null {
276
- return this.accessToken;
277
- }
278
-
279
- public getRefreshToken(): string | null {
280
- return this.refreshToken;
281
- }
282
-
283
- public async createUser(
284
- firstName: string, lastName: string,
285
- email: string, password: string): Promise<User> {
286
-
287
- const createUserDto: CreateUserDto = {
288
- firstName,
289
- lastName,
290
- email,
291
- password,
292
- organizationId: this.user?.organizationId,
293
- };
294
-
295
- const user = await this.request<User>(
296
- urls.users,
297
- 'POST',
298
- createUserDto
299
- );
300
- return user;
301
- }
302
-
303
- private async assignRoleToUser(userId: string, roleName: OrganizationRoleType, organizationId?: string): Promise<User> {
304
- const orgId = organizationId || this.user?.organizationId;
305
- const organization = await this.request<Organization>(
306
- `${urls.organizations}/${orgId}`,
307
- 'GET'
308
- );
309
- const orgRoleEditor = organization.roles!.find(
310
- r => r.name === roleName);
311
- const assignRoleDto:AssignOrganizationRoleDto = {
312
- userId: userId,
313
- organizationRoleId: orgRoleEditor!.id,
314
- };
315
- this.request(urls.userOrganizationRoles, 'POST', assignRoleDto);
316
- const userWithOrgRole = await this.request<User>(
317
- `${urls.user}/${userId}`,
318
- 'GET'
319
- );
320
- return userWithOrgRole;
321
- }
322
-
323
- public async assignEditorToRoleToUser(userId: string, organizationId?: string): Promise<User> {
324
- return this.assignRoleToUser(userId, OrganizationRoleType.EDITOR, organizationId);
325
- }
326
-
327
- public async assignAdminToRoleToUser(userId: string, organizationId?: string): Promise<User> {
328
- return this.assignRoleToUser(userId, OrganizationRoleType.ADMIN, organizationId);
329
- }
330
-
331
- public async assignDisabledToRoleToUser(userId: string, organizationId?: string): Promise<User> {
332
- return this.assignRoleToUser(userId, OrganizationRoleType.DISABLED, organizationId);
333
- }
334
-
335
- public async createEditorUser(firstName: string, lastName: string,
336
- email: string, password: string): Promise<User> {
337
- const user = await this.createUser(firstName, lastName, email, password);
338
- const userWithOrgRole = await this.assignEditorToRoleToUser(user.id);
339
- return userWithOrgRole;
340
- }
341
-
342
- public async createAdminUser(firstName: string, lastName: string,
343
- email: string, password: string): Promise<User> {
344
- const user = await this.createUser(firstName, lastName, email, password);
345
- const userWithOrgRole = await this.assignAdminToRoleToUser(user.id);
346
- return userWithOrgRole;
347
- }
348
-
349
- public async createDisabledUser(firstName: string, lastName: string,
350
- email: string, password: string): Promise<User> {
351
- const user = await this.createUser(firstName, lastName, email, password);
352
- const userWithOrgRole = await this.assignDisabledToRoleToUser(user.id);
353
- return userWithOrgRole;
354
- }
355
-
356
- public async createTeam(name: string, description: string): Promise<Team> {
357
- const teamDto: CreateTeamDto = {
358
- name,
359
- description,
360
- organizationId: this.user!.organizationId,
361
- };
362
- return this.request(urls.teams, 'POST', teamDto);
363
- }
364
-
365
- public async updateTeam(id: string, name: string, description: string): Promise<Team> {
366
- const teamDto: UpdateTeamDto = {
367
- name,
368
- description,
369
- };
370
- return this.request<Team>(`${urls.teams}/${id}`, 'PATCH', teamDto);
371
- }
372
-
373
- public async addUserToTeam(teamId: string, userId: string, roleName: string): Promise<any> {
374
- const assignRoleDto: AssignTeamRoleDto = {
375
- teamId,
376
- userId,
377
- name: roleName,
378
- };
379
- return this.request(urls.teamRoles, 'POST', assignRoleDto);
380
- }
381
-
382
- public async removeUserFromTeam(teamId: string, userId: string): Promise<void> {
383
- await this.request(`${urls.teamRoles}/user/${userId}/team/${teamId}`, 'DELETE');
384
- }
385
- public async createTemplate(title: string, content: string, categoryId?: string, workflowId?: string, agentId?: string): Promise<Template> {
386
- let finalCategoryId = categoryId;
387
- if (!finalCategoryId) {
388
- const templateCategories = await this.request<TemplateCategory[]>(
389
- urls.templateCategories,
390
- 'GET'
391
- );
392
- finalCategoryId = templateCategories[0]?.id;
393
- if (!finalCategoryId) {
394
- throw new Error('No template categories available. Please create one first.');
395
- }
396
- }
397
-
398
- const createTemplateDto: CreateTemplateDto = {
399
- title,
400
- content,
401
- isGlobal: false,
402
- categoryId: finalCategoryId,
403
- createdById: this.user!.id,
404
- organizationId: this.user!.organizationId,
405
- workflowId,
406
- agentId,
407
- };
408
- return this.request<Template>(urls.templates, 'POST', createTemplateDto);
409
- }
410
-
411
- public async createUserTemplate(
412
- title: string, content: string, originalTemplateId: string | undefined): Promise<UserTemplate> {
413
- const createUserTemplateDto: CreateUserTemplateDto = {
414
- title,
415
- content,
416
- originalTemplateId,
417
- userId: this.user!.id,
418
- };
419
- return this.request(urls.userTemplates, 'POST', createUserTemplateDto);
420
- }
421
-
422
- public async updateTemplate(
423
- title: string, content: string, id: string, workflowId?: string, agentId?: string): Promise<Template> {
424
- const templateDto: UpdateTemplateDto = {
425
- title,
426
- content,
427
- isGlobal: false,
428
- organizationId: this.user!.organizationId,
429
- workflowId,
430
- agentId,
431
- };
432
- return this.request<Template>(
433
- `${urls.templates}/${id}`,
434
- 'PATCH',
435
- templateDto,
436
- );
437
- }
438
-
439
- public async updateUserTemplate(
440
- title: string, content: string, id: string): Promise<UserTemplate> {
441
- const userTemplateDto: UpdateUserTemplateDto = {
442
- title,
443
- content,
444
- };
445
- return this.request<UserTemplate>(
446
- `${urls.userTemplates}/${id}`,
447
- 'PATCH',
448
- userTemplateDto,
449
- );
450
- }
451
-
452
- public async getTemplates(): Promise<Template[]> {
453
- return this.request<Template[]>(urls.templates, 'GET');
454
- }
455
-
456
- public async getTemplatesByOrganization(): Promise<Template[]> {
457
- return this.request<Template[]>(`${urls.templates}/organization`, 'GET');
458
- }
459
-
460
- public async getUserTemplates(): Promise<UserTemplate[]> {
461
- const url = `${urls.userTemplates}/user/${this.user!.id}`;
462
- return this.request<UserTemplate[]>(url, 'GET');
463
- }
464
-
465
- // ======================
466
- // trANSCRIPTION SUMMARY METHODS
467
- // ======================
468
-
469
- public async generateTranscriptionSummary(
470
- templateId: string, sessionId: string): Promise<TranscriptionSummary> {
471
- const generateSummaryDto: GenerateTranscriptionSummaryDto = {
472
- templateId,
473
- userId: this.user!.id,
474
- fromUserTemplate: false,
475
- sessionId: sessionId,
476
- };
477
- const transcriptionSummary:TranscriptionSummary = await this.request(
478
- urls.transcriptionSummary,
479
- 'POST',
480
- generateSummaryDto
481
- );
482
- return transcriptionSummary;
483
- }
484
-
485
- public async getByOrganizationTranscriptionSummaries(
486
- organizationId: string): Promise<TranscriptionSummary[]> {
487
- return this.request<TranscriptionSummary[]>(
488
- `${urls.transcriptionSummaries}/organization/${organizationId}`,
489
- 'GET'
490
- );
491
- }
492
-
493
- public async generateTranscriptionSummaryFromUserTemplate(
494
- userTemplateId: string, sessionId: string): Promise<TranscriptionSummary> {
495
- const generateSummaryDto: GenerateTranscriptionSummaryDto = {
496
- templateId: userTemplateId,
497
- userId: this.user!.id,
498
- fromUserTemplate: true,
499
- sessionId: sessionId,
500
- };
501
- const transcriptionSummary: TranscriptionSummary = await this.request(
502
- urls.transcriptionSummary,
503
- 'POST',
504
- generateSummaryDto
505
- );
506
- return transcriptionSummary;
507
- }
508
-
509
- public async updateTranscriptionSummary(
510
- id: string, content: string): Promise<TranscriptionSummary> {
511
- const updateSummaryDto: UpdateTranscriptionSummaryDto = {
512
- content,
513
- };
514
- return this.request<TranscriptionSummary>(
515
- `${urls.transcriptionSummary}/${id}`,
516
- 'PATCH',
517
- updateSummaryDto,
518
- );
519
- }
520
-
521
- public async uploadLargeAudioFile(formData: FormData): Promise<string> {
522
- const uploadId: string = await this.fileUploadRequest(
523
- urls.uploadAudioLarge,
524
- formData
525
- );
526
- const uploadIds: string = await this.storage!.getItem('uploadIds') || '[]';
527
- const uploadIdsArray = JSON.parse(uploadIds);
528
- await this.storage!.setItem('uploadIds', JSON.stringify([...uploadIdsArray, uploadId]));
529
- return uploadId;
530
- }
531
-
532
- public async uploadAudioFile(formData: FormData): Promise<TranscriptionAudioUploadResponse | null> {
533
- const data: TranscriptionAudioUploadResponse = await this.fileUploadRequest(
534
- urls.uploadAudio,
535
- formData,
536
- );
537
- return data;
538
- }
539
-
540
- public async transcribeBase64Audio(base64String: string): Promise<string> {
541
- const transcript = await this.request<any>(
542
- urls.transcribeBase64Audio,
543
- 'POST',
544
- { base64Audio: base64String });
545
- return transcript.transcript;
546
- }
547
-
548
- // ======================
549
- // AUTH METHODS
550
- // ======================
551
-
552
- public async getProfile(): Promise<User> {
553
- return this.request<User>(urls.profile, 'GET');
554
- }
555
-
556
- public async changePassword(currentPassword: string, newPassword: string): Promise<PasswordChangeResponse> {
557
- const dto: ChangePasswordDto = {
558
- currentPassword,
559
- newPassword,
560
- };
561
- return this.request<PasswordChangeResponse>(urls.changePassword, 'PATCH', dto);
562
- }
563
-
564
- public async adminChangePassword(userId: string, newPassword: string): Promise<PasswordChangeResponse> {
565
- const dto: AdminChangePasswordDto = {
566
- userId,
567
- newPassword,
568
- };
569
- return this.request<PasswordChangeResponse>(urls.adminChangePassword, 'PATCH', dto);
570
- }
571
-
572
- // ======================
573
- // ORGANIZATION METHODS
574
- // ======================
575
-
576
- public async createOrganization(name: string, description?: string): Promise<Organization> {
577
- const dto: CreateOrganizationDto = { name, description };
578
- return this.request<Organization>(urls.organizations, 'POST', dto);
579
- }
580
-
581
- public async getOrganizations(): Promise<Organization[]> {
582
- return this.request<Organization[]>(urls.organizations, 'GET');
583
- }
584
-
585
- public async getOrganization(id: string): Promise<Organization> {
586
- return this.request<Organization>(`${urls.organizations}/${id}`, 'GET');
587
- }
588
-
589
- public async updateOrganization(id: string, name?: string, description?: string): Promise<Organization> {
590
- const dto: UpdateOrganizationDto = { name, description };
591
- return this.request<Organization>(`${urls.organizations}/${id}`, 'PATCH', dto);
592
- }
593
-
594
- public async deleteOrganization(id: string): Promise<void> {
595
- await this.request(`${urls.organizations}/${id}`, 'DELETE');
596
- }
597
-
598
- public async addUserToOrganization(organizationId: string, userId: string): Promise<void> {
599
- await this.request(`${urls.organizations}/${organizationId}/users/${userId}`, 'POST');
600
- }
601
-
602
- public async removeUserFromOrganization(organizationId: string, userId: string): Promise<void> {
603
- await this.request(`${urls.organizations}/${organizationId}/users/${userId}`, 'DELETE');
604
- }
605
-
606
- // ======================
607
- // USER METHODS
608
- // ======================
609
-
610
- public async getUsers(): Promise<User[]> {
611
- return this.request<User[]>(urls.users, 'GET');
612
- }
613
-
614
- public async getUser(id: string): Promise<User> {
615
- return this.request<User>(`${urls.users}/${id}`, 'GET');
616
- }
617
-
618
- public async getUsersByOrganization(organizationId: string): Promise<User[]> {
619
- return this.request<User[]>(`${urls.users}/organization/${organizationId}`, 'GET');
620
- }
621
-
622
- public async updateUser(id: string, data: UpdateUserDto): Promise<User> {
623
- return this.request<User>(`${urls.users}/${id}`, 'PATCH', data);
624
- }
625
-
626
- public async deleteUser(id: string): Promise<void> {
627
- await this.request(`${urls.users}/${id}`, 'DELETE');
628
- }
629
-
630
- // ======================
631
- // TEAM METHODS
632
- // ======================
633
-
634
- public async getTeams(): Promise<Team[]> {
635
- return this.request<Team[]>(urls.teams, 'GET');
636
- }
637
-
638
- public async getTeam(id: string): Promise<Team> {
639
- return this.request<Team>(`${urls.teams}/${id}`, 'GET');
640
- }
641
-
642
- public async getTeamsByOrganization(organizationId: string): Promise<Team[]> {
643
- return this.request<Team[]>(`${urls.teams}/organization/${organizationId}`, 'GET');
644
- }
645
-
646
- public async deleteTeam(id: string): Promise<void> {
647
- await this.request(`${urls.teams}/${id}`, 'DELETE');
648
- }
649
-
650
- // ======================
651
- // TEMPLATE CATEGORY METHODS
652
- // ======================
653
-
654
- public async getTemplateCategories(): Promise<TemplateCategory[]> {
655
- return this.request<TemplateCategory[]>(urls.templateCategories, 'GET');
656
- }
657
-
658
- public async getTemplateCategory(id: string): Promise<TemplateCategory> {
659
- return this.request<TemplateCategory>(`${urls.templateCategories}/${id}`, 'GET');
660
- }
661
-
662
- public async createTemplateCategory(name: string): Promise<TemplateCategory> {
663
- const dto: CreateTemplateCategoryDto = { name };
664
- return this.request<TemplateCategory>(urls.templateCategories, 'POST', dto);
665
- }
666
-
667
- public async updateTemplateCategory(id: string, name: string): Promise<TemplateCategory> {
668
- const dto: UpdateTemplateCategoryDto = { name };
669
- return this.request<TemplateCategory>(`${urls.templateCategories}/${id}`, 'PATCH', dto);
670
- }
671
-
672
- public async deleteTemplateCategory(id: string): Promise<void> {
673
- await this.request(`${urls.templateCategories}/${id}`, 'DELETE');
674
- }
675
-
676
- // ======================
677
- // ENHANCED TEMPLATE METHODS
678
- // ======================
679
-
680
- public async getTemplate(id: string): Promise<Template> {
681
- return this.request<Template>(`${urls.templates}/${id}`, 'GET');
682
- }
683
-
684
- public async deleteTemplate(id: string): Promise<void> {
685
- await this.request(`${urls.templates}/${id}`, 'DELETE');
686
- }
687
-
688
- public async getUserTemplate(id: string): Promise<UserTemplate> {
689
- return this.request<UserTemplate>(`${urls.userTemplates}/${id}`, 'GET');
690
- }
691
-
692
- public async deleteUserTemplate(id: string): Promise<void> {
693
- await this.request(`${urls.userTemplates}/${id}`, 'DELETE');
694
- }
695
-
696
- // ======================
697
- // TEAM TEMPLATE METHODS
698
- // ======================
699
-
700
- public async assignTemplateToTeam(teamId: string, templateId: string): Promise<void> {
701
- const dto: AssignTeamTemplateDto = { teamId, templateId };
702
- await this.request(urls.teamTemplates, 'POST', dto);
703
- }
704
-
705
- public async removeTemplateFromTeam(teamId: string, templateId: string): Promise<void> {
706
- await this.request(`${urls.teamTemplates}/team/${teamId}/template/${templateId}`, 'DELETE');
707
- }
708
-
709
- // ======================
710
- // TRANSCRIPTION SUMMARY METHODS
711
- // ======================
712
-
713
- public async getTranscriptionSummaries(): Promise<TranscriptionSummary[]> {
714
- return this.request<TranscriptionSummary[]>(urls.transcriptionSummaries, 'GET');
715
- }
716
-
717
- public async getTranscriptionSummary(id: string): Promise<TranscriptionSummary> {
718
- return this.request<TranscriptionSummary>(`${urls.transcriptionSummaries}/${id}`, 'GET');
719
- }
720
-
721
- public async getTranscriptionSummariesByUser(userId: string): Promise<TranscriptionSummary[]> {
722
- return this.request<TranscriptionSummary[]>(`${urls.transcriptionSummaries}/user/${userId}`, 'GET');
723
- }
724
-
725
- public async deleteTranscriptionSummary(id: string): Promise<void> {
726
- await this.request(`${urls.transcriptionSummaries}/${id}`, 'DELETE');
727
- }
728
-
729
- // ======================
730
- // ENHANCED TEAM ROLE METHODS
731
- // ======================
732
-
733
- public async removeUserFromTeamFixed(teamId: string, userId: string): Promise<void> {
734
- await this.request(`${urls.teamRoles}/user/${userId}/team/${teamId}`, 'DELETE');
735
- }
736
-
737
- // ======================
738
- // SESSION METHODS
739
- // ======================
740
-
741
- public async createSession(sessionData: CreateSessionDto): Promise<Session> {
742
- return this.request<Session>(urls.sessions, 'POST', sessionData);
743
- }
744
-
745
- public async getSessions(): Promise<Session[]> {
746
- return this.request<Session[]>(`${urls.sessions}/my-sessions`, 'GET');
747
- }
748
-
749
- public async getSession(id: string): Promise<Session> {
750
- return this.request<Session>(`${urls.sessions}/${id}`, 'GET');
751
- }
752
-
753
- public async getSessionsByUser(userId: string): Promise<Session[]> {
754
- return this.request<Session[]>(`${urls.sessions}/user/${userId}`, 'GET');
755
- }
756
-
757
- public async getSessionsByOrganization(): Promise<Session[]> {
758
- return this.request<Session[]>(`${urls.sessions}/organization`, 'GET');
759
- }
760
-
761
- public async updateSession(id: string, sessionData: UpdateSessionDto): Promise<Session> {
762
- return this.request<Session>(`${urls.sessions}/${id}`, 'PATCH', sessionData);
763
- }
764
-
765
- public async deleteSession(id: string): Promise<void> {
766
- await this.request(`${urls.sessions}/${id}`, 'DELETE');
767
- }
768
-
769
- public async setPrimaryTranscriptionSummary(sessionId: string, summaryId: string): Promise<Session> {
770
- return this.request<Session>(`${urls.sessions}/${sessionId}/primary-summary/${summaryId}`, 'PATCH');
771
- }
772
-
773
- public async rerunTranscription(sessionId: string): Promise<{ message: string; sessionId: string }> {
774
- return this.request<{ message: string; sessionId: string }>(`${urls.sessions}/${sessionId}/rerun-transcription`, 'POST');
775
- }
776
-
777
- // ======================
778
- // AGENT METHODS
779
- // ======================
780
-
781
- public async createAgent(name: string, templateTextReplacement?: string): Promise<Agent> {
782
- const dto: CreateAgentDto = { name, templateTextReplacement };
783
- return this.request<Agent>(urls.agents, 'POST', dto);
784
- }
785
-
786
- public async getAgents(): Promise<Agent[]> {
787
- return this.request<Agent[]>(urls.agents, 'GET');
788
- }
789
-
790
- public async getAgent(id: string): Promise<Agent> {
791
- return this.request<Agent>(`${urls.agents}/${id}`, 'GET');
792
- }
793
-
794
- public async updateAgent(id: string, name: string, templateTextReplacement?: string): Promise<Agent> {
795
- const dto: UpdateAgentDto = { name, templateTextReplacement };
796
- return this.request<Agent>(`${urls.agents}/${id}`, 'PATCH', dto);
797
- }
798
-
799
- public async deleteAgent(id: string): Promise<void> {
800
- await this.request(`${urls.agents}/${id}`, 'DELETE');
801
- }
802
-
803
- public async addAgentToOrganization(agentId: string, organizationId: string): Promise<void> {
804
- await this.request(`${urls.agents}/${agentId}/organizations/${organizationId}`, 'POST');
805
- }
806
-
807
- public async removeAgentFromOrganization(agentId: string, organizationId: string): Promise<void> {
808
- await this.request(`${urls.agents}/${agentId}/organizations/${organizationId}`, 'DELETE');
809
- }
810
-
811
- // ======================
812
- // AGENT SETTINGS METHODS
813
- // ======================
814
-
815
- public async createAgentSettings(settingsData: CreateAgentSettingsDto): Promise<AgentSettings> {
816
- return this.request<AgentSettings>(urls.agentSettings, 'POST', settingsData);
817
- }
818
-
819
- public async getAgentSettings(organizationId?: string, agentId?: string): Promise<AgentSettings[]> {
820
- const params = new URLSearchParams();
821
- if (organizationId) params.append('organizationId', organizationId);
822
- if (agentId) params.append('agentId', agentId);
823
-
824
- const queryString = params.toString();
825
- const endpoint = queryString ? `${urls.agentSettings}?${queryString}` : urls.agentSettings;
826
-
827
- return this.request<AgentSettings[]>(endpoint, 'GET');
828
- }
829
-
830
- public async getAgentSettingsById(id: string): Promise<AgentSettings> {
831
- return this.request<AgentSettings>(`${urls.agentSettings}/${id}`, 'GET');
832
- }
833
-
834
- public async getAgentSettingsByAgentAndOrganization(agentId: string, organizationId: string): Promise<AgentSettings> {
835
- return this.request<AgentSettings>(`${urls.agentSettings}/agent/${agentId}/organization/${organizationId}`, 'GET');
836
- }
837
-
838
- public async updateAgentSettings(id: string, settingsData: UpdateAgentSettingsDto): Promise<AgentSettings> {
839
- return this.request<AgentSettings>(`${urls.agentSettings}/${id}`, 'PATCH', settingsData);
840
- }
841
-
842
- public async deleteAgentSettings(id: string): Promise<void> {
843
- await this.request(`${urls.agentSettings}/${id}`, 'DELETE');
844
- }
845
-
846
- // ======================
847
- // AUDIO FILE METHODS
848
- // ======================
849
-
850
- public async uploadAudioFileToSession(sessionId: string, file: File | Blob, fileName?: string, culturalTranscription?: string): Promise<AudioFile> {
851
- const formData = new FormData();
852
- formData.append('file', file, fileName);
853
-
854
- if (culturalTranscription) {
855
- formData.append('cultural_transcription', culturalTranscription);
856
- }
857
-
858
- return this.fileUploadRequest<AudioFile>(`${urls.audioFiles}/upload/${sessionId}`, formData);
859
- }
860
-
861
- public async uploadAudioFileWithTranscriptionQueue(sessionId: string, file: File | Blob, options?: { fileName?: string; culturalTranscription?: string }): Promise<AudioFile> {
862
- const formData = new FormData();
863
- formData.append('file', file, options?.fileName);
864
-
865
- if (options?.culturalTranscription) {
866
- formData.append('cultural_transcription', options.culturalTranscription);
867
- }
868
-
869
- // This will automatically trigger the transcription queue
870
- return this.fileUploadRequest<AudioFile>(`${urls.audioFiles}/upload/${sessionId}`, formData);
871
- }
872
-
873
- public async getMyAudioFiles(): Promise<AudioFile[]> {
874
- return this.request<AudioFile[]>(`${urls.audioFiles}/my-files`, 'GET');
875
- }
876
-
877
- public async getAllAudioFiles(): Promise<AudioFile[]> {
878
- return this.request<AudioFile[]>(`${urls.audioFiles}/all`, 'GET');
879
- }
880
-
881
- public async getOrganizationAudioFiles(): Promise<AudioFile[]> {
882
- return this.request<AudioFile[]>(`${urls.audioFiles}/organization`, 'GET');
883
- }
884
-
885
- public async getAudioFilesBySession(sessionId: string): Promise<AudioFile[]> {
886
- return this.request<AudioFile[]>(`${urls.audioFiles}/session/${sessionId}`, 'GET');
887
- }
888
-
889
- public async getAudioFile(id: string): Promise<AudioFile> {
890
- return this.request<AudioFile>(`${urls.audioFiles}/${id}`, 'GET');
891
- }
892
-
893
- public async updateAudioFile(id: string, updates: UpdateAudioFileDto): Promise<AudioFile> {
894
- return this.request<AudioFile>(`${urls.audioFiles}/${id}`, 'PATCH', updates);
895
- }
896
-
897
- public async deleteAudioFile(id: string): Promise<void> {
898
- await this.request(`${urls.audioFiles}/${id}`, 'DELETE');
899
- }
900
-
901
- public async downloadAudioFile(id: string): Promise<Blob> {
902
- // For file downloads, we need a different approach than JSON requests
903
- const url = `${this.baseUrl}${urls.audioFiles}/${id}/download`;
904
-
905
- // Get token first
906
- await this.getToken();
907
-
908
- const defaultHeaders: Record<string, string> = {
909
- 'ngrok-skip-browser-warning': 'true'
910
- };
911
-
912
- if (this.accessToken) {
913
- defaultHeaders['Authorization'] = `Bearer ${this.accessToken}`;
914
- }
915
-
916
- const response = await fetch(url, {
917
- method: 'GET',
918
- headers: defaultHeaders,
919
- });
920
-
921
- if (!response.ok) {
922
- const errorData = await response.json().catch(() => ({}));
923
- throw new Error(
924
- errorData.message || `Download failed with status ${response.status}`
925
- );
926
- }
927
-
928
- return response.blob();
929
- }
930
-
931
- public async downloadAudioFileAsUrl(id: string): Promise<string> {
932
- const blob = await this.downloadAudioFile(id);
933
- return URL.createObjectURL(blob);
934
- }
935
-
936
- // ======================
937
- // TRANSCRIPTION QUEUE HELPER METHODS
938
- // ======================
939
-
940
- public async getTranscribedAudioFiles(): Promise<AudioFile[]> {
941
- const audioFiles = await this.getMyAudioFiles();
942
- return audioFiles.filter(file => file.status === AudioFileStatus.TRANSCRIBED && file.transcription);
943
- }
944
-
945
- public async getProcessingAudioFiles(): Promise<AudioFile[]> {
946
- const audioFiles = await this.getMyAudioFiles();
947
- return audioFiles.filter(file => file.status === AudioFileStatus.PROCESSING);
948
- }
949
-
950
- public async getFailedAudioFiles(): Promise<AudioFile[]> {
951
- const audioFiles = await this.getMyAudioFiles();
952
- return audioFiles.filter(file => file.status === AudioFileStatus.FAILED);
953
- }
954
-
955
- // ======================
956
- // BASE64 AUDIO FILE METHODS
957
- // ======================
958
-
959
- public async createBase64AudioFile(dto: CreateBase64AudioFileDto): Promise<Base64AudioFile> {
960
- return this.request<Base64AudioFile>(`${urls.audioFiles}/base64`, 'POST', dto);
961
- }
962
-
963
- public async getAllBase64AudioFiles(): Promise<Base64AudioFile[]> {
964
- return this.request<Base64AudioFile[]>(`${urls.audioFiles}/base64/all`, 'GET');
965
- }
966
-
967
- public async getBase64AudioFilesBySession(sessionId: string): Promise<Base64AudioFile[]> {
968
- return this.request<Base64AudioFile[]>(`${urls.audioFiles}/base64/session/${sessionId}`, 'GET');
969
- }
970
-
971
- public async getBase64AudioFile(id: string): Promise<Base64AudioFile> {
972
- return this.request<Base64AudioFile>(`${urls.audioFiles}/base64/${id}`, 'GET');
973
- }
974
-
975
- public async updateBase64AudioFile(id: string, updates: UpdateBase64AudioFileDto): Promise<Base64AudioFile> {
976
- return this.request<Base64AudioFile>(`${urls.audioFiles}/base64/${id}`, 'PATCH', updates);
977
- }
978
-
979
- public async deleteBase64AudioFile(id: string): Promise<void> {
980
- await this.request(`${urls.audioFiles}/base64/${id}`, 'DELETE');
981
- }
982
-
983
- public async addBase64Chunk(sessionId: string, base64Chunks: string[]): Promise<AddBase64ChunkResponse> {
984
- return this.request<AddBase64ChunkResponse>(`${urls.audioFiles}/base64/add-chunk/${sessionId}`, 'POST', { base64Chunks });
985
- }
986
-
987
- public async queueSessionBase64AudioForTranscription(sessionId: string): Promise<{ success: boolean }> {
988
- return this.request<{ success: boolean }>(`${urls.audioFiles}/session/${sessionId}/transcribe`, 'POST');
989
- }
990
-
991
- // ======================
992
- // WORKFLOW METHODS
993
- // ======================
994
-
995
- public async createWorkflow(name: string, organizationId?: string): Promise<Workflow> {
996
- const dto: CreateWorkflowDto = {
997
- name,
998
- organizationId: organizationId || this.user!.organizationId,
999
- };
1000
- return this.request<Workflow>(urls.workflows, 'POST', dto);
1001
- }
1002
-
1003
- public async getWorkflows(organizationId?: string): Promise<Workflow[]> {
1004
- const params = organizationId ? `?organizationId=${organizationId}` : '';
1005
- return this.request<Workflow[]>(`${urls.workflows}${params}`, 'GET');
1006
- }
1007
-
1008
- public async getWorkflow(id: string): Promise<Workflow> {
1009
- return this.request<Workflow>(`${urls.workflows}/${id}`, 'GET');
1010
- }
1011
-
1012
- public async getWorkflowsByOrganization(organizationId?: string): Promise<Workflow[]> {
1013
- const orgId = organizationId || this.user!.organizationId;
1014
- return this.request<Workflow[]>(`${urls.workflows}?organizationId=${orgId}`, 'GET');
1015
- }
1016
-
1017
- public async updateWorkflow(id: string, name: string, organizationId?: string): Promise<Workflow> {
1018
- const dto: UpdateWorkflowDto = {
1019
- name,
1020
- organizationId: organizationId || this.user!.organizationId,
1021
- };
1022
- return this.request<Workflow>(`${urls.workflows}/${id}`, 'PATCH', dto);
1023
- }
1024
-
1025
- public async deleteWorkflow(id: string): Promise<void> {
1026
- await this.request(`${urls.workflows}/${id}`, 'DELETE');
1027
- }
1028
-
1029
- // ===== LOGS METHODS =====
1030
-
1031
- /**
1032
- * Get logs with advanced filtering options
1033
- */
1034
- public async getLogs(filters?: FilterLogsDto): Promise<LogsResponse> {
1035
- const params = new URLSearchParams();
1036
-
1037
- if (filters) {
1038
- Object.entries(filters).forEach(([key, value]) => {
1039
- if (value !== undefined && value !== null) {
1040
- params.append(key, value.toString());
1041
- }
1042
- });
1043
- }
1044
-
1045
- const queryString = params.toString();
1046
- const url = queryString ? `${urls.logs}?${queryString}` : urls.logs;
1047
-
1048
- return this.request<LogsResponse>(url, 'GET');
1049
- }
1050
-
1051
- /**
1052
- * Get logs for a specific user
1053
- */
1054
- public async getLogsByUser(userId: string, limit?: number, offset?: number): Promise<LogsResponse> {
1055
- const params = new URLSearchParams();
1056
- if (limit !== undefined) params.append('limit', limit.toString());
1057
- if (offset !== undefined) params.append('offset', offset.toString());
1058
-
1059
- const queryString = params.toString();
1060
- const url = queryString ? `${urls.logs}/user/${userId}?${queryString}` : `${urls.logs}/user/${userId}`;
1061
-
1062
- return this.request<LogsResponse>(url, 'GET');
1063
- }
1064
-
1065
- /**
1066
- * Get logs for a specific controller
1067
- */
1068
- public async getLogsByController(controller: string, limit?: number, offset?: number): Promise<LogsResponse> {
1069
- const params = new URLSearchParams();
1070
- if (limit !== undefined) params.append('limit', limit.toString());
1071
- if (offset !== undefined) params.append('offset', offset.toString());
1072
-
1073
- const queryString = params.toString();
1074
- const url = queryString ? `${urls.logs}/controller/${controller}?${queryString}` : `${urls.logs}/controller/${controller}`;
1075
-
1076
- return this.request<LogsResponse>(url, 'GET');
1077
- }
1078
-
1079
- /**
1080
- * Get logs for the current authenticated user
1081
- */
1082
- public async getMyLogs(limit?: number, offset?: number): Promise<LogsResponse> {
1083
- const params = new URLSearchParams();
1084
- if (limit !== undefined) params.append('limit', limit.toString());
1085
- if (offset !== undefined) params.append('offset', offset.toString());
1086
-
1087
- const queryString = params.toString();
1088
- const url = queryString ? `${urls.logs}/my-logs?${queryString}` : `${urls.logs}/my-logs`;
1089
-
1090
- return this.request<LogsResponse>(url, 'GET');
1091
- }
1092
-
1093
- /**
1094
- * Get logs within a date range
1095
- */
1096
- public async getLogsByDateRange(
1097
- startDate: string,
1098
- endDate: string,
1099
- limit?: number,
1100
- offset?: number
1101
- ): Promise<LogsResponse> {
1102
- const params = new URLSearchParams();
1103
- params.append('startDate', startDate);
1104
- params.append('endDate', endDate);
1105
- if (limit !== undefined) params.append('limit', limit.toString());
1106
- if (offset !== undefined) params.append('offset', offset.toString());
1107
-
1108
- return this.request<LogsResponse>(`${urls.logs}/date-range?${params.toString()}`, 'GET');
1109
- }
1110
-
1111
- /**
1112
- * Get logging statistics
1113
- */
1114
- public async getLogStats(): Promise<LogStats> {
1115
- return this.request<LogStats>(`${urls.logs}/stats`, 'GET');
1116
- }
1117
-
1118
- /**
1119
- * Create a manual log entry (app logs)
1120
- */
1121
- public async createLog(logData: CreateLogDto): Promise<Log> {
1122
- return this.request<Log>(urls.logs, 'POST', logData);
1123
- }
1124
-
1125
- /**
1126
- * Convenience methods for different log levels
1127
- */
1128
- public async logInfo(message: string, context?: string, action?: string, data?: any): Promise<Log> {
1129
- return this.createLog({
1130
- level: 'info',
1131
- message,
1132
- context,
1133
- action,
1134
- data,
1135
- });
1136
- }
1137
-
1138
- public async logError(message: string, context?: string, action?: string, data?: any): Promise<Log> {
1139
- return this.createLog({
1140
- level: 'error',
1141
- message,
1142
- context,
1143
- action,
1144
- data,
1145
- });
1146
- }
1147
-
1148
- public async logWarn(message: string, context?: string, action?: string, data?: any): Promise<Log> {
1149
- return this.createLog({
1150
- level: 'warn',
1151
- message,
1152
- context,
1153
- action,
1154
- data,
1155
- });
1156
- }
1157
-
1158
- public async logDebug(message: string, context?: string, action?: string, data?: any): Promise<Log> {
1159
- return this.createLog({
1160
- level: 'debug',
1161
- message,
1162
- context,
1163
- action,
1164
- data,
1165
- });
1166
- }
1167
-
1168
- /**
1169
- * Get logs by role
1170
- */
1171
- public async getLogsByRole(role: string, limit?: number, offset?: number): Promise<LogsResponse> {
1172
- const params = new URLSearchParams();
1173
- if (limit !== undefined) params.append('limit', limit.toString());
1174
- if (offset !== undefined) params.append('offset', offset.toString());
1175
-
1176
- const queryString = params.toString();
1177
- const url = queryString ? `${urls.logs}/role/${role}?${queryString}` : `${urls.logs}/role/${role}`;
1178
-
1179
- return this.request<LogsResponse>(url, 'GET');
1180
- }
1181
-
1182
- /**
1183
- * Get logs by organization role
1184
- */
1185
- public async getLogsByOrganizationRole(organizationRole: string, limit?: number, offset?: number): Promise<LogsResponse> {
1186
- const params = new URLSearchParams();
1187
- if (limit !== undefined) params.append('limit', limit.toString());
1188
- if (offset !== undefined) params.append('offset', offset.toString());
1189
-
1190
- const queryString = params.toString();
1191
- const url = queryString ? `${urls.logs}/organization-role/${organizationRole}?${queryString}` : `${urls.logs}/organization-role/${organizationRole}`;
1192
-
1193
- return this.request<LogsResponse>(url, 'GET');
1194
- }
1195
-
1196
- /**
1197
- * Get logs by team role
1198
- */
1199
- public async getLogsByTeamRole(teamRole: string, limit?: number, offset?: number): Promise<LogsResponse> {
1200
- const params = new URLSearchParams();
1201
- if (limit !== undefined) params.append('limit', limit.toString());
1202
- if (offset !== undefined) params.append('offset', offset.toString());
1203
-
1204
- const queryString = params.toString();
1205
- const url = queryString ? `${urls.logs}/team-role/${teamRole}?${queryString}` : `${urls.logs}/team-role/${teamRole}`;
1206
-
1207
- return this.request<LogsResponse>(url, 'GET');
1208
- }
1209
-
1210
- /**
1211
- * Get available roles for filtering
1212
- */
1213
- public async getAvailableRoles(): Promise<{
1214
- roles: string[];
1215
- organizationRoles: string[];
1216
- teamRoles: string[];
1217
- }> {
1218
- return this.request<{
1219
- roles: string[];
1220
- organizationRoles: string[];
1221
- teamRoles: string[];
1222
- }>(`${urls.logs}/available-roles`, 'GET');
1223
- }
1224
-
1225
- /**
1226
- * Get logs for a specific session ID
1227
- * Searches both log messages and meta data for the session ID
1228
- */
1229
- public async getSessionLogs(sessionId: string, limit?: number, offset?: number): Promise<LogsResponse> {
1230
- const params = new URLSearchParams();
1231
- if (limit !== undefined) params.append('limit', limit.toString());
1232
- if (offset !== undefined) params.append('offset', offset.toString());
1233
-
1234
- const queryString = params.toString();
1235
- const url = queryString ? `${urls.logs}/session/${sessionId}?${queryString}` : `${urls.logs}/session/${sessionId}`;
1236
-
1237
- return this.request<LogsResponse>(url, 'GET');
1238
- }
1239
-
1240
- // ===== DEBUG METHODS =====
1241
-
1242
- /**
1243
- * Get sessions that do not have medical transcriptions and primary transcription summaries
1244
- * for the current user's organization
1245
- */
1246
- public async getSessionsWithoutMedicalTranscriptions(): Promise<DebugSessionSummary[]> {
1247
- return this.request<DebugSessionSummary[]>(`${urls.debug}/sessions/missing-medical-transcriptions`, 'GET');
1248
- }
1249
-
1250
- /**
1251
- * Download a session as a ZIP file containing all related data (decrypted)
1252
- * Returns a Blob that can be used to create a download link
1253
- */
1254
- public async downloadSessionAsZip(sessionId: string): Promise<Blob> {
1255
- const url = `${this.baseUrl}${urls.debug}/sessions/${sessionId}/download`;
1256
-
1257
- // Get token first
1258
- await this.getToken();
1259
-
1260
- const defaultHeaders: Record<string, string> = {
1261
- 'ngrok-skip-browser-warning': 'true'
1262
- };
1263
-
1264
- if (this.accessToken) {
1265
- defaultHeaders['Authorization'] = `Bearer ${this.accessToken}`;
1266
- }
1267
-
1268
- const response = await fetch(url, {
1269
- method: 'GET',
1270
- headers: defaultHeaders,
1271
- });
1272
-
1273
- if (!response.ok) {
1274
- const errorData = await response.json().catch(() => ({}));
1275
- throw new Error(
1276
- errorData.message || `Download failed with status ${response.status}`
1277
- );
1278
- }
1279
-
1280
- return response.blob();
1281
- }
1282
-
1283
- /**
1284
- * Download a session as a ZIP file and create a download URL
1285
- * Returns a URL that can be used for direct download
1286
- */
1287
- public async downloadSessionAsZipUrl(sessionId: string): Promise<string> {
1288
- const blob = await this.downloadSessionAsZip(sessionId);
1289
- return URL.createObjectURL(blob);
1290
- }
1291
-
1292
- /**
1293
- * Download a session as a ZIP file and trigger browser download
1294
- * Optionally provide a custom filename
1295
- */
1296
- public async downloadSessionAndTriggerDownload(sessionId: string, filename?: string): Promise<void> {
1297
- const blob = await this.downloadSessionAsZip(sessionId);
1298
- const url = URL.createObjectURL(blob);
1299
-
1300
- // Create temporary download link and click it
1301
- const link = document.createElement('a');
1302
- link.href = url;
1303
- link.download = filename || `session_${sessionId}_${new Date().toISOString().split('T')[0]}.zip`;
1304
- document.body.appendChild(link);
1305
- link.click();
1306
- document.body.removeChild(link);
1307
-
1308
- // Clean up the URL object
1309
- URL.revokeObjectURL(url);
1310
- }
1311
-
1312
- }