@absolutejs/voice 0.0.22-beta.655 → 0.0.22-beta.657
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/dist/angular/index.js +204 -70
- package/dist/client/connection.d.ts +3 -0
- package/dist/client/htmxBootstrap.js +204 -70
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +206 -71
- package/dist/core/types.d.ts +4 -0
- package/dist/embed/index.js +204 -70
- package/dist/embed/voice-widget.js +8 -8
- package/dist/react/index.js +204 -70
- package/dist/svelte/index.js +204 -70
- package/dist/testing/index.js +205 -71
- package/dist/vue/index.js +204 -70
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -335,48 +335,89 @@ var createMicrophoneCapture = (options) => {
|
|
|
335
335
|
let sourceNode = null;
|
|
336
336
|
let processorNode = null;
|
|
337
337
|
let mediaStream = null;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
338
|
+
let lifecycleGeneration = 0;
|
|
339
|
+
let startPromise = null;
|
|
340
|
+
const release = (resources) => {
|
|
341
|
+
resources.processorNode?.disconnect();
|
|
342
|
+
resources.sourceNode?.disconnect();
|
|
343
|
+
resources.mediaStream?.getTracks().forEach((track) => track.stop());
|
|
344
|
+
resources.audioContext?.close();
|
|
345
|
+
};
|
|
346
|
+
const start = () => {
|
|
347
|
+
if (mediaStream)
|
|
348
|
+
return Promise.resolve();
|
|
349
|
+
if (startPromise)
|
|
350
|
+
return startPromise;
|
|
351
|
+
const generation = ++lifecycleGeneration;
|
|
352
|
+
const operation = async () => {
|
|
353
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
354
|
+
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
355
|
+
}
|
|
356
|
+
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
357
|
+
if (!AudioContextCtor) {
|
|
358
|
+
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
359
|
+
}
|
|
360
|
+
let pendingAudioContext = null;
|
|
361
|
+
let pendingMediaStream = null;
|
|
362
|
+
let pendingProcessorNode = null;
|
|
363
|
+
let pendingSourceNode = null;
|
|
364
|
+
try {
|
|
365
|
+
pendingMediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
366
|
+
audio: {
|
|
367
|
+
autoGainControl: true,
|
|
368
|
+
channelCount: options.channelCount ?? 1,
|
|
369
|
+
echoCancellation: true,
|
|
370
|
+
noiseSuppression: true
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
if (generation !== lifecycleGeneration) {
|
|
374
|
+
throw new Error("Microphone capture stopped during startup.");
|
|
353
375
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
376
|
+
pendingAudioContext = new AudioContextCtor;
|
|
377
|
+
if (pendingAudioContext.state === "suspended") {
|
|
378
|
+
await pendingAudioContext.resume();
|
|
379
|
+
}
|
|
380
|
+
if (generation !== lifecycleGeneration) {
|
|
381
|
+
throw new Error("Microphone capture stopped during startup.");
|
|
382
|
+
}
|
|
383
|
+
pendingSourceNode = pendingAudioContext.createMediaStreamSource(pendingMediaStream);
|
|
384
|
+
pendingProcessorNode = pendingAudioContext.createScriptProcessor(4096, 1, 1);
|
|
385
|
+
pendingProcessorNode.onaudioprocess = (event) => {
|
|
386
|
+
const channel = event.inputBuffer.getChannelData(0);
|
|
387
|
+
const downsampled = downsampleBuffer(channel, pendingAudioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
388
|
+
const pcm = floatTo16BitPCM(downsampled);
|
|
389
|
+
options.onLevel?.(getPcmLevel(pcm));
|
|
390
|
+
options.onAudio(pcm);
|
|
391
|
+
};
|
|
392
|
+
pendingSourceNode.connect(pendingProcessorNode);
|
|
393
|
+
pendingProcessorNode.connect(pendingAudioContext.destination);
|
|
394
|
+
if (generation !== lifecycleGeneration) {
|
|
395
|
+
throw new Error("Microphone capture stopped during startup.");
|
|
396
|
+
}
|
|
397
|
+
audioContext = pendingAudioContext;
|
|
398
|
+
mediaStream = pendingMediaStream;
|
|
399
|
+
processorNode = pendingProcessorNode;
|
|
400
|
+
sourceNode = pendingSourceNode;
|
|
401
|
+
} catch (error) {
|
|
402
|
+
release({
|
|
403
|
+
audioContext: pendingAudioContext,
|
|
404
|
+
mediaStream: pendingMediaStream,
|
|
405
|
+
processorNode: pendingProcessorNode,
|
|
406
|
+
sourceNode: pendingSourceNode
|
|
407
|
+
});
|
|
408
|
+
throw error;
|
|
358
409
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
options.onAudio(pcm);
|
|
367
|
-
};
|
|
368
|
-
sourceNode.connect(processorNode);
|
|
369
|
-
processorNode.connect(audioContext.destination);
|
|
370
|
-
} catch (error) {
|
|
371
|
-
stop();
|
|
372
|
-
throw error;
|
|
373
|
-
}
|
|
410
|
+
};
|
|
411
|
+
const pending = operation().finally(() => {
|
|
412
|
+
if (startPromise === pending)
|
|
413
|
+
startPromise = null;
|
|
414
|
+
});
|
|
415
|
+
startPromise = pending;
|
|
416
|
+
return pending;
|
|
374
417
|
};
|
|
375
418
|
const stop = () => {
|
|
376
|
-
|
|
377
|
-
sourceNode
|
|
378
|
-
mediaStream?.getTracks().forEach((track) => track.stop());
|
|
379
|
-
audioContext?.close();
|
|
419
|
+
lifecycleGeneration += 1;
|
|
420
|
+
release({ audioContext, mediaStream, processorNode, sourceNode });
|
|
380
421
|
options.onLevel?.(0);
|
|
381
422
|
audioContext = null;
|
|
382
423
|
mediaStream = null;
|
|
@@ -588,11 +629,19 @@ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 15;
|
|
|
588
629
|
var DEFAULT_PING_INTERVAL = 30000;
|
|
589
630
|
var DEFAULT_RECONNECT_RESET_AFTER_MS = 30000;
|
|
590
631
|
var DEFAULT_CALL_CONTROL_ACK_TIMEOUT_MS = 5000;
|
|
632
|
+
var DEFAULT_PREPARE_RECONNECT_TIMEOUT_MS = 1e4;
|
|
591
633
|
var MAX_PENDING_CONTROL_MESSAGES = 100;
|
|
592
634
|
var RECONNECT_BASE_DELAY_MS = 500;
|
|
593
635
|
var DEFAULT_RECONNECT_MAX_DELAY_MS = 8000;
|
|
594
636
|
var computeVoiceReconnectDelayMs = (attempt, baseMs, maxDelayMs) => Math.min(maxDelayMs, baseMs * 2 ** (Math.max(1, attempt) - 1));
|
|
595
637
|
var DEFAULT_SCENARIO_QUERY_PARAM = "scenarioId";
|
|
638
|
+
|
|
639
|
+
class VoiceReconnectRejectedError extends Error {
|
|
640
|
+
constructor(message = "Voice authorization could not be renewed.") {
|
|
641
|
+
super(message);
|
|
642
|
+
this.name = "VoiceReconnectRejectedError";
|
|
643
|
+
}
|
|
644
|
+
}
|
|
596
645
|
var noop = () => {};
|
|
597
646
|
var noopAsync = () => Promise.resolve();
|
|
598
647
|
var noopUnsubscribe = () => noop;
|
|
@@ -672,6 +721,9 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
672
721
|
const reconnectMaxDelayMs = options.reconnectMaxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
|
|
673
722
|
const pingInterval = options.pingInterval ?? DEFAULT_PING_INTERVAL;
|
|
674
723
|
const reconnectResetAfterMs = options.reconnectResetAfterMs ?? DEFAULT_RECONNECT_RESET_AFTER_MS;
|
|
724
|
+
let lifecycleGeneration = 0;
|
|
725
|
+
let disposed = false;
|
|
726
|
+
let reconnectPreparationAbort = null;
|
|
675
727
|
const computeReconnectDelayMs = (attempt) => computeVoiceReconnectDelayMs(attempt, RECONNECT_BASE_DELAY_MS, reconnectMaxDelayMs);
|
|
676
728
|
const state = {
|
|
677
729
|
isConnected: false,
|
|
@@ -735,6 +787,9 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
735
787
|
pendingCallControls.clear();
|
|
736
788
|
};
|
|
737
789
|
const scheduleReconnect = () => {
|
|
790
|
+
if (disposed)
|
|
791
|
+
return;
|
|
792
|
+
const scheduledGeneration = lifecycleGeneration;
|
|
738
793
|
state.reconnectAttempts += 1;
|
|
739
794
|
const delayMs = computeReconnectDelayMs(state.reconnectAttempts);
|
|
740
795
|
const nextAttemptAt = Date.now() + delayMs;
|
|
@@ -749,18 +804,44 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
749
804
|
type: "connection"
|
|
750
805
|
});
|
|
751
806
|
state.reconnectTimeout = setTimeout(async () => {
|
|
807
|
+
if (disposed || lifecycleGeneration !== scheduledGeneration)
|
|
808
|
+
return;
|
|
752
809
|
if (state.reconnectAttempts > maxReconnectAttempts) {
|
|
753
810
|
emitTerminalFailure("Voice connection could not be restored.");
|
|
754
811
|
return;
|
|
755
812
|
}
|
|
756
813
|
try {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
814
|
+
if (options.prepareReconnect) {
|
|
815
|
+
const preparationAbort = new AbortController;
|
|
816
|
+
reconnectPreparationAbort = preparationAbort;
|
|
817
|
+
const timeout = setTimeout(() => preparationAbort.abort("Voice reconnect preparation timed out"), options.prepareReconnectTimeoutMs ?? DEFAULT_PREPARE_RECONNECT_TIMEOUT_MS);
|
|
818
|
+
try {
|
|
819
|
+
await Promise.race([
|
|
820
|
+
options.prepareReconnect({
|
|
821
|
+
attempt: state.reconnectAttempts,
|
|
822
|
+
path,
|
|
823
|
+
scenarioId: state.scenarioId,
|
|
824
|
+
sessionId: state.sessionId,
|
|
825
|
+
signal: preparationAbort.signal
|
|
826
|
+
}),
|
|
827
|
+
new Promise((_, reject) => {
|
|
828
|
+
preparationAbort.signal.addEventListener("abort", () => reject(new Error("Voice reconnect preparation timed out.")), { once: true });
|
|
829
|
+
})
|
|
830
|
+
]);
|
|
831
|
+
} finally {
|
|
832
|
+
clearTimeout(timeout);
|
|
833
|
+
if (reconnectPreparationAbort === preparationAbort) {
|
|
834
|
+
reconnectPreparationAbort = null;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
} catch (error) {
|
|
839
|
+
if (disposed || lifecycleGeneration !== scheduledGeneration)
|
|
840
|
+
return;
|
|
841
|
+
if (error instanceof VoiceReconnectRejectedError) {
|
|
842
|
+
emitTerminalFailure(error.message);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
764
845
|
if (state.reconnectAttempts < maxReconnectAttempts) {
|
|
765
846
|
scheduleReconnect();
|
|
766
847
|
} else {
|
|
@@ -768,10 +849,14 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
768
849
|
}
|
|
769
850
|
return;
|
|
770
851
|
}
|
|
852
|
+
if (disposed || lifecycleGeneration !== scheduledGeneration)
|
|
853
|
+
return;
|
|
771
854
|
connect();
|
|
772
855
|
}, delayMs);
|
|
773
856
|
};
|
|
774
857
|
const connect = () => {
|
|
858
|
+
if (disposed)
|
|
859
|
+
return;
|
|
775
860
|
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId, options.query ?? {}));
|
|
776
861
|
ws.binaryType = "arraybuffer";
|
|
777
862
|
ws.onopen = () => {
|
|
@@ -842,6 +927,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
842
927
|
state.ws = null;
|
|
843
928
|
state.isConnected = false;
|
|
844
929
|
clearTimers();
|
|
930
|
+
rejectPendingCallControls("Voice connection interrupted");
|
|
845
931
|
const reconnectable = shouldReconnect && event.code !== WS_NORMAL_CLOSURE && event.code !== WS_UNAUTHORIZED && event.code !== WS_FORBIDDEN && state.reconnectAttempts < maxReconnectAttempts;
|
|
846
932
|
const authorizationFailure = event.code === WS_UNAUTHORIZED || event.code === WS_FORBIDDEN;
|
|
847
933
|
if (authorizationFailure) {
|
|
@@ -872,6 +958,8 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
872
958
|
state.ws = ws;
|
|
873
959
|
};
|
|
874
960
|
const sendSerialized = (value) => {
|
|
961
|
+
if (disposed)
|
|
962
|
+
return;
|
|
875
963
|
if (state.ws?.readyState === WS_OPEN) {
|
|
876
964
|
state.ws.send(value);
|
|
877
965
|
return;
|
|
@@ -907,6 +995,9 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
907
995
|
send({ type: "end_turn" });
|
|
908
996
|
};
|
|
909
997
|
const callControl = (message) => {
|
|
998
|
+
if (state.ws?.readyState !== WS_OPEN) {
|
|
999
|
+
return Promise.reject(new Error(`${message.action} is unavailable while disconnected`));
|
|
1000
|
+
}
|
|
910
1001
|
const requestId = crypto.randomUUID();
|
|
911
1002
|
const { promise, reject, resolve } = Promise.withResolvers();
|
|
912
1003
|
const timeout = setTimeout(() => {
|
|
@@ -914,16 +1005,21 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
914
1005
|
reject(new Error(`${message.action} acknowledgement timed out`));
|
|
915
1006
|
}, DEFAULT_CALL_CONTROL_ACK_TIMEOUT_MS);
|
|
916
1007
|
pendingCallControls.set(requestId, { reject, resolve, timeout });
|
|
917
|
-
send({
|
|
1008
|
+
state.ws.send(JSON.stringify({
|
|
918
1009
|
...message,
|
|
919
1010
|
requestId,
|
|
920
1011
|
type: "call_control"
|
|
921
|
-
});
|
|
1012
|
+
}));
|
|
922
1013
|
return promise;
|
|
923
1014
|
};
|
|
924
1015
|
const close = (reason = "client-close") => {
|
|
1016
|
+
disposed = true;
|
|
1017
|
+
reconnectPreparationAbort?.abort();
|
|
1018
|
+
reconnectPreparationAbort = null;
|
|
1019
|
+
lifecycleGeneration += 1;
|
|
925
1020
|
clearTimers();
|
|
926
1021
|
rejectPendingCallControls("Voice connection closed");
|
|
1022
|
+
state.pendingMessages.length = 0;
|
|
927
1023
|
if (state.ws) {
|
|
928
1024
|
const ws = state.ws;
|
|
929
1025
|
state.ws = null;
|
|
@@ -936,8 +1032,13 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
936
1032
|
listeners.clear();
|
|
937
1033
|
};
|
|
938
1034
|
const disconnect = () => {
|
|
1035
|
+
disposed = true;
|
|
1036
|
+
reconnectPreparationAbort?.abort();
|
|
1037
|
+
reconnectPreparationAbort = null;
|
|
1038
|
+
lifecycleGeneration += 1;
|
|
939
1039
|
clearTimers();
|
|
940
1040
|
rejectPendingCallControls("Voice connection disconnected");
|
|
1041
|
+
state.pendingMessages.length = 0;
|
|
941
1042
|
if (state.ws) {
|
|
942
1043
|
const ws = state.ws;
|
|
943
1044
|
state.ws = null;
|
|
@@ -1185,7 +1286,10 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1185
1286
|
getSessionId: () => options.browserMedia ? options.browserMedia.getSessionId?.() ?? connection.getSessionId() : connection.getSessionId()
|
|
1186
1287
|
}) : null;
|
|
1187
1288
|
const subscribers = new Set;
|
|
1289
|
+
let disposed = false;
|
|
1188
1290
|
const start = (input) => Promise.resolve().then(() => {
|
|
1291
|
+
if (disposed)
|
|
1292
|
+
return;
|
|
1189
1293
|
if (!input?.sessionId && !input?.scenarioId) {
|
|
1190
1294
|
return;
|
|
1191
1295
|
}
|
|
@@ -1244,6 +1348,7 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1244
1348
|
return connection.callControl(message);
|
|
1245
1349
|
},
|
|
1246
1350
|
close(reason) {
|
|
1351
|
+
disposed = true;
|
|
1247
1352
|
unsubscribeConnection();
|
|
1248
1353
|
browserMediaReporter?.close();
|
|
1249
1354
|
connection.close(reason);
|
|
@@ -1251,6 +1356,7 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1251
1356
|
notify();
|
|
1252
1357
|
},
|
|
1253
1358
|
disconnect() {
|
|
1359
|
+
disposed = true;
|
|
1254
1360
|
unsubscribeConnection();
|
|
1255
1361
|
browserMediaReporter?.close();
|
|
1256
1362
|
connection.disconnect();
|
|
@@ -1654,6 +1760,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1654
1760
|
...options.connection
|
|
1655
1761
|
});
|
|
1656
1762
|
let capture = null;
|
|
1763
|
+
let captureGeneration = 0;
|
|
1764
|
+
let disposed = false;
|
|
1765
|
+
let startRecordingPromise = null;
|
|
1657
1766
|
let state = createInitialState2(stream);
|
|
1658
1767
|
const subscribers = new Set;
|
|
1659
1768
|
const notify = () => {
|
|
@@ -1710,6 +1819,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1710
1819
|
return capture;
|
|
1711
1820
|
};
|
|
1712
1821
|
const stopRecording = () => {
|
|
1822
|
+
captureGeneration += 1;
|
|
1713
1823
|
capture?.stop();
|
|
1714
1824
|
capture = null;
|
|
1715
1825
|
state = {
|
|
@@ -1719,39 +1829,63 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1719
1829
|
notify();
|
|
1720
1830
|
};
|
|
1721
1831
|
const startRecording = async () => {
|
|
1832
|
+
if (disposed) {
|
|
1833
|
+
throw new Error("Voice controller is closed.");
|
|
1834
|
+
}
|
|
1722
1835
|
if (state.isRecording) {
|
|
1723
1836
|
return;
|
|
1724
1837
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1838
|
+
if (startRecordingPromise)
|
|
1839
|
+
return startRecordingPromise;
|
|
1840
|
+
const generation = ++captureGeneration;
|
|
1841
|
+
const activeCapture = ensureCapture();
|
|
1842
|
+
const operation = (async () => {
|
|
1843
|
+
try {
|
|
1844
|
+
state = {
|
|
1845
|
+
...state,
|
|
1846
|
+
recordingError: null
|
|
1847
|
+
};
|
|
1848
|
+
notify();
|
|
1849
|
+
await activeCapture.start();
|
|
1850
|
+
if (disposed || generation !== captureGeneration || capture !== activeCapture) {
|
|
1851
|
+
activeCapture.stop();
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
state = {
|
|
1855
|
+
...state,
|
|
1856
|
+
isRecording: true
|
|
1857
|
+
};
|
|
1858
|
+
notify();
|
|
1859
|
+
} catch (error) {
|
|
1860
|
+
activeCapture.stop();
|
|
1861
|
+
if (generation !== captureGeneration || capture !== activeCapture) {
|
|
1862
|
+
throw error;
|
|
1863
|
+
}
|
|
1864
|
+
capture = null;
|
|
1865
|
+
state = {
|
|
1866
|
+
...state,
|
|
1867
|
+
isRecording: false,
|
|
1868
|
+
recordingError: error instanceof Error ? error.message : String(error)
|
|
1869
|
+
};
|
|
1870
|
+
notify();
|
|
1871
|
+
throw error;
|
|
1872
|
+
}
|
|
1873
|
+
})();
|
|
1874
|
+
const pending = operation.finally(() => {
|
|
1875
|
+
if (startRecordingPromise === pending)
|
|
1876
|
+
startRecordingPromise = null;
|
|
1877
|
+
});
|
|
1878
|
+
startRecordingPromise = pending;
|
|
1879
|
+
return startRecordingPromise;
|
|
1748
1880
|
};
|
|
1749
1881
|
const close = (reason) => {
|
|
1882
|
+
disposed = true;
|
|
1750
1883
|
unsubscribeStream();
|
|
1751
1884
|
stopRecording();
|
|
1752
1885
|
stream.close(reason);
|
|
1753
1886
|
};
|
|
1754
1887
|
const disconnect = () => {
|
|
1888
|
+
disposed = true;
|
|
1755
1889
|
unsubscribeStream();
|
|
1756
1890
|
stopRecording();
|
|
1757
1891
|
stream.disconnect();
|
|
@@ -22,5 +22,8 @@ type VoiceConnectionHandle = {
|
|
|
22
22
|
simulateDisconnect: () => void;
|
|
23
23
|
subscribe: (callback: (message: VoiceServerMessage) => void) => () => void;
|
|
24
24
|
};
|
|
25
|
+
export declare class VoiceReconnectRejectedError extends Error {
|
|
26
|
+
constructor(message?: string);
|
|
27
|
+
}
|
|
25
28
|
export declare const createVoiceConnection: (path: string, options?: VoiceConnectionOptions) => VoiceConnectionHandle;
|
|
26
29
|
export {};
|