Files
2026-03-03 23:49:13 +01:00

178 lines
5.5 KiB
JavaScript

//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let hono_ws = require("hono/ws");
hono_ws = __toESM(hono_ws);
let ws = require("ws");
ws = __toESM(ws);
let node_http = require("node:http");
node_http = __toESM(node_http);
//#region src/events.ts
/**
* @link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
*/
const CloseEvent = globalThis.CloseEvent ?? class extends Event {
#eventInitDict;
constructor(type, eventInitDict = {}) {
super(type, eventInitDict);
this.#eventInitDict = eventInitDict;
}
get wasClean() {
return this.#eventInitDict.wasClean ?? false;
}
get code() {
return this.#eventInitDict.code ?? 0;
}
get reason() {
return this.#eventInitDict.reason ?? "";
}
};
//#endregion
//#region src/index.ts
const generateConnectionSymbol = () => Symbol("connection");
/** @example `c.env[CONNECTION_SYMBOL_KEY]` */
const CONNECTION_SYMBOL_KEY = Symbol("CONNECTION_SYMBOL_KEY");
/**
* Create WebSockets for Node.js
* @param init Options
* @returns NodeWebSocket
*/
const createNodeWebSocket = (init) => {
const wss = new ws.WebSocketServer({ noServer: true });
const waiterMap = /* @__PURE__ */ new Map();
wss.on("connection", (ws$1, request) => {
const waiter = waiterMap.get(request);
if (waiter) {
waiter.resolve(ws$1);
waiterMap.delete(request);
}
});
const nodeUpgradeWebSocket = (request, connectionSymbol) => {
return new Promise((resolve) => {
waiterMap.set(request, {
resolve,
connectionSymbol
});
});
};
return {
wss,
injectWebSocket(server) {
server.on("upgrade", async (request, socket, head) => {
const url = new URL(request.url ?? "/", init.baseUrl ?? "http://localhost");
const headers = new Headers();
for (const key in request.headers) {
const value = request.headers[key];
if (!value) continue;
headers.append(key, Array.isArray(value) ? value[0] : value);
}
const env = {
incoming: request,
outgoing: void 0
};
const response = await init.app.request(url, { headers }, env);
const waiter = waiterMap.get(request);
if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
socket.end(`HTTP/1.1 ${response.status.toString()} ${node_http.STATUS_CODES[response.status] ?? ""}\r\nConnection: close\r
Content-Length: 0\r
\r
`);
waiterMap.delete(request);
return;
}
wss.handleUpgrade(request, socket, head, (ws$1) => {
wss.emit("connection", ws$1, request);
});
});
},
upgradeWebSocket: (0, hono_ws.defineWebSocketHelper)(async (c, events, options) => {
if (c.req.header("upgrade")?.toLowerCase() !== "websocket") return;
const connectionSymbol = generateConnectionSymbol();
c.env[CONNECTION_SYMBOL_KEY] = connectionSymbol;
(async () => {
const ws$1 = await nodeUpgradeWebSocket(c.env.incoming, connectionSymbol);
const messagesReceivedInStarting = [];
const bufferMessage = (data, isBinary) => {
messagesReceivedInStarting.push([data, isBinary]);
};
ws$1.on("message", bufferMessage);
const ctx = {
binaryType: "arraybuffer",
close(code, reason) {
ws$1.close(code, reason);
},
protocol: ws$1.protocol,
raw: ws$1,
get readyState() {
return ws$1.readyState;
},
send(source, opts) {
ws$1.send(source, { compress: opts?.compress });
},
url: new URL(c.req.url)
};
try {
events?.onOpen?.(new Event("open"), ctx);
} catch (e) {
(options?.onError ?? console.error)(e);
}
const handleMessage = (data, isBinary) => {
const datas = Array.isArray(data) ? data : [data];
for (const data$1 of datas) try {
events?.onMessage?.(new MessageEvent("message", { data: isBinary ? data$1 instanceof ArrayBuffer ? data$1 : data$1.buffer.slice(data$1.byteOffset, data$1.byteOffset + data$1.byteLength) : data$1.toString("utf-8") }), ctx);
} catch (e) {
(options?.onError ?? console.error)(e);
}
};
ws$1.off("message", bufferMessage);
for (const message of messagesReceivedInStarting) handleMessage(...message);
ws$1.on("message", (data, isBinary) => {
handleMessage(data, isBinary);
});
ws$1.on("close", (code, reason) => {
try {
events?.onClose?.(new CloseEvent("close", {
code,
reason: reason.toString()
}), ctx);
} catch (e) {
(options?.onError ?? console.error)(e);
}
});
ws$1.on("error", (error) => {
try {
events?.onError?.(new ErrorEvent("error", { error }), ctx);
} catch (e) {
(options?.onError ?? console.error)(e);
}
});
})();
return new Response();
})
};
};
//#endregion
exports.createNodeWebSocket = createNodeWebSocket;