aboutsummaryrefslogtreecommitdiff
path: root/src/js/out/modules/thirdparty/ws.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/out/modules/thirdparty/ws.js')
-rw-r--r--src/js/out/modules/thirdparty/ws.js681
1 files changed, 681 insertions, 0 deletions
diff --git a/src/js/out/modules/thirdparty/ws.js b/src/js/out/modules/thirdparty/ws.js
new file mode 100644
index 000000000..dd616d86a
--- /dev/null
+++ b/src/js/out/modules/thirdparty/ws.js
@@ -0,0 +1,681 @@
+var EventEmitter = import.meta.require("node:events");
+var http = import.meta.require("node:http");
+var emitWarning = function(type, message) {
+ if (emittedWarnings.has(type))
+ return;
+ emittedWarnings.add(type), console.warn("[bun] Warning:", message);
+}, subprotocolParse = function(header) {
+ const protocols = new Set;
+ let start = -1, end = -1, i = 0;
+ for (i;i < header.length; i++) {
+ const code = header.charCodeAt(i);
+ if (end === -1 && wsTokenChars[code] === 1) {
+ if (start === -1)
+ start = i;
+ } else if (i !== 0 && (code === 32 || code === 9)) {
+ if (end === -1 && start !== -1)
+ end = i;
+ } else if (code === 44) {
+ if (start === -1)
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ if (end === -1)
+ end = i;
+ const protocol2 = header.slice(start, end);
+ if (protocols.has(protocol2))
+ throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`);
+ protocols.add(protocol2), start = end = -1;
+ } else
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ if (start === -1 || end !== -1)
+ throw new SyntaxError("Unexpected end of input");
+ const protocol = header.slice(start, i);
+ if (protocols.has(protocol))
+ throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
+ return protocols.add(protocol), protocols;
+}, wsEmitClose = function(server) {
+ server._state = CLOSED, server.emit("close");
+}, abortHandshake = function(response, code, message, headers) {
+ message = message || http.STATUS_CODES[code], headers = {
+ Connection: "close",
+ "Content-Type": "text/html",
+ "Content-Length": Buffer.byteLength(message),
+ ...headers
+ }, response.writeHead(code, headers), response.write(message), response.end();
+}, abortHandshakeOrEmitwsClientError = function(server, req, response, socket, code, message) {
+ if (server.listenerCount("wsClientError")) {
+ const err = new Error(message);
+ Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError), server.emit("wsClientError", err, socket, req);
+ } else
+ abortHandshake(response, code, message);
+}, kBunInternals = Symbol.for("::bunternal::"), readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"], encoder = new TextEncoder, emittedWarnings = new Set;
+
+class BunWebSocket extends EventEmitter {
+ static CONNECTING = 0;
+ static OPEN = 1;
+ static CLOSING = 2;
+ static CLOSED = 3;
+ #ws;
+ #paused = !1;
+ #fragments = !1;
+ #binaryType = "nodebuffer";
+ readyState = BunWebSocket.CONNECTING;
+ constructor(url, protocols, options) {
+ super();
+ let ws = this.#ws = new WebSocket(url, protocols);
+ ws.binaryType = "nodebuffer", ws.addEventListener("open", () => {
+ this.readyState = BunWebSocket.OPEN, this.emit("open");
+ }), ws.addEventListener("error", (err) => {
+ this.readyState = BunWebSocket.CLOSED, this.emit("error", err);
+ }), ws.addEventListener("close", (ev) => {
+ this.readyState = BunWebSocket.CLOSED, this.emit("close", ev.code, ev.reason);
+ }), ws.addEventListener("message", (ev) => {
+ const isBinary = typeof ev.data !== "string";
+ if (isBinary)
+ this.emit("message", this.#fragments ? [ev.data] : ev.data, isBinary);
+ else {
+ var encoded = encoder.encode(ev.data);
+ if (this.#binaryType !== "arraybuffer")
+ encoded = Buffer.from(encoded.buffer, encoded.byteOffset, encoded.byteLength);
+ this.emit("message", this.#fragments ? [encoded] : encoded, isBinary);
+ }
+ });
+ }
+ on(event, listener) {
+ if (event === "unexpected-response" || event === "upgrade" || event === "ping" || event === "pong" || event === "redirect")
+ emitWarning(event, "ws.WebSocket '" + event + "' event is not implemented in bun");
+ return super.on(event, listener);
+ }
+ send(data, opts, cb) {
+ this.#ws.send(data, opts?.compress), typeof cb === "function" && cb();
+ }
+ close(code, reason) {
+ this.#ws.close(code, reason);
+ }
+ get binaryType() {
+ return this.#binaryType;
+ }
+ set binaryType(value) {
+ if (value)
+ this.#ws.binaryType = value;
+ }
+ set binaryType(value) {
+ if (value === "nodebuffer" || value === "arraybuffer")
+ this.#ws.binaryType = this.#binaryType = value, this.#fragments = !1;
+ else if (value === "fragments")
+ this.#ws.binaryType = "nodebuffer", this.#binaryType = "fragments", this.#fragments = !0;
+ }
+ get protocol() {
+ return this.#ws.protocol;
+ }
+ get extensions() {
+ return this.#ws.extensions;
+ }
+ addEventListener(type, listener, options) {
+ this.#ws.addEventListener(type, listener, options);
+ }
+ removeEventListener(type, listener) {
+ this.#ws.removeEventListener(type, listener);
+ }
+ get onopen() {
+ return this.#ws.onopen;
+ }
+ set onopen(value) {
+ this.#ws.onopen = value;
+ }
+ get onerror() {
+ return this.#ws.onerror;
+ }
+ set onerror(value) {
+ this.#ws.onerror = value;
+ }
+ get onclose() {
+ return this.#ws.onclose;
+ }
+ set onclose(value) {
+ this.#ws.onclose = value;
+ }
+ get onmessage() {
+ return this.#ws.onmessage;
+ }
+ set onmessage(value) {
+ this.#ws.onmessage = value;
+ }
+ get bufferedAmount() {
+ return this.#ws.bufferedAmount;
+ }
+ get isPaused() {
+ return this.#paused;
+ }
+ ping(data, mask, cb) {
+ if (this.readyState === BunWebSocket.CONNECTING)
+ throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
+ if (typeof data === "function")
+ cb = data, data = mask = void 0;
+ else if (typeof mask === "function")
+ cb = mask, mask = void 0;
+ if (typeof data === "number")
+ data = data.toString();
+ emitWarning("ping()", "ws.WebSocket.ping() is not implemented in bun"), typeof cb === "function" && cb();
+ }
+ pong(data, mask, cb) {
+ if (this.readyState === BunWebSocket.CONNECTING)
+ throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
+ if (typeof data === "function")
+ cb = data, data = mask = void 0;
+ else if (typeof mask === "function")
+ cb = mask, mask = void 0;
+ if (typeof data === "number")
+ data = data.toString();
+ emitWarning("pong()", "ws.WebSocket.pong() is not implemented in bun"), typeof cb === "function" && cb();
+ }
+ pause() {
+ if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED)
+ return;
+ this.#paused = !0, emitWarning("pause()", "ws.WebSocket.pause() is not implemented in bun");
+ }
+ resume() {
+ if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED)
+ return;
+ this.#paused = !1, emitWarning("resume()", "ws.WebSocket.resume() is not implemented in bun");
+ }
+}
+BunWebSocket.WebSocket = BunWebSocket;
+var wsKeyRegex = /^[+/0-9A-Za-z]{22}==$/, wsTokenChars = [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0
+], RUNNING = 0, CLOSING = 1, CLOSED = 2;
+
+class BunWebSocketMocked extends EventEmitter {
+ #ws;
+ #state;
+ #enquedMessages = [];
+ #url;
+ #protocol;
+ #extensions;
+ #bufferedAmount = 0;
+ #binaryType = "arraybuffer";
+ #onclose;
+ #onerror;
+ #onmessage;
+ #onopen;
+ constructor(url, protocol, extensions, binaryType) {
+ super();
+ if (this.#ws = null, this.#state = 0, this.#url = url, this.#bufferedAmount = 0, binaryType = binaryType || "arraybuffer", binaryType !== "nodebuffer" && binaryType !== "blob" && binaryType !== "arraybuffer")
+ throw new TypeError("binaryType must be either 'blob', 'arraybuffer' or 'nodebuffer'");
+ this.#binaryType = binaryType, this.#protocol = protocol, this.#extensions = extensions;
+ const message = this.#message.bind(this), open = this.#open.bind(this), close = this.#close.bind(this), drain = this.#drain.bind(this);
+ this[kBunInternals] = {
+ message,
+ open,
+ close,
+ drain
+ };
+ }
+ #message(ws, message) {
+ if (this.#ws = ws, typeof message === "string")
+ if (this.#binaryType === "arraybuffer")
+ message = encoder.encode(message).buffer;
+ else if (this.#binaryType === "blob")
+ message = new Blob([message], { type: "text/plain" });
+ else
+ message = Buffer.from(message);
+ else if (this.#binaryType !== "nodebuffer") {
+ if (this.#binaryType === "arraybuffer")
+ message = new Uint8Array(message);
+ else if (this.#binaryType === "blob")
+ message = new Blob([message]);
+ }
+ this.emit("message", message);
+ }
+ #open(ws) {
+ this.#ws = ws, this.#state = 1, this.emit("open", this), this.#drain(ws);
+ }
+ #close(ws, code, reason) {
+ this.#state = 3, this.#ws = null, this.emit("close", code, reason);
+ }
+ #drain(ws) {
+ const chunk = this.#enquedMessages[0];
+ if (chunk) {
+ const [data, compress, cb] = chunk;
+ if (ws.send(data, compress) == -1)
+ return;
+ typeof cb === "function" && cb(), this.#bufferedAmount -= chunk.length, this.#enquedMessages.shift();
+ }
+ }
+ send(data, opts, cb) {
+ if (this.#state === 1) {
+ const compress = opts?.compress;
+ if (this.#ws.send(data, compress) == -1) {
+ this.#enquedMessages.push([data, compress, cb]), this.#bufferedAmount += data.length;
+ return;
+ }
+ typeof cb === "function" && cb();
+ } else if (this.#state === 0)
+ this.#enquedMessages.push([data, opts?.compress, cb]), this.#bufferedAmount += data.length;
+ }
+ close(code, reason) {
+ if (this.#state === 1)
+ this.#state = 2, this.#ws.close(code, reason);
+ }
+ get binaryType() {
+ return this.#binaryType;
+ }
+ set binaryType(type) {
+ if (type !== "nodebuffer" && type !== "blob" && type !== "arraybuffer")
+ throw new TypeError("binaryType must be either 'blob', 'arraybuffer' or 'nodebuffer'");
+ this.#binaryType = type;
+ }
+ get readyState() {
+ return readyStates[this.#state];
+ }
+ get url() {
+ return this.#url;
+ }
+ get protocol() {
+ return this.#protocol;
+ }
+ get extensions() {
+ return this.#extensions;
+ }
+ get bufferedAmount() {
+ return this.#bufferedAmount ?? 0;
+ }
+ setSocket(socket, head, options) {
+ throw new Error("Not implemented");
+ }
+ set onclose(cb) {
+ if (this.#onclose)
+ this.removeListener("close", this.#onclose);
+ this.on("close", cb), this.#onclose = cb;
+ }
+ set onerror(cb) {
+ if (this.#onerror)
+ this.removeListener("error", this.#onerror);
+ this.on("error", cb), this.#onerror = cb;
+ }
+ set onmessage(cb) {
+ if (this.#onmessage)
+ this.removeListener("message", this.#onmessage);
+ this.on("message", cb), this.#onmessage = cb;
+ }
+ set onopen(cb) {
+ if (this.#onopen)
+ this.removeListener("open", this.#onopen);
+ this.on("open", cb), this.#onopen = cb;
+ }
+ get onclose() {
+ return this.#onclose;
+ }
+ get onerror() {
+ return this.#onerror;
+ }
+ get onmessage() {
+ return this.#onmessage;
+ }
+ get onopen() {
+ return this.#onopen;
+ }
+}
+
+class Server extends EventEmitter {
+ _server;
+ options;
+ clients;
+ _shouldEmitClose;
+ _state;
+ _removeListeners;
+ constructor(options, callback) {
+ super();
+ if (options = {
+ maxPayload: 104857600,
+ skipUTF8Validation: !1,
+ perMessageDeflate: !1,
+ handleProtocols: null,
+ clientTracking: !0,
+ verifyClient: null,
+ noServer: !1,
+ backlog: null,
+ server: null,
+ host: null,
+ path: null,
+ port: null,
+ ...options
+ }, options.port == null && !options.server && !options.noServer || options.port != null && (options.server || options.noServer) || options.server && options.noServer)
+ throw new TypeError('One and only one of the "port", "server", or "noServer" options must be specified');
+ if (options.port != null)
+ this._server = http.createServer((req, res) => {
+ const body = http.STATUS_CODES[426];
+ res.writeHead(426, {
+ "Content-Length": body.length,
+ "Content-Type": "text/plain"
+ }), res.end(body);
+ }), this._server.listen(options.port, options.host, options.backlog, callback);
+ else if (options.server)
+ this._server = options.server;
+ if (this._server) {
+ const emitConnection = this.emit.bind(this, "connection"), emitListening = this.emit.bind(this, "listening"), emitError = this.emit.bind(this, "error"), doUpgrade = (req, socket, head) => {
+ this.handleUpgrade(req, socket, head, emitConnection);
+ };
+ this._server.on("listening", emitListening), this._server.on("error", emitError), this._server.on("upgrade", doUpgrade), this._removeListeners = () => {
+ this._server.removeListener("upgrade", doUpgrade), this._server.removeListener("listening", emitListening), this._server.removeListener("error", emitError);
+ };
+ }
+ if (options.perMessageDeflate === !0)
+ options.perMessageDeflate = {};
+ if (options.clientTracking)
+ this.clients = new Set, this._shouldEmitClose = !1;
+ this.options = options, this._state = RUNNING;
+ }
+ address() {
+ if (this.options.noServer)
+ throw new Error('The server is operating in "noServer" mode');
+ if (!this._server)
+ return null;
+ return this._server.address();
+ }
+ close(cb) {
+ if (this._state === CLOSED) {
+ if (cb)
+ this.once("close", () => {
+ cb(new Error("The server is not running"));
+ });
+ process.nextTick((server) => {
+ server._state = CLOSED, server.emit("close");
+ }, this);
+ return;
+ }
+ if (cb)
+ this.once("close", cb);
+ if (this._state === CLOSING)
+ return;
+ if (this._state = CLOSING, this.options.noServer || this.options.server) {
+ if (this._server)
+ this._removeListeners(), this._removeListeners = this._server = null;
+ if (this.clients)
+ if (!this.clients.size)
+ process.nextTick((server) => {
+ server._state = CLOSED, server.emit("close");
+ }, this);
+ else
+ this._shouldEmitClose = !0;
+ else
+ process.nextTick((server) => {
+ server._state = CLOSED, server.emit("close");
+ }, this);
+ } else {
+ const server = this._server;
+ this._removeListeners(), this._removeListeners = this._server = null, server.close(() => {
+ this._state = CLOSED, this.emit("close");
+ });
+ }
+ }
+ shouldHandle(req) {
+ if (this.options.path) {
+ const index = req.url.indexOf("?");
+ if ((index !== -1 ? req.url.slice(0, index) : req.url) !== this.options.path)
+ return !1;
+ }
+ return !0;
+ }
+ completeUpgrade(extensions, key, protocols, request, socket, head, cb) {
+ const [server, response, req] = socket[kBunInternals];
+ if (this._state > RUNNING)
+ return abortHandshake(response, 503);
+ let protocol = "";
+ if (protocols.size)
+ protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, request) : protocols.values().next().value;
+ const ws = new BunWebSocketMocked(request.url, protocol, extensions, "nodebuffer"), headers = ["HTTP/1.1 101 Switching Protocols", "Upgrade: websocket", "Connection: Upgrade"];
+ if (this.emit("headers", headers, request), server.upgrade(req, {
+ data: ws[kBunInternals]
+ })) {
+ if (response._reply(void 0), this.clients)
+ this.clients.add(ws), ws.on("close", () => {
+ if (this.clients.delete(ws), this._shouldEmitClose && !this.clients.size)
+ process.nextTick(wsEmitClose, this);
+ });
+ cb(ws, request);
+ } else
+ abortHandshake(response, 500);
+ }
+ handleUpgrade(req, socket, head, cb) {
+ const [_, response] = socket[kBunInternals], key = req.headers["sec-websocket-key"], version = +req.headers["sec-websocket-version"];
+ if (req.method !== "GET") {
+ abortHandshakeOrEmitwsClientError(this, req, response, socket, 405, "Invalid HTTP method");
+ return;
+ }
+ if (req.headers.upgrade.toLowerCase() !== "websocket") {
+ abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, "Invalid Upgrade header");
+ return;
+ }
+ if (!key || !wsKeyRegex.test(key)) {
+ abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, "Missing or invalid Sec-WebSocket-Key header");
+ return;
+ }
+ if (version !== 8 && version !== 13) {
+ abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, "Missing or invalid Sec-WebSocket-Version header");
+ return;
+ }
+ if (!this.shouldHandle(req)) {
+ abortHandshake(response, 400);
+ return;
+ }
+ const secWebSocketProtocol = req.headers["sec-websocket-protocol"];
+ let protocols = new Set;
+ if (secWebSocketProtocol !== void 0)
+ try {
+ protocols = subprotocolParse(secWebSocketProtocol);
+ } catch (err) {
+ abortHandshakeOrEmitwsClientError(this, req, response, socket, 400, "Invalid Sec-WebSocket-Protocol header");
+ return;
+ }
+ const extensions = {};
+ if (this.options.verifyClient) {
+ const info = {
+ origin: req.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`],
+ secure: !!(req.socket.authorized || req.socket.encrypted),
+ req
+ };
+ if (this.options.verifyClient.length === 2) {
+ this.options.verifyClient(info, (verified, code, message, headers) => {
+ if (!verified)
+ return abortHandshake(response, code || 401, message, headers);
+ this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
+ });
+ return;
+ }
+ if (!this.options.verifyClient(info))
+ return abortHandshake(response, 401);
+ }
+ this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
+ }
+}
+BunWebSocket.WebSocketServer = Server;
+BunWebSocket.Server = Server;
+Object.defineProperty(BunWebSocket, "CONNECTING", {
+ enumerable: !0,
+ value: readyStates.indexOf("CONNECTING")
+});
+Object.defineProperty(BunWebSocket.prototype, "CONNECTING", {
+ enumerable: !0,
+ value: readyStates.indexOf("CONNECTING")
+});
+Object.defineProperty(BunWebSocket, "OPEN", {
+ enumerable: !0,
+ value: readyStates.indexOf("OPEN")
+});
+Object.defineProperty(BunWebSocket.prototype, "OPEN", {
+ enumerable: !0,
+ value: readyStates.indexOf("OPEN")
+});
+Object.defineProperty(BunWebSocket, "CLOSING", {
+ enumerable: !0,
+ value: readyStates.indexOf("CLOSING")
+});
+Object.defineProperty(BunWebSocket.prototype, "CLOSING", {
+ enumerable: !0,
+ value: readyStates.indexOf("CLOSING")
+});
+Object.defineProperty(BunWebSocket, "CLOSED", {
+ enumerable: !0,
+ value: readyStates.indexOf("CLOSED")
+});
+Object.defineProperty(BunWebSocket.prototype, "CLOSED", {
+ enumerable: !0,
+ value: readyStates.indexOf("CLOSED")
+});
+
+class Sender {
+ constructor() {
+ throw new Error("Not supported yet in Bun");
+ }
+}
+BunWebSocket.Sender = Sender;
+
+class Receiver {
+ constructor() {
+ throw new Error("Not supported yet in Bun");
+ }
+}
+BunWebSocket.Receiver = Receiver;
+var createWebSocketStream = (ws) => {
+ throw new Error("Not supported yet in Bun");
+};
+BunWebSocket.createWebSocketStream = createWebSocketStream;
+BunWebSocket[Symbol.for("CommonJS")] = 0;
+var ws_default = BunWebSocket;
+export {
+ ws_default as default,
+ createWebSocketStream,
+ Server as WebSocketServer,
+ BunWebSocket as WebSocket,
+ Server,
+ Sender,
+ Receiver
+};