From 89c6d1e70092aabd6ccf7d2d8c4f9c3d978bf09c Mon Sep 17 00:00:00 2001 From: Murad Sofiyev Date: Fri, 29 Nov 2024 14:29:53 +0400 Subject: [PATCH] chore: Refactor WebSocket URL Construction in RealtimeAPI. - Introduced a private `#buildWebSocketUrl` method for constructing WebSocket URLs with optional query parameters. - Updated both browser and Node.js WebSocket connection logic to use the new URL builder method. --- lib/api.js | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/api.js b/lib/api.js index cc8f904..4b70df0 100644 --- a/lib/api.js +++ b/lib/api.js @@ -23,6 +23,39 @@ export class RealtimeAPI extends RealtimeEventHandler { } } + /** + * Private method to build a WebSocket URL with optional query parameters. + * @param {string} baseUrl - Base URL to which query parameters will be added. + * @param {Object} queryParams - Key-value pairs of query parameters. + * @returns {string} - The constructed WebSocket URL. + */ + #buildWebSocketUrl(baseUrl, queryParams) { + if (typeof URL === 'function') { + try { + const urlObj = new URL(baseUrl); + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined && value !== null) { + urlObj.searchParams.set(key, value); + } + } + return urlObj.toString(); + } catch (error) { + console.warn('Failed to use URL constructor:', error); + } + } + + // Fallback for environments without `URL` support + let url = baseUrl; + const queryString = Object.entries(queryParams) + .filter(([_, value]) => value !== undefined && value !== null) + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); + if (queryString) { + url += (url.includes('?') ? '&' : '?') + queryString; + } + return url; + } + /** * Tells us whether or not the WebSocket is connected * @returns {boolean} @@ -73,7 +106,7 @@ export class RealtimeAPI extends RealtimeEventHandler { ); } const WebSocket = globalThis.WebSocket; - const ws = new WebSocket(`${this.url}${model ? `?model=${model}` : ''}`, [ + const ws = new WebSocket( this.#buildWebSocketUrl(this.url, { model }), [ 'realtime', `openai-insecure-api-key.${this.apiKey}`, 'openai-beta.realtime-v1', @@ -113,7 +146,7 @@ export class RealtimeAPI extends RealtimeEventHandler { const wsModule = await import(/* webpackIgnore: true */ moduleName); const WebSocket = wsModule.default; const ws = new WebSocket( - 'wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01', + this.#buildWebSocketUrl(this.url, { model }), [], { finishRequest: (request) => {