fix(voice): start socket timeout after auth preparation

This commit is contained in:
Vincent Koc
2026-08-04 14:17:18 +08:00
parent 84cfc43684
commit ebf335f1a6
3 changed files with 27 additions and 11 deletions
@@ -787,6 +787,9 @@ class OpenAIRealtimeVoiceBridge implements RealtimeVoiceBridge {
attempt.resolve();
return;
}
// Auth preparation owns its own timeout. Start the socket deadline only
// after connection parameters are available.
attempt.startTimeout();
const url = resolvedConnection.url;
this.connectionUrl = resolvedConnection.url;
const debugProxy = resolveDebugProxySettings();
+3
View File
@@ -160,6 +160,9 @@ export class XaiRealtimeVoiceBridge extends XaiRealtimeVoiceEvents implements Re
attempt.resolve();
return;
}
// Credential refresh has its own bounded lifecycle. Arm the socket timeout
// only once valid connection parameters are ready.
attempt.startTimeout();
const { url, headers } = resolvedConnection;
this.connectionUrl = url;
const proxyAgent = createDebugProxyWebSocketAgent(resolveDebugProxySettings());
+21 -11
View File
@@ -88,6 +88,7 @@ type RealtimeVoiceConnectAttempt = {
reject: (error: Error) => void;
rejectStartup: (error: Error) => boolean;
resolve: (providerReady?: boolean) => void;
startTimeout: () => void;
};
type RealtimeVoiceConnectAttemptOptions = {
@@ -174,8 +175,11 @@ export class RealtimeVoiceSessionLifecycle {
rejectPromise = reject;
});
let removeAbortListener = () => {};
let timeout: ReturnType<typeof setTimeout> | undefined;
const cleanup = () => {
clearTimeout(timeout);
if (timeout) {
clearTimeout(timeout);
}
removeAbortListener();
};
const resolve = (providerReady = false) => {
@@ -203,17 +207,22 @@ export class RealtimeVoiceSessionLifecycle {
reject(error);
return true;
};
const timeout = setTimeout(() => {
if (
this.isCurrent(options.connection) &&
!ready &&
this.terminalOutcome(options.connection) !== "completed"
) {
startupFailed = true;
options.onTimeout();
reject(options.timeoutError());
const startTimeout = () => {
if (settled || timeout) {
return;
}
}, options.timeoutMs);
timeout = setTimeout(() => {
if (
this.isCurrent(options.connection) &&
!ready &&
this.terminalOutcome(options.connection) !== "completed"
) {
startupFailed = true;
options.onTimeout();
reject(options.timeoutError());
}
}, options.timeoutMs);
};
const onAbort = () => {
const outcome = this.terminalOutcome(options.connection);
options.onAbort(outcome);
@@ -243,6 +252,7 @@ export class RealtimeVoiceSessionLifecycle {
reject,
rejectStartup,
resolve,
startTimeout,
};
}