elit 3.3.4 → 3.3.5
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/cli.js +34 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +33 -3
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +33 -3
- package/dist/server.mjs.map +1 -1
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +23 -2
- package/dist/ws.js.map +1 -1
- package/dist/ws.mjs +23 -2
- package/dist/ws.mjs.map +1 -1
- package/dist/wss.js +23 -2
- package/dist/wss.js.map +1 -1
- package/dist/wss.mjs +23 -2
- package/dist/wss.mjs.map +1 -1
- package/package.json +1 -1
- package/src/server.ts +13 -1
- package/src/ws.ts +32 -2
package/dist/ws.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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"}
|
package/dist/ws.js
CHANGED
|
@@ -253,13 +253,34 @@ var WebSocketServer = class extends import_events.EventEmitter {
|
|
|
253
253
|
client.emit("close", CLOSE_CODES.NORMAL, "");
|
|
254
254
|
});
|
|
255
255
|
socket.on("error", (error) => {
|
|
256
|
+
const errorCode = error.code;
|
|
257
|
+
if (errorCode === "ECONNABORTED" || errorCode === "ECONNRESET" || errorCode === "EPIPE") {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
256
260
|
client.emit("error", error);
|
|
257
261
|
});
|
|
258
262
|
client.send = (data, _options, callback) => {
|
|
263
|
+
if (!socket.writable || client.readyState !== 1 /* OPEN */) {
|
|
264
|
+
const err = new Error("WebSocket is not open");
|
|
265
|
+
err.code = "WS_NOT_OPEN";
|
|
266
|
+
queueCallback(callback, err);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
259
269
|
try {
|
|
260
270
|
const frame = this._createFrame(data);
|
|
261
|
-
socket.write(frame)
|
|
262
|
-
|
|
271
|
+
socket.write(frame, (err) => {
|
|
272
|
+
if (err) {
|
|
273
|
+
const errorCode = err.code;
|
|
274
|
+
if (errorCode !== "ECONNABORTED" && errorCode !== "ECONNRESET" && errorCode !== "EPIPE") {
|
|
275
|
+
queueCallback(callback, err);
|
|
276
|
+
} else {
|
|
277
|
+
client.readyState = 3 /* CLOSED */;
|
|
278
|
+
queueCallback(callback);
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
queueCallback(callback);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
263
284
|
} catch (error) {
|
|
264
285
|
queueCallback(callback, error);
|
|
265
286
|
}
|
package/dist/ws.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ws.ts","../src/runtime.ts"],"sourcesContent":["/**\n * WebSocket module with unified API across runtimes\n * Pure implementation without external dependencies\n * - Node.js: uses native 'ws' module (built-in WebSocket implementation)\n * - Bun: uses native WebSocket\n * - Deno: uses native WebSocket\n */\n\nimport { EventEmitter } from 'events';\nimport type { IncomingMessage } from './http';\nimport { runtime } from './runtime';\n\n/**\n * WebSocket ready state\n */\nexport enum ReadyState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket close codes\n */\nexport const CLOSE_CODES = {\n NORMAL: 1000,\n GOING_AWAY: 1001,\n PROTOCOL_ERROR: 1002,\n UNSUPPORTED_DATA: 1003,\n NO_STATUS: 1005,\n ABNORMAL: 1006,\n INVALID_DATA: 1007,\n POLICY_VIOLATION: 1008,\n MESSAGE_TOO_BIG: 1009,\n EXTENSION_REQUIRED: 1010,\n INTERNAL_ERROR: 1011,\n SERVICE_RESTART: 1012,\n TRY_AGAIN_LATER: 1013,\n BAD_GATEWAY: 1014,\n TLS_HANDSHAKE_FAIL: 1015,\n} as const;\n\n/**\n * WebSocket data types\n */\nexport type Data = string | Buffer | ArrayBuffer | Buffer[];\n\n/**\n * WebSocket send options\n */\nexport interface SendOptions {\n binary?: boolean;\n compress?: boolean;\n fin?: boolean;\n mask?: boolean;\n}\n\n/**\n * WebSocket server options\n */\nexport interface ServerOptions {\n host?: string;\n port?: number;\n backlog?: number;\n server?: any;\n verifyClient?: VerifyClientCallback;\n handleProtocols?: (protocols: Set<string>, request: IncomingMessage) => string | false;\n path?: string;\n noServer?: boolean;\n clientTracking?: boolean;\n perMessageDeflate?: boolean | object;\n maxPayload?: number;\n}\n\n/**\n * Verify client callback\n */\nexport type VerifyClientCallback = (\n info: {\n origin: string;\n secure: boolean;\n req: IncomingMessage;\n },\n callback?: (result: boolean, code?: number, message?: string) => void\n) => boolean | void;\n\n/**\n * Helper: Queue callback with optional error (eliminates duplication in callback handling)\n */\nfunction queueCallback(callback?: (err?: Error) => void, error?: Error): void {\n if (callback) {\n queueMicrotask(() => callback(error));\n }\n}\n\n/**\n * Helper: Create native WebSocket instance (eliminates duplication in constructor)\n */\nfunction createNativeWebSocket(url: string, protocols?: string[]): any {\n // @ts-ignore - WebSocket is available in Node.js 18+ and all modern runtimes\n if (runtime === 'node' && typeof globalThis.WebSocket === 'undefined') {\n throw new Error('WebSocket is not available. Please use Node.js 18+ or install ws package.');\n }\n // @ts-ignore\n return new globalThis.WebSocket(url, protocols);\n}\n\n/**\n * WebSocket class - Pure implementation\n */\nexport class WebSocket extends EventEmitter {\n public readyState: ReadyState = ReadyState.CONNECTING;\n public url: string;\n public protocol: string = '';\n public extensions: string = '';\n public binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments' = 'nodebuffer';\n\n /** @internal */\n public _socket: any;\n\n constructor(address: string | URL, protocols?: string | string[], _options?: any) {\n super();\n this.url = typeof address === 'string' ? address : address.toString();\n const protocolsArray = Array.isArray(protocols) ? protocols : protocols ? [protocols] : undefined;\n this._socket = createNativeWebSocket(this.url, protocolsArray);\n this._setupNativeSocket();\n }\n\n private _setupNativeSocket(): void {\n this._socket.onopen = () => {\n this.readyState = ReadyState.OPEN;\n this.emit('open');\n };\n\n this._socket.onmessage = (event: MessageEvent) => {\n const isBinary = event.data instanceof ArrayBuffer || event.data instanceof Blob;\n this.emit('message', event.data, isBinary);\n };\n\n this._socket.onclose = (event: CloseEvent) => {\n this.readyState = ReadyState.CLOSED;\n this.emit('close', event.code, event.reason);\n };\n\n this._socket.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n }\n\n /**\n * Send data through WebSocket\n */\n send(data: Data, options?: SendOptions | ((err?: Error) => void), callback?: (err?: Error) => void): void {\n const cb = typeof options === 'function' ? options : callback;\n\n if (this.readyState !== ReadyState.OPEN) {\n return queueCallback(cb, new Error('WebSocket is not open'));\n }\n\n try {\n this._socket.send(data);\n queueCallback(cb);\n } catch (error) {\n queueCallback(cb, error as Error);\n }\n }\n\n /**\n * Close the WebSocket connection\n */\n close(code?: number, reason?: string | Buffer): void {\n if (this.readyState === ReadyState.CLOSED || this.readyState === ReadyState.CLOSING) {\n return;\n }\n\n this.readyState = ReadyState.CLOSING;\n this._socket.close(code, typeof reason === 'string' ? reason : reason?.toString());\n }\n\n /**\n * Pause the socket (no-op for native WebSocket)\n */\n pause(): void {\n // Native WebSocket doesn't support pause\n }\n\n /**\n * Resume the socket (no-op for native WebSocket)\n */\n resume(): void {\n // Native WebSocket doesn't support resume\n }\n\n /**\n * Send a ping frame (no-op for native WebSocket)\n */\n ping(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose ping\n }\n\n /**\n * Send a pong frame (no-op for native WebSocket)\n */\n pong(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose pong\n }\n\n /**\n * Terminate the connection\n */\n terminate(): void {\n this._socket.close();\n this.readyState = ReadyState.CLOSED;\n }\n\n /**\n * Get buffered amount\n */\n get bufferedAmount(): number {\n return this._socket.bufferedAmount || 0;\n }\n}\n\n/**\n * WebSocket Server - Server-side WebSocket implementation\n */\nexport class WebSocketServer extends EventEmitter {\n public clients: Set<WebSocket> = new Set();\n public options: ServerOptions;\n public path: string;\n\n private _httpServer: any;\n\n constructor(options?: ServerOptions, callback?: () => void) {\n super();\n this.options = options || {};\n this.path = options?.path || '/';\n\n if (runtime === 'node') {\n // Node.js - create HTTP server with WebSocket upgrade\n if (options?.server) {\n this._httpServer = options.server;\n this._setupUpgradeHandler();\n } else if (options?.noServer) {\n // No server mode - user will call handleUpgrade manually\n } else {\n // Create new HTTP server\n const http = require('http');\n this._httpServer = http.createServer();\n this._setupUpgradeHandler();\n\n if (options?.port) {\n this._httpServer.listen(options.port, options.host, callback);\n }\n }\n } else {\n // Bun/Deno - WebSocket server setup\n queueCallback(callback as any);\n }\n }\n\n private _setupUpgradeHandler(): void {\n this._httpServer.on('upgrade', (request: any, socket: any, head: Buffer) => {\n console.log('[WebSocket] Upgrade request:', request.url, 'Expected:', this.path);\n if (this.path && this.path !== '/' && request.url !== this.path) {\n console.log('[WebSocket] Path mismatch, ignoring');\n return;\n }\n\n this.handleUpgrade(request, socket, head, (client) => {\n console.log('[WebSocket] Client connected');\n this.emit('connection', client, request);\n });\n });\n }\n\n /**\n * Handle HTTP upgrade for WebSocket\n */\n handleUpgrade(request: IncomingMessage, socket: any, _head: Buffer, callback: (client: WebSocket) => void): void {\n // Simple WebSocket handshake\n const key = request.headers['sec-websocket-key'];\n if (!key) {\n socket.end('HTTP/1.1 400 Bad Request\\r\\n\\r\\n');\n return;\n }\n\n // Generate accept key\n const crypto = require('crypto');\n const acceptKey = crypto\n .createHash('sha1')\n .update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')\n .digest('base64');\n\n // Send handshake response\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${acceptKey}`,\n '',\n ''\n ];\n\n socket.write(headers.join('\\r\\n'));\n\n // Create WebSocket client from raw socket\n const client = this._createClientFromSocket(socket);\n\n if (this.options.clientTracking !== false) {\n this.clients.add(client);\n client.on('close', () => {\n this.clients.delete(client);\n });\n }\n\n callback(client);\n }\n\n private _createClientFromSocket(socket: any): WebSocket {\n const client = Object.create(WebSocket.prototype);\n EventEmitter.call(client);\n\n client.readyState = ReadyState.OPEN;\n client.url = 'ws://localhost';\n client.protocol = '';\n client.extensions = '';\n client.binaryType = 'nodebuffer';\n client._socket = socket;\n\n // Handle incoming frames\n socket.on('data', (data: Buffer) => {\n // Simple frame parsing (minimal implementation)\n try {\n const message = this._parseFrame(data);\n if (message) {\n client.emit('message', message, false);\n }\n } catch (error) {\n client.emit('error', error);\n }\n });\n\n socket.on('end', () => {\n client.readyState = ReadyState.CLOSED;\n client.emit('close', CLOSE_CODES.NORMAL, '');\n });\n\n socket.on('error', (error: Error) => {\n client.emit('error', error);\n });\n\n // Override send method\n client.send = (data: Data, _options?: any, callback?: (err?: Error) => void) => {\n try {\n const frame = this._createFrame(data);\n socket.write(frame);\n queueCallback(callback);\n } catch (error) {\n queueCallback(callback, error as Error);\n }\n };\n\n // Override close method\n client.close = (_code?: number, _reason?: string) => {\n socket.end();\n client.readyState = ReadyState.CLOSED;\n };\n\n return client;\n }\n\n private _parseFrame(data: Buffer): string | null {\n // Minimal WebSocket frame parsing\n if (data.length < 2) return null;\n\n const firstByte = data[0];\n const secondByte = data[1];\n\n const opcode = firstByte & 0x0f;\n const isMasked = (secondByte & 0x80) === 0x80;\n let payloadLength = secondByte & 0x7f;\n let offset = 2;\n\n if (payloadLength === 126) {\n payloadLength = data.readUInt16BE(2);\n offset = 4;\n } else if (payloadLength === 127) {\n payloadLength = Number(data.readBigUInt64BE(2));\n offset = 10;\n }\n\n let payload = data.subarray(offset);\n\n if (isMasked) {\n const maskKey = data.subarray(offset, offset + 4);\n payload = data.subarray(offset + 4, offset + 4 + payloadLength);\n\n // Unmask payload\n for (let i = 0; i < payload.length; i++) {\n payload[i] ^= maskKey[i % 4];\n }\n }\n\n // Text frame (opcode 1)\n if (opcode === 1) {\n return payload.toString('utf8');\n }\n\n return null;\n }\n\n private _createFrame(data: Data): Buffer {\n // Create simple text frame (opcode 1, no masking)\n const payload = typeof data === 'string' ? Buffer.from(data) : data;\n const payloadLength = Buffer.isBuffer(payload) ? payload.length : 0;\n\n let frame: Buffer;\n let offset = 2;\n\n if (payloadLength < 126) {\n frame = Buffer.allocUnsafe(2 + payloadLength);\n frame[1] = payloadLength;\n } else if (payloadLength < 65536) {\n frame = Buffer.allocUnsafe(4 + payloadLength);\n frame[1] = 126;\n frame.writeUInt16BE(payloadLength, 2);\n offset = 4;\n } else {\n frame = Buffer.allocUnsafe(10 + payloadLength);\n frame[1] = 127;\n frame.writeBigUInt64BE(BigInt(payloadLength), 2);\n offset = 10;\n }\n\n frame[0] = 0x81; // FIN + text frame\n\n if (Buffer.isBuffer(payload)) {\n payload.copy(frame, offset);\n }\n\n return frame;\n }\n\n /**\n * Close the server\n */\n close(callback?: (err?: Error) => void): void {\n this.clients.forEach(client => client.close());\n this.clients.clear();\n\n if (this._httpServer) {\n this._httpServer.close(callback);\n } else {\n this.emit('close');\n queueCallback(callback);\n }\n }\n\n /**\n * Check if server should handle request\n */\n shouldHandle(request: IncomingMessage): boolean {\n if (this.path && request.url !== this.path) {\n return false;\n }\n return true;\n }\n\n /**\n * Get server address\n */\n address(): { port: number; family: string; address: string } | null {\n if (this._httpServer && this._httpServer.address) {\n return this._httpServer.address();\n }\n return null;\n }\n}\n\n/**\n * Create WebSocket server\n */\nexport function createWebSocketServer(options?: ServerOptions, callback?: () => void): WebSocketServer {\n return new WebSocketServer(options, callback);\n}\n\n/**\n * Get current runtime\n */\nexport function getRuntime(): 'node' | 'bun' | 'deno' {\n return runtime;\n}\n\n/**\n * Default export\n */\nexport default {\n WebSocket,\n WebSocketServer,\n createWebSocketServer,\n ReadyState,\n CLOSE_CODES,\n getRuntime,\n};\n","/**\n * Runtime detection and global type declarations\n * Shared across all modules for consistency\n */\n\n/**\n * Runtime detection (cached at module load)\n */\nexport const runtime = (() => {\n // @ts-ignore - Deno global\n if (typeof Deno !== 'undefined') return 'deno';\n // @ts-ignore - Bun global\n if (typeof Bun !== 'undefined') return 'bun';\n return 'node';\n})() as 'node' | 'bun' | 'deno';\n\nexport const isNode = runtime === 'node';\nexport const isBun = runtime === 'bun';\nexport const isDeno = runtime === 'deno';\n\n// Global declarations for runtime-specific APIs\ndeclare global {\n // @ts-ignore - Bun global\n const Bun: {\n build(options: {\n entrypoints: string[];\n outdir?: string;\n target?: string;\n format?: string;\n minify?: boolean;\n sourcemap?: string;\n external?: string[];\n naming?: string;\n plugins?: any[];\n define?: Record<string, string>;\n }): Promise<{\n success: boolean;\n outputs: Array<{ path: string; size: number }>;\n logs: any[];\n }>;\n Transpiler: new (options?: {\n loader?: string;\n target?: string;\n minify?: boolean;\n }) => {\n transform(code: string, loader?: string): Promise<string>;\n transformSync(code: string, loader?: string): string;\n };\n file(path: string): {\n size: number;\n arrayBuffer(): ArrayBuffer | Promise<ArrayBuffer>;\n exists(): Promise<boolean>;\n };\n write(path: string, data: string | Buffer | Uint8Array): Promise<void>;\n } | undefined;\n\n // @ts-ignore - Deno global\n const Deno: {\n emit(rootSpecifier: string | URL, options?: {\n bundle?: 'module' | 'classic';\n check?: boolean;\n compilerOptions?: any;\n importMap?: string;\n importMapPath?: string;\n sources?: Record<string, string>;\n }): Promise<{\n files: Record<string, string>;\n diagnostics: any[];\n }>;\n writeTextFile(path: string, data: string): Promise<void>;\n readFile(path: string): Promise<Uint8Array>;\n readFileSync(path: string): Uint8Array;\n writeFile(path: string, data: Uint8Array): Promise<void>;\n writeFileSync(path: string, data: Uint8Array): void;\n stat(path: string): Promise<any>;\n statSync(path: string): any;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n mkdirSync(path: string, options?: { recursive?: boolean }): void;\n readDir(path: string): AsyncIterable<any>;\n readDirSync(path: string): Iterable<any>;\n remove(path: string, options?: { recursive?: boolean }): Promise<void>;\n removeSync(path: string, options?: { recursive?: boolean }): void;\n rename(oldPath: string, newPath: string): Promise<void>;\n renameSync(oldPath: string, newPath: string): void;\n copyFile(src: string, dest: string): Promise<void>;\n copyFileSync(src: string, dest: string): void;\n realPath(path: string): Promise<string>;\n realPathSync(path: string): string;\n watchFs(paths: string | string[]): AsyncIterable<{\n kind: string;\n paths: string[];\n }>;\n build: {\n os: string;\n };\n } | undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,oBAA6B;;;ACAtB,IAAM,WAAW,MAAM;AAE5B,MAAI,OAAO,SAAS,YAAa,QAAO;AAExC,MAAI,OAAO,QAAQ,YAAa,QAAO;AACvC,SAAO;AACT,GAAG;;;ADCI,IAAK,aAAL,kBAAKA,gBAAL;AACL,EAAAA,wBAAA,gBAAa,KAAb;AACA,EAAAA,wBAAA,UAAO,KAAP;AACA,EAAAA,wBAAA,aAAU,KAAV;AACA,EAAAA,wBAAA,YAAS,KAAT;AAJU,SAAAA;AAAA,GAAA;AAUL,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,oBAAoB;AACtB;AAiDA,SAAS,cAAc,UAAkC,OAAqB;AAC5E,MAAI,UAAU;AACZ,mBAAe,MAAM,SAAS,KAAK,CAAC;AAAA,EACtC;AACF;AAKA,SAAS,sBAAsB,KAAa,WAA2B;AAErE,MAAI,YAAY,UAAU,OAAO,WAAW,cAAc,aAAa;AACrE,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC7F;AAEA,SAAO,IAAI,WAAW,UAAU,KAAK,SAAS;AAChD;AAKO,IAAM,YAAN,cAAwB,2BAAa;AAAA,EAU1C,YAAY,SAAuB,WAA+B,UAAgB;AAChF,UAAM;AAVR,SAAO,aAAyB;AAEhC,SAAO,WAAmB;AAC1B,SAAO,aAAqB;AAC5B,SAAO,aAAyD;AAO9D,SAAK,MAAM,OAAO,YAAY,WAAW,UAAU,QAAQ,SAAS;AACpE,UAAM,iBAAiB,MAAM,QAAQ,SAAS,IAAI,YAAY,YAAY,CAAC,SAAS,IAAI;AACxF,SAAK,UAAU,sBAAsB,KAAK,KAAK,cAAc;AAC7D,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEQ,qBAA2B;AACjC,SAAK,QAAQ,SAAS,MAAM;AAC1B,WAAK,aAAa;AAClB,WAAK,KAAK,MAAM;AAAA,IAClB;AAEA,SAAK,QAAQ,YAAY,CAAC,UAAwB;AAChD,YAAM,WAAW,MAAM,gBAAgB,eAAe,MAAM,gBAAgB;AAC5E,WAAK,KAAK,WAAW,MAAM,MAAM,QAAQ;AAAA,IAC3C;AAEA,SAAK,QAAQ,UAAU,CAAC,UAAsB;AAC5C,WAAK,aAAa;AAClB,WAAK,KAAK,SAAS,MAAM,MAAM,MAAM,MAAM;AAAA,IAC7C;AAEA,SAAK,QAAQ,UAAU,MAAM;AAC3B,WAAK,KAAK,SAAS,IAAI,MAAM,iBAAiB,CAAC;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,MAAY,SAAiD,UAAwC;AACxG,UAAM,KAAK,OAAO,YAAY,aAAa,UAAU;AAErD,QAAI,KAAK,eAAe,cAAiB;AACvC,aAAO,cAAc,IAAI,IAAI,MAAM,uBAAuB,CAAC;AAAA,IAC7D;AAEA,QAAI;AACF,WAAK,QAAQ,KAAK,IAAI;AACtB,oBAAc,EAAE;AAAA,IAClB,SAAS,OAAO;AACd,oBAAc,IAAI,KAAc;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAe,QAAgC;AACnD,QAAI,KAAK,eAAe,kBAAqB,KAAK,eAAe,iBAAoB;AACnF;AAAA,IACF;AAEA,SAAK,aAAa;AAClB,SAAK,QAAQ,MAAM,MAAM,OAAO,WAAW,WAAW,SAAS,QAAQ,SAAS,CAAC;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AAAA,EAEd;AAAA;AAAA;AAAA;AAAA,EAKA,SAAe;AAAA,EAEf;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAAc,OAAiB,UAAwC;AAC1E,kBAAc,QAAQ;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAAc,OAAiB,UAAwC;AAC1E,kBAAc,QAAQ;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAkB;AAChB,SAAK,QAAQ,MAAM;AACnB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,QAAQ,kBAAkB;AAAA,EACxC;AACF;AAKO,IAAM,kBAAN,cAA8B,2BAAa;AAAA,EAOhD,YAAY,SAAyB,UAAuB;AAC1D,UAAM;AAPR,SAAO,UAA0B,oBAAI,IAAI;AAQvC,SAAK,UAAU,WAAW,CAAC;AAC3B,SAAK,OAAO,SAAS,QAAQ;AAE7B,QAAI,YAAY,QAAQ;AAEtB,UAAI,SAAS,QAAQ;AACnB,aAAK,cAAc,QAAQ;AAC3B,aAAK,qBAAqB;AAAA,MAC5B,WAAW,SAAS,UAAU;AAAA,MAE9B,OAAO;AAEL,cAAM,OAAO,QAAQ,MAAM;AAC3B,aAAK,cAAc,KAAK,aAAa;AACrC,aAAK,qBAAqB;AAE1B,YAAI,SAAS,MAAM;AACjB,eAAK,YAAY,OAAO,QAAQ,MAAM,QAAQ,MAAM,QAAQ;AAAA,QAC9D;AAAA,MACF;AAAA,IACF,OAAO;AAEL,oBAAc,QAAe;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,uBAA6B;AACnC,SAAK,YAAY,GAAG,WAAW,CAAC,SAAc,QAAa,SAAiB;AAC1E,cAAQ,IAAI,gCAAgC,QAAQ,KAAK,aAAa,KAAK,IAAI;AAC/E,UAAI,KAAK,QAAQ,KAAK,SAAS,OAAO,QAAQ,QAAQ,KAAK,MAAM;AAC/D,gBAAQ,IAAI,qCAAqC;AACjD;AAAA,MACF;AAEA,WAAK,cAAc,SAAS,QAAQ,MAAM,CAAC,WAAW;AACpD,gBAAQ,IAAI,8BAA8B;AAC1C,aAAK,KAAK,cAAc,QAAQ,OAAO;AAAA,MACzC,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,SAA0B,QAAa,OAAe,UAA6C;AAE/G,UAAM,MAAM,QAAQ,QAAQ,mBAAmB;AAC/C,QAAI,CAAC,KAAK;AACR,aAAO,IAAI,kCAAkC;AAC7C;AAAA,IACF;AAGA,UAAM,SAAS,QAAQ,QAAQ;AAC/B,UAAM,YAAY,OACf,WAAW,MAAM,EACjB,OAAO,MAAM,sCAAsC,EACnD,OAAO,QAAQ;AAGlB,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA,yBAAyB,SAAS;AAAA,MAClC;AAAA,MACA;AAAA,IACF;AAEA,WAAO,MAAM,QAAQ,KAAK,MAAM,CAAC;AAGjC,UAAM,SAAS,KAAK,wBAAwB,MAAM;AAElD,QAAI,KAAK,QAAQ,mBAAmB,OAAO;AACzC,WAAK,QAAQ,IAAI,MAAM;AACvB,aAAO,GAAG,SAAS,MAAM;AACvB,aAAK,QAAQ,OAAO,MAAM;AAAA,MAC5B,CAAC;AAAA,IACH;AAEA,aAAS,MAAM;AAAA,EACjB;AAAA,EAEQ,wBAAwB,QAAwB;AACtD,UAAM,SAAS,OAAO,OAAO,UAAU,SAAS;AAChD,+BAAa,KAAK,MAAM;AAExB,WAAO,aAAa;AACpB,WAAO,MAAM;AACb,WAAO,WAAW;AAClB,WAAO,aAAa;AACpB,WAAO,aAAa;AACpB,WAAO,UAAU;AAGjB,WAAO,GAAG,QAAQ,CAAC,SAAiB;AAElC,UAAI;AACF,cAAM,UAAU,KAAK,YAAY,IAAI;AACrC,YAAI,SAAS;AACX,iBAAO,KAAK,WAAW,SAAS,KAAK;AAAA,QACvC;AAAA,MACF,SAAS,OAAO;AACd,eAAO,KAAK,SAAS,KAAK;AAAA,MAC5B;AAAA,IACF,CAAC;AAED,WAAO,GAAG,OAAO,MAAM;AACrB,aAAO,aAAa;AACpB,aAAO,KAAK,SAAS,YAAY,QAAQ,EAAE;AAAA,IAC7C,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,UAAiB;AACnC,aAAO,KAAK,SAAS,KAAK;AAAA,IAC5B,CAAC;AAGD,WAAO,OAAO,CAAC,MAAY,UAAgB,aAAqC;AAC9E,UAAI;AACF,cAAM,QAAQ,KAAK,aAAa,IAAI;AACpC,eAAO,MAAM,KAAK;AAClB,sBAAc,QAAQ;AAAA,MACxB,SAAS,OAAO;AACd,sBAAc,UAAU,KAAc;AAAA,MACxC;AAAA,IACF;AAGA,WAAO,QAAQ,CAAC,OAAgB,YAAqB;AACnD,aAAO,IAAI;AACX,aAAO,aAAa;AAAA,IACtB;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,MAA6B;AAE/C,QAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,UAAM,YAAY,KAAK,CAAC;AACxB,UAAM,aAAa,KAAK,CAAC;AAEzB,UAAM,SAAS,YAAY;AAC3B,UAAM,YAAY,aAAa,SAAU;AACzC,QAAI,gBAAgB,aAAa;AACjC,QAAI,SAAS;AAEb,QAAI,kBAAkB,KAAK;AACzB,sBAAgB,KAAK,aAAa,CAAC;AACnC,eAAS;AAAA,IACX,WAAW,kBAAkB,KAAK;AAChC,sBAAgB,OAAO,KAAK,gBAAgB,CAAC,CAAC;AAC9C,eAAS;AAAA,IACX;AAEA,QAAI,UAAU,KAAK,SAAS,MAAM;AAElC,QAAI,UAAU;AACZ,YAAM,UAAU,KAAK,SAAS,QAAQ,SAAS,CAAC;AAChD,gBAAU,KAAK,SAAS,SAAS,GAAG,SAAS,IAAI,aAAa;AAG9D,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,gBAAQ,CAAC,KAAK,QAAQ,IAAI,CAAC;AAAA,MAC7B;AAAA,IACF;AAGA,QAAI,WAAW,GAAG;AAChB,aAAO,QAAQ,SAAS,MAAM;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,MAAoB;AAEvC,UAAM,UAAU,OAAO,SAAS,WAAW,OAAO,KAAK,IAAI,IAAI;AAC/D,UAAM,gBAAgB,OAAO,SAAS,OAAO,IAAI,QAAQ,SAAS;AAElE,QAAI;AACJ,QAAI,SAAS;AAEb,QAAI,gBAAgB,KAAK;AACvB,cAAQ,OAAO,YAAY,IAAI,aAAa;AAC5C,YAAM,CAAC,IAAI;AAAA,IACb,WAAW,gBAAgB,OAAO;AAChC,cAAQ,OAAO,YAAY,IAAI,aAAa;AAC5C,YAAM,CAAC,IAAI;AACX,YAAM,cAAc,eAAe,CAAC;AACpC,eAAS;AAAA,IACX,OAAO;AACL,cAAQ,OAAO,YAAY,KAAK,aAAa;AAC7C,YAAM,CAAC,IAAI;AACX,YAAM,iBAAiB,OAAO,aAAa,GAAG,CAAC;AAC/C,eAAS;AAAA,IACX;AAEA,UAAM,CAAC,IAAI;AAEX,QAAI,OAAO,SAAS,OAAO,GAAG;AAC5B,cAAQ,KAAK,OAAO,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAwC;AAC5C,SAAK,QAAQ,QAAQ,YAAU,OAAO,MAAM,CAAC;AAC7C,SAAK,QAAQ,MAAM;AAEnB,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,MAAM,QAAQ;AAAA,IACjC,OAAO;AACL,WAAK,KAAK,OAAO;AACjB,oBAAc,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAmC;AAC9C,QAAI,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAAM;AAC1C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAoE;AAClE,QAAI,KAAK,eAAe,KAAK,YAAY,SAAS;AAChD,aAAO,KAAK,YAAY,QAAQ;AAAA,IAClC;AACA,WAAO;AAAA,EACT;AACF;AAKO,SAAS,sBAAsB,SAAyB,UAAwC;AACrG,SAAO,IAAI,gBAAgB,SAAS,QAAQ;AAC9C;AAKO,SAAS,aAAsC;AACpD,SAAO;AACT;AAKA,IAAO,aAAQ;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","names":["ReadyState"]}
|
|
1
|
+
{"version":3,"sources":["../src/ws.ts","../src/runtime.ts"],"sourcesContent":["/**\n * WebSocket module with unified API across runtimes\n * Pure implementation without external dependencies\n * - Node.js: uses native 'ws' module (built-in WebSocket implementation)\n * - Bun: uses native WebSocket\n * - Deno: uses native WebSocket\n */\n\nimport { EventEmitter } from 'events';\nimport type { IncomingMessage } from './http';\nimport { runtime } from './runtime';\n\n/**\n * WebSocket ready state\n */\nexport enum ReadyState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket close codes\n */\nexport const CLOSE_CODES = {\n NORMAL: 1000,\n GOING_AWAY: 1001,\n PROTOCOL_ERROR: 1002,\n UNSUPPORTED_DATA: 1003,\n NO_STATUS: 1005,\n ABNORMAL: 1006,\n INVALID_DATA: 1007,\n POLICY_VIOLATION: 1008,\n MESSAGE_TOO_BIG: 1009,\n EXTENSION_REQUIRED: 1010,\n INTERNAL_ERROR: 1011,\n SERVICE_RESTART: 1012,\n TRY_AGAIN_LATER: 1013,\n BAD_GATEWAY: 1014,\n TLS_HANDSHAKE_FAIL: 1015,\n} as const;\n\n/**\n * WebSocket data types\n */\nexport type Data = string | Buffer | ArrayBuffer | Buffer[];\n\n/**\n * WebSocket send options\n */\nexport interface SendOptions {\n binary?: boolean;\n compress?: boolean;\n fin?: boolean;\n mask?: boolean;\n}\n\n/**\n * WebSocket server options\n */\nexport interface ServerOptions {\n host?: string;\n port?: number;\n backlog?: number;\n server?: any;\n verifyClient?: VerifyClientCallback;\n handleProtocols?: (protocols: Set<string>, request: IncomingMessage) => string | false;\n path?: string;\n noServer?: boolean;\n clientTracking?: boolean;\n perMessageDeflate?: boolean | object;\n maxPayload?: number;\n}\n\n/**\n * Verify client callback\n */\nexport type VerifyClientCallback = (\n info: {\n origin: string;\n secure: boolean;\n req: IncomingMessage;\n },\n callback?: (result: boolean, code?: number, message?: string) => void\n) => boolean | void;\n\n/**\n * Helper: Queue callback with optional error (eliminates duplication in callback handling)\n */\nfunction queueCallback(callback?: (err?: Error) => void, error?: Error): void {\n if (callback) {\n queueMicrotask(() => callback(error));\n }\n}\n\n/**\n * Helper: Create native WebSocket instance (eliminates duplication in constructor)\n */\nfunction createNativeWebSocket(url: string, protocols?: string[]): any {\n // @ts-ignore - WebSocket is available in Node.js 18+ and all modern runtimes\n if (runtime === 'node' && typeof globalThis.WebSocket === 'undefined') {\n throw new Error('WebSocket is not available. Please use Node.js 18+ or install ws package.');\n }\n // @ts-ignore\n return new globalThis.WebSocket(url, protocols);\n}\n\n/**\n * WebSocket class - Pure implementation\n */\nexport class WebSocket extends EventEmitter {\n public readyState: ReadyState = ReadyState.CONNECTING;\n public url: string;\n public protocol: string = '';\n public extensions: string = '';\n public binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments' = 'nodebuffer';\n\n /** @internal */\n public _socket: any;\n\n constructor(address: string | URL, protocols?: string | string[], _options?: any) {\n super();\n this.url = typeof address === 'string' ? address : address.toString();\n const protocolsArray = Array.isArray(protocols) ? protocols : protocols ? [protocols] : undefined;\n this._socket = createNativeWebSocket(this.url, protocolsArray);\n this._setupNativeSocket();\n }\n\n private _setupNativeSocket(): void {\n this._socket.onopen = () => {\n this.readyState = ReadyState.OPEN;\n this.emit('open');\n };\n\n this._socket.onmessage = (event: MessageEvent) => {\n const isBinary = event.data instanceof ArrayBuffer || event.data instanceof Blob;\n this.emit('message', event.data, isBinary);\n };\n\n this._socket.onclose = (event: CloseEvent) => {\n this.readyState = ReadyState.CLOSED;\n this.emit('close', event.code, event.reason);\n };\n\n this._socket.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n }\n\n /**\n * Send data through WebSocket\n */\n send(data: Data, options?: SendOptions | ((err?: Error) => void), callback?: (err?: Error) => void): void {\n const cb = typeof options === 'function' ? options : callback;\n\n if (this.readyState !== ReadyState.OPEN) {\n return queueCallback(cb, new Error('WebSocket is not open'));\n }\n\n try {\n this._socket.send(data);\n queueCallback(cb);\n } catch (error) {\n queueCallback(cb, error as Error);\n }\n }\n\n /**\n * Close the WebSocket connection\n */\n close(code?: number, reason?: string | Buffer): void {\n if (this.readyState === ReadyState.CLOSED || this.readyState === ReadyState.CLOSING) {\n return;\n }\n\n this.readyState = ReadyState.CLOSING;\n this._socket.close(code, typeof reason === 'string' ? reason : reason?.toString());\n }\n\n /**\n * Pause the socket (no-op for native WebSocket)\n */\n pause(): void {\n // Native WebSocket doesn't support pause\n }\n\n /**\n * Resume the socket (no-op for native WebSocket)\n */\n resume(): void {\n // Native WebSocket doesn't support resume\n }\n\n /**\n * Send a ping frame (no-op for native WebSocket)\n */\n ping(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose ping\n }\n\n /**\n * Send a pong frame (no-op for native WebSocket)\n */\n pong(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose pong\n }\n\n /**\n * Terminate the connection\n */\n terminate(): void {\n this._socket.close();\n this.readyState = ReadyState.CLOSED;\n }\n\n /**\n * Get buffered amount\n */\n get bufferedAmount(): number {\n return this._socket.bufferedAmount || 0;\n }\n}\n\n/**\n * WebSocket Server - Server-side WebSocket implementation\n */\nexport class WebSocketServer extends EventEmitter {\n public clients: Set<WebSocket> = new Set();\n public options: ServerOptions;\n public path: string;\n\n private _httpServer: any;\n\n constructor(options?: ServerOptions, callback?: () => void) {\n super();\n this.options = options || {};\n this.path = options?.path || '/';\n\n if (runtime === 'node') {\n // Node.js - create HTTP server with WebSocket upgrade\n if (options?.server) {\n this._httpServer = options.server;\n this._setupUpgradeHandler();\n } else if (options?.noServer) {\n // No server mode - user will call handleUpgrade manually\n } else {\n // Create new HTTP server\n const http = require('http');\n this._httpServer = http.createServer();\n this._setupUpgradeHandler();\n\n if (options?.port) {\n this._httpServer.listen(options.port, options.host, callback);\n }\n }\n } else {\n // Bun/Deno - WebSocket server setup\n queueCallback(callback as any);\n }\n }\n\n private _setupUpgradeHandler(): void {\n this._httpServer.on('upgrade', (request: any, socket: any, head: Buffer) => {\n console.log('[WebSocket] Upgrade request:', request.url, 'Expected:', this.path);\n if (this.path && this.path !== '/' && request.url !== this.path) {\n console.log('[WebSocket] Path mismatch, ignoring');\n return;\n }\n\n this.handleUpgrade(request, socket, head, (client) => {\n console.log('[WebSocket] Client connected');\n this.emit('connection', client, request);\n });\n });\n }\n\n /**\n * Handle HTTP upgrade for WebSocket\n */\n handleUpgrade(request: IncomingMessage, socket: any, _head: Buffer, callback: (client: WebSocket) => void): void {\n // Simple WebSocket handshake\n const key = request.headers['sec-websocket-key'];\n if (!key) {\n socket.end('HTTP/1.1 400 Bad Request\\r\\n\\r\\n');\n return;\n }\n\n // Generate accept key\n const crypto = require('crypto');\n const acceptKey = crypto\n .createHash('sha1')\n .update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')\n .digest('base64');\n\n // Send handshake response\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${acceptKey}`,\n '',\n ''\n ];\n\n socket.write(headers.join('\\r\\n'));\n\n // Create WebSocket client from raw socket\n const client = this._createClientFromSocket(socket);\n\n if (this.options.clientTracking !== false) {\n this.clients.add(client);\n client.on('close', () => {\n this.clients.delete(client);\n });\n }\n\n callback(client);\n }\n\n private _createClientFromSocket(socket: any): WebSocket {\n const client = Object.create(WebSocket.prototype);\n EventEmitter.call(client);\n\n client.readyState = ReadyState.OPEN;\n client.url = 'ws://localhost';\n client.protocol = '';\n client.extensions = '';\n client.binaryType = 'nodebuffer';\n client._socket = socket;\n\n // Handle incoming frames\n socket.on('data', (data: Buffer) => {\n // Simple frame parsing (minimal implementation)\n try {\n const message = this._parseFrame(data);\n if (message) {\n client.emit('message', message, false);\n }\n } catch (error) {\n client.emit('error', error);\n }\n });\n\n socket.on('end', () => {\n client.readyState = ReadyState.CLOSED;\n client.emit('close', CLOSE_CODES.NORMAL, '');\n });\n\n socket.on('error', (error: Error) => {\n // Silently ignore connection errors (ECONNABORTED, ECONNRESET, etc.)\n // These are normal when clients disconnect during HMR\n const errorCode = (error as any).code;\n if (errorCode === 'ECONNABORTED' || errorCode === 'ECONNRESET' || errorCode === 'EPIPE') {\n // Silently ignore - connection was closed by client\n return;\n }\n // Only emit other errors\n client.emit('error', error);\n });\n\n // Override send method\n client.send = (data: Data, _options?: any, callback?: (err?: Error) => void) => {\n // Check if socket is still writable\n if (!socket.writable || client.readyState !== ReadyState.OPEN) {\n const err = new Error('WebSocket is not open');\n (err as any).code = 'WS_NOT_OPEN';\n queueCallback(callback, err);\n return;\n }\n\n try {\n const frame = this._createFrame(data);\n socket.write(frame, (err?: Error) => {\n // Handle async write errors (ECONNABORTED, ECONNRESET, etc.)\n if (err) {\n const errorCode = (err as any).code;\n // Silently ignore connection errors - these are normal during HMR\n if (errorCode !== 'ECONNABORTED' && errorCode !== 'ECONNRESET' && errorCode !== 'EPIPE') {\n queueCallback(callback, err);\n } else {\n // Connection closed - mark client as closed\n client.readyState = ReadyState.CLOSED;\n queueCallback(callback); // Call without error for graceful handling\n }\n } else {\n queueCallback(callback);\n }\n });\n } catch (error) {\n queueCallback(callback, error as Error);\n }\n };\n\n // Override close method\n client.close = (_code?: number, _reason?: string) => {\n socket.end();\n client.readyState = ReadyState.CLOSED;\n };\n\n return client;\n }\n\n private _parseFrame(data: Buffer): string | null {\n // Minimal WebSocket frame parsing\n if (data.length < 2) return null;\n\n const firstByte = data[0];\n const secondByte = data[1];\n\n const opcode = firstByte & 0x0f;\n const isMasked = (secondByte & 0x80) === 0x80;\n let payloadLength = secondByte & 0x7f;\n let offset = 2;\n\n if (payloadLength === 126) {\n payloadLength = data.readUInt16BE(2);\n offset = 4;\n } else if (payloadLength === 127) {\n payloadLength = Number(data.readBigUInt64BE(2));\n offset = 10;\n }\n\n let payload = data.subarray(offset);\n\n if (isMasked) {\n const maskKey = data.subarray(offset, offset + 4);\n payload = data.subarray(offset + 4, offset + 4 + payloadLength);\n\n // Unmask payload\n for (let i = 0; i < payload.length; i++) {\n payload[i] ^= maskKey[i % 4];\n }\n }\n\n // Text frame (opcode 1)\n if (opcode === 1) {\n return payload.toString('utf8');\n }\n\n return null;\n }\n\n private _createFrame(data: Data): Buffer {\n // Create simple text frame (opcode 1, no masking)\n const payload = typeof data === 'string' ? Buffer.from(data) : data;\n const payloadLength = Buffer.isBuffer(payload) ? payload.length : 0;\n\n let frame: Buffer;\n let offset = 2;\n\n if (payloadLength < 126) {\n frame = Buffer.allocUnsafe(2 + payloadLength);\n frame[1] = payloadLength;\n } else if (payloadLength < 65536) {\n frame = Buffer.allocUnsafe(4 + payloadLength);\n frame[1] = 126;\n frame.writeUInt16BE(payloadLength, 2);\n offset = 4;\n } else {\n frame = Buffer.allocUnsafe(10 + payloadLength);\n frame[1] = 127;\n frame.writeBigUInt64BE(BigInt(payloadLength), 2);\n offset = 10;\n }\n\n frame[0] = 0x81; // FIN + text frame\n\n if (Buffer.isBuffer(payload)) {\n payload.copy(frame, offset);\n }\n\n return frame;\n }\n\n /**\n * Close the server\n */\n close(callback?: (err?: Error) => void): void {\n this.clients.forEach(client => client.close());\n this.clients.clear();\n\n if (this._httpServer) {\n this._httpServer.close(callback);\n } else {\n this.emit('close');\n queueCallback(callback);\n }\n }\n\n /**\n * Check if server should handle request\n */\n shouldHandle(request: IncomingMessage): boolean {\n if (this.path && request.url !== this.path) {\n return false;\n }\n return true;\n }\n\n /**\n * Get server address\n */\n address(): { port: number; family: string; address: string } | null {\n if (this._httpServer && this._httpServer.address) {\n return this._httpServer.address();\n }\n return null;\n }\n}\n\n/**\n * Create WebSocket server\n */\nexport function createWebSocketServer(options?: ServerOptions, callback?: () => void): WebSocketServer {\n return new WebSocketServer(options, callback);\n}\n\n/**\n * Get current runtime\n */\nexport function getRuntime(): 'node' | 'bun' | 'deno' {\n return runtime;\n}\n\n/**\n * Default export\n */\nexport default {\n WebSocket,\n WebSocketServer,\n createWebSocketServer,\n ReadyState,\n CLOSE_CODES,\n getRuntime,\n};\n","/**\n * Runtime detection and global type declarations\n * Shared across all modules for consistency\n */\n\n/**\n * Runtime detection (cached at module load)\n */\nexport const runtime = (() => {\n // @ts-ignore - Deno global\n if (typeof Deno !== 'undefined') return 'deno';\n // @ts-ignore - Bun global\n if (typeof Bun !== 'undefined') return 'bun';\n return 'node';\n})() as 'node' | 'bun' | 'deno';\n\nexport const isNode = runtime === 'node';\nexport const isBun = runtime === 'bun';\nexport const isDeno = runtime === 'deno';\n\n// Global declarations for runtime-specific APIs\ndeclare global {\n // @ts-ignore - Bun global\n const Bun: {\n build(options: {\n entrypoints: string[];\n outdir?: string;\n target?: string;\n format?: string;\n minify?: boolean;\n sourcemap?: string;\n external?: string[];\n naming?: string;\n plugins?: any[];\n define?: Record<string, string>;\n }): Promise<{\n success: boolean;\n outputs: Array<{ path: string; size: number }>;\n logs: any[];\n }>;\n Transpiler: new (options?: {\n loader?: string;\n target?: string;\n minify?: boolean;\n }) => {\n transform(code: string, loader?: string): Promise<string>;\n transformSync(code: string, loader?: string): string;\n };\n file(path: string): {\n size: number;\n arrayBuffer(): ArrayBuffer | Promise<ArrayBuffer>;\n exists(): Promise<boolean>;\n };\n write(path: string, data: string | Buffer | Uint8Array): Promise<void>;\n } | undefined;\n\n // @ts-ignore - Deno global\n const Deno: {\n emit(rootSpecifier: string | URL, options?: {\n bundle?: 'module' | 'classic';\n check?: boolean;\n compilerOptions?: any;\n importMap?: string;\n importMapPath?: string;\n sources?: Record<string, string>;\n }): Promise<{\n files: Record<string, string>;\n diagnostics: any[];\n }>;\n writeTextFile(path: string, data: string): Promise<void>;\n readFile(path: string): Promise<Uint8Array>;\n readFileSync(path: string): Uint8Array;\n writeFile(path: string, data: Uint8Array): Promise<void>;\n writeFileSync(path: string, data: Uint8Array): void;\n stat(path: string): Promise<any>;\n statSync(path: string): any;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n mkdirSync(path: string, options?: { recursive?: boolean }): void;\n readDir(path: string): AsyncIterable<any>;\n readDirSync(path: string): Iterable<any>;\n remove(path: string, options?: { recursive?: boolean }): Promise<void>;\n removeSync(path: string, options?: { recursive?: boolean }): void;\n rename(oldPath: string, newPath: string): Promise<void>;\n renameSync(oldPath: string, newPath: string): void;\n copyFile(src: string, dest: string): Promise<void>;\n copyFileSync(src: string, dest: string): void;\n realPath(path: string): Promise<string>;\n realPathSync(path: string): string;\n watchFs(paths: string | string[]): AsyncIterable<{\n kind: string;\n paths: string[];\n }>;\n build: {\n os: string;\n };\n } | undefined;\n}\n"],"mappings":"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","names":["ReadyState"]}
|
package/dist/ws.mjs
CHANGED
|
@@ -231,13 +231,34 @@ var WebSocketServer = class extends EventEmitter {
|
|
|
231
231
|
client.emit("close", CLOSE_CODES.NORMAL, "");
|
|
232
232
|
});
|
|
233
233
|
socket.on("error", (error) => {
|
|
234
|
+
const errorCode = error.code;
|
|
235
|
+
if (errorCode === "ECONNABORTED" || errorCode === "ECONNRESET" || errorCode === "EPIPE") {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
234
238
|
client.emit("error", error);
|
|
235
239
|
});
|
|
236
240
|
client.send = (data, _options, callback) => {
|
|
241
|
+
if (!socket.writable || client.readyState !== 1 /* OPEN */) {
|
|
242
|
+
const err = new Error("WebSocket is not open");
|
|
243
|
+
err.code = "WS_NOT_OPEN";
|
|
244
|
+
queueCallback(callback, err);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
237
247
|
try {
|
|
238
248
|
const frame = this._createFrame(data);
|
|
239
|
-
socket.write(frame)
|
|
240
|
-
|
|
249
|
+
socket.write(frame, (err) => {
|
|
250
|
+
if (err) {
|
|
251
|
+
const errorCode = err.code;
|
|
252
|
+
if (errorCode !== "ECONNABORTED" && errorCode !== "ECONNRESET" && errorCode !== "EPIPE") {
|
|
253
|
+
queueCallback(callback, err);
|
|
254
|
+
} else {
|
|
255
|
+
client.readyState = 3 /* CLOSED */;
|
|
256
|
+
queueCallback(callback);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
queueCallback(callback);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
241
262
|
} catch (error) {
|
|
242
263
|
queueCallback(callback, error);
|
|
243
264
|
}
|
package/dist/ws.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ws.ts","../src/runtime.ts"],"sourcesContent":["/**\n * WebSocket module with unified API across runtimes\n * Pure implementation without external dependencies\n * - Node.js: uses native 'ws' module (built-in WebSocket implementation)\n * - Bun: uses native WebSocket\n * - Deno: uses native WebSocket\n */\n\nimport { EventEmitter } from 'events';\nimport type { IncomingMessage } from './http';\nimport { runtime } from './runtime';\n\n/**\n * WebSocket ready state\n */\nexport enum ReadyState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket close codes\n */\nexport const CLOSE_CODES = {\n NORMAL: 1000,\n GOING_AWAY: 1001,\n PROTOCOL_ERROR: 1002,\n UNSUPPORTED_DATA: 1003,\n NO_STATUS: 1005,\n ABNORMAL: 1006,\n INVALID_DATA: 1007,\n POLICY_VIOLATION: 1008,\n MESSAGE_TOO_BIG: 1009,\n EXTENSION_REQUIRED: 1010,\n INTERNAL_ERROR: 1011,\n SERVICE_RESTART: 1012,\n TRY_AGAIN_LATER: 1013,\n BAD_GATEWAY: 1014,\n TLS_HANDSHAKE_FAIL: 1015,\n} as const;\n\n/**\n * WebSocket data types\n */\nexport type Data = string | Buffer | ArrayBuffer | Buffer[];\n\n/**\n * WebSocket send options\n */\nexport interface SendOptions {\n binary?: boolean;\n compress?: boolean;\n fin?: boolean;\n mask?: boolean;\n}\n\n/**\n * WebSocket server options\n */\nexport interface ServerOptions {\n host?: string;\n port?: number;\n backlog?: number;\n server?: any;\n verifyClient?: VerifyClientCallback;\n handleProtocols?: (protocols: Set<string>, request: IncomingMessage) => string | false;\n path?: string;\n noServer?: boolean;\n clientTracking?: boolean;\n perMessageDeflate?: boolean | object;\n maxPayload?: number;\n}\n\n/**\n * Verify client callback\n */\nexport type VerifyClientCallback = (\n info: {\n origin: string;\n secure: boolean;\n req: IncomingMessage;\n },\n callback?: (result: boolean, code?: number, message?: string) => void\n) => boolean | void;\n\n/**\n * Helper: Queue callback with optional error (eliminates duplication in callback handling)\n */\nfunction queueCallback(callback?: (err?: Error) => void, error?: Error): void {\n if (callback) {\n queueMicrotask(() => callback(error));\n }\n}\n\n/**\n * Helper: Create native WebSocket instance (eliminates duplication in constructor)\n */\nfunction createNativeWebSocket(url: string, protocols?: string[]): any {\n // @ts-ignore - WebSocket is available in Node.js 18+ and all modern runtimes\n if (runtime === 'node' && typeof globalThis.WebSocket === 'undefined') {\n throw new Error('WebSocket is not available. Please use Node.js 18+ or install ws package.');\n }\n // @ts-ignore\n return new globalThis.WebSocket(url, protocols);\n}\n\n/**\n * WebSocket class - Pure implementation\n */\nexport class WebSocket extends EventEmitter {\n public readyState: ReadyState = ReadyState.CONNECTING;\n public url: string;\n public protocol: string = '';\n public extensions: string = '';\n public binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments' = 'nodebuffer';\n\n /** @internal */\n public _socket: any;\n\n constructor(address: string | URL, protocols?: string | string[], _options?: any) {\n super();\n this.url = typeof address === 'string' ? address : address.toString();\n const protocolsArray = Array.isArray(protocols) ? protocols : protocols ? [protocols] : undefined;\n this._socket = createNativeWebSocket(this.url, protocolsArray);\n this._setupNativeSocket();\n }\n\n private _setupNativeSocket(): void {\n this._socket.onopen = () => {\n this.readyState = ReadyState.OPEN;\n this.emit('open');\n };\n\n this._socket.onmessage = (event: MessageEvent) => {\n const isBinary = event.data instanceof ArrayBuffer || event.data instanceof Blob;\n this.emit('message', event.data, isBinary);\n };\n\n this._socket.onclose = (event: CloseEvent) => {\n this.readyState = ReadyState.CLOSED;\n this.emit('close', event.code, event.reason);\n };\n\n this._socket.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n }\n\n /**\n * Send data through WebSocket\n */\n send(data: Data, options?: SendOptions | ((err?: Error) => void), callback?: (err?: Error) => void): void {\n const cb = typeof options === 'function' ? options : callback;\n\n if (this.readyState !== ReadyState.OPEN) {\n return queueCallback(cb, new Error('WebSocket is not open'));\n }\n\n try {\n this._socket.send(data);\n queueCallback(cb);\n } catch (error) {\n queueCallback(cb, error as Error);\n }\n }\n\n /**\n * Close the WebSocket connection\n */\n close(code?: number, reason?: string | Buffer): void {\n if (this.readyState === ReadyState.CLOSED || this.readyState === ReadyState.CLOSING) {\n return;\n }\n\n this.readyState = ReadyState.CLOSING;\n this._socket.close(code, typeof reason === 'string' ? reason : reason?.toString());\n }\n\n /**\n * Pause the socket (no-op for native WebSocket)\n */\n pause(): void {\n // Native WebSocket doesn't support pause\n }\n\n /**\n * Resume the socket (no-op for native WebSocket)\n */\n resume(): void {\n // Native WebSocket doesn't support resume\n }\n\n /**\n * Send a ping frame (no-op for native WebSocket)\n */\n ping(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose ping\n }\n\n /**\n * Send a pong frame (no-op for native WebSocket)\n */\n pong(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose pong\n }\n\n /**\n * Terminate the connection\n */\n terminate(): void {\n this._socket.close();\n this.readyState = ReadyState.CLOSED;\n }\n\n /**\n * Get buffered amount\n */\n get bufferedAmount(): number {\n return this._socket.bufferedAmount || 0;\n }\n}\n\n/**\n * WebSocket Server - Server-side WebSocket implementation\n */\nexport class WebSocketServer extends EventEmitter {\n public clients: Set<WebSocket> = new Set();\n public options: ServerOptions;\n public path: string;\n\n private _httpServer: any;\n\n constructor(options?: ServerOptions, callback?: () => void) {\n super();\n this.options = options || {};\n this.path = options?.path || '/';\n\n if (runtime === 'node') {\n // Node.js - create HTTP server with WebSocket upgrade\n if (options?.server) {\n this._httpServer = options.server;\n this._setupUpgradeHandler();\n } else if (options?.noServer) {\n // No server mode - user will call handleUpgrade manually\n } else {\n // Create new HTTP server\n const http = require('http');\n this._httpServer = http.createServer();\n this._setupUpgradeHandler();\n\n if (options?.port) {\n this._httpServer.listen(options.port, options.host, callback);\n }\n }\n } else {\n // Bun/Deno - WebSocket server setup\n queueCallback(callback as any);\n }\n }\n\n private _setupUpgradeHandler(): void {\n this._httpServer.on('upgrade', (request: any, socket: any, head: Buffer) => {\n console.log('[WebSocket] Upgrade request:', request.url, 'Expected:', this.path);\n if (this.path && this.path !== '/' && request.url !== this.path) {\n console.log('[WebSocket] Path mismatch, ignoring');\n return;\n }\n\n this.handleUpgrade(request, socket, head, (client) => {\n console.log('[WebSocket] Client connected');\n this.emit('connection', client, request);\n });\n });\n }\n\n /**\n * Handle HTTP upgrade for WebSocket\n */\n handleUpgrade(request: IncomingMessage, socket: any, _head: Buffer, callback: (client: WebSocket) => void): void {\n // Simple WebSocket handshake\n const key = request.headers['sec-websocket-key'];\n if (!key) {\n socket.end('HTTP/1.1 400 Bad Request\\r\\n\\r\\n');\n return;\n }\n\n // Generate accept key\n const crypto = require('crypto');\n const acceptKey = crypto\n .createHash('sha1')\n .update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')\n .digest('base64');\n\n // Send handshake response\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${acceptKey}`,\n '',\n ''\n ];\n\n socket.write(headers.join('\\r\\n'));\n\n // Create WebSocket client from raw socket\n const client = this._createClientFromSocket(socket);\n\n if (this.options.clientTracking !== false) {\n this.clients.add(client);\n client.on('close', () => {\n this.clients.delete(client);\n });\n }\n\n callback(client);\n }\n\n private _createClientFromSocket(socket: any): WebSocket {\n const client = Object.create(WebSocket.prototype);\n EventEmitter.call(client);\n\n client.readyState = ReadyState.OPEN;\n client.url = 'ws://localhost';\n client.protocol = '';\n client.extensions = '';\n client.binaryType = 'nodebuffer';\n client._socket = socket;\n\n // Handle incoming frames\n socket.on('data', (data: Buffer) => {\n // Simple frame parsing (minimal implementation)\n try {\n const message = this._parseFrame(data);\n if (message) {\n client.emit('message', message, false);\n }\n } catch (error) {\n client.emit('error', error);\n }\n });\n\n socket.on('end', () => {\n client.readyState = ReadyState.CLOSED;\n client.emit('close', CLOSE_CODES.NORMAL, '');\n });\n\n socket.on('error', (error: Error) => {\n client.emit('error', error);\n });\n\n // Override send method\n client.send = (data: Data, _options?: any, callback?: (err?: Error) => void) => {\n try {\n const frame = this._createFrame(data);\n socket.write(frame);\n queueCallback(callback);\n } catch (error) {\n queueCallback(callback, error as Error);\n }\n };\n\n // Override close method\n client.close = (_code?: number, _reason?: string) => {\n socket.end();\n client.readyState = ReadyState.CLOSED;\n };\n\n return client;\n }\n\n private _parseFrame(data: Buffer): string | null {\n // Minimal WebSocket frame parsing\n if (data.length < 2) return null;\n\n const firstByte = data[0];\n const secondByte = data[1];\n\n const opcode = firstByte & 0x0f;\n const isMasked = (secondByte & 0x80) === 0x80;\n let payloadLength = secondByte & 0x7f;\n let offset = 2;\n\n if (payloadLength === 126) {\n payloadLength = data.readUInt16BE(2);\n offset = 4;\n } else if (payloadLength === 127) {\n payloadLength = Number(data.readBigUInt64BE(2));\n offset = 10;\n }\n\n let payload = data.subarray(offset);\n\n if (isMasked) {\n const maskKey = data.subarray(offset, offset + 4);\n payload = data.subarray(offset + 4, offset + 4 + payloadLength);\n\n // Unmask payload\n for (let i = 0; i < payload.length; i++) {\n payload[i] ^= maskKey[i % 4];\n }\n }\n\n // Text frame (opcode 1)\n if (opcode === 1) {\n return payload.toString('utf8');\n }\n\n return null;\n }\n\n private _createFrame(data: Data): Buffer {\n // Create simple text frame (opcode 1, no masking)\n const payload = typeof data === 'string' ? Buffer.from(data) : data;\n const payloadLength = Buffer.isBuffer(payload) ? payload.length : 0;\n\n let frame: Buffer;\n let offset = 2;\n\n if (payloadLength < 126) {\n frame = Buffer.allocUnsafe(2 + payloadLength);\n frame[1] = payloadLength;\n } else if (payloadLength < 65536) {\n frame = Buffer.allocUnsafe(4 + payloadLength);\n frame[1] = 126;\n frame.writeUInt16BE(payloadLength, 2);\n offset = 4;\n } else {\n frame = Buffer.allocUnsafe(10 + payloadLength);\n frame[1] = 127;\n frame.writeBigUInt64BE(BigInt(payloadLength), 2);\n offset = 10;\n }\n\n frame[0] = 0x81; // FIN + text frame\n\n if (Buffer.isBuffer(payload)) {\n payload.copy(frame, offset);\n }\n\n return frame;\n }\n\n /**\n * Close the server\n */\n close(callback?: (err?: Error) => void): void {\n this.clients.forEach(client => client.close());\n this.clients.clear();\n\n if (this._httpServer) {\n this._httpServer.close(callback);\n } else {\n this.emit('close');\n queueCallback(callback);\n }\n }\n\n /**\n * Check if server should handle request\n */\n shouldHandle(request: IncomingMessage): boolean {\n if (this.path && request.url !== this.path) {\n return false;\n }\n return true;\n }\n\n /**\n * Get server address\n */\n address(): { port: number; family: string; address: string } | null {\n if (this._httpServer && this._httpServer.address) {\n return this._httpServer.address();\n }\n return null;\n }\n}\n\n/**\n * Create WebSocket server\n */\nexport function createWebSocketServer(options?: ServerOptions, callback?: () => void): WebSocketServer {\n return new WebSocketServer(options, callback);\n}\n\n/**\n * Get current runtime\n */\nexport function getRuntime(): 'node' | 'bun' | 'deno' {\n return runtime;\n}\n\n/**\n * Default export\n */\nexport default {\n WebSocket,\n WebSocketServer,\n createWebSocketServer,\n ReadyState,\n CLOSE_CODES,\n getRuntime,\n};\n","/**\n * Runtime detection and global type declarations\n * Shared across all modules for consistency\n */\n\n/**\n * Runtime detection (cached at module load)\n */\nexport const runtime = (() => {\n // @ts-ignore - Deno global\n if (typeof Deno !== 'undefined') return 'deno';\n // @ts-ignore - Bun global\n if (typeof Bun !== 'undefined') return 'bun';\n return 'node';\n})() as 'node' | 'bun' | 'deno';\n\nexport const isNode = runtime === 'node';\nexport const isBun = runtime === 'bun';\nexport const isDeno = runtime === 'deno';\n\n// Global declarations for runtime-specific APIs\ndeclare global {\n // @ts-ignore - Bun global\n const Bun: {\n build(options: {\n entrypoints: string[];\n outdir?: string;\n target?: string;\n format?: string;\n minify?: boolean;\n sourcemap?: string;\n external?: string[];\n naming?: string;\n plugins?: any[];\n define?: Record<string, string>;\n }): Promise<{\n success: boolean;\n outputs: Array<{ path: string; size: number }>;\n logs: any[];\n }>;\n Transpiler: new (options?: {\n loader?: string;\n target?: string;\n minify?: boolean;\n }) => {\n transform(code: string, loader?: string): Promise<string>;\n transformSync(code: string, loader?: string): string;\n };\n file(path: string): {\n size: number;\n arrayBuffer(): ArrayBuffer | Promise<ArrayBuffer>;\n exists(): Promise<boolean>;\n };\n write(path: string, data: string | Buffer | Uint8Array): Promise<void>;\n } | undefined;\n\n // @ts-ignore - Deno global\n const Deno: {\n emit(rootSpecifier: string | URL, options?: {\n bundle?: 'module' | 'classic';\n check?: boolean;\n compilerOptions?: any;\n importMap?: string;\n importMapPath?: string;\n sources?: Record<string, string>;\n }): Promise<{\n files: Record<string, string>;\n diagnostics: any[];\n }>;\n writeTextFile(path: string, data: string): Promise<void>;\n readFile(path: string): Promise<Uint8Array>;\n readFileSync(path: string): Uint8Array;\n writeFile(path: string, data: Uint8Array): Promise<void>;\n writeFileSync(path: string, data: Uint8Array): void;\n stat(path: string): Promise<any>;\n statSync(path: string): any;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n mkdirSync(path: string, options?: { recursive?: boolean }): void;\n readDir(path: string): AsyncIterable<any>;\n readDirSync(path: string): Iterable<any>;\n remove(path: string, options?: { recursive?: boolean }): Promise<void>;\n removeSync(path: string, options?: { recursive?: boolean }): void;\n rename(oldPath: string, newPath: string): Promise<void>;\n renameSync(oldPath: string, newPath: string): void;\n copyFile(src: string, dest: string): Promise<void>;\n copyFileSync(src: string, dest: string): void;\n realPath(path: string): Promise<string>;\n realPathSync(path: string): string;\n watchFs(paths: string | string[]): AsyncIterable<{\n kind: string;\n paths: string[];\n }>;\n build: {\n os: string;\n };\n } | undefined;\n}\n"],"mappings":"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","names":["ReadyState"]}
|
|
1
|
+
{"version":3,"sources":["../src/ws.ts","../src/runtime.ts"],"sourcesContent":["/**\n * WebSocket module with unified API across runtimes\n * Pure implementation without external dependencies\n * - Node.js: uses native 'ws' module (built-in WebSocket implementation)\n * - Bun: uses native WebSocket\n * - Deno: uses native WebSocket\n */\n\nimport { EventEmitter } from 'events';\nimport type { IncomingMessage } from './http';\nimport { runtime } from './runtime';\n\n/**\n * WebSocket ready state\n */\nexport enum ReadyState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket close codes\n */\nexport const CLOSE_CODES = {\n NORMAL: 1000,\n GOING_AWAY: 1001,\n PROTOCOL_ERROR: 1002,\n UNSUPPORTED_DATA: 1003,\n NO_STATUS: 1005,\n ABNORMAL: 1006,\n INVALID_DATA: 1007,\n POLICY_VIOLATION: 1008,\n MESSAGE_TOO_BIG: 1009,\n EXTENSION_REQUIRED: 1010,\n INTERNAL_ERROR: 1011,\n SERVICE_RESTART: 1012,\n TRY_AGAIN_LATER: 1013,\n BAD_GATEWAY: 1014,\n TLS_HANDSHAKE_FAIL: 1015,\n} as const;\n\n/**\n * WebSocket data types\n */\nexport type Data = string | Buffer | ArrayBuffer | Buffer[];\n\n/**\n * WebSocket send options\n */\nexport interface SendOptions {\n binary?: boolean;\n compress?: boolean;\n fin?: boolean;\n mask?: boolean;\n}\n\n/**\n * WebSocket server options\n */\nexport interface ServerOptions {\n host?: string;\n port?: number;\n backlog?: number;\n server?: any;\n verifyClient?: VerifyClientCallback;\n handleProtocols?: (protocols: Set<string>, request: IncomingMessage) => string | false;\n path?: string;\n noServer?: boolean;\n clientTracking?: boolean;\n perMessageDeflate?: boolean | object;\n maxPayload?: number;\n}\n\n/**\n * Verify client callback\n */\nexport type VerifyClientCallback = (\n info: {\n origin: string;\n secure: boolean;\n req: IncomingMessage;\n },\n callback?: (result: boolean, code?: number, message?: string) => void\n) => boolean | void;\n\n/**\n * Helper: Queue callback with optional error (eliminates duplication in callback handling)\n */\nfunction queueCallback(callback?: (err?: Error) => void, error?: Error): void {\n if (callback) {\n queueMicrotask(() => callback(error));\n }\n}\n\n/**\n * Helper: Create native WebSocket instance (eliminates duplication in constructor)\n */\nfunction createNativeWebSocket(url: string, protocols?: string[]): any {\n // @ts-ignore - WebSocket is available in Node.js 18+ and all modern runtimes\n if (runtime === 'node' && typeof globalThis.WebSocket === 'undefined') {\n throw new Error('WebSocket is not available. Please use Node.js 18+ or install ws package.');\n }\n // @ts-ignore\n return new globalThis.WebSocket(url, protocols);\n}\n\n/**\n * WebSocket class - Pure implementation\n */\nexport class WebSocket extends EventEmitter {\n public readyState: ReadyState = ReadyState.CONNECTING;\n public url: string;\n public protocol: string = '';\n public extensions: string = '';\n public binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments' = 'nodebuffer';\n\n /** @internal */\n public _socket: any;\n\n constructor(address: string | URL, protocols?: string | string[], _options?: any) {\n super();\n this.url = typeof address === 'string' ? address : address.toString();\n const protocolsArray = Array.isArray(protocols) ? protocols : protocols ? [protocols] : undefined;\n this._socket = createNativeWebSocket(this.url, protocolsArray);\n this._setupNativeSocket();\n }\n\n private _setupNativeSocket(): void {\n this._socket.onopen = () => {\n this.readyState = ReadyState.OPEN;\n this.emit('open');\n };\n\n this._socket.onmessage = (event: MessageEvent) => {\n const isBinary = event.data instanceof ArrayBuffer || event.data instanceof Blob;\n this.emit('message', event.data, isBinary);\n };\n\n this._socket.onclose = (event: CloseEvent) => {\n this.readyState = ReadyState.CLOSED;\n this.emit('close', event.code, event.reason);\n };\n\n this._socket.onerror = () => {\n this.emit('error', new Error('WebSocket error'));\n };\n }\n\n /**\n * Send data through WebSocket\n */\n send(data: Data, options?: SendOptions | ((err?: Error) => void), callback?: (err?: Error) => void): void {\n const cb = typeof options === 'function' ? options : callback;\n\n if (this.readyState !== ReadyState.OPEN) {\n return queueCallback(cb, new Error('WebSocket is not open'));\n }\n\n try {\n this._socket.send(data);\n queueCallback(cb);\n } catch (error) {\n queueCallback(cb, error as Error);\n }\n }\n\n /**\n * Close the WebSocket connection\n */\n close(code?: number, reason?: string | Buffer): void {\n if (this.readyState === ReadyState.CLOSED || this.readyState === ReadyState.CLOSING) {\n return;\n }\n\n this.readyState = ReadyState.CLOSING;\n this._socket.close(code, typeof reason === 'string' ? reason : reason?.toString());\n }\n\n /**\n * Pause the socket (no-op for native WebSocket)\n */\n pause(): void {\n // Native WebSocket doesn't support pause\n }\n\n /**\n * Resume the socket (no-op for native WebSocket)\n */\n resume(): void {\n // Native WebSocket doesn't support resume\n }\n\n /**\n * Send a ping frame (no-op for native WebSocket)\n */\n ping(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose ping\n }\n\n /**\n * Send a pong frame (no-op for native WebSocket)\n */\n pong(_data?: Data, _mask?: boolean, callback?: (err?: Error) => void): void {\n queueCallback(callback); // Native WebSocket doesn't expose pong\n }\n\n /**\n * Terminate the connection\n */\n terminate(): void {\n this._socket.close();\n this.readyState = ReadyState.CLOSED;\n }\n\n /**\n * Get buffered amount\n */\n get bufferedAmount(): number {\n return this._socket.bufferedAmount || 0;\n }\n}\n\n/**\n * WebSocket Server - Server-side WebSocket implementation\n */\nexport class WebSocketServer extends EventEmitter {\n public clients: Set<WebSocket> = new Set();\n public options: ServerOptions;\n public path: string;\n\n private _httpServer: any;\n\n constructor(options?: ServerOptions, callback?: () => void) {\n super();\n this.options = options || {};\n this.path = options?.path || '/';\n\n if (runtime === 'node') {\n // Node.js - create HTTP server with WebSocket upgrade\n if (options?.server) {\n this._httpServer = options.server;\n this._setupUpgradeHandler();\n } else if (options?.noServer) {\n // No server mode - user will call handleUpgrade manually\n } else {\n // Create new HTTP server\n const http = require('http');\n this._httpServer = http.createServer();\n this._setupUpgradeHandler();\n\n if (options?.port) {\n this._httpServer.listen(options.port, options.host, callback);\n }\n }\n } else {\n // Bun/Deno - WebSocket server setup\n queueCallback(callback as any);\n }\n }\n\n private _setupUpgradeHandler(): void {\n this._httpServer.on('upgrade', (request: any, socket: any, head: Buffer) => {\n console.log('[WebSocket] Upgrade request:', request.url, 'Expected:', this.path);\n if (this.path && this.path !== '/' && request.url !== this.path) {\n console.log('[WebSocket] Path mismatch, ignoring');\n return;\n }\n\n this.handleUpgrade(request, socket, head, (client) => {\n console.log('[WebSocket] Client connected');\n this.emit('connection', client, request);\n });\n });\n }\n\n /**\n * Handle HTTP upgrade for WebSocket\n */\n handleUpgrade(request: IncomingMessage, socket: any, _head: Buffer, callback: (client: WebSocket) => void): void {\n // Simple WebSocket handshake\n const key = request.headers['sec-websocket-key'];\n if (!key) {\n socket.end('HTTP/1.1 400 Bad Request\\r\\n\\r\\n');\n return;\n }\n\n // Generate accept key\n const crypto = require('crypto');\n const acceptKey = crypto\n .createHash('sha1')\n .update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')\n .digest('base64');\n\n // Send handshake response\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${acceptKey}`,\n '',\n ''\n ];\n\n socket.write(headers.join('\\r\\n'));\n\n // Create WebSocket client from raw socket\n const client = this._createClientFromSocket(socket);\n\n if (this.options.clientTracking !== false) {\n this.clients.add(client);\n client.on('close', () => {\n this.clients.delete(client);\n });\n }\n\n callback(client);\n }\n\n private _createClientFromSocket(socket: any): WebSocket {\n const client = Object.create(WebSocket.prototype);\n EventEmitter.call(client);\n\n client.readyState = ReadyState.OPEN;\n client.url = 'ws://localhost';\n client.protocol = '';\n client.extensions = '';\n client.binaryType = 'nodebuffer';\n client._socket = socket;\n\n // Handle incoming frames\n socket.on('data', (data: Buffer) => {\n // Simple frame parsing (minimal implementation)\n try {\n const message = this._parseFrame(data);\n if (message) {\n client.emit('message', message, false);\n }\n } catch (error) {\n client.emit('error', error);\n }\n });\n\n socket.on('end', () => {\n client.readyState = ReadyState.CLOSED;\n client.emit('close', CLOSE_CODES.NORMAL, '');\n });\n\n socket.on('error', (error: Error) => {\n // Silently ignore connection errors (ECONNABORTED, ECONNRESET, etc.)\n // These are normal when clients disconnect during HMR\n const errorCode = (error as any).code;\n if (errorCode === 'ECONNABORTED' || errorCode === 'ECONNRESET' || errorCode === 'EPIPE') {\n // Silently ignore - connection was closed by client\n return;\n }\n // Only emit other errors\n client.emit('error', error);\n });\n\n // Override send method\n client.send = (data: Data, _options?: any, callback?: (err?: Error) => void) => {\n // Check if socket is still writable\n if (!socket.writable || client.readyState !== ReadyState.OPEN) {\n const err = new Error('WebSocket is not open');\n (err as any).code = 'WS_NOT_OPEN';\n queueCallback(callback, err);\n return;\n }\n\n try {\n const frame = this._createFrame(data);\n socket.write(frame, (err?: Error) => {\n // Handle async write errors (ECONNABORTED, ECONNRESET, etc.)\n if (err) {\n const errorCode = (err as any).code;\n // Silently ignore connection errors - these are normal during HMR\n if (errorCode !== 'ECONNABORTED' && errorCode !== 'ECONNRESET' && errorCode !== 'EPIPE') {\n queueCallback(callback, err);\n } else {\n // Connection closed - mark client as closed\n client.readyState = ReadyState.CLOSED;\n queueCallback(callback); // Call without error for graceful handling\n }\n } else {\n queueCallback(callback);\n }\n });\n } catch (error) {\n queueCallback(callback, error as Error);\n }\n };\n\n // Override close method\n client.close = (_code?: number, _reason?: string) => {\n socket.end();\n client.readyState = ReadyState.CLOSED;\n };\n\n return client;\n }\n\n private _parseFrame(data: Buffer): string | null {\n // Minimal WebSocket frame parsing\n if (data.length < 2) return null;\n\n const firstByte = data[0];\n const secondByte = data[1];\n\n const opcode = firstByte & 0x0f;\n const isMasked = (secondByte & 0x80) === 0x80;\n let payloadLength = secondByte & 0x7f;\n let offset = 2;\n\n if (payloadLength === 126) {\n payloadLength = data.readUInt16BE(2);\n offset = 4;\n } else if (payloadLength === 127) {\n payloadLength = Number(data.readBigUInt64BE(2));\n offset = 10;\n }\n\n let payload = data.subarray(offset);\n\n if (isMasked) {\n const maskKey = data.subarray(offset, offset + 4);\n payload = data.subarray(offset + 4, offset + 4 + payloadLength);\n\n // Unmask payload\n for (let i = 0; i < payload.length; i++) {\n payload[i] ^= maskKey[i % 4];\n }\n }\n\n // Text frame (opcode 1)\n if (opcode === 1) {\n return payload.toString('utf8');\n }\n\n return null;\n }\n\n private _createFrame(data: Data): Buffer {\n // Create simple text frame (opcode 1, no masking)\n const payload = typeof data === 'string' ? Buffer.from(data) : data;\n const payloadLength = Buffer.isBuffer(payload) ? payload.length : 0;\n\n let frame: Buffer;\n let offset = 2;\n\n if (payloadLength < 126) {\n frame = Buffer.allocUnsafe(2 + payloadLength);\n frame[1] = payloadLength;\n } else if (payloadLength < 65536) {\n frame = Buffer.allocUnsafe(4 + payloadLength);\n frame[1] = 126;\n frame.writeUInt16BE(payloadLength, 2);\n offset = 4;\n } else {\n frame = Buffer.allocUnsafe(10 + payloadLength);\n frame[1] = 127;\n frame.writeBigUInt64BE(BigInt(payloadLength), 2);\n offset = 10;\n }\n\n frame[0] = 0x81; // FIN + text frame\n\n if (Buffer.isBuffer(payload)) {\n payload.copy(frame, offset);\n }\n\n return frame;\n }\n\n /**\n * Close the server\n */\n close(callback?: (err?: Error) => void): void {\n this.clients.forEach(client => client.close());\n this.clients.clear();\n\n if (this._httpServer) {\n this._httpServer.close(callback);\n } else {\n this.emit('close');\n queueCallback(callback);\n }\n }\n\n /**\n * Check if server should handle request\n */\n shouldHandle(request: IncomingMessage): boolean {\n if (this.path && request.url !== this.path) {\n return false;\n }\n return true;\n }\n\n /**\n * Get server address\n */\n address(): { port: number; family: string; address: string } | null {\n if (this._httpServer && this._httpServer.address) {\n return this._httpServer.address();\n }\n return null;\n }\n}\n\n/**\n * Create WebSocket server\n */\nexport function createWebSocketServer(options?: ServerOptions, callback?: () => void): WebSocketServer {\n return new WebSocketServer(options, callback);\n}\n\n/**\n * Get current runtime\n */\nexport function getRuntime(): 'node' | 'bun' | 'deno' {\n return runtime;\n}\n\n/**\n * Default export\n */\nexport default {\n WebSocket,\n WebSocketServer,\n createWebSocketServer,\n ReadyState,\n CLOSE_CODES,\n getRuntime,\n};\n","/**\n * Runtime detection and global type declarations\n * Shared across all modules for consistency\n */\n\n/**\n * Runtime detection (cached at module load)\n */\nexport const runtime = (() => {\n // @ts-ignore - Deno global\n if (typeof Deno !== 'undefined') return 'deno';\n // @ts-ignore - Bun global\n if (typeof Bun !== 'undefined') return 'bun';\n return 'node';\n})() as 'node' | 'bun' | 'deno';\n\nexport const isNode = runtime === 'node';\nexport const isBun = runtime === 'bun';\nexport const isDeno = runtime === 'deno';\n\n// Global declarations for runtime-specific APIs\ndeclare global {\n // @ts-ignore - Bun global\n const Bun: {\n build(options: {\n entrypoints: string[];\n outdir?: string;\n target?: string;\n format?: string;\n minify?: boolean;\n sourcemap?: string;\n external?: string[];\n naming?: string;\n plugins?: any[];\n define?: Record<string, string>;\n }): Promise<{\n success: boolean;\n outputs: Array<{ path: string; size: number }>;\n logs: any[];\n }>;\n Transpiler: new (options?: {\n loader?: string;\n target?: string;\n minify?: boolean;\n }) => {\n transform(code: string, loader?: string): Promise<string>;\n transformSync(code: string, loader?: string): string;\n };\n file(path: string): {\n size: number;\n arrayBuffer(): ArrayBuffer | Promise<ArrayBuffer>;\n exists(): Promise<boolean>;\n };\n write(path: string, data: string | Buffer | Uint8Array): Promise<void>;\n } | undefined;\n\n // @ts-ignore - Deno global\n const Deno: {\n emit(rootSpecifier: string | URL, options?: {\n bundle?: 'module' | 'classic';\n check?: boolean;\n compilerOptions?: any;\n importMap?: string;\n importMapPath?: string;\n sources?: Record<string, string>;\n }): Promise<{\n files: Record<string, string>;\n diagnostics: any[];\n }>;\n writeTextFile(path: string, data: string): Promise<void>;\n readFile(path: string): Promise<Uint8Array>;\n readFileSync(path: string): Uint8Array;\n writeFile(path: string, data: Uint8Array): Promise<void>;\n writeFileSync(path: string, data: Uint8Array): void;\n stat(path: string): Promise<any>;\n statSync(path: string): any;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n mkdirSync(path: string, options?: { recursive?: boolean }): void;\n readDir(path: string): AsyncIterable<any>;\n readDirSync(path: string): Iterable<any>;\n remove(path: string, options?: { recursive?: boolean }): Promise<void>;\n removeSync(path: string, options?: { recursive?: boolean }): void;\n rename(oldPath: string, newPath: string): Promise<void>;\n renameSync(oldPath: string, newPath: string): void;\n copyFile(src: string, dest: string): Promise<void>;\n copyFileSync(src: string, dest: string): void;\n realPath(path: string): Promise<string>;\n realPathSync(path: string): string;\n watchFs(paths: string | string[]): AsyncIterable<{\n kind: string;\n paths: string[];\n }>;\n build: {\n os: string;\n };\n } | undefined;\n}\n"],"mappings":"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","names":["ReadyState"]}
|
package/dist/wss.js
CHANGED
|
@@ -1068,13 +1068,34 @@ var WebSocketServer = class extends import_events2.EventEmitter {
|
|
|
1068
1068
|
client.emit("close", CLOSE_CODES.NORMAL, "");
|
|
1069
1069
|
});
|
|
1070
1070
|
socket.on("error", (error) => {
|
|
1071
|
+
const errorCode = error.code;
|
|
1072
|
+
if (errorCode === "ECONNABORTED" || errorCode === "ECONNRESET" || errorCode === "EPIPE") {
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1071
1075
|
client.emit("error", error);
|
|
1072
1076
|
});
|
|
1073
1077
|
client.send = (data, _options, callback) => {
|
|
1078
|
+
if (!socket.writable || client.readyState !== 1 /* OPEN */) {
|
|
1079
|
+
const err = new Error("WebSocket is not open");
|
|
1080
|
+
err.code = "WS_NOT_OPEN";
|
|
1081
|
+
queueCallback3(callback, err);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1074
1084
|
try {
|
|
1075
1085
|
const frame = this._createFrame(data);
|
|
1076
|
-
socket.write(frame)
|
|
1077
|
-
|
|
1086
|
+
socket.write(frame, (err) => {
|
|
1087
|
+
if (err) {
|
|
1088
|
+
const errorCode = err.code;
|
|
1089
|
+
if (errorCode !== "ECONNABORTED" && errorCode !== "ECONNRESET" && errorCode !== "EPIPE") {
|
|
1090
|
+
queueCallback3(callback, err);
|
|
1091
|
+
} else {
|
|
1092
|
+
client.readyState = 3 /* CLOSED */;
|
|
1093
|
+
queueCallback3(callback);
|
|
1094
|
+
}
|
|
1095
|
+
} else {
|
|
1096
|
+
queueCallback3(callback);
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1078
1099
|
} catch (error) {
|
|
1079
1100
|
queueCallback3(callback, error);
|
|
1080
1101
|
}
|