@vapi-ai/web 2.3.9 → 2.4.0
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.
- package/api.ts +5864 -4194
- package/daily-guards.ts +81 -0
- package/dist/api.d.ts +7858 -6678
- package/dist/api.js +532 -445
- package/dist/daily-guards.d.ts +11 -0
- package/dist/daily-guards.js +50 -0
- package/dist/vapi.d.ts +2 -2
- package/dist/vapi.js +21 -18
- package/package.json +2 -2
- package/vapi.ts +26 -18
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DailyCall, DailyAdvancedConfig, DailyFactoryOptions } from '@daily-co/daily-js';
|
|
2
|
+
export interface SafeDailyAdvancedConfig extends Omit<DailyAdvancedConfig, 'alwaysIncludeMicInPermissionPrompt'> {
|
|
3
|
+
alwaysIncludeMicInPermissionPrompt?: true;
|
|
4
|
+
}
|
|
5
|
+
export interface SafeDailyFactoryOptions extends Omit<DailyFactoryOptions, 'audioSource'> {
|
|
6
|
+
audioSource?: string | boolean | MediaStreamTrack;
|
|
7
|
+
}
|
|
8
|
+
export declare function createSafeDailyConfig(config?: Pick<DailyAdvancedConfig, 'avoidEval' | 'alwaysIncludeMicInPermissionPrompt'>): SafeDailyAdvancedConfig;
|
|
9
|
+
export declare function safeSetLocalAudio(call: DailyCall | null, enabled: boolean): void;
|
|
10
|
+
export declare function safeSetInputDevicesAsync(call: DailyCall | null, options: Parameters<DailyCall['setInputDevicesAsync']>[0]): Promise<void>;
|
|
11
|
+
export declare function createSafeDailyFactoryOptions(options?: Pick<DailyFactoryOptions, 'audioSource' | 'startAudioOff'>): SafeDailyFactoryOptions;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSafeDailyConfig = createSafeDailyConfig;
|
|
4
|
+
exports.safeSetLocalAudio = safeSetLocalAudio;
|
|
5
|
+
exports.safeSetInputDevicesAsync = safeSetInputDevicesAsync;
|
|
6
|
+
exports.createSafeDailyFactoryOptions = createSafeDailyFactoryOptions;
|
|
7
|
+
function createSafeDailyConfig(config) {
|
|
8
|
+
if (!config)
|
|
9
|
+
return {};
|
|
10
|
+
const { alwaysIncludeMicInPermissionPrompt, ...rest } = config;
|
|
11
|
+
// Force true or remove the property entirely. This can cause Chrome 140+ issues
|
|
12
|
+
if (alwaysIncludeMicInPermissionPrompt === false) {
|
|
13
|
+
console.warn('[Vapi] alwaysIncludeMicInPermissionPrompt:false detected. ' +
|
|
14
|
+
'This can cause Chrome 140+ issues. Removing the property.');
|
|
15
|
+
return rest;
|
|
16
|
+
}
|
|
17
|
+
return config;
|
|
18
|
+
}
|
|
19
|
+
function safeSetLocalAudio(call, enabled) {
|
|
20
|
+
if (!call) {
|
|
21
|
+
throw new Error('Call object is not available.');
|
|
22
|
+
}
|
|
23
|
+
// Never use forceDiscardTrack. This can cause Chrome 140+ issues
|
|
24
|
+
call.setLocalAudio(enabled);
|
|
25
|
+
}
|
|
26
|
+
async function safeSetInputDevicesAsync(call, options) {
|
|
27
|
+
if (!call) {
|
|
28
|
+
throw new Error('Call object is not available.');
|
|
29
|
+
}
|
|
30
|
+
// Validate audioSource
|
|
31
|
+
if ('audioSource' in options && options.audioSource === false) {
|
|
32
|
+
console.warn('[Vapi] setInputDevicesAsync with audioSource:false detected. ' +
|
|
33
|
+
'This can cause Chrome 140+ issues. Using default device instead.');
|
|
34
|
+
const { audioSource, ...safeOptions } = options;
|
|
35
|
+
await call.setInputDevicesAsync(safeOptions);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await call.setInputDevicesAsync(options);
|
|
39
|
+
}
|
|
40
|
+
function createSafeDailyFactoryOptions(options) {
|
|
41
|
+
if (!options)
|
|
42
|
+
return {};
|
|
43
|
+
// Ensure audioSource is never false
|
|
44
|
+
if (options.audioSource === false) {
|
|
45
|
+
console.warn('[Vapi] audioSource:false detected in factory options. ' +
|
|
46
|
+
'This can cause Chrome 140+ issues. Defaulting to true.');
|
|
47
|
+
return { ...options, audioSource: true };
|
|
48
|
+
}
|
|
49
|
+
return options;
|
|
50
|
+
}
|
package/dist/vapi.d.ts
CHANGED
|
@@ -79,12 +79,12 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
79
79
|
start(assistant?: CreateAssistantDTO | string, assistantOverrides?: AssistantOverrides, squad?: CreateSquadDTO | string, workflow?: CreateWorkflowDTO | string, workflowOverrides?: WorkflowOverrides): Promise<Call | null>;
|
|
80
80
|
private onAppMessage;
|
|
81
81
|
private handleRemoteParticipantsAudioLevel;
|
|
82
|
-
stop(): void
|
|
82
|
+
stop(): Promise<void>;
|
|
83
83
|
send(message: VapiClientToServerMessage): void;
|
|
84
84
|
setMuted(mute: boolean): void;
|
|
85
85
|
isMuted(): boolean;
|
|
86
86
|
say(message: string, endCallAfterSpoken?: boolean, interruptionsEnabled?: boolean, interruptAssistantEnabled?: boolean): void;
|
|
87
|
-
setInputDevicesAsync(options: Parameters<DailyCall['setInputDevicesAsync']>[0]): void
|
|
87
|
+
setInputDevicesAsync(options: Parameters<DailyCall['setInputDevicesAsync']>[0]): Promise<void>;
|
|
88
88
|
increaseMicLevel(gain: number): Promise<void>;
|
|
89
89
|
setOutputDeviceAsync(options: Parameters<DailyCall['setOutputDeviceAsync']>[0]): void;
|
|
90
90
|
getDailyCallObject(): DailyCall | null;
|
package/dist/vapi.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const daily_js_1 = __importDefault(require("@daily-co/daily-js"));
|
|
7
7
|
const events_1 = __importDefault(require("events"));
|
|
8
8
|
const client_1 = require("./client");
|
|
9
|
+
const daily_guards_1 = require("./daily-guards");
|
|
9
10
|
async function startAudioPlayer(player, track) {
|
|
10
11
|
player.muted = false;
|
|
11
12
|
player.autoplay = true;
|
|
@@ -67,14 +68,16 @@ class Vapi extends VapiEventEmitter {
|
|
|
67
68
|
super();
|
|
68
69
|
client_1.client.baseUrl = apiBaseUrl ?? 'https://api.vapi.ai';
|
|
69
70
|
client_1.client.setSecurityData(apiToken);
|
|
70
|
-
this.dailyCallConfig = dailyCallConfig
|
|
71
|
-
this.dailyCallObject = dailyCallObject
|
|
71
|
+
this.dailyCallConfig = (0, daily_guards_1.createSafeDailyConfig)(dailyCallConfig);
|
|
72
|
+
this.dailyCallObject = (0, daily_guards_1.createSafeDailyFactoryOptions)(dailyCallObject);
|
|
72
73
|
}
|
|
73
|
-
cleanup() {
|
|
74
|
+
async cleanup() {
|
|
74
75
|
this.started = false;
|
|
75
76
|
this.hasEmittedCallEndedStatus = false;
|
|
76
|
-
this.call
|
|
77
|
-
|
|
77
|
+
if (this.call) {
|
|
78
|
+
await this.call.destroy();
|
|
79
|
+
this.call = null;
|
|
80
|
+
}
|
|
78
81
|
this.speakingTimeout = null;
|
|
79
82
|
}
|
|
80
83
|
isMobileDevice() {
|
|
@@ -157,7 +160,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
157
160
|
timestamp: new Date().toISOString(),
|
|
158
161
|
metadata: { action: 'cleanup-existing' }
|
|
159
162
|
});
|
|
160
|
-
this.cleanup();
|
|
163
|
+
await this.cleanup();
|
|
161
164
|
}
|
|
162
165
|
const isVideoRecordingEnabled = webCall?.artifactPlan?.videoRecordingEnabled ?? false;
|
|
163
166
|
const isVideoEnabled = webCall?.assistant?.voice?.provider === 'tavus';
|
|
@@ -219,7 +222,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
219
222
|
if (isVideoRecordingEnabled) {
|
|
220
223
|
this.call?.stopRecording();
|
|
221
224
|
}
|
|
222
|
-
this.cleanup();
|
|
225
|
+
this.cleanup().catch(console.error);
|
|
223
226
|
});
|
|
224
227
|
this.call.on('error', (error) => {
|
|
225
228
|
this.emit('error', error);
|
|
@@ -455,7 +458,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
455
458
|
},
|
|
456
459
|
})
|
|
457
460
|
.then(() => {
|
|
458
|
-
this.call
|
|
461
|
+
(0, daily_guards_1.safeSetLocalAudio)(this.call, true);
|
|
459
462
|
});
|
|
460
463
|
}
|
|
461
464
|
});
|
|
@@ -536,7 +539,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
536
539
|
isMobile: this.isMobileDevice()
|
|
537
540
|
}
|
|
538
541
|
});
|
|
539
|
-
this.cleanup();
|
|
542
|
+
await this.cleanup();
|
|
540
543
|
return null;
|
|
541
544
|
}
|
|
542
545
|
}
|
|
@@ -584,19 +587,19 @@ class Vapi extends VapiEventEmitter {
|
|
|
584
587
|
this.speakingTimeout = null;
|
|
585
588
|
}, 1000);
|
|
586
589
|
}
|
|
587
|
-
stop() {
|
|
590
|
+
async stop() {
|
|
588
591
|
this.started = false;
|
|
589
|
-
this.call
|
|
590
|
-
|
|
592
|
+
if (this.call) {
|
|
593
|
+
await this.call.destroy();
|
|
594
|
+
this.call = null;
|
|
595
|
+
}
|
|
596
|
+
this.speakingTimeout = null;
|
|
591
597
|
}
|
|
592
598
|
send(message) {
|
|
593
599
|
this.call?.sendAppMessage(JSON.stringify(message));
|
|
594
600
|
}
|
|
595
601
|
setMuted(mute) {
|
|
596
|
-
|
|
597
|
-
throw new Error('Call object is not available.');
|
|
598
|
-
}
|
|
599
|
-
this.call.setLocalAudio(!mute);
|
|
602
|
+
(0, daily_guards_1.safeSetLocalAudio)(this.call, !mute);
|
|
600
603
|
}
|
|
601
604
|
isMuted() {
|
|
602
605
|
if (!this.call) {
|
|
@@ -614,7 +617,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
614
617
|
});
|
|
615
618
|
}
|
|
616
619
|
setInputDevicesAsync(options) {
|
|
617
|
-
this.call
|
|
620
|
+
return (0, daily_guards_1.safeSetInputDevicesAsync)(this.call, options);
|
|
618
621
|
}
|
|
619
622
|
async increaseMicLevel(gain) {
|
|
620
623
|
if (!this.call) {
|
|
@@ -630,7 +633,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
630
633
|
const destination = audioContext.createMediaStreamDestination();
|
|
631
634
|
gainNode.connect(destination);
|
|
632
635
|
const [boostedTrack] = destination.stream.getAudioTracks();
|
|
633
|
-
await this.call
|
|
636
|
+
await (0, daily_guards_1.safeSetInputDevicesAsync)(this.call, { audioSource: boostedTrack });
|
|
634
637
|
}
|
|
635
638
|
catch (error) {
|
|
636
639
|
console.error("Error adjusting microphone level:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vapi-ai/web",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/vapi.js",
|
|
6
6
|
"types": "dist/vapi.d.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"node": ">=18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@daily-co/daily-js": "^0.
|
|
33
|
+
"@daily-co/daily-js": "^0.84.0",
|
|
34
34
|
"events": "^3.3.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
package/vapi.ts
CHANGED
|
@@ -21,6 +21,12 @@ import {
|
|
|
21
21
|
WorkflowOverrides,
|
|
22
22
|
} from './api';
|
|
23
23
|
import { client } from './client';
|
|
24
|
+
import {
|
|
25
|
+
createSafeDailyConfig,
|
|
26
|
+
createSafeDailyFactoryOptions,
|
|
27
|
+
safeSetLocalAudio,
|
|
28
|
+
safeSetInputDevicesAsync,
|
|
29
|
+
} from './daily-guards';
|
|
24
30
|
|
|
25
31
|
export interface AddMessageMessage {
|
|
26
32
|
type: 'add-message';
|
|
@@ -206,15 +212,17 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
206
212
|
super();
|
|
207
213
|
client.baseUrl = apiBaseUrl ?? 'https://api.vapi.ai';
|
|
208
214
|
client.setSecurityData(apiToken);
|
|
209
|
-
this.dailyCallConfig = dailyCallConfig
|
|
210
|
-
this.dailyCallObject = dailyCallObject
|
|
215
|
+
this.dailyCallConfig = createSafeDailyConfig(dailyCallConfig);
|
|
216
|
+
this.dailyCallObject = createSafeDailyFactoryOptions(dailyCallObject);
|
|
211
217
|
}
|
|
212
218
|
|
|
213
|
-
private cleanup() {
|
|
219
|
+
private async cleanup() {
|
|
214
220
|
this.started = false;
|
|
215
221
|
this.hasEmittedCallEndedStatus = false;
|
|
216
|
-
this.call
|
|
217
|
-
|
|
222
|
+
if (this.call) {
|
|
223
|
+
await this.call.destroy();
|
|
224
|
+
this.call = null;
|
|
225
|
+
}
|
|
218
226
|
this.speakingTimeout = null;
|
|
219
227
|
}
|
|
220
228
|
|
|
@@ -319,7 +327,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
319
327
|
timestamp: new Date().toISOString(),
|
|
320
328
|
metadata: { action: 'cleanup-existing' }
|
|
321
329
|
});
|
|
322
|
-
this.cleanup();
|
|
330
|
+
await this.cleanup();
|
|
323
331
|
}
|
|
324
332
|
|
|
325
333
|
const isVideoRecordingEnabled =
|
|
@@ -389,7 +397,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
389
397
|
if (isVideoRecordingEnabled) {
|
|
390
398
|
this.call?.stopRecording();
|
|
391
399
|
}
|
|
392
|
-
this.cleanup();
|
|
400
|
+
this.cleanup().catch(console.error);
|
|
393
401
|
});
|
|
394
402
|
|
|
395
403
|
this.call.on('error', (error: any) => {
|
|
@@ -649,7 +657,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
649
657
|
},
|
|
650
658
|
})
|
|
651
659
|
.then(() => {
|
|
652
|
-
this.call
|
|
660
|
+
safeSetLocalAudio(this.call, true);
|
|
653
661
|
});
|
|
654
662
|
}
|
|
655
663
|
});
|
|
@@ -737,7 +745,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
737
745
|
}
|
|
738
746
|
});
|
|
739
747
|
|
|
740
|
-
this.cleanup();
|
|
748
|
+
await this.cleanup();
|
|
741
749
|
return null;
|
|
742
750
|
}
|
|
743
751
|
}
|
|
@@ -794,10 +802,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
794
802
|
}, 1000);
|
|
795
803
|
}
|
|
796
804
|
|
|
797
|
-
stop(): void {
|
|
805
|
+
async stop(): Promise<void> {
|
|
798
806
|
this.started = false;
|
|
799
|
-
this.call
|
|
800
|
-
|
|
807
|
+
if (this.call) {
|
|
808
|
+
await this.call.destroy();
|
|
809
|
+
this.call = null;
|
|
810
|
+
}
|
|
811
|
+
this.speakingTimeout = null;
|
|
801
812
|
}
|
|
802
813
|
|
|
803
814
|
send(message: VapiClientToServerMessage): void {
|
|
@@ -805,10 +816,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
805
816
|
}
|
|
806
817
|
|
|
807
818
|
public setMuted(mute: boolean) {
|
|
808
|
-
|
|
809
|
-
throw new Error('Call object is not available.');
|
|
810
|
-
}
|
|
811
|
-
this.call.setLocalAudio(!mute);
|
|
819
|
+
safeSetLocalAudio(this.call, !mute);
|
|
812
820
|
}
|
|
813
821
|
|
|
814
822
|
public isMuted() {
|
|
@@ -832,7 +840,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
832
840
|
public setInputDevicesAsync(
|
|
833
841
|
options: Parameters<DailyCall['setInputDevicesAsync']>[0],
|
|
834
842
|
) {
|
|
835
|
-
this.call
|
|
843
|
+
return safeSetInputDevicesAsync(this.call, options);
|
|
836
844
|
}
|
|
837
845
|
|
|
838
846
|
public async increaseMicLevel(gain: number) {
|
|
@@ -855,7 +863,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
855
863
|
gainNode.connect(destination);
|
|
856
864
|
|
|
857
865
|
const [boostedTrack] = destination.stream.getAudioTracks();
|
|
858
|
-
await this.call
|
|
866
|
+
await safeSetInputDevicesAsync(this.call, { audioSource: boostedTrack });
|
|
859
867
|
} catch (error) {
|
|
860
868
|
console.error("Error adjusting microphone level:", error);
|
|
861
869
|
}
|