UNPKG

@brainfish-ai/web-tracker

Version:

Brainfish Tracker for Web

1,767 lines 944 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2; var __publicField = (obj, key, value2) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value2); const PACKET_TYPES = /* @__PURE__ */ Object.create(null); PACKET_TYPES["open"] = "0"; PACKET_TYPES["close"] = "1"; PACKET_TYPES["ping"] = "2"; PACKET_TYPES["pong"] = "3"; PACKET_TYPES["message"] = "4"; PACKET_TYPES["upgrade"] = "5"; PACKET_TYPES["noop"] = "6"; const PACKET_TYPES_REVERSE = /* @__PURE__ */ Object.create(null); Object.keys(PACKET_TYPES).forEach((key) => { PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key; }); const ERROR_PACKET = { type: "error", data: "parser error" }; const withNativeBlob$1 = typeof Blob === "function" || typeof Blob !== "undefined" && Object.prototype.toString.call(Blob) === "[object BlobConstructor]"; const withNativeArrayBuffer$2 = typeof ArrayBuffer === "function"; const isView$1 = (obj) => { return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj && obj.buffer instanceof ArrayBuffer; }; const encodePacket = ({ type, data }, supportsBinary, callback) => { if (withNativeBlob$1 && data instanceof Blob) { if (supportsBinary) { return callback(data); } else { return encodeBlobAsBase64(data, callback); } } else if (withNativeArrayBuffer$2 && (data instanceof ArrayBuffer || isView$1(data))) { if (supportsBinary) { return callback(data); } else { return encodeBlobAsBase64(new Blob([data]), callback); } } return callback(PACKET_TYPES[type] + (data || "")); }; const encodeBlobAsBase64 = (data, callback) => { const fileReader = new FileReader(); fileReader.onload = function() { const content = fileReader.result.split(",")[1]; callback("b" + (content || "")); }; return fileReader.readAsDataURL(data); }; function toArray$1(data) { if (data instanceof Uint8Array) { return data; } else if (data instanceof ArrayBuffer) { return new Uint8Array(data); } else { return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); } } let TEXT_ENCODER; function encodePacketToBinary(packet, callback) { if (withNativeBlob$1 && packet.data instanceof Blob) { return packet.data.arrayBuffer().then(toArray$1).then(callback); } else if (withNativeArrayBuffer$2 && (packet.data instanceof ArrayBuffer || isView$1(packet.data))) { return callback(toArray$1(packet.data)); } encodePacket(packet, false, (encoded) => { if (!TEXT_ENCODER) { TEXT_ENCODER = new TextEncoder(); } callback(TEXT_ENCODER.encode(encoded)); }); } const chars$2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const lookup$3 = typeof Uint8Array === "undefined" ? [] : new Uint8Array(256); for (let i = 0; i < chars$2.length; i++) { lookup$3[chars$2.charCodeAt(i)] = i; } const decode$1 = (base64) => { let bufferLength = base64.length * 0.75, len = base64.length, i, p = 0, encoded1, encoded2, encoded3, encoded4; if (base64[base64.length - 1] === "=") { bufferLength--; if (base64[base64.length - 2] === "=") { bufferLength--; } } const arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer); for (i = 0; i < len; i += 4) { encoded1 = lookup$3[base64.charCodeAt(i)]; encoded2 = lookup$3[base64.charCodeAt(i + 1)]; encoded3 = lookup$3[base64.charCodeAt(i + 2)]; encoded4 = lookup$3[base64.charCodeAt(i + 3)]; bytes[p++] = encoded1 << 2 | encoded2 >> 4; bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2; bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63; } return arraybuffer; }; const withNativeArrayBuffer$1 = typeof ArrayBuffer === "function"; const decodePacket = (encodedPacket, binaryType) => { if (typeof encodedPacket !== "string") { return { type: "message", data: mapBinary(encodedPacket, binaryType) }; } const type = encodedPacket.charAt(0); if (type === "b") { return { type: "message", data: decodeBase64Packet(encodedPacket.substring(1), binaryType) }; } const packetType = PACKET_TYPES_REVERSE[type]; if (!packetType) { return ERROR_PACKET; } return encodedPacket.length > 1 ? { type: PACKET_TYPES_REVERSE[type], data: encodedPacket.substring(1) } : { type: PACKET_TYPES_REVERSE[type] }; }; const decodeBase64Packet = (data, binaryType) => { if (withNativeArrayBuffer$1) { const decoded = decode$1(data); return mapBinary(decoded, binaryType); } else { return { base64: true, data }; } }; const mapBinary = (data, binaryType) => { switch (binaryType) { case "blob": if (data instanceof Blob) { return data; } else { return new Blob([data]); } case "arraybuffer": default: if (data instanceof ArrayBuffer) { return data; } else { return data.buffer; } } }; const SEPARATOR = String.fromCharCode(30); const encodePayload = (packets, callback) => { const length = packets.length; const encodedPackets = new Array(length); let count = 0; packets.forEach((packet, i) => { encodePacket(packet, false, (encodedPacket) => { encodedPackets[i] = encodedPacket; if (++count === length) { callback(encodedPackets.join(SEPARATOR)); } }); }); }; const decodePayload = (encodedPayload, binaryType) => { const encodedPackets = encodedPayload.split(SEPARATOR); const packets = []; for (let i = 0; i < encodedPackets.length; i++) { const decodedPacket = decodePacket(encodedPackets[i], binaryType); packets.push(decodedPacket); if (decodedPacket.type === "error") { break; } } return packets; }; function createPacketEncoderStream() { return new TransformStream({ transform(packet, controller) { encodePacketToBinary(packet, (encodedPacket) => { const payloadLength = encodedPacket.length; let header; if (payloadLength < 126) { header = new Uint8Array(1); new DataView(header.buffer).setUint8(0, payloadLength); } else if (payloadLength < 65536) { header = new Uint8Array(3); const view = new DataView(header.buffer); view.setUint8(0, 126); view.setUint16(1, payloadLength); } else { header = new Uint8Array(9); const view = new DataView(header.buffer); view.setUint8(0, 127); view.setBigUint64(1, BigInt(payloadLength)); } if (packet.data && typeof packet.data !== "string") { header[0] |= 128; } controller.enqueue(header); controller.enqueue(encodedPacket); }); } }); } let TEXT_DECODER; function totalLength(chunks) { return chunks.reduce((acc, chunk) => acc + chunk.length, 0); } function concatChunks(chunks, size) { if (chunks[0].length === size) { return chunks.shift(); } const buffer = new Uint8Array(size); let j = 0; for (let i = 0; i < size; i++) { buffer[i] = chunks[0][j++]; if (j === chunks[0].length) { chunks.shift(); j = 0; } } if (chunks.length && j < chunks[0].length) { chunks[0] = chunks[0].slice(j); } return buffer; } function createPacketDecoderStream(maxPayload, binaryType) { if (!TEXT_DECODER) { TEXT_DECODER = new TextDecoder(); } const chunks = []; let state = 0; let expectedLength = -1; let isBinary2 = false; return new TransformStream({ transform(chunk, controller) { chunks.push(chunk); while (true) { if (state === 0) { if (totalLength(chunks) < 1) { break; } const header = concatChunks(chunks, 1); isBinary2 = (header[0] & 128) === 128; expectedLength = header[0] & 127; if (expectedLength < 126) { state = 3; } else if (expectedLength === 126) { state = 1; } else { state = 2; } } else if (state === 1) { if (totalLength(chunks) < 2) { break; } const headerArray = concatChunks(chunks, 2); expectedLength = new DataView(headerArray.buffer, headerArray.byteOffset, headerArray.length).getUint16(0); state = 3; } else if (state === 2) { if (totalLength(chunks) < 8) { break; } const headerArray = concatChunks(chunks, 8); const view = new DataView(headerArray.buffer, headerArray.byteOffset, headerArray.length); const n2 = view.getUint32(0); if (n2 > Math.pow(2, 53 - 32) - 1) { controller.enqueue(ERROR_PACKET); break; } expectedLength = n2 * Math.pow(2, 32) + view.getUint32(4); state = 3; } else { if (totalLength(chunks) < expectedLength) { break; } const data = concatChunks(chunks, expectedLength); controller.enqueue(decodePacket(isBinary2 ? data : TEXT_DECODER.decode(data), binaryType)); state = 0; } if (expectedLength === 0 || expectedLength > maxPayload) { controller.enqueue(ERROR_PACKET); break; } } } }); } const protocol$1 = 4; function Emitter(obj) { if (obj) return mixin(obj); } function mixin(obj) { for (var key in Emitter.prototype) { obj[key] = Emitter.prototype[key]; } return obj; } Emitter.prototype.on = Emitter.prototype.addEventListener = function(event, fn) { this._callbacks = this._callbacks || {}; (this._callbacks["$" + event] = this._callbacks["$" + event] || []).push(fn); return this; }; Emitter.prototype.once = function(event, fn) { function on2() { this.off(event, on2); fn.apply(this, arguments); } on2.fn = fn; this.on(event, on2); return this; }; Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function(event, fn) { this._callbacks = this._callbacks || {}; if (0 == arguments.length) { this._callbacks = {}; return this; } var callbacks = this._callbacks["$" + event]; if (!callbacks) return this; if (1 == arguments.length) { delete this._callbacks["$" + event]; return this; } var cb; for (var i = 0; i < callbacks.length; i++) { cb = callbacks[i]; if (cb === fn || cb.fn === fn) { callbacks.splice(i, 1); break; } } if (callbacks.length === 0) { delete this._callbacks["$" + event]; } return this; }; Emitter.prototype.emit = function(event) { this._callbacks = this._callbacks || {}; var args = new Array(arguments.length - 1), callbacks = this._callbacks["$" + event]; for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } if (callbacks) { callbacks = callbacks.slice(0); for (var i = 0, len = callbacks.length; i < len; ++i) { callbacks[i].apply(this, args); } } return this; }; Emitter.prototype.emitReserved = Emitter.prototype.emit; Emitter.prototype.listeners = function(event) { this._callbacks = this._callbacks || {}; return this._callbacks["$" + event] || []; }; Emitter.prototype.hasListeners = function(event) { return !!this.listeners(event).length; }; const nextTick = (() => { const isPromiseAvailable = typeof Promise === "function" && typeof Promise.resolve === "function"; if (isPromiseAvailable) { return (cb) => Promise.resolve().then(cb); } else { return (cb, setTimeoutFn) => setTimeoutFn(cb, 0); } })(); const globalThisShim = (() => { if (typeof self !== "undefined") { return self; } else if (typeof window !== "undefined") { return window; } else { return Function("return this")(); } })(); const defaultBinaryType = "arraybuffer"; function createCookieJar() { } function pick(obj, ...attr) { return attr.reduce((acc, k) => { if (obj.hasOwnProperty(k)) { acc[k] = obj[k]; } return acc; }, {}); } const NATIVE_SET_TIMEOUT = globalThisShim.setTimeout; const NATIVE_CLEAR_TIMEOUT = globalThisShim.clearTimeout; function installTimerFunctions(obj, opts) { if (opts.useNativeTimers) { obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThisShim); obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThisShim); } else { obj.setTimeoutFn = globalThisShim.setTimeout.bind(globalThisShim); obj.clearTimeoutFn = globalThisShim.clearTimeout.bind(globalThisShim); } } const BASE64_OVERHEAD = 1.33; function byteLength(obj) { if (typeof obj === "string") { return utf8Length(obj); } return Math.ceil((obj.byteLength || obj.size) * BASE64_OVERHEAD); } function utf8Length(str) { let c = 0, length = 0; for (let i = 0, l = str.length; i < l; i++) { c = str.charCodeAt(i); if (c < 128) { length += 1; } else if (c < 2048) { length += 2; } else if (c < 55296 || c >= 57344) { length += 3; } else { i++; length += 4; } } return length; } function randomString() { return Date.now().toString(36).substring(3) + Math.random().toString(36).substring(2, 5); } function encode$1(obj) { let str = ""; for (let i in obj) { if (obj.hasOwnProperty(i)) { if (str.length) str += "&"; str += encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]); } } return str; } function decode(qs) { let qry = {}; let pairs = qs.split("&"); for (let i = 0, l = pairs.length; i < l; i++) { let pair = pairs[i].split("="); qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); } return qry; } class TransportError extends Error { constructor(reason, description, context) { super(reason); this.description = description; this.context = context; this.type = "TransportError"; } } class Transport extends Emitter { /** * Transport abstract constructor. * * @param {Object} opts - options * @protected */ constructor(opts) { super(); this.writable = false; installTimerFunctions(this, opts); this.opts = opts; this.query = opts.query; this.socket = opts.socket; this.supportsBinary = !opts.forceBase64; } /** * Emits an error. * * @param {String} reason * @param description * @param context - the error context * @return {Transport} for chaining * @protected */ onError(reason, description, context) { super.emitReserved("error", new TransportError(reason, description, context)); return this; } /** * Opens the transport. */ open() { this.readyState = "opening"; this.doOpen(); return this; } /** * Closes the transport. */ close() { if (this.readyState === "opening" || this.readyState === "open") { this.doClose(); this.onClose(); } return this; } /** * Sends multiple packets. * * @param {Array} packets */ send(packets) { if (this.readyState === "open") { this.write(packets); } } /** * Called upon open * * @protected */ onOpen() { this.readyState = "open"; this.writable = true; super.emitReserved("open"); } /** * Called with data. * * @param {String} data * @protected */ onData(data) { const packet = decodePacket(data, this.socket.binaryType); this.onPacket(packet); } /** * Called with a decoded packet. * * @protected */ onPacket(packet) { super.emitReserved("packet", packet); } /** * Called upon close. * * @protected */ onClose(details) { this.readyState = "closed"; super.emitReserved("close", details); } /** * Pauses the transport, in order not to lose packets during an upgrade. * * @param onPause */ pause(onPause) { } createUri(schema, query = {}) { return schema + "://" + this._hostname() + this._port() + this.opts.path + this._query(query); } _hostname() { const hostname = this.opts.hostname; return hostname.indexOf(":") === -1 ? hostname : "[" + hostname + "]"; } _port() { if (this.opts.port && (this.opts.secure && Number(this.opts.port !== 443) || !this.opts.secure && Number(this.opts.port) !== 80)) { return ":" + this.opts.port; } else { return ""; } } _query(query) { const encodedQuery = encode$1(query); return encodedQuery.length ? "?" + encodedQuery : ""; } } class Polling extends Transport { constructor() { super(...arguments); this._polling = false; } get name() { return "polling"; } /** * Opens the socket (triggers polling). We write a PING message to determine * when the transport is open. * * @protected */ doOpen() { this._poll(); } /** * Pauses polling. * * @param {Function} onPause - callback upon buffers are flushed and transport is paused * @package */ pause(onPause) { this.readyState = "pausing"; const pause = () => { this.readyState = "paused"; onPause(); }; if (this._polling || !this.writable) { let total = 0; if (this._polling) { total++; this.once("pollComplete", function() { --total || pause(); }); } if (!this.writable) { total++; this.once("drain", function() { --total || pause(); }); } } else { pause(); } } /** * Starts polling cycle. * * @private */ _poll() { this._polling = true; this.doPoll(); this.emitReserved("poll"); } /** * Overloads onData to detect payloads. * * @protected */ onData(data) { const callback = (packet) => { if ("opening" === this.readyState && packet.type === "open") { this.onOpen(); } if ("close" === packet.type) { this.onClose({ description: "transport closed by the server" }); return false; } this.onPacket(packet); }; decodePayload(data, this.socket.binaryType).forEach(callback); if ("closed" !== this.readyState) { this._polling = false; this.emitReserved("pollComplete"); if ("open" === this.readyState) { this._poll(); } } } /** * For polling, send a close packet. * * @protected */ doClose() { const close = () => { this.write([{ type: "close" }]); }; if ("open" === this.readyState) { close(); } else { this.once("open", close); } } /** * Writes a packets payload. * * @param {Array} packets - data packets * @protected */ write(packets) { this.writable = false; encodePayload(packets, (data) => { this.doWrite(data, () => { this.writable = true; this.emitReserved("drain"); }); }); } /** * Generates uri for connection. * * @private */ uri() { const schema = this.opts.secure ? "https" : "http"; const query = this.query || {}; if (false !== this.opts.timestampRequests) { query[this.opts.timestampParam] = randomString(); } if (!this.supportsBinary && !query.sid) { query.b64 = 1; } return this.createUri(schema, query); } } let value = false; try { value = typeof XMLHttpRequest !== "undefined" && "withCredentials" in new XMLHttpRequest(); } catch (err) { } const hasCORS = value; function empty() { } class BaseXHR extends Polling { /** * XHR Polling constructor. * * @param {Object} opts * @package */ constructor(opts) { super(opts); if (typeof location !== "undefined") { const isSSL = "https:" === location.protocol; let port = location.port; if (!port) { port = isSSL ? "443" : "80"; } this.xd = typeof location !== "undefined" && opts.hostname !== location.hostname || port !== opts.port; } } /** * Sends data. * * @param {String} data to send. * @param {Function} called upon flush. * @private */ doWrite(data, fn) { const req = this.request({ method: "POST", data }); req.on("success", fn); req.on("error", (xhrStatus, context) => { this.onError("xhr post error", xhrStatus, context); }); } /** * Starts a poll cycle. * * @private */ doPoll() { const req = this.request(); req.on("data", this.onData.bind(this)); req.on("error", (xhrStatus, context) => { this.onError("xhr poll error", xhrStatus, context); }); this.pollXhr = req; } } class Request extends Emitter { /** * Request constructor * * @param {Object} options * @package */ constructor(createRequest, uri, opts) { super(); this.createRequest = createRequest; installTimerFunctions(this, opts); this._opts = opts; this._method = opts.method || "GET"; this._uri = uri; this._data = void 0 !== opts.data ? opts.data : null; this._create(); } /** * Creates the XHR object and sends the request. * * @private */ _create() { var _a2; const opts = pick(this._opts, "agent", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "autoUnref"); opts.xdomain = !!this._opts.xd; const xhr = this._xhr = this.createRequest(opts); try { xhr.open(this._method, this._uri, true); try { if (this._opts.extraHeaders) { xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true); for (let i in this._opts.extraHeaders) { if (this._opts.extraHeaders.hasOwnProperty(i)) { xhr.setRequestHeader(i, this._opts.extraHeaders[i]); } } } } catch (e) { } if ("POST" === this._method) { try { xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8"); } catch (e) { } } try { xhr.setRequestHeader("Accept", "*/*"); } catch (e) { } (_a2 = this._opts.cookieJar) === null || _a2 === void 0 ? void 0 : _a2.addCookies(xhr); if ("withCredentials" in xhr) { xhr.withCredentials = this._opts.withCredentials; } if (this._opts.requestTimeout) { xhr.timeout = this._opts.requestTimeout; } xhr.onreadystatechange = () => { var _a3; if (xhr.readyState === 3) { (_a3 = this._opts.cookieJar) === null || _a3 === void 0 ? void 0 : _a3.parseCookies( // @ts-ignore xhr.getResponseHeader("set-cookie") ); } if (4 !== xhr.readyState) return; if (200 === xhr.status || 1223 === xhr.status) { this._onLoad(); } else { this.setTimeoutFn(() => { this._onError(typeof xhr.status === "number" ? xhr.status : 0); }, 0); } }; xhr.send(this._data); } catch (e) { this.setTimeoutFn(() => { this._onError(e); }, 0); return; } if (typeof document !== "undefined") { this._index = Request.requestsCount++; Request.requests[this._index] = this; } } /** * Called upon error. * * @private */ _onError(err) { this.emitReserved("error", err, this._xhr); this._cleanup(true); } /** * Cleans up house. * * @private */ _cleanup(fromError) { if ("undefined" === typeof this._xhr || null === this._xhr) { return; } this._xhr.onreadystatechange = empty; if (fromError) { try { this._xhr.abort(); } catch (e) { } } if (typeof document !== "undefined") { delete Request.requests[this._index]; } this._xhr = null; } /** * Called upon load. * * @private */ _onLoad() { const data = this._xhr.responseText; if (data !== null) { this.emitReserved("data", data); this.emitReserved("success"); this._cleanup(); } } /** * Aborts the request. * * @package */ abort() { this._cleanup(); } } Request.requestsCount = 0; Request.requests = {}; if (typeof document !== "undefined") { if (typeof attachEvent === "function") { attachEvent("onunload", unloadHandler); } else if (typeof addEventListener === "function") { const terminationEvent = "onpagehide" in globalThisShim ? "pagehide" : "unload"; addEventListener(terminationEvent, unloadHandler, false); } } function unloadHandler() { for (let i in Request.requests) { if (Request.requests.hasOwnProperty(i)) { Request.requests[i].abort(); } } } const hasXHR2 = function() { const xhr = newRequest({ xdomain: false }); return xhr && xhr.responseType !== null; }(); class XHR extends BaseXHR { constructor(opts) { super(opts); const forceBase64 = opts && opts.forceBase64; this.supportsBinary = hasXHR2 && !forceBase64; } request(opts = {}) { Object.assign(opts, { xd: this.xd }, this.opts); return new Request(newRequest, this.uri(), opts); } } function newRequest(opts) { const xdomain = opts.xdomain; try { if ("undefined" !== typeof XMLHttpRequest && (!xdomain || hasCORS)) { return new XMLHttpRequest(); } } catch (e) { } if (!xdomain) { try { return new globalThisShim[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP"); } catch (e) { } } } const isReactNative = typeof navigator !== "undefined" && typeof navigator.product === "string" && navigator.product.toLowerCase() === "reactnative"; class BaseWS extends Transport { get name() { return "websocket"; } doOpen() { const uri = this.uri(); const protocols = this.opts.protocols; const opts = isReactNative ? {} : pick(this.opts, "agent", "perMessageDeflate", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "localAddress", "protocolVersion", "origin", "maxPayload", "family", "checkServerIdentity"); if (this.opts.extraHeaders) { opts.headers = this.opts.extraHeaders; } try { this.ws = this.createSocket(uri, protocols, opts); } catch (err) { return this.emitReserved("error", err); } this.ws.binaryType = this.socket.binaryType; this.addEventListeners(); } /** * Adds event listeners to the socket * * @private */ addEventListeners() { this.ws.onopen = () => { if (this.opts.autoUnref) { this.ws._socket.unref(); } this.onOpen(); }; this.ws.onclose = (closeEvent) => this.onClose({ description: "websocket connection closed", context: closeEvent }); this.ws.onmessage = (ev) => this.onData(ev.data); this.ws.onerror = (e) => this.onError("websocket error", e); } write(packets) { this.writable = false; for (let i = 0; i < packets.length; i++) { const packet = packets[i]; const lastPacket = i === packets.length - 1; encodePacket(packet, this.supportsBinary, (data) => { try { this.doWrite(packet, data); } catch (e) { } if (lastPacket) { nextTick(() => { this.writable = true; this.emitReserved("drain"); }, this.setTimeoutFn); } }); } } doClose() { if (typeof this.ws !== "undefined") { this.ws.onerror = () => { }; this.ws.close(); this.ws = null; } } /** * Generates uri for connection. * * @private */ uri() { const schema = this.opts.secure ? "wss" : "ws"; const query = this.query || {}; if (this.opts.timestampRequests) { query[this.opts.timestampParam] = randomString(); } if (!this.supportsBinary) { query.b64 = 1; } return this.createUri(schema, query); } } const WebSocketCtor = globalThisShim.WebSocket || globalThisShim.MozWebSocket; class WS extends BaseWS { createSocket(uri, protocols, opts) { return !isReactNative ? protocols ? new WebSocketCtor(uri, protocols) : new WebSocketCtor(uri) : new WebSocketCtor(uri, protocols, opts); } doWrite(_packet, data) { this.ws.send(data); } } class WT extends Transport { get name() { return "webtransport"; } doOpen() { try { this._transport = new WebTransport(this.createUri("https"), this.opts.transportOptions[this.name]); } catch (err) { return this.emitReserved("error", err); } this._transport.closed.then(() => { this.onClose(); }).catch((err) => { this.onError("webtransport error", err); }); this._transport.ready.then(() => { this._transport.createBidirectionalStream().then((stream) => { const decoderStream = createPacketDecoderStream(Number.MAX_SAFE_INTEGER, this.socket.binaryType); const reader = stream.readable.pipeThrough(decoderStream).getReader(); const encoderStream = createPacketEncoderStream(); encoderStream.readable.pipeTo(stream.writable); this._writer = encoderStream.writable.getWriter(); const read = () => { reader.read().then(({ done, value: value2 }) => { if (done) { return; } this.onPacket(value2); read(); }).catch((err) => { }); }; read(); const packet = { type: "open" }; if (this.query.sid) { packet.data = `{"sid":"${this.query.sid}"}`; } this._writer.write(packet).then(() => this.onOpen()); }); }); } write(packets) { this.writable = false; for (let i = 0; i < packets.length; i++) { const packet = packets[i]; const lastPacket = i === packets.length - 1; this._writer.write(packet).then(() => { if (lastPacket) { nextTick(() => { this.writable = true; this.emitReserved("drain"); }, this.setTimeoutFn); } }); } } doClose() { var _a2; (_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.close(); } } const transports = { websocket: WS, webtransport: WT, polling: XHR }; const re = /^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; const parts = [ "source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor" ]; function parse$8(str) { if (str.length > 8e3) { throw "URI too long"; } const src = str, b = str.indexOf("["), e = str.indexOf("]"); if (b != -1 && e != -1) { str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ";") + str.substring(e, str.length); } let m = re.exec(str || ""), uri = {}, i = 14; while (i--) { uri[parts[i]] = m[i] || ""; } if (b != -1 && e != -1) { uri.source = src; uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ":"); uri.authority = uri.authority.replace("[", "").replace("]", "").replace(/;/g, ":"); uri.ipv6uri = true; } uri.pathNames = pathNames(uri, uri["path"]); uri.queryKey = queryKey(uri, uri["query"]); return uri; } function pathNames(obj, path) { const regx = /\/{2,9}/g, names = path.replace(regx, "/").split("/"); if (path.slice(0, 1) == "/" || path.length === 0) { names.splice(0, 1); } if (path.slice(-1) == "/") { names.splice(names.length - 1, 1); } return names; } function queryKey(uri, query) { const data = {}; query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function($0, $1, $2) { if ($1) { data[$1] = $2; } }); return data; } const withEventListeners = typeof addEventListener === "function" && typeof removeEventListener === "function"; const OFFLINE_EVENT_LISTENERS = []; if (withEventListeners) { addEventListener("offline", () => { OFFLINE_EVENT_LISTENERS.forEach((listener) => listener()); }, false); } class SocketWithoutUpgrade extends Emitter { /** * Socket constructor. * * @param {String|Object} uri - uri or options * @param {Object} opts - options */ constructor(uri, opts) { super(); this.binaryType = defaultBinaryType; this.writeBuffer = []; this._prevBufferLen = 0; this._pingInterval = -1; this._pingTimeout = -1; this._maxPayload = -1; this._pingTimeoutTime = Infinity; if (uri && "object" === typeof uri) { opts = uri; uri = null; } if (uri) { const parsedUri = parse$8(uri); opts.hostname = parsedUri.host; opts.secure = parsedUri.protocol === "https" || parsedUri.protocol === "wss"; opts.port = parsedUri.port; if (parsedUri.query) opts.query = parsedUri.query; } else if (opts.host) { opts.hostname = parse$8(opts.host).host; } installTimerFunctions(this, opts); this.secure = null != opts.secure ? opts.secure : typeof location !== "undefined" && "https:" === location.protocol; if (opts.hostname && !opts.port) { opts.port = this.secure ? "443" : "80"; } this.hostname = opts.hostname || (typeof location !== "undefined" ? location.hostname : "localhost"); this.port = opts.port || (typeof location !== "undefined" && location.port ? location.port : this.secure ? "443" : "80"); this.transports = []; this._transportsByName = {}; opts.transports.forEach((t) => { const transportName = t.prototype.name; this.transports.push(transportName); this._transportsByName[transportName] = t; }); this.opts = Object.assign({ path: "/engine.io", agent: false, withCredentials: false, upgrade: true, timestampParam: "t", rememberUpgrade: false, addTrailingSlash: true, rejectUnauthorized: true, perMessageDeflate: { threshold: 1024 }, transportOptions: {}, closeOnBeforeunload: false }, opts); this.opts.path = this.opts.path.replace(/\/$/, "") + (this.opts.addTrailingSlash ? "/" : ""); if (typeof this.opts.query === "string") { this.opts.query = decode(this.opts.query); } if (withEventListeners) { if (this.opts.closeOnBeforeunload) { this._beforeunloadEventListener = () => { if (this.transport) { this.transport.removeAllListeners(); this.transport.close(); } }; addEventListener("beforeunload", this._beforeunloadEventListener, false); } if (this.hostname !== "localhost") { this._offlineEventListener = () => { this._onClose("transport close", { description: "network connection lost" }); }; OFFLINE_EVENT_LISTENERS.push(this._offlineEventListener); } } if (this.opts.withCredentials) { this._cookieJar = createCookieJar(); } this._open(); } /** * Creates transport of the given type. * * @param {String} name - transport name * @return {Transport} * @private */ createTransport(name) { const query = Object.assign({}, this.opts.query); query.EIO = protocol$1; query.transport = name; if (this.id) query.sid = this.id; const opts = Object.assign({}, this.opts, { query, socket: this, hostname: this.hostname, secure: this.secure, port: this.port }, this.opts.transportOptions[name]); return new this._transportsByName[name](opts); } /** * Initializes transport to use and starts probe. * * @private */ _open() { if (this.transports.length === 0) { this.setTimeoutFn(() => { this.emitReserved("error", "No transports available"); }, 0); return; } const transportName = this.opts.rememberUpgrade && SocketWithoutUpgrade.priorWebsocketSuccess && this.transports.indexOf("websocket") !== -1 ? "websocket" : this.transports[0]; this.readyState = "opening"; const transport = this.createTransport(transportName); transport.open(); this.setTransport(transport); } /** * Sets the current transport. Disables the existing one (if any). * * @private */ setTransport(transport) { if (this.transport) { this.transport.removeAllListeners(); } this.transport = transport; transport.on("drain", this._onDrain.bind(this)).on("packet", this._onPacket.bind(this)).on("error", this._onError.bind(this)).on("close", (reason) => this._onClose("transport close", reason)); } /** * Called when connection is deemed open. * * @private */ onOpen() { this.readyState = "open"; SocketWithoutUpgrade.priorWebsocketSuccess = "websocket" === this.transport.name; this.emitReserved("open"); this.flush(); } /** * Handles a packet. * * @private */ _onPacket(packet) { if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) { this.emitReserved("packet", packet); this.emitReserved("heartbeat"); switch (packet.type) { case "open": this.onHandshake(JSON.parse(packet.data)); break; case "ping": this._sendPacket("pong"); this.emitReserved("ping"); this.emitReserved("pong"); this._resetPingTimeout(); break; case "error": const err = new Error("server error"); err.code = packet.data; this._onError(err); break; case "message": this.emitReserved("data", packet.data); this.emitReserved("message", packet.data); break; } } } /** * Called upon handshake completion. * * @param {Object} data - handshake obj * @private */ onHandshake(data) { this.emitReserved("handshake", data); this.id = data.sid; this.transport.query.sid = data.sid; this._pingInterval = data.pingInterval; this._pingTimeout = data.pingTimeout; this._maxPayload = data.maxPayload; this.onOpen(); if ("closed" === this.readyState) return; this._resetPingTimeout(); } /** * Sets and resets ping timeout timer based on server pings. * * @private */ _resetPingTimeout() { this.clearTimeoutFn(this._pingTimeoutTimer); const delay = this._pingInterval + this._pingTimeout; this._pingTimeoutTime = Date.now() + delay; this._pingTimeoutTimer = this.setTimeoutFn(() => { this._onClose("ping timeout"); }, delay); if (this.opts.autoUnref) { this._pingTimeoutTimer.unref(); } } /** * Called on `drain` event * * @private */ _onDrain() { this.writeBuffer.splice(0, this._prevBufferLen); this._prevBufferLen = 0; if (0 === this.writeBuffer.length) { this.emitReserved("drain"); } else { this.flush(); } } /** * Flush write buffers. * * @private */ flush() { if ("closed" !== this.readyState && this.transport.writable && !this.upgrading && this.writeBuffer.length) { const packets = this._getWritablePackets(); this.transport.send(packets); this._prevBufferLen = packets.length; this.emitReserved("flush"); } } /** * Ensure the encoded size of the writeBuffer is below the maxPayload value sent by the server (only for HTTP * long-polling) * * @private */ _getWritablePackets() { const shouldCheckPayloadSize = this._maxPayload && this.transport.name === "polling" && this.writeBuffer.length > 1; if (!shouldCheckPayloadSize) { return this.writeBuffer; } let payloadSize = 1; for (let i = 0; i < this.writeBuffer.length; i++) { const data = this.writeBuffer[i].data; if (data) { payloadSize += byteLength(data); } if (i > 0 && payloadSize > this._maxPayload) { return this.writeBuffer.slice(0, i); } payloadSize += 2; } return this.writeBuffer; } /** * Checks whether the heartbeat timer has expired but the socket has not yet been notified. * * Note: this method is private for now because it does not really fit the WebSocket API, but if we put it in the * `write()` method then the message would not be buffered by the Socket.IO client. * * @return {boolean} * @private */ /* private */ _hasPingExpired() { if (!this._pingTimeoutTime) return true; const hasExpired = Date.now() > this._pingTimeoutTime; if (hasExpired) { this._pingTimeoutTime = 0; nextTick(() => { this._onClose("ping timeout"); }, this.setTimeoutFn); } return hasExpired; } /** * Sends a message. * * @param {String} msg - message. * @param {Object} options. * @param {Function} fn - callback function. * @return {Socket} for chaining. */ write(msg, options, fn) { this._sendPacket("message", msg, options, fn); return this; } /** * Sends a message. Alias of {@link Socket#write}. * * @param {String} msg - message. * @param {Object} options. * @param {Function} fn - callback function. * @return {Socket} for chaining. */ send(msg, options, fn) { this._sendPacket("message", msg, options, fn); return this; } /** * Sends a packet. * * @param {String} type: packet type. * @param {String} data. * @param {Object} options. * @param {Function} fn - callback function. * @private */ _sendPacket(type, data, options, fn) { if ("function" === typeof data) { fn = data; data = void 0; } if ("function" === typeof options) { fn = options; options = null; } if ("closing" === this.readyState || "closed" === this.readyState) { return; } options = options || {}; options.compress = false !== options.compress; const packet = { type, data, options }; this.emitReserved("packetCreate", packet); this.writeBuffer.push(packet); if (fn) this.once("flush", fn); this.flush(); } /** * Closes the connection. */ close() { const close = () => { this._onClose("forced close"); this.transport.close(); }; const cleanupAndClose = () => { this.off("upgrade", cleanupAndClose); this.off("upgradeError", cleanupAndClose); close(); }; const waitForUpgrade = () => { this.once("upgrade", cleanupAndClose); this.once("upgradeError", cleanupAndClose); }; if ("opening" === this.readyState || "open" === this.readyState) { this.readyState = "closing"; if (this.writeBuffer.length) { this.once("drain", () => { if (this.upgrading) { waitForUpgrade(); } else { close(); } }); } else if (this.upgrading) { waitForUpgrade(); } else { close(); } } return this; } /** * Called upon transport error * * @private */ _onError(err) { SocketWithoutUpgrade.priorWebsocketSuccess = false; if (this.opts.tryAllTransports && this.transports.length > 1 && this.readyState === "opening") { this.transports.shift(); return this._open(); } this.emitReserved("error", err); this._onClose("transport error", err); } /** * Called upon transport close. * * @private */ _onClose(reason, description) { if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) { this.clearTimeoutFn(this._pingTimeoutTimer); this.transport.removeAllListeners("close"); this.transport.close(); this.transport.removeAllListeners(); if (withEventListeners) { if (this._beforeunloadEventListener) { removeEventListener("beforeunload", this._beforeunloadEventListener, false); } if (this._offlineEventListener) { const i = OFFLINE_EVENT_LISTENERS.indexOf(this._offlineEventListener); if (i !== -1) { OFFLINE_EVENT_LISTENERS.splice(i, 1); } } } this.readyState = "closed"; this.id = null; this.emitReserved("close", reason, description); this.writeBuffer = []; this._prevBufferLen = 0; } } } SocketWithoutUpgrade.protocol = protocol$1; class SocketWithUpgrade extends SocketWithoutUpgrade { constructor() { super(...arguments); this._upgrades = []; } onOpen() { super.onOpen(); if ("open" === this.readyState && this.opts.upgrade) { for (let i = 0; i < this._upgrades.length; i++) { this._probe(this._upgrades[i]); } } } /** * Probes a transport. * * @param {String} name - transport name * @private */ _probe(name) { let transport = this.createTransport(name); let failed = false; SocketWithoutUpgrade.priorWebsocketSuccess = false; const onTransportOpen = () => { if (failed) return; transport.send([{ type: "ping", data: "probe" }]); transport.once("packet", (msg) => { if (failed) return; if ("pong" === msg.type && "probe" === msg.data) { this.upgrading = true; this.emitReserved("upgrading", transport); if (!transport) return; SocketWithoutUpgrade.priorWebsocketSuccess = "websocket" === transport.name; this.transport.pause(() => { if (failed) return; if ("closed" === this.readyState) return; cleanup(); this.setTransport(transport); transport.send([{ type: "upgrade" }]); this.emitReserved("upgrade", transport); transport = null; this.upgrading = false; this.flush(); }); } else { const err = new Error("probe error"); err.transport = transport.name; this.emitReserved("upgradeError", err); } }); }; function freezeTransport() { if (failed) return; failed = true; cleanup(); transport.close(); transport = null; } const onerror = (err) => { const error = new Error("probe error: " + err); error.transport = transport.name; freezeTransport(); this.emitReserved("upgradeError", error); }; function onTransportClose() { onerror("transport closed"); } function onclose() { onerror("socket closed"); } function onupgrade(to) { if (transport && to.name !== transport.name) { freezeTransport(); } } const cleanup = () => { transport.removeListener("open", onTransportOpen); transport.removeListener("error", onerror); transport.removeListener("close", onTransportClose); this.off("close", onclose); this.off("upgrading", onupgrade); }; transport.once("open", onTransportOpen); transport.once("error", onerror); transport.once("close", onTransportClose); this.once("close", onclose); this.once("upgrading", onupgrade); if (this._upgrades.indexOf("webtransport") !== -1 && name !== "webtransport") { this.setTimeoutFn(() => { if (!failed) { transport.open(); } }, 200); } else { transport.open(); } } onHandshake(data) { this._upgrades = this._filterUpgrades(data.upgrades); super.onHandshake(data); } /** * Filters upgrades, returning only those matching client transports. * * @param {Array} upgrades - server upgrades * @private */ _filterUpgrades(upgrades) { const filteredUpgrades = []; for (let i = 0; i < upgrades.length; i++) { if (~this.transports.indexOf(upgrades[i])) filteredUpgrades.push(upgrades[i]); } return filteredUpgrades; } } let Socket$1 = class Socket extends SocketWithUpgrade { constructor(uri, opts = {}) { const o = typeof uri === "object" ? uri : opts; if (!o.transports || o.transports && typeof o.transports[0] === "string") { o.transports = (o.transports || ["polling", "websocket", "webtransport"]).map((transportName) => transports[transportName]).filter((t) => !!t); } super(uri, o); } }; function url$1(uri, path = "", loc) { let obj = uri; loc = loc || typeof location !== "undefined" && location; if (null == uri) uri = loc.protocol + "//" + loc.host; if (typeof uri === "string") { if ("/" === uri.charAt(0)) { if ("/" === uri.charAt(1)) { uri = loc.protocol + uri; } else { uri = loc.host + uri; } } if (!/^(https?|wss?):\/\//.test(uri)) { if ("undefined" !== typeof loc) { uri = loc.protocol + "//" + uri; } else { uri = "https://" + uri; } } obj = parse$8(uri); } if (!obj.port) { if (/^(http|ws)$/.test(obj.protocol)) { obj.port = "80"; } else if (/^(http|ws)s$/.test(obj.protocol)) { obj.port = "443"; } } obj.path = obj.path || "/"; const ipv6 = obj.host.indexOf(":") !== -1; const host2 = ipv6 ? "[" + obj.host + "]" : obj.host; obj.id = obj.protocol + "://" + host2 + ":" + obj.port + path; obj.href = obj.protocol + "://" + host2 + (loc && loc.port === obj.port ? "" : ":" + obj.port); return obj; } const withNativeArrayBuffer = typeof ArrayBuffer === "function"; const isView = (obj) => { return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj.buffer instanceof ArrayBuffer; }; const toString = Object.prototype.toString; const withNativeBlob = typeof Blob === "function" || typeof Blob !== "undefined" && toString.call(Blob) === "[object BlobConstructor]"; const withNativeFile = typeof File === "function" || typeof File !== "undefined" && toString.call(File) === "[object FileConstructor]"; function isBinary(obj) { return withNativeArrayBuffer &