@vapi-ai/web 2.5.1 → 2.5.2
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 +380 -414
- package/dist/api.d.ts +2004 -2034
- package/dist/api.js +17 -28
- package/dist/vapi.js +101 -24
- package/package.json +1 -1
- package/vapi.ts +117 -24
package/vapi.ts
CHANGED
|
@@ -98,6 +98,73 @@ interface CallStartFailedEvent {
|
|
|
98
98
|
context: Record<string, any>;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
interface SerializedError {
|
|
102
|
+
message: string;
|
|
103
|
+
name?: string;
|
|
104
|
+
stack?: string;
|
|
105
|
+
code?: string | number;
|
|
106
|
+
cause?: string;
|
|
107
|
+
[key: string]: any;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Extracts error details into a plain object that serializes properly to JSON.
|
|
112
|
+
* Error objects don't serialize well because their properties (message, stack, name)
|
|
113
|
+
* are not enumerable and get lost when using JSON.stringify().
|
|
114
|
+
*/
|
|
115
|
+
function serializeError(error: unknown): SerializedError {
|
|
116
|
+
if (error === null || error === undefined) {
|
|
117
|
+
return { message: 'Unknown error (null or undefined)' };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (error instanceof Error) {
|
|
121
|
+
const serialized: SerializedError = {
|
|
122
|
+
message: error.message,
|
|
123
|
+
name: error.name,
|
|
124
|
+
stack: error.stack,
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Include any additional properties that might be on the error
|
|
128
|
+
const errorAsAny = error as any;
|
|
129
|
+
if (errorAsAny.code !== undefined) {
|
|
130
|
+
serialized.code = errorAsAny.code;
|
|
131
|
+
}
|
|
132
|
+
if (errorAsAny.cause !== undefined) {
|
|
133
|
+
serialized.cause = String(errorAsAny.cause);
|
|
134
|
+
}
|
|
135
|
+
if (errorAsAny.reason !== undefined) {
|
|
136
|
+
serialized.reason = errorAsAny.reason;
|
|
137
|
+
}
|
|
138
|
+
if (errorAsAny.details !== undefined) {
|
|
139
|
+
serialized.details = errorAsAny.details;
|
|
140
|
+
}
|
|
141
|
+
// Daily.co specific error properties
|
|
142
|
+
if (errorAsAny.errorMsg !== undefined) {
|
|
143
|
+
serialized.errorMsg = errorAsAny.errorMsg;
|
|
144
|
+
}
|
|
145
|
+
if (errorAsAny.error !== undefined && typeof errorAsAny.error === 'string') {
|
|
146
|
+
serialized.errorDetail = errorAsAny.error;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return serialized;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (typeof error === 'string') {
|
|
153
|
+
return { message: error };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (typeof error === 'object') {
|
|
157
|
+
// It's already a plain object, but let's ensure message exists
|
|
158
|
+
const errorObj = error as Record<string, any>;
|
|
159
|
+
return {
|
|
160
|
+
message: errorObj.message || errorObj.error || JSON.stringify(error),
|
|
161
|
+
...errorObj
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return { message: String(error) };
|
|
166
|
+
}
|
|
167
|
+
|
|
101
168
|
type VapiEventListeners = {
|
|
102
169
|
'call-end': () => void;
|
|
103
170
|
'call-start': () => void;
|
|
@@ -298,7 +365,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
298
365
|
this.emit('error', {
|
|
299
366
|
type: 'validation-error',
|
|
300
367
|
stage: 'input-validation',
|
|
301
|
-
|
|
368
|
+
error: serializeError(error),
|
|
302
369
|
timestamp: new Date().toISOString()
|
|
303
370
|
});
|
|
304
371
|
throw error;
|
|
@@ -410,17 +477,18 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
410
477
|
});
|
|
411
478
|
} catch (error) {
|
|
412
479
|
const dailyCallDuration = Date.now() - dailyCallStartTime;
|
|
480
|
+
const serializedError = serializeError(error);
|
|
413
481
|
this.emit('call-start-progress', {
|
|
414
482
|
stage: 'daily-call-object-creation',
|
|
415
483
|
status: 'failed',
|
|
416
484
|
duration: dailyCallDuration,
|
|
417
485
|
timestamp: new Date().toISOString(),
|
|
418
|
-
metadata: { error:
|
|
486
|
+
metadata: { error: serializedError.message }
|
|
419
487
|
});
|
|
420
488
|
this.emit('error', {
|
|
421
489
|
type: 'daily-call-object-creation-error',
|
|
422
490
|
stage: 'daily-call-object-creation',
|
|
423
|
-
error,
|
|
491
|
+
error: serializedError,
|
|
424
492
|
timestamp: new Date().toISOString()
|
|
425
493
|
});
|
|
426
494
|
throw error;
|
|
@@ -445,14 +513,22 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
445
513
|
});
|
|
446
514
|
|
|
447
515
|
this.call.on('error', (error: any) => {
|
|
448
|
-
this.emit('error',
|
|
516
|
+
this.emit('error', {
|
|
517
|
+
type: 'daily-error',
|
|
518
|
+
error: serializeError(error),
|
|
519
|
+
timestamp: new Date().toISOString()
|
|
520
|
+
});
|
|
449
521
|
if (isVideoRecordingEnabled) {
|
|
450
522
|
this.call?.stopRecording();
|
|
451
523
|
}
|
|
452
524
|
});
|
|
453
525
|
|
|
454
526
|
this.call.on('camera-error', (error: any) => {
|
|
455
|
-
this.emit('camera-error',
|
|
527
|
+
this.emit('camera-error', {
|
|
528
|
+
type: 'camera-error',
|
|
529
|
+
error: serializeError(error),
|
|
530
|
+
timestamp: new Date().toISOString()
|
|
531
|
+
});
|
|
456
532
|
});
|
|
457
533
|
|
|
458
534
|
this.call.on('network-quality-change', (event: any) => {
|
|
@@ -560,17 +636,18 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
560
636
|
});
|
|
561
637
|
} catch (error) {
|
|
562
638
|
const joinDuration = Date.now() - joinStartTime;
|
|
639
|
+
const serializedError = serializeError(error);
|
|
563
640
|
this.emit('call-start-progress', {
|
|
564
641
|
stage: 'daily-call-join',
|
|
565
642
|
status: 'failed',
|
|
566
643
|
duration: joinDuration,
|
|
567
644
|
timestamp: new Date().toISOString(),
|
|
568
|
-
metadata: { error:
|
|
645
|
+
metadata: { error: serializedError.message }
|
|
569
646
|
});
|
|
570
647
|
this.emit('error', {
|
|
571
648
|
type: 'daily-call-join-error',
|
|
572
649
|
stage: 'daily-call-join',
|
|
573
|
-
error,
|
|
650
|
+
error: serializedError,
|
|
574
651
|
duration: joinDuration,
|
|
575
652
|
timestamp: new Date().toISOString()
|
|
576
653
|
});
|
|
@@ -623,17 +700,18 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
623
700
|
});
|
|
624
701
|
} catch (error) {
|
|
625
702
|
const recordingSetupDuration = Date.now() - recordingStartTime;
|
|
703
|
+
const serializedError = serializeError(error);
|
|
626
704
|
this.emit('call-start-progress', {
|
|
627
705
|
stage: 'video-recording-setup',
|
|
628
706
|
status: 'failed',
|
|
629
707
|
duration: recordingSetupDuration,
|
|
630
708
|
timestamp: new Date().toISOString(),
|
|
631
|
-
metadata: { error:
|
|
709
|
+
metadata: { error: serializedError.message }
|
|
632
710
|
});
|
|
633
711
|
this.emit('error', {
|
|
634
712
|
type: 'video-recording-setup-error',
|
|
635
713
|
stage: 'video-recording-setup',
|
|
636
|
-
error,
|
|
714
|
+
error: serializedError,
|
|
637
715
|
timestamp: new Date().toISOString()
|
|
638
716
|
});
|
|
639
717
|
// Don't throw here, video recording is optional
|
|
@@ -667,17 +745,18 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
667
745
|
});
|
|
668
746
|
} catch (error) {
|
|
669
747
|
const audioObserverDuration = Date.now() - audioObserverStartTime;
|
|
748
|
+
const serializedError = serializeError(error);
|
|
670
749
|
this.emit('call-start-progress', {
|
|
671
750
|
stage: 'audio-observer-setup',
|
|
672
751
|
status: 'failed',
|
|
673
752
|
duration: audioObserverDuration,
|
|
674
753
|
timestamp: new Date().toISOString(),
|
|
675
|
-
metadata: { error:
|
|
754
|
+
metadata: { error: serializedError.message }
|
|
676
755
|
});
|
|
677
756
|
this.emit('error', {
|
|
678
757
|
type: 'audio-observer-setup-error',
|
|
679
758
|
stage: 'audio-observer-setup',
|
|
680
|
-
error,
|
|
759
|
+
error: serializedError,
|
|
681
760
|
timestamp: new Date().toISOString()
|
|
682
761
|
});
|
|
683
762
|
// Don't throw here, this is non-critical
|
|
@@ -733,17 +812,18 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
733
812
|
});
|
|
734
813
|
} catch (error) {
|
|
735
814
|
const audioProcessingDuration = Date.now() - audioProcessingStartTime;
|
|
815
|
+
const serializedError = serializeError(error);
|
|
736
816
|
this.emit('call-start-progress', {
|
|
737
817
|
stage: 'audio-processing-setup',
|
|
738
818
|
status: 'failed',
|
|
739
819
|
duration: audioProcessingDuration,
|
|
740
820
|
timestamp: new Date().toISOString(),
|
|
741
|
-
metadata: { error:
|
|
821
|
+
metadata: { error: serializedError.message }
|
|
742
822
|
});
|
|
743
823
|
this.emit('error', {
|
|
744
824
|
type: 'audio-processing-setup-error',
|
|
745
825
|
stage: 'audio-processing-setup',
|
|
746
|
-
error,
|
|
826
|
+
error: serializedError,
|
|
747
827
|
timestamp: new Date().toISOString()
|
|
748
828
|
});
|
|
749
829
|
// Don't throw here, this is non-critical
|
|
@@ -759,12 +839,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
759
839
|
return webCall;
|
|
760
840
|
} catch (e) {
|
|
761
841
|
const totalDuration = Date.now() - startTime;
|
|
842
|
+
const serializedError = serializeError(e);
|
|
762
843
|
|
|
763
844
|
this.emit('call-start-failed', {
|
|
764
845
|
stage: 'unknown',
|
|
765
846
|
totalDuration,
|
|
766
|
-
error:
|
|
767
|
-
errorStack:
|
|
847
|
+
error: serializedError.message,
|
|
848
|
+
errorStack: serializedError.stack || 'No stack trace available',
|
|
768
849
|
timestamp: new Date().toISOString(),
|
|
769
850
|
context: {
|
|
770
851
|
hasAssistant: !!assistant,
|
|
@@ -778,7 +859,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
778
859
|
this.emit('error', {
|
|
779
860
|
type: 'start-method-error',
|
|
780
861
|
stage: 'unknown',
|
|
781
|
-
error:
|
|
862
|
+
error: serializedError,
|
|
782
863
|
totalDuration,
|
|
783
864
|
timestamp: new Date().toISOString(),
|
|
784
865
|
context: {
|
|
@@ -1054,14 +1135,22 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1054
1135
|
});
|
|
1055
1136
|
|
|
1056
1137
|
this.call.on('error', (error: any) => {
|
|
1057
|
-
this.emit('error',
|
|
1138
|
+
this.emit('error', {
|
|
1139
|
+
type: 'daily-error',
|
|
1140
|
+
error: serializeError(error),
|
|
1141
|
+
timestamp: new Date().toISOString()
|
|
1142
|
+
});
|
|
1058
1143
|
if (isVideoRecordingEnabled) {
|
|
1059
1144
|
this.call?.stopRecording();
|
|
1060
1145
|
}
|
|
1061
1146
|
});
|
|
1062
1147
|
|
|
1063
1148
|
this.call.on('camera-error', (error: any) => {
|
|
1064
|
-
this.emit('camera-error',
|
|
1149
|
+
this.emit('camera-error', {
|
|
1150
|
+
type: 'camera-error',
|
|
1151
|
+
error: serializeError(error),
|
|
1152
|
+
timestamp: new Date().toISOString()
|
|
1153
|
+
});
|
|
1065
1154
|
});
|
|
1066
1155
|
|
|
1067
1156
|
this.call.on('network-quality-change', (event: any) => {
|
|
@@ -1234,12 +1323,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1234
1323
|
});
|
|
1235
1324
|
} catch (error) {
|
|
1236
1325
|
const recordingSetupDuration = Date.now() - recordingStartTime;
|
|
1326
|
+
const serializedError = serializeError(error);
|
|
1237
1327
|
this.emit('call-start-progress', {
|
|
1238
1328
|
stage: 'video-recording-setup',
|
|
1239
1329
|
status: 'failed',
|
|
1240
1330
|
duration: recordingSetupDuration,
|
|
1241
1331
|
timestamp: new Date().toISOString(),
|
|
1242
|
-
metadata: { error:
|
|
1332
|
+
metadata: { error: serializedError.message }
|
|
1243
1333
|
});
|
|
1244
1334
|
// Don't throw here, video recording is optional
|
|
1245
1335
|
}
|
|
@@ -1272,12 +1362,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1272
1362
|
});
|
|
1273
1363
|
} catch (error) {
|
|
1274
1364
|
const audioObserverDuration = Date.now() - audioObserverStartTime;
|
|
1365
|
+
const serializedError = serializeError(error);
|
|
1275
1366
|
this.emit('call-start-progress', {
|
|
1276
1367
|
stage: 'audio-observer-setup',
|
|
1277
1368
|
status: 'failed',
|
|
1278
1369
|
duration: audioObserverDuration,
|
|
1279
1370
|
timestamp: new Date().toISOString(),
|
|
1280
|
-
metadata: { error:
|
|
1371
|
+
metadata: { error: serializedError.message }
|
|
1281
1372
|
});
|
|
1282
1373
|
// Don't throw here, this is non-critical
|
|
1283
1374
|
}
|
|
@@ -1309,12 +1400,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1309
1400
|
});
|
|
1310
1401
|
} catch (error) {
|
|
1311
1402
|
const audioProcessingDuration = Date.now() - audioProcessingStartTime;
|
|
1403
|
+
const serializedError = serializeError(error);
|
|
1312
1404
|
this.emit('call-start-progress', {
|
|
1313
1405
|
stage: 'audio-processing-setup',
|
|
1314
1406
|
status: 'failed',
|
|
1315
1407
|
duration: audioProcessingDuration,
|
|
1316
1408
|
timestamp: new Date().toISOString(),
|
|
1317
|
-
metadata: { error:
|
|
1409
|
+
metadata: { error: serializedError.message }
|
|
1318
1410
|
});
|
|
1319
1411
|
// Don't throw here, this is non-critical
|
|
1320
1412
|
}
|
|
@@ -1330,12 +1422,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1330
1422
|
|
|
1331
1423
|
} catch (e) {
|
|
1332
1424
|
const totalDuration = Date.now() - startTime;
|
|
1425
|
+
const serializedError = serializeError(e);
|
|
1333
1426
|
|
|
1334
1427
|
this.emit('call-start-failed', {
|
|
1335
1428
|
stage: 'reconnect',
|
|
1336
1429
|
totalDuration,
|
|
1337
|
-
error:
|
|
1338
|
-
errorStack:
|
|
1430
|
+
error: serializedError.message,
|
|
1431
|
+
errorStack: serializedError.stack || 'No stack trace available',
|
|
1339
1432
|
timestamp: new Date().toISOString(),
|
|
1340
1433
|
context: {
|
|
1341
1434
|
isReconnect: true,
|
|
@@ -1349,7 +1442,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1349
1442
|
// Also emit the generic error event for backward compatibility
|
|
1350
1443
|
this.emit('error', {
|
|
1351
1444
|
type: 'reconnect-error',
|
|
1352
|
-
error:
|
|
1445
|
+
error: serializedError,
|
|
1353
1446
|
totalDuration,
|
|
1354
1447
|
timestamp: new Date().toISOString(),
|
|
1355
1448
|
context: {
|