UNPKG

@supabase/realtime-js

Version:
126 lines 5.41 kB
/** * Utilities for creating WebSocket instances across runtimes. */ export class WebSocketFactory { /** * Static-only utility – prevent instantiation. */ constructor() { } static detectEnvironment() { var _a; if (typeof WebSocket !== 'undefined') { return { type: 'native', constructor: WebSocket }; } if (typeof globalThis !== 'undefined' && typeof globalThis.WebSocket !== 'undefined') { return { type: 'native', constructor: globalThis.WebSocket }; } if (typeof global !== 'undefined' && typeof global.WebSocket !== 'undefined') { return { type: 'native', constructor: global.WebSocket }; } if (typeof globalThis !== 'undefined' && typeof globalThis.WebSocketPair !== 'undefined' && typeof globalThis.WebSocket === 'undefined') { return { type: 'cloudflare', error: 'Cloudflare Workers detected. WebSocket clients are not supported in Cloudflare Workers.', workaround: 'Use Cloudflare Workers WebSocket API for server-side WebSocket handling, or deploy to a different runtime.', }; } if ((typeof globalThis !== 'undefined' && globalThis.EdgeRuntime) || (typeof navigator !== 'undefined' && ((_a = navigator.userAgent) === null || _a === void 0 ? void 0 : _a.includes('Vercel-Edge')))) { return { type: 'unsupported', error: 'Edge runtime detected (Vercel Edge/Netlify Edge). WebSockets are not supported in edge functions.', workaround: 'Use serverless functions or a different deployment target for WebSocket functionality.', }; } if (typeof process !== 'undefined') { // Use dynamic property access to avoid Next.js Edge Runtime static analysis warnings const processVersions = process['versions']; if (processVersions && processVersions['node']) { // Remove 'v' prefix if present and parse the major version const versionString = processVersions['node']; const nodeVersion = parseInt(versionString.replace(/^v/, '').split('.')[0]); // Node.js 22+ should have native WebSocket if (nodeVersion >= 22) { // Check if native WebSocket is available (should be in Node.js 22+) if (typeof globalThis.WebSocket !== 'undefined') { return { type: 'native', constructor: globalThis.WebSocket }; } // If not available, user needs to provide it return { type: 'unsupported', error: `Node.js ${nodeVersion} detected but native WebSocket not found.`, workaround: 'Provide a WebSocket implementation via the transport option.', }; } // Node.js < 22 doesn't have native WebSocket return { type: 'unsupported', error: `Node.js ${nodeVersion} detected without native WebSocket support.`, workaround: 'For Node.js < 22, install "ws" package and provide it via the transport option:\n' + 'import ws from "ws"\n' + 'new RealtimeClient(url, { transport: ws })', }; } } return { type: 'unsupported', error: 'Unknown JavaScript runtime without WebSocket support.', workaround: "Ensure you're running in a supported environment (browser, Node.js, Deno) or provide a custom WebSocket implementation.", }; } /** * Returns the best available WebSocket constructor for the current runtime. * * @example * ```ts * const WS = WebSocketFactory.getWebSocketConstructor() * const socket = new WS('wss://realtime.supabase.co/socket') * ``` */ static getWebSocketConstructor() { const env = this.detectEnvironment(); if (env.constructor) { return env.constructor; } let errorMessage = env.error || 'WebSocket not supported in this environment.'; if (env.workaround) { errorMessage += `\n\nSuggested solution: ${env.workaround}`; } throw new Error(errorMessage); } /** * Creates a WebSocket using the detected constructor. * * @example * ```ts * const socket = WebSocketFactory.createWebSocket('wss://realtime.supabase.co/socket') * ``` */ static createWebSocket(url, protocols) { const WS = this.getWebSocketConstructor(); return new WS(url, protocols); } /** * Detects whether the runtime can establish WebSocket connections. * * @example * ```ts * if (!WebSocketFactory.isWebSocketSupported()) { * console.warn('Falling back to long polling') * } * ``` */ static isWebSocketSupported() { try { const env = this.detectEnvironment(); return env.type === 'native' || env.type === 'ws'; } catch (_a) { return false; } } } export default WebSocketFactory; //# sourceMappingURL=websocket-factory.js.map