( server: HttpServer | null, config: ResolvedConfig, httpsOptions?: HttpsServerOptions, )
| 116 | } |
| 117 | |
| 118 | export function createWebSocketServer( |
| 119 | server: HttpServer | null, |
| 120 | config: ResolvedConfig, |
| 121 | httpsOptions?: HttpsServerOptions, |
| 122 | ): WebSocketServer { |
| 123 | if (config.server.ws === false) { |
| 124 | return { |
| 125 | [isWebSocketServer]: true, |
| 126 | get clients() { |
| 127 | return new Set<WebSocketClient>() |
| 128 | }, |
| 129 | async close() { |
| 130 | // noop |
| 131 | }, |
| 132 | on: noop as any as WebSocketServer['on'], |
| 133 | off: noop as any as WebSocketServer['off'], |
| 134 | setInvokeHandler: noop, |
| 135 | handleInvoke: async () => ({ |
| 136 | error: { |
| 137 | name: 'TransportError', |
| 138 | message: 'handleInvoke not implemented', |
| 139 | stack: new Error().stack, |
| 140 | }, |
| 141 | }), |
| 142 | listen: noop, |
| 143 | send: noop, |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | let wsHttpServer: Server | undefined = undefined |
| 148 | |
| 149 | const wsOptions = isObject(config.server.ws) ? config.server.ws : undefined |
| 150 | const wsCustomServer = wsOptions?.server |
| 151 | const wsPort = wsOptions?.port |
| 152 | // TODO: the main server port may not have been chosen yet as it may use the next available |
| 153 | const portsAreCompatible = !wsPort || wsPort === config.server.port |
| 154 | const wsServer = wsCustomServer || (portsAreCompatible && server) |
| 155 | let hmrServerWsListener: ( |
| 156 | req: InstanceType<typeof IncomingMessage>, |
| 157 | socket: Duplex, |
| 158 | head: Buffer, |
| 159 | ) => void |
| 160 | const customListeners = new Map<string, Set<WebSocketCustomListener<any>>>() |
| 161 | const clientsMap = new WeakMap<WebSocketRaw, WebSocketClient>() |
| 162 | const port = wsPort || 24678 |
| 163 | const host = wsOptions?.host || undefined |
| 164 | const allowedHosts = |
| 165 | config.server.allowedHosts === true |
| 166 | ? config.server.allowedHosts |
| 167 | : Object.freeze([...config.server.allowedHosts]) // Freeze the array to allow caching |
| 168 | |
| 169 | const shouldHandle = (req: IncomingMessage) => { |
| 170 | const protocol = req.headers['sec-websocket-protocol']! |
| 171 | // vite-ping is allowed to connect from anywhere |
| 172 | // because it needs to be connected before the client fetches the new `/@vite/client` |
| 173 | // this is fine because vite-ping does not receive / send any meaningful data |
| 174 | if (protocol === 'vite-ping') return true |
| 175 |
no test coverage detected