import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs'; import { A as AdapterHookable, a as adapterUtils } from '../shared/crossws.D9ehKjSh.mjs'; import { W as WSError } from '../shared/crossws.By9qWDAI.mjs'; import { _ as _WebSocketServer } from '../shared/crossws.CipVM6lf.mjs'; import 'uncrypto'; import 'stream'; import 'events'; import 'http'; import 'crypto'; import 'buffer'; import 'zlib'; import 'https'; import 'net'; import 'tls'; import 'url'; const nodeAdapter = (options = {}) => { const hooks = new AdapterHookable(options); const peers = /* @__PURE__ */ new Set(); const wss = options.wss || new _WebSocketServer({ noServer: true, ...options.serverOptions }); wss.on("connection", (ws, nodeReq) => { const request = new NodeReqProxy(nodeReq); const peer = new NodePeer({ ws, request, peers, nodeReq }); peers.add(peer); hooks.callHook("open", peer); ws.on("message", (data) => { if (Array.isArray(data)) { data = Buffer.concat(data); } hooks.callHook("message", peer, new Message(data, peer)); }); ws.on("error", (error) => { peers.delete(peer); hooks.callHook("error", peer, new WSError(error)); }); ws.on("close", (code, reason) => { peers.delete(peer); hooks.callHook("close", peer, { code, reason: reason?.toString() }); }); }); wss.on("headers", (outgoingHeaders, req) => { const upgradeHeaders = req._upgradeHeaders; if (upgradeHeaders) { for (const [key, value] of new Headers(upgradeHeaders)) { outgoingHeaders.push(`${key}: ${value}`); } } }); return { ...adapterUtils(peers), handleUpgrade: async (nodeReq, socket, head) => { const request = new NodeReqProxy(nodeReq); const { upgradeHeaders, endResponse, context } = await hooks.upgrade(request); if (endResponse) { return sendResponse(socket, endResponse); } nodeReq._request = request; nodeReq._upgradeHeaders = upgradeHeaders; nodeReq._context = context; wss.handleUpgrade(nodeReq, socket, head, (ws) => { wss.emit("connection", ws, nodeReq); }); }, closeAll: (code, data, force) => { for (const client of wss.clients) { if (force) { client.terminate(); } else { client.close(code, data); } } } }; }; class NodePeer extends Peer { get remoteAddress() { return this._internal.nodeReq.socket?.remoteAddress; } get context() { return this._internal.nodeReq._context; } send(data, options) { const dataBuff = toBufferLike(data); const isBinary = typeof dataBuff !== "string"; this._internal.ws.send(dataBuff, { compress: options?.compress, binary: isBinary, ...options }); return 0; } publish(topic, data, options) { const dataBuff = toBufferLike(data); const isBinary = typeof data !== "string"; const sendOptions = { compress: options?.compress, binary: isBinary, ...options }; for (const peer of this._internal.peers) { if (peer !== this && peer._topics.has(topic)) { peer._internal.ws.send(dataBuff, sendOptions); } } } close(code, data) { this._internal.ws.close(code, data); } terminate() { this._internal.ws.terminate(); } } class NodeReqProxy { _req; _headers; _url; constructor(req) { this._req = req; } get url() { if (!this._url) { const req = this._req; const host = req.headers["host"] || "localhost"; const isSecure = req.socket?.encrypted ?? req.headers["x-forwarded-proto"] === "https"; this._url = `${isSecure ? "https" : "http"}://${host}${req.url}`; } return this._url; } get headers() { if (!this._headers) { this._headers = new Headers(this._req.headers); } return this._headers; } } async function sendResponse(socket, res) { const head = [ `HTTP/1.1 ${res.status || 200} ${res.statusText || ""}`, ...[...res.headers.entries()].map( ([key, value]) => `${encodeURIComponent(key)}: ${encodeURIComponent(value)}` ) ]; socket.write(head.join("\r\n") + "\r\n\r\n"); if (res.body) { for await (const chunk of res.body) { socket.write(chunk); } } return new Promise((resolve) => { socket.end(() => { socket.destroy(); resolve(); }); }); } export { nodeAdapter as default };