From 02c483950c56f8c9f566d139191e1afdf104554b Mon Sep 17 00:00:00 2001 From: Dunemask Date: Tue, 17 May 2022 12:32:04 +0000 Subject: [PATCH] Savepoint --- .breakpoints | 3 + ROADMAP.md | 10 +- dev/query.js | 18 + dist/bundles/qualiteer-executor.js | 3982 ++++++++++++++++- lib/core/internal-deploy.js | 13 +- lib/core/kubernetes.js | 18 +- lib/core/server.js | 8 +- lib/database/TABLES.md | 37 +- .../1_create_test_results_table.sql | 23 +- .../migrations/2_create_catalog_table.sql | 18 + lib/database/postgres.js | 2 +- .../{silenced_tests.js => alerting.js} | 1 - lib/database/queries/{tests.js => catalog.js} | 1 - lib/database/queries/results.js | 64 + lib/database/queries/test_results.js | 51 - lib/routes/alerting-route.js | 6 +- .../{tests-route.js => catalog-route.js} | 6 +- lib/routes/jobs-route.js | 4 +- lib/routes/mock-route.js | 37 + lib/routes/mocks/alerting.json | 32 + lib/routes/mocks/catalog.json | 92 + lib/routes/mocks/results.json | 48 + lib/routes/results-route.js | 6 +- lib/sockets/clients/Executor.js | 3 +- package-lock.json | 134 +- package.json | 3 + public/assets/QA.jpg | Bin 18707 -> 0 bytes public/assets/QA.png | Bin 0 -> 58887 bytes public/favicon.ico | Bin 0 -> 5430 bytes rollup.config.js | 2 +- src/Dashboard.jsx | 9 +- src/Views.jsx | 189 +- src/ctx/JobContext.jsx | 24 +- src/ctx/StoreContext.jsx | 13 +- src/ctx/ViewContext.jsx | 32 - src/views/About.jsx | 32 + src/views/Alerting.jsx | 61 + src/views/Catalog.jsx | 29 + src/views/Failing.jsx | 70 + src/views/Jobs.jsx | 55 + src/views/Settings.jsx | 124 + src/views/components/CatalogSearch.jsx | 31 + src/views/components/MultiOptionDialog.jsx | 73 + tests/api.js | 22 + tests/index.js | 6 +- 45 files changed, 5136 insertions(+), 256 deletions(-) create mode 100644 .breakpoints create mode 100644 dev/query.js create mode 100644 lib/database/migrations/2_create_catalog_table.sql rename lib/database/queries/{silenced_tests.js => alerting.js} (99%) rename lib/database/queries/{tests.js => catalog.js} (99%) create mode 100644 lib/database/queries/results.js delete mode 100644 lib/database/queries/test_results.js rename lib/routes/{tests-route.js => catalog-route.js} (70%) create mode 100644 lib/routes/mock-route.js create mode 100644 lib/routes/mocks/alerting.json create mode 100644 lib/routes/mocks/catalog.json create mode 100644 lib/routes/mocks/results.json delete mode 100644 public/assets/QA.jpg create mode 100644 public/assets/QA.png create mode 100644 public/favicon.ico delete mode 100644 src/ctx/ViewContext.jsx create mode 100644 src/views/About.jsx create mode 100644 src/views/Alerting.jsx create mode 100644 src/views/Catalog.jsx create mode 100644 src/views/Failing.jsx create mode 100644 src/views/Jobs.jsx create mode 100644 src/views/Settings.jsx create mode 100644 src/views/components/CatalogSearch.jsx create mode 100644 src/views/components/MultiOptionDialog.jsx create mode 100644 tests/api.js diff --git a/.breakpoints b/.breakpoints new file mode 100644 index 0000000..5cc232f --- /dev/null +++ b/.breakpoints @@ -0,0 +1,3 @@ +{ + "files": {} +} \ No newline at end of file diff --git a/ROADMAP.md b/ROADMAP.md index 23384cb..96ed771 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,32 +1,38 @@ # Roadmap + ### The end goal of this application is to provide a powerful application able to process and handle all of the your realtime QA data needs ## v0.0.1 + - [x] Initial Skeleton - [x] Frontend Drafts - [ ] Frontend Core - [ ] Frontend Pages ## v0.0.2 + - [ ] Database Queries (Req PG) - [ ] Database Tables (Req PG) - [ ] Backend Routes (Req Database) - [ ] Crons ## v0.0.3 + - [ ] Rabbitmq Consumers (Req Database) -- [ ] Alerting +- [ ] Alerting - [ ] Silencing ## v0.0.4 + - [ ] Auth ## v0.0.5 + - [ ] Docker config - [ ] Gitlab Integration - [ ] Garden config ## v0.0.6 + - [ ] Internal Tests - [ ] Self Test Suite - diff --git a/dev/query.js b/dev/query.js new file mode 100644 index 0000000..a61a873 --- /dev/null +++ b/dev/query.js @@ -0,0 +1,18 @@ +import { + insertQuery, + selectWhereAnyQuery, + updateWhereAnyQuery, +} from "../lib/database/pg-query.js"; +import { readFileSync } from "fs"; +var data = JSON.parse(readFileSync("lib/routes/mocks/results.json")); + +var table = "test_results"; +var queries = data.results.map((r) => insertQuery(table, r)); +queries.forEach((q) => console.log(q + ";")); + +console.log(); + +table = "test_catalog"; +data = JSON.parse(readFileSync("lib/routes/mocks/catalog.json")); +queries = data["tests:full"].map((r) => insertQuery(table, r)); +queries.forEach((q) => console.log(q + ";")); diff --git a/dist/bundles/qualiteer-executor.js b/dist/bundles/qualiteer-executor.js index 5082148..230a0c5 100644 --- a/dist/bundles/qualiteer-executor.js +++ b/dist/bundles/qualiteer-executor.js @@ -1,4 +1,265 @@ -"use strict";var e=require("fs"),t=require("url"),s=require("child_process"),r=require("http"),i=require("https"),n=require("stream"),o=require("zlib"),a=require("net"),h=require("tls"),c=require("crypto"),l=require("events");function d(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function u(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(s){if("default"!==s&&!(s in e)){var r=Object.getOwnPropertyDescriptor(t,s);Object.defineProperty(e,s,r.get?r:{enumerable:!0,get:function(){return t[s]}})}}))})),Object.freeze(e)}var p=d(e),f=d(t),_=d(s),y=d(r),m=d(i),g=d(n),b=d(o),v=d(a),E=d(h),w=d(c),S=d(l);const k=Object.create(null);k.open="0",k.close="1",k.ping="2",k.pong="3",k.message="4",k.upgrade="5",k.noop="6";const x=Object.create(null);Object.keys(k).forEach((e=>{x[k[e]]=e}));const O={type:"error",data:"parser error"},T=({type:e,data:t},s,r)=>{if(t instanceof ArrayBuffer||ArrayBuffer.isView(t)){const e=N(t);return r(R(e,s))}return r(k[e]+(t||""))},N=e=>Buffer.isBuffer(e)?e:e instanceof ArrayBuffer?Buffer.from(e):Buffer.from(e.buffer,e.byteOffset,e.byteLength),R=(e,t)=>t?e:"b"+e.toString("base64"),C=(e,t)=>{if("string"!=typeof e)return{type:"message",data:L(e,t)};const s=e.charAt(0);if("b"===s){const s=Buffer.from(e.substring(1),"base64");return{type:"message",data:L(s,t)}}return x[s]?e.length>1?{type:x[s],data:e.substring(1)}:{type:x[s]}:O},L=(e,t)=>{const s=Buffer.isBuffer(e);return"arraybuffer"===t&&s?A(e):e},A=e=>{const t=new ArrayBuffer(e.length),s=new Uint8Array(t);for(let t=0;t(e.hasOwnProperty(s)&&(t[s]=e[s]),t)),{})}const U=setTimeout,q=clearTimeout;function j(e,t){t.useNativeTimers?(e.setTimeoutFn=U.bind(I),e.clearTimeoutFn=q.bind(I)):(e.setTimeoutFn=setTimeout.bind(I),e.clearTimeoutFn=clearTimeout.bind(I))}class F extends Error{constructor(e,t,s){super(e),this.description=t,this.context=s,this.type="TransportError"}}class M extends P{constructor(e){super(),this.writable=!1,j(this,e),this.opts=e,this.query=e.query,this.readyState="",this.socket=e.socket}onError(e,t,s){return super.emitReserved("error",new F(e,t,s)),this}open(){return"closed"!==this.readyState&&""!==this.readyState||(this.readyState="opening",this.doOpen()),this}close(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}send(e){"open"===this.readyState&&this.write(e)}onOpen(){this.readyState="open",this.writable=!0,super.emitReserved("open")}onData(e){const t=C(e,this.socket.binaryType);this.onPacket(t)}onPacket(e){super.emitReserved("packet",e)}onClose(e){this.readyState="closed",super.emitReserved("close",e)}}const W="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),V={};let $,G=0,H=0;function z(e){let t="";do{t=W[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}function Y(){const e=z(+new Date);return e!==$?(G=0,$=e):e+"."+z(G++)}for(;H<64;H++)V[W[H]]=H;function K(e){let t="";for(let s in e)e.hasOwnProperty(s)&&(t.length&&(t+="&"),t+=encodeURIComponent(s)+"="+encodeURIComponent(e[s]));return t} +"use strict"; +var e = require("fs"), + t = require("url"), + s = require("child_process"), + r = require("http"), + i = require("https"), + n = require("stream"), + o = require("zlib"), + a = require("net"), + h = require("tls"), + c = require("crypto"), + l = require("events"); +function d(e) { + return e && "object" == typeof e && "default" in e ? e : { default: e }; +} +function u(e, t) { + return ( + t.forEach(function (t) { + t && + "string" != typeof t && + !Array.isArray(t) && + Object.keys(t).forEach(function (s) { + if ("default" !== s && !(s in e)) { + var r = Object.getOwnPropertyDescriptor(t, s); + Object.defineProperty( + e, + s, + r.get + ? r + : { + enumerable: !0, + get: function () { + return t[s]; + }, + } + ); + } + }); + }), + Object.freeze(e) + ); +} +var p = d(e), + f = d(t), + _ = d(s), + y = d(r), + m = d(i), + g = d(n), + b = d(o), + v = d(a), + E = d(h), + w = d(c), + S = d(l); +const k = Object.create(null); +(k.open = "0"), + (k.close = "1"), + (k.ping = "2"), + (k.pong = "3"), + (k.message = "4"), + (k.upgrade = "5"), + (k.noop = "6"); +const x = Object.create(null); +Object.keys(k).forEach((e) => { + x[k[e]] = e; +}); +const O = { type: "error", data: "parser error" }, + T = ({ type: e, data: t }, s, r) => { + if (t instanceof ArrayBuffer || ArrayBuffer.isView(t)) { + const e = N(t); + return r(R(e, s)); + } + return r(k[e] + (t || "")); + }, + N = (e) => + Buffer.isBuffer(e) + ? e + : e instanceof ArrayBuffer + ? Buffer.from(e) + : Buffer.from(e.buffer, e.byteOffset, e.byteLength), + R = (e, t) => (t ? e : "b" + e.toString("base64")), + C = (e, t) => { + if ("string" != typeof e) return { type: "message", data: L(e, t) }; + const s = e.charAt(0); + if ("b" === s) { + const s = Buffer.from(e.substring(1), "base64"); + return { type: "message", data: L(s, t) }; + } + return x[s] + ? e.length > 1 + ? { type: x[s], data: e.substring(1) } + : { type: x[s] } + : O; + }, + L = (e, t) => { + const s = Buffer.isBuffer(e); + return "arraybuffer" === t && s ? A(e) : e; + }, + A = (e) => { + const t = new ArrayBuffer(e.length), + s = new Uint8Array(t); + for (let t = 0; t < e.length; t++) s[t] = e[t]; + return t; + }, + B = String.fromCharCode(30); +function P(e) { + if (e) + return (function (e) { + for (var t in P.prototype) e[t] = P.prototype[t]; + return e; + })(e); +} +(P.prototype.on = P.prototype.addEventListener = + function (e, t) { + return ( + (this._callbacks = this._callbacks || {}), + (this._callbacks["$" + e] = this._callbacks["$" + e] || []).push(t), + this + ); + }), + (P.prototype.once = function (e, t) { + function s() { + this.off(e, s), t.apply(this, arguments); + } + return (s.fn = t), this.on(e, s), this; + }), + (P.prototype.off = + P.prototype.removeListener = + P.prototype.removeAllListeners = + P.prototype.removeEventListener = + function (e, t) { + if (((this._callbacks = this._callbacks || {}), 0 == arguments.length)) + return (this._callbacks = {}), this; + var s, + r = this._callbacks["$" + e]; + if (!r) return this; + if (1 == arguments.length) return delete this._callbacks["$" + e], this; + for (var i = 0; i < r.length; i++) + if ((s = r[i]) === t || s.fn === t) { + r.splice(i, 1); + break; + } + return 0 === r.length && delete this._callbacks["$" + e], this; + }), + (P.prototype.emit = function (e) { + this._callbacks = this._callbacks || {}; + for ( + var t = new Array(arguments.length - 1), + s = this._callbacks["$" + e], + r = 1; + r < arguments.length; + r++ + ) + t[r - 1] = arguments[r]; + if (s) { + r = 0; + for (var i = (s = s.slice(0)).length; r < i; ++r) s[r].apply(this, t); + } + return this; + }), + (P.prototype.emitReserved = P.prototype.emit), + (P.prototype.listeners = function (e) { + return ( + (this._callbacks = this._callbacks || {}), this._callbacks["$" + e] || [] + ); + }), + (P.prototype.hasListeners = function (e) { + return !!this.listeners(e).length; + }); +const I = global; +function D(e, ...t) { + return t.reduce((t, s) => (e.hasOwnProperty(s) && (t[s] = e[s]), t), {}); +} +const U = setTimeout, + q = clearTimeout; +function j(e, t) { + t.useNativeTimers + ? ((e.setTimeoutFn = U.bind(I)), (e.clearTimeoutFn = q.bind(I))) + : ((e.setTimeoutFn = setTimeout.bind(I)), + (e.clearTimeoutFn = clearTimeout.bind(I))); +} +class F extends Error { + constructor(e, t, s) { + super(e), + (this.description = t), + (this.context = s), + (this.type = "TransportError"); + } +} +class M extends P { + constructor(e) { + super(), + (this.writable = !1), + j(this, e), + (this.opts = e), + (this.query = e.query), + (this.readyState = ""), + (this.socket = e.socket); + } + onError(e, t, s) { + return super.emitReserved("error", new F(e, t, s)), this; + } + open() { + return ( + ("closed" !== this.readyState && "" !== this.readyState) || + ((this.readyState = "opening"), this.doOpen()), + this + ); + } + close() { + return ( + ("opening" !== this.readyState && "open" !== this.readyState) || + (this.doClose(), this.onClose()), + this + ); + } + send(e) { + "open" === this.readyState && this.write(e); + } + onOpen() { + (this.readyState = "open"), + (this.writable = !0), + super.emitReserved("open"); + } + onData(e) { + const t = C(e, this.socket.binaryType); + this.onPacket(t); + } + onPacket(e) { + super.emitReserved("packet", e); + } + onClose(e) { + (this.readyState = "closed"), super.emitReserved("close", e); + } +} +const W = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split( + "" + ), + V = {}; +let $, + G = 0, + H = 0; +function z(e) { + let t = ""; + do { + (t = W[e % 64] + t), (e = Math.floor(e / 64)); + } while (e > 0); + return t; +} +function Y() { + const e = z(+new Date()); + return e !== $ ? ((G = 0), ($ = e)) : e + "." + z(G++); +} +for (; H < 64; H++) V[W[H]] = H; +function K(e) { + let t = ""; + for (let s in e) + e.hasOwnProperty(s) && + (t.length && (t += "&"), + (t += encodeURIComponent(s) + "=" + encodeURIComponent(e[s]))); + return t; +} /** * Wrapper for built-in http.js to emulate the browser XMLHttpRequest object. * @@ -11,4 +272,3721 @@ * @contributor David Ellis * @license MIT */ -var X=p.default,J=f.default,Q=_.default.spawn,Z=ee;function ee(e){e=e||{};var t,s,r=this,i=y.default,n=m.default,o={},a=!1,h={"User-Agent":"node-XMLHttpRequest",Accept:"*/*"},c=Object.assign({},h),l=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","content-transfer-encoding","cookie","cookie2","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","via"],d=["TRACE","TRACK","CONNECT"],u=!1,p=!1,f=!1,_={};this.UNSENT=0,this.OPENED=1,this.HEADERS_RECEIVED=2,this.LOADING=3,this.DONE=4,this.readyState=this.UNSENT,this.onreadystatechange=null,this.responseText="",this.responseXML="",this.status=null,this.statusText=null;this.open=function(e,t,s,r,i){if(this.abort(),p=!1,f=!1,!function(e){return e&&-1===d.indexOf(e)}(e))throw new Error("SecurityError: Request method not allowed");o={method:e,url:t.toString(),async:"boolean"!=typeof s||s,user:r||null,password:i||null},g(this.OPENED)},this.setDisableHeaderCheck=function(e){a=e},this.setRequestHeader=function(e,t){if(this.readyState!=this.OPENED)throw new Error("INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN");if(!function(e){return a||e&&-1===l.indexOf(e.toLowerCase())}(e))return console.warn('Refused to set unsafe header "'+e+'"'),!1;if(u)throw new Error("INVALID_STATE_ERR: send flag is true");return c[e]=t,!0},this.getResponseHeader=function(e){return"string"==typeof e&&this.readyState>this.OPENED&&s.headers[e.toLowerCase()]&&!p?s.headers[e.toLowerCase()]:null},this.getAllResponseHeaders=function(){if(this.readyState{e.unref()})),a&&t.write(a),t.end(),r.dispatchEvent("loadstart")}else{var k=".node-xmlhttprequest-content-"+process.pid,x=".node-xmlhttprequest-sync-"+process.pid;X.writeFileSync(x,"","utf8");for(var O="var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http"+(l?"s":"")+".request;var options = "+JSON.stringify(v)+";var responseText = '';var req = doRequest(options, function(response) {response.setEncoding('utf8');response.on('data', function(chunk) { responseText += chunk;});response.on('end', function() {fs.writeFileSync('"+k+"', 'NODE-XMLHTTPREQUEST-STATUS:' + response.statusCode + ',' + responseText, 'utf8');fs.unlinkSync('"+x+"');});response.on('error', function(error) {fs.writeFileSync('"+k+"', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('"+x+"');});}).on('error', function(error) {fs.writeFileSync('"+k+"', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('"+x+"');});"+(a?"req.write('"+JSON.stringify(a).slice(1,-1).replace(/'/g,"\\'")+"');":"")+"req.end();",T=Q(process.argv[0],["-e",O]);X.existsSync(x););if(r.responseText=X.readFileSync(k,"utf8"),T.stdin.end(),X.unlinkSync(k),r.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)){var N=r.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/,"");r.handleError(N,503)}else r.status=r.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/,"$1"),r.responseText=r.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:[0-9]*,(.*)/,"$1"),g(r.DONE)}}},this.handleError=function(e,t){this.status=t||0,this.statusText=e,this.responseText=e.stack,p=!0,g(this.DONE)},this.abort=function(){t&&(t.abort(),t=null),c=Object.assign({},h),this.responseText="",this.responseXML="",p=f=!0,this.readyState===this.UNSENT||this.readyState===this.OPENED&&!u||this.readyState===this.DONE||(u=!1,g(this.DONE)),this.readyState=this.UNSENT},this.addEventListener=function(e,t){e in _||(_[e]=[]),_[e].push(t)},this.removeEventListener=function(e,t){e in _&&(_[e]=_[e].filter((function(e){return e!==t})))},this.dispatchEvent=function(e){if("function"==typeof r["on"+e]&&(this.readyState===this.DONE?setImmediate((function(){r["on"+e]()})):r["on"+e]()),e in _)for(let t=0,s=_[e].length;t{4===t.readyState&&(200===t.status||1223===t.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof t.status?t.status:0)}),0))},t.send(this.data)}catch(e){return void this.setTimeoutFn((()=>{this.onError(e)}),0)}"undefined"!=typeof document&&(this.index=ie.requestsCount++,ie.requests[this.index]=this)}onError(e){this.emitReserved("error",e,this.xhr),this.cleanup(!0)}cleanup(e){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=se,e)try{this.xhr.abort()}catch(e){}"undefined"!=typeof document&&delete ie.requests[this.index],this.xhr=null}}onLoad(){const e=this.xhr.responseText;null!==e&&(this.emitReserved("data",e),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(ie.requestsCount=0,ie.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",ne);else if("function"==typeof addEventListener){addEventListener("onpagehide"in I?"pagehide":"unload",ne,!1)}function ne(){for(let e in ie.requests)ie.requests.hasOwnProperty(e)&&ie.requests[e].abort()}var oe={exports:{}},ae={BINARY_TYPES:["nodebuffer","arraybuffer","fragments"],EMPTY_BUFFER:Buffer.alloc(0),GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",kForOnEventAttribute:Symbol("kIsForOnEventAttribute"),kListener:Symbol("kListener"),kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),NOOP:()=>{}};const{EMPTY_BUFFER:he}=ae;function ce(e,t){if(0===e.length)return he;if(1===e.length)return e[0];const s=Buffer.allocUnsafe(t);let r=0;for(let t=0;t{this.pending--,this[_e]()},this.concurrency=e||1/0,this.jobs=[],this.pending=0}add(e){this.jobs.push(e),this[_e]()}[_e](){if(this.pending!==this.concurrency&&this.jobs.length){const e=this.jobs.shift();this.pending++,e(this[fe])}}};const me=b.default,ge=oe.exports,be=ye,{kStatusCode:ve}=ae,Ee=Buffer.from([0,0,255,255]),we=Symbol("permessage-deflate"),Se=Symbol("total-length"),ke=Symbol("callback"),xe=Symbol("buffers"),Oe=Symbol("error");let Te;var Ne=class{constructor(e,t,s){if(this._maxPayload=0|s,this._options=e||{},this._threshold=void 0!==this._options.threshold?this._options.threshold:1024,this._isServer=!!t,this._deflate=null,this._inflate=null,this.params=null,!Te){const e=void 0!==this._options.concurrencyLimit?this._options.concurrencyLimit:10;Te=new be(e)}}static get extensionName(){return"permessage-deflate"}offer(){const e={};return this._options.serverNoContextTakeover&&(e.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(e.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(e.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?e.client_max_window_bits=this._options.clientMaxWindowBits:null==this._options.clientMaxWindowBits&&(e.client_max_window_bits=!0),e}accept(e){return e=this.normalizeParams(e),this.params=this._isServer?this.acceptAsServer(e):this.acceptAsClient(e),this.params}cleanup(){if(this._inflate&&(this._inflate.close(),this._inflate=null),this._deflate){const e=this._deflate[ke];this._deflate.close(),this._deflate=null,e&&e(new Error("The deflate stream was closed while data was being processed"))}}acceptAsServer(e){const t=this._options,s=e.find((e=>!(!1===t.serverNoContextTakeover&&e.server_no_context_takeover||e.server_max_window_bits&&(!1===t.serverMaxWindowBits||"number"==typeof t.serverMaxWindowBits&&t.serverMaxWindowBits>e.server_max_window_bits)||"number"==typeof t.clientMaxWindowBits&&!e.client_max_window_bits)));if(!s)throw new Error("None of the extension offers can be accepted");return t.serverNoContextTakeover&&(s.server_no_context_takeover=!0),t.clientNoContextTakeover&&(s.client_no_context_takeover=!0),"number"==typeof t.serverMaxWindowBits&&(s.server_max_window_bits=t.serverMaxWindowBits),"number"==typeof t.clientMaxWindowBits?s.client_max_window_bits=t.clientMaxWindowBits:!0!==s.client_max_window_bits&&!1!==t.clientMaxWindowBits||delete s.client_max_window_bits,s}acceptAsClient(e){const t=e[0];if(!1===this._options.clientNoContextTakeover&&t.client_no_context_takeover)throw new Error('Unexpected parameter "client_no_context_takeover"');if(t.client_max_window_bits){if(!1===this._options.clientMaxWindowBits||"number"==typeof this._options.clientMaxWindowBits&&t.client_max_window_bits>this._options.clientMaxWindowBits)throw new Error('Unexpected or invalid parameter "client_max_window_bits"')}else"number"==typeof this._options.clientMaxWindowBits&&(t.client_max_window_bits=this._options.clientMaxWindowBits);return t}normalizeParams(e){return e.forEach((e=>{Object.keys(e).forEach((t=>{let s=e[t];if(s.length>1)throw new Error(`Parameter "${t}" must have only a single value`);if(s=s[0],"client_max_window_bits"===t){if(!0!==s){const e=+s;if(!Number.isInteger(e)||e<8||e>15)throw new TypeError(`Invalid value for parameter "${t}": ${s}`);s=e}else if(!this._isServer)throw new TypeError(`Invalid value for parameter "${t}": ${s}`)}else if("server_max_window_bits"===t){const e=+s;if(!Number.isInteger(e)||e<8||e>15)throw new TypeError(`Invalid value for parameter "${t}": ${s}`);s=e}else{if("client_no_context_takeover"!==t&&"server_no_context_takeover"!==t)throw new Error(`Unknown parameter "${t}"`);if(!0!==s)throw new TypeError(`Invalid value for parameter "${t}": ${s}`)}e[t]=s}))})),e}decompress(e,t,s){Te.add((r=>{this._decompress(e,t,((e,t)=>{r(),s(e,t)}))}))}compress(e,t,s){Te.add((r=>{this._compress(e,t,((e,t)=>{r(),s(e,t)}))}))}_decompress(e,t,s){const r=this._isServer?"client":"server";if(!this._inflate){const e=`${r}_max_window_bits`,t="number"!=typeof this.params[e]?me.Z_DEFAULT_WINDOWBITS:this.params[e];this._inflate=me.createInflateRaw({...this._options.zlibInflateOptions,windowBits:t}),this._inflate[we]=this,this._inflate[Se]=0,this._inflate[xe]=[],this._inflate.on("error",Le),this._inflate.on("data",Ce)}this._inflate[ke]=s,this._inflate.write(e),t&&this._inflate.write(Ee),this._inflate.flush((()=>{const e=this._inflate[Oe];if(e)return this._inflate.close(),this._inflate=null,void s(e);const i=ge.concat(this._inflate[xe],this._inflate[Se]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[Se]=0,this._inflate[xe]=[],t&&this.params[`${r}_no_context_takeover`]&&this._inflate.reset()),s(null,i)}))}_compress(e,t,s){const r=this._isServer?"server":"client";if(!this._deflate){const e=`${r}_max_window_bits`,t="number"!=typeof this.params[e]?me.Z_DEFAULT_WINDOWBITS:this.params[e];this._deflate=me.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:t}),this._deflate[Se]=0,this._deflate[xe]=[],this._deflate.on("data",Re)}this._deflate[ke]=s,this._deflate.write(e),this._deflate.flush(me.Z_SYNC_FLUSH,(()=>{if(!this._deflate)return;let e=ge.concat(this._deflate[xe],this._deflate[Se]);t&&(e=e.slice(0,e.length-4)),this._deflate[ke]=null,this._deflate[Se]=0,this._deflate[xe]=[],t&&this.params[`${r}_no_context_takeover`]&&this._deflate.reset(),s(null,e)}))}};function Re(e){this[xe].push(e),this[Se]+=e.length}function Ce(e){this[Se]+=e.length,this[we]._maxPayload<1||this[Se]<=this[we]._maxPayload?this[xe].push(e):(this[Oe]=new RangeError("Max payload size exceeded"),this[Oe].code="WS_ERR_UNSUPPORTED_MESSAGE_LENGTH",this[Oe][ve]=1009,this.removeListener("data",Ce),this.reset())}function Le(e){this[we]._inflate=null,e[ve]=1007,this[ke](e)}var Ae={exports:{}};const Be=[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];function Pe(e){return e>=1e3&&e<=1014&&1004!==e&&1005!==e&&1006!==e||e>=3e3&&e<=4999}function Ie(e){const t=e.length;let s=0;for(;s=t||128!=(192&e[s+1])||128!=(192&e[s+2])||224===e[s]&&128==(224&e[s+1])||237===e[s]&&160==(224&e[s+1]))return!1;s+=3}else{if(240!=(248&e[s]))return!1;if(s+3>=t||128!=(192&e[s+1])||128!=(192&e[s+2])||128!=(192&e[s+3])||240===e[s]&&128==(240&e[s+1])||244===e[s]&&e[s+1]>143||e[s]>244)return!1;s+=4}return!0}try{const e=require("utf-8-validate");Ae.exports={isValidStatusCode:Pe,isValidUTF8:t=>t.length<150?Ie(t):e(t),tokenChars:Be}}catch(e){Ae.exports={isValidStatusCode:Pe,isValidUTF8:Ie,tokenChars:Be}}const{Writable:De}=g.default,Ue=Ne,{BINARY_TYPES:qe,EMPTY_BUFFER:je,kStatusCode:Fe,kWebSocket:Me}=ae,{concat:We,toArrayBuffer:Ve,unmask:$e}=oe.exports,{isValidStatusCode:Ge,isValidUTF8:He}=Ae.exports;var ze=class extends De{constructor(e={}){super(),this._binaryType=e.binaryType||qe[0],this._extensions=e.extensions||{},this._isServer=!!e.isServer,this._maxPayload=0|e.maxPayload,this._skipUTF8Validation=!!e.skipUTF8Validation,this[Me]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._fragments=[],this._state=0,this._loop=!1}_write(e,t,s){if(8===this._opcode&&0==this._state)return s();this._bufferedBytes+=e.length,this._buffers.push(e),this.startLoop(s)}consume(e){if(this._bufferedBytes-=e,e===this._buffers[0].length)return this._buffers.shift();if(e=s.length?t.set(this._buffers.shift(),r):(t.set(new Uint8Array(s.buffer,s.byteOffset,e),r),this._buffers[0]=s.slice(e)),e-=s.length}while(e>0);return t}startLoop(e){let t;this._loop=!0;do{switch(this._state){case 0:t=this.getInfo();break;case 1:t=this.getPayloadLength16();break;case 2:t=this.getPayloadLength64();break;case 3:this.getMask();break;case 4:t=this.getData(e);break;default:return void(this._loop=!1)}}while(this._loop);e(t)}getInfo(){if(this._bufferedBytes<2)return void(this._loop=!1);const e=this.consume(2);if(0!=(48&e[0]))return this._loop=!1,Ye(RangeError,"RSV2 and RSV3 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_2_3");const t=64==(64&e[0]);if(t&&!this._extensions[Ue.extensionName])return this._loop=!1,Ye(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");if(this._fin=128==(128&e[0]),this._opcode=15&e[0],this._payloadLength=127&e[1],0===this._opcode){if(t)return this._loop=!1,Ye(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");if(!this._fragmented)return this._loop=!1,Ye(RangeError,"invalid opcode 0",!0,1002,"WS_ERR_INVALID_OPCODE");this._opcode=this._fragmented}else if(1===this._opcode||2===this._opcode){if(this._fragmented)return this._loop=!1,Ye(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");this._compressed=t}else{if(!(this._opcode>7&&this._opcode<11))return this._loop=!1,Ye(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");if(!this._fin)return this._loop=!1,Ye(RangeError,"FIN must be set",!0,1002,"WS_ERR_EXPECTED_FIN");if(t)return this._loop=!1,Ye(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");if(this._payloadLength>125)return this._loop=!1,Ye(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH")}if(this._fin||this._fragmented||(this._fragmented=this._opcode),this._masked=128==(128&e[1]),this._isServer){if(!this._masked)return this._loop=!1,Ye(RangeError,"MASK must be set",!0,1002,"WS_ERR_EXPECTED_MASK")}else if(this._masked)return this._loop=!1,Ye(RangeError,"MASK must be clear",!0,1002,"WS_ERR_UNEXPECTED_MASK");if(126===this._payloadLength)this._state=1;else{if(127!==this._payloadLength)return this.haveLength();this._state=2}}getPayloadLength16(){if(!(this._bufferedBytes<2))return this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength();this._loop=!1}getPayloadLength64(){if(this._bufferedBytes<8)return void(this._loop=!1);const e=this.consume(8),t=e.readUInt32BE(0);return t>Math.pow(2,21)-1?(this._loop=!1,Ye(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009,"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH")):(this._payloadLength=t*Math.pow(2,32)+e.readUInt32BE(4),this.haveLength())}haveLength(){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0))return this._loop=!1,Ye(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");this._masked?this._state=3:this._state=4}getMask(){this._bufferedBytes<4?this._loop=!1:(this._mask=this.consume(4),this._state=4)}getData(e){let t=je;if(this._payloadLength){if(this._bufferedBytes7?this.controlMessage(t):this._compressed?(this._state=5,void this.decompress(t,e)):(t.length&&(this._messageLength=this._totalPayloadLength,this._fragments.push(t)),this.dataMessage())}decompress(e,t){this._extensions[Ue.extensionName].decompress(e,this._fin,((e,s)=>{if(e)return t(e);if(s.length){if(this._messageLength+=s.length,this._messageLength>this._maxPayload&&this._maxPayload>0)return t(Ye(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"));this._fragments.push(s)}const r=this.dataMessage();if(r)return t(r);this.startLoop(t)}))}dataMessage(){if(this._fin){const e=this._messageLength,t=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._fragments=[],2===this._opcode){let s;s="nodebuffer"===this._binaryType?We(t,e):"arraybuffer"===this._binaryType?Ve(We(t,e)):t,this.emit("message",s,!0)}else{const s=We(t,e);if(!this._skipUTF8Validation&&!He(s))return this._loop=!1,Ye(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");this.emit("message",s,!1)}}this._state=0}controlMessage(e){if(8===this._opcode)if(this._loop=!1,0===e.length)this.emit("conclude",1005,je),this.end();else{if(1===e.length)return Ye(RangeError,"invalid payload length 1",!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH");{const t=e.readUInt16BE(0);if(!Ge(t))return Ye(RangeError,`invalid status code ${t}`,!0,1002,"WS_ERR_INVALID_CLOSE_CODE");const s=e.slice(2);if(!this._skipUTF8Validation&&!He(s))return Ye(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");this.emit("conclude",t,s),this.end()}}else 9===this._opcode?this.emit("ping",e):this.emit("pong",e);this._state=0}};function Ye(e,t,s,r,i){const n=new e(s?`Invalid WebSocket frame: ${t}`:t);return Error.captureStackTrace(n,Ye),n.code=i,n[Fe]=r,n}const{randomFillSync:Ke}=w.default,Xe=Ne,{EMPTY_BUFFER:Je}=ae,{isValidStatusCode:Qe}=Ae.exports,{mask:Ze,toBuffer:et}=oe.exports,tt=Buffer.alloc(4);class st{constructor(e,t){this._extensions=t||{},this._socket=e,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._deflating=!1,this._queue=[]}static frame(e,t){const s=t.mask&&t.readOnly;let r=t.mask?6:2,i=e.length;e.length>=65536?(r+=8,i=127):e.length>125&&(r+=2,i=126);const n=Buffer.allocUnsafe(s?e.length+r:r);return n[0]=t.fin?128|t.opcode:t.opcode,t.rsv1&&(n[0]|=64),n[1]=i,126===i?n.writeUInt16BE(e.length,2):127===i&&(n.writeUInt32BE(0,2),n.writeUInt32BE(e.length,6)),t.mask?(Ke(tt,0,4),n[1]|=128,n[r-4]=tt[0],n[r-3]=tt[1],n[r-2]=tt[2],n[r-1]=tt[3],s?(Ze(e,tt,n,r,e.length),[n]):(Ze(e,tt,e,0,e.length),[n,e])):[n,e]}close(e,t,s,r){let i;if(void 0===e)i=Je;else{if("number"!=typeof e||!Qe(e))throw new TypeError("First argument must be a valid error code number");if(void 0!==t&&t.length){const s=Buffer.byteLength(t);if(s>123)throw new RangeError("The message must not be greater than 123 bytes");i=Buffer.allocUnsafe(2+s),i.writeUInt16BE(e,0),"string"==typeof t?i.write(t,2):i.set(t,2)}else i=Buffer.allocUnsafe(2),i.writeUInt16BE(e,0)}this._deflating?this.enqueue([this.doClose,i,s,r]):this.doClose(i,s,r)}doClose(e,t,s){this.sendFrame(st.frame(e,{fin:!0,rsv1:!1,opcode:8,mask:t,readOnly:!1}),s)}ping(e,t,s){const r=et(e);if(r.length>125)throw new RangeError("The data size must not be greater than 125 bytes");this._deflating?this.enqueue([this.doPing,r,t,et.readOnly,s]):this.doPing(r,t,et.readOnly,s)}doPing(e,t,s,r){this.sendFrame(st.frame(e,{fin:!0,rsv1:!1,opcode:9,mask:t,readOnly:s}),r)}pong(e,t,s){const r=et(e);if(r.length>125)throw new RangeError("The data size must not be greater than 125 bytes");this._deflating?this.enqueue([this.doPong,r,t,et.readOnly,s]):this.doPong(r,t,et.readOnly,s)}doPong(e,t,s,r){this.sendFrame(st.frame(e,{fin:!0,rsv1:!1,opcode:10,mask:t,readOnly:s}),r)}send(e,t,s){const r=et(e),i=this._extensions[Xe.extensionName];let n=t.binary?2:1,o=t.compress;if(this._firstFragment?(this._firstFragment=!1,o&&i&&i.params[i._isServer?"server_no_context_takeover":"client_no_context_takeover"]&&(o=r.length>=i._threshold),this._compress=o):(o=!1,n=0),t.fin&&(this._firstFragment=!0),i){const e={fin:t.fin,rsv1:o,opcode:n,mask:t.mask,readOnly:et.readOnly};this._deflating?this.enqueue([this.dispatch,r,this._compress,e,s]):this.dispatch(r,this._compress,e,s)}else this.sendFrame(st.frame(r,{fin:t.fin,rsv1:!1,opcode:n,mask:t.mask,readOnly:et.readOnly}),s)}dispatch(e,t,s,r){if(!t)return void this.sendFrame(st.frame(e,s),r);const i=this._extensions[Xe.extensionName];this._bufferedBytes+=e.length,this._deflating=!0,i.compress(e,s.fin,((t,i)=>{if(this._socket.destroyed){const e=new Error("The socket was closed while data was being compressed");"function"==typeof r&&r(e);for(let t=0;t{let s=e[t];return Array.isArray(s)||(s=[s]),s.map((e=>[t].concat(Object.keys(e).map((t=>{let s=e[t];return Array.isArray(s)||(s=[s]),s.map((e=>!0===e?t:`${t}=${e}`)).join("; ")}))).join("; "))).join(", ")})).join(", ")},parse:function(e){const t=Object.create(null);let s,r,i=Object.create(null),n=!1,o=!1,a=!1,h=-1,c=-1,l=-1,d=0;for(;d0&&e.unshift(t),e.on("close",ls),e.on("data",ds),e.on("end",us),e.on("error",ps),this._readyState=Xt.OPEN,this.emit("open")}emitClose(){if(!this._socket)return this._readyState=Xt.CLOSED,void this.emit("close",this._closeCode,this._closeMessage);this._extensions[Lt.extensionName]&&this._extensions[Lt.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=Xt.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close(e,t){if(this.readyState!==Xt.CLOSED){if(this.readyState===Xt.CONNECTING){const e="WebSocket was closed before the connection was established";return es(this,this._req,e)}this.readyState!==Xt.CLOSING?(this._readyState=Xt.CLOSING,this._sender.close(e,t,!this._isServer,(e=>{e||(this._closeFrameSent=!0,(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end())})),this._closeTimer=setTimeout(this._socket.destroy.bind(this._socket),3e4)):this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end()}}ping(e,t,s){if(this.readyState===Xt.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");"function"==typeof e?(s=e,e=t=void 0):"function"==typeof t&&(s=t,t=void 0),"number"==typeof e&&(e=e.toString()),this.readyState===Xt.OPEN?(void 0===t&&(t=!this._isServer),this._sender.ping(e||It,t,s)):ts(this,e,s)}pong(e,t,s){if(this.readyState===Xt.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");"function"==typeof e?(s=e,e=t=void 0):"function"==typeof t&&(s=t,t=void 0),"number"==typeof e&&(e=e.toString()),this.readyState===Xt.OPEN?(void 0===t&&(t=!this._isServer),this._sender.pong(e||It,t,s)):ts(this,e,s)}send(e,t,s){if(this.readyState===Xt.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if("function"==typeof t&&(s=t,t={}),"number"==typeof e&&(e=e.toString()),this.readyState!==Xt.OPEN)return void ts(this,e,s);const r={binary:"string"!=typeof e,mask:!this._isServer,compress:!0,fin:!0,...t};this._extensions[Lt.extensionName]||(r.compress=!1),this._sender.send(e||It,r,s)}terminate(){if(this.readyState!==Xt.CLOSED){if(this.readyState===Xt.CONNECTING){const e="WebSocket was closed before the connection was established";return es(this,this._req,e)}this._socket&&(this._readyState=Xt.CLOSING,this._socket.destroy())}}}function Jt(e,t,s,r){const i={protocolVersion:Kt[1],maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...r,createConnection:void 0,socketPath:void 0,hostname:void 0,protocol:void 0,timeout:void 0,method:void 0,host:void 0,path:void 0,port:void 0};if(!Kt.includes(i.protocolVersion))throw new RangeError(`Unsupported protocol version: ${i.protocolVersion} (supported versions: ${Kt.join(", ")})`);let n;if(t instanceof Ct)n=t,e._url=t.href;else{try{n=new Ct(t)}catch(e){throw new SyntaxError(`Invalid URL: ${t}`)}e._url=t}const o="wss:"===n.protocol,a="ws+unix:"===n.protocol;if("ws:"!==n.protocol&&!o&&!a)throw new SyntaxError('The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"');if(a&&!n.pathname)throw new SyntaxError("The URL's pathname is empty");if(n.hash)throw new SyntaxError("The URL contains a fragment identifier");const h=o?443:80,c=Nt(16).toString("base64"),l=o?kt.get:xt.get,d=new Set;let u;if(i.createConnection=o?Zt:Qt,i.defaultPort=i.defaultPort||h,i.port=n.port||h,i.host=n.hostname.startsWith("[")?n.hostname.slice(1,-1):n.hostname,i.headers={"Sec-WebSocket-Version":i.protocolVersion,"Sec-WebSocket-Key":c,Connection:"Upgrade",Upgrade:"websocket",...i.headers},i.path=n.pathname+n.search,i.timeout=i.handshakeTimeout,i.perMessageDeflate&&(u=new Lt(!0!==i.perMessageDeflate?i.perMessageDeflate:{},!1,i.maxPayload),i.headers["Sec-WebSocket-Extensions"]=$t({[Lt.extensionName]:u.offer()})),s.length){for(const e of s){if("string"!=typeof e||!Yt.test(e)||d.has(e))throw new SyntaxError("An invalid or duplicated subprotocol was specified");d.add(e)}i.headers["Sec-WebSocket-Protocol"]=s.join(",")}if(i.origin&&(i.protocolVersion<13?i.headers["Sec-WebSocket-Origin"]=i.origin:i.headers.Origin=i.origin),(n.username||n.password)&&(i.auth=`${n.username}:${n.password}`),a){const e=i.path.split(":");i.socketPath=e[0],i.path=e[1]}let p=e._req=l(i);i.timeout&&p.on("timeout",(()=>{es(e,p,"Opening handshake has timed out")})),p.on("error",(t=>{null===p||p.aborted||(p=e._req=null,e._readyState=Xt.CLOSING,e.emit("error",t),e.emitClose())})),p.on("response",(n=>{const o=n.headers.location,a=n.statusCode;if(o&&i.followRedirects&&a>=300&&a<400){if(++e._redirects>i.maxRedirects)return void es(e,p,"Maximum redirects exceeded");p.abort();const n=new Ct(o,t);Jt(e,n,s,r)}else e.emit("unexpected-response",p,n)||es(e,p,`Unexpected server response: ${n.statusCode}`)})),p.on("upgrade",((t,s,r)=>{if(e.emit("upgrade",t),e.readyState!==Xt.CONNECTING)return;p=e._req=null;const n=Rt("sha1").update(c+Dt).digest("base64");if(t.headers["sec-websocket-accept"]!==n)return void es(e,s,"Invalid Sec-WebSocket-Accept header");const o=t.headers["sec-websocket-protocol"];let a;if(void 0!==o?d.size?d.has(o)||(a="Server sent an invalid subprotocol"):a="Server sent a subprotocol but none was requested":d.size&&(a="Server sent no subprotocol"),a)return void es(e,s,a);o&&(e._protocol=o);const h=t.headers["sec-websocket-extensions"];if(void 0!==h){if(!u){return void es(e,s,"Server sent a Sec-WebSocket-Extensions header but no extension was requested")}let t;try{t=Gt(h)}catch(t){return void es(e,s,"Invalid Sec-WebSocket-Extensions header")}const r=Object.keys(t);if(1!==r.length||r[0]!==Lt.extensionName){return void es(e,s,"Server indicated an extension that was not requested")}try{u.accept(t[Lt.extensionName])}catch(t){return void es(e,s,"Invalid Sec-WebSocket-Extensions header")}e._extensions[Lt.extensionName]=u}e.setSocket(s,r,{maxPayload:i.maxPayload,skipUTF8Validation:i.skipUTF8Validation})}))}function Qt(e){return e.path=e.socketPath,Ot.connect(e)}function Zt(e){return e.path=void 0,e.servername||""===e.servername||(e.servername=Ot.isIP(e.host)?"":e.host),Tt.connect(e)}function es(e,t,s){e._readyState=Xt.CLOSING;const r=new Error(s);Error.captureStackTrace(r,es),t.setHeader?(t.abort(),t.socket&&!t.socket.destroyed&&t.socket.destroy(),t.once("abort",e.emitClose.bind(e)),e.emit("error",r)):(t.destroy(r),t.once("error",e.emit.bind(e,"error")),t.once("close",e.emitClose.bind(e)))}function ts(e,t,s){if(t){const s=Ht(t).length;e._socket?e._sender._bufferedBytes+=s:e._bufferedAmount+=s}if(s){s(new Error(`WebSocket is not open: readyState ${e.readyState} (${zt[e.readyState]})`))}}function ss(e,t){const s=this[Ft];s._closeFrameReceived=!0,s._closeMessage=t,s._closeCode=e,void 0!==s._socket[Ft]&&(s._socket.removeListener("data",ds),process.nextTick(cs,s._socket),1005===e?s.close():s.close(e,t))}function rs(){this[Ft]._socket.resume()}function is(e){const t=this[Ft];void 0!==t._socket[Ft]&&(t._socket.removeListener("data",ds),process.nextTick(cs,t._socket),t.close(e[jt])),t.emit("error",e)}function ns(){this[Ft].emitClose()}function os(e,t){this[Ft].emit("message",e,t)}function as(e){const t=this[Ft];t.pong(e,!t._isServer,Mt),t.emit("ping",e)}function hs(e){this[Ft].emit("pong",e)}function cs(e){e.resume()}function ls(){const e=this[Ft];let t;this.removeListener("close",ls),this.removeListener("data",ds),this.removeListener("end",us),e._readyState=Xt.CLOSING,this._readableState.endEmitted||e._closeFrameReceived||e._receiver._writableState.errorEmitted||null===(t=e._socket.read())||e._receiver.write(t),e._receiver.end(),this[Ft]=void 0,clearTimeout(e._closeTimer),e._receiver._writableState.finished||e._receiver._writableState.errorEmitted?e.emitClose():(e._receiver.on("error",ns),e._receiver.on("finish",ns))}function ds(e){this[Ft]._receiver.write(e)||this.pause()}function us(){const e=this[Ft];e._readyState=Xt.CLOSING,e._receiver.end(),this.end()}function ps(){const e=this[Ft];this.removeListener("error",ps),this.on("error",Mt),e&&(e._readyState=Xt.CLOSING,this.destroy())}Object.defineProperty(Xt,"CONNECTING",{enumerable:!0,value:zt.indexOf("CONNECTING")}),Object.defineProperty(Xt.prototype,"CONNECTING",{enumerable:!0,value:zt.indexOf("CONNECTING")}),Object.defineProperty(Xt,"OPEN",{enumerable:!0,value:zt.indexOf("OPEN")}),Object.defineProperty(Xt.prototype,"OPEN",{enumerable:!0,value:zt.indexOf("OPEN")}),Object.defineProperty(Xt,"CLOSING",{enumerable:!0,value:zt.indexOf("CLOSING")}),Object.defineProperty(Xt.prototype,"CLOSING",{enumerable:!0,value:zt.indexOf("CLOSING")}),Object.defineProperty(Xt,"CLOSED",{enumerable:!0,value:zt.indexOf("CLOSED")}),Object.defineProperty(Xt.prototype,"CLOSED",{enumerable:!0,value:zt.indexOf("CLOSED")}),["binaryType","bufferedAmount","extensions","protocol","readyState","url"].forEach((e=>{Object.defineProperty(Xt.prototype,e,{enumerable:!0})})),["open","error","close","message"].forEach((e=>{Object.defineProperty(Xt.prototype,`on${e}`,{enumerable:!0,get(){for(const t of this.listeners(e))if(t[Ut])return t[qt];return null},set(t){for(const t of this.listeners(e))if(t[Ut]){this.removeListener(e,t);break}"function"==typeof t&&this.addEventListener(e,t,{[Ut]:!0})}})})),Xt.prototype.addEventListener=Wt,Xt.prototype.removeEventListener=Vt;const fs=Xt,_s=process.nextTick,ys="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();const ms={websocket:class extends M{constructor(e){super(e),this.supportsBinary=!e.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protocols,s=ys?{}:D(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(s.headers=this.opts.extraHeaders);try{this.ws=new fs(e,t,s)}catch(e){return this.emitReserved("error",e)}this.ws.binaryType=this.socket.binaryType||"nodebuffer",this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t{const t={};if(s.options&&(t.compress=s.options.compress),this.opts.perMessageDeflate){("string"==typeof e?Buffer.byteLength(e):e.length){this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="";this.opts.port&&("wss"===t&&443!==Number(this.opts.port)||"ws"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port),this.opts.timestampRequests&&(e[this.opts.timestampParam]=Y()),this.supportsBinary||(e.b64=1);const r=K(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(r.length?"?"+r:"")}check(){return!!fs}},polling:class extends M{constructor(e){if(super(e),this.polling=!1,"undefined"!=typeof location){const t="https:"===location.protocol;let s=location.port;s||(s=t?"443":"80"),this.xd="undefined"!=typeof location&&e.hostname!==location.hostname||s!==e.port,this.xs=e.secure!==t}const t=e&&e.forceBase64;this.supportsBinary=re&&!t}get name(){return"polling"}doOpen(){this.poll()}pause(e){this.readyState="pausing";const t=()=>{this.readyState="paused",e()};if(this.polling||!this.writable){let e=0;this.polling&&(e++,this.once("pollComplete",(function(){--e||t()}))),this.writable||(e++,this.once("drain",(function(){--e||t()})))}else t()}poll(){this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){((e,t)=>{const s=e.split(B),r=[];for(let e=0;e{if("opening"===this.readyState&&"open"===e.type&&this.onOpen(),"close"===e.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState&&this.poll())}doClose(){const e=()=>{this.write([{type:"close"}])};"open"===this.readyState?e():this.once("open",e)}write(e){this.writable=!1,((e,t)=>{const s=e.length,r=new Array(s);let i=0;e.forEach(((e,n)=>{T(e,!1,(e=>{r[n]=e,++i===s&&t(r.join(B))}))}))})(e,(e=>{this.doWrite(e,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){let e=this.query||{};const t=this.opts.secure?"https":"http";let s="";!1!==this.opts.timestampRequests&&(e[this.opts.timestampParam]=Y()),this.supportsBinary||e.sid||(e.b64=1),this.opts.port&&("https"===t&&443!==Number(this.opts.port)||"http"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port);const r=K(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(r.length?"?"+r:"")}request(e={}){return Object.assign(e,{xd:this.xd,xs:this.xs},this.opts),new ie(this.uri(),e)}doWrite(e,t){const s=this.request({method:"POST",data:e});s.on("success",t),s.on("error",((e,t)=>{this.onError("xhr post error",e,t)}))}doPoll(){const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",((e,t)=>{this.onError("xhr poll error",e,t)})),this.pollXhr=e}}},gs=/^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,bs=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];function vs(e){const t=e,s=e.indexOf("["),r=e.indexOf("]");-1!=s&&-1!=r&&(e=e.substring(0,s)+e.substring(s,r).replace(/:/g,";")+e.substring(r,e.length));let i=gs.exec(e||""),n={},o=14;for(;o--;)n[bs[o]]=i[o]||"";return-1!=s&&-1!=r&&(n.source=t,n.host=n.host.substring(1,n.host.length-1).replace(/;/g,":"),n.authority=n.authority.replace("[","").replace("]","").replace(/;/g,":"),n.ipv6uri=!0),n.pathNames=function(e,t){const s=/\/{2,9}/g,r=t.replace(s,"/").split("/");"/"!=t.substr(0,1)&&0!==t.length||r.splice(0,1);"/"==t.substr(t.length-1,1)&&r.splice(r.length-1,1);return r}(0,n.path),n.queryKey=function(e,t){const s={};return t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(e,t,r){t&&(s[t]=r)})),s}(0,n.query),n}class Es extends P{constructor(e,t={}){super(),e&&"object"==typeof e&&(t=e,e=null),e?(e=vs(e),t.hostname=e.host,t.secure="https"===e.protocol||"wss"===e.protocol,t.port=e.port,e.query&&(t.query=e.query)):t.host&&(t.hostname=vs(t.host).host),j(this,t),this.secure=null!=t.secure?t.secure:"undefined"!=typeof location&&"https:"===location.protocol,t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=t.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=t.transports||["polling","websocket"],this.readyState="",this.writeBuffer=[],this.prevBufferLen=0,this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},t),this.opts.path=this.opts.path.replace(/\/$/,"")+"/","string"==typeof this.opts.query&&(this.opts.query=function(e){let t={},s=e.split("&");for(let e=0,r=s.length;e{this.transport&&(this.transport.removeAllListeners(),this.transport.close())}),!1),"localhost"!==this.hostname&&(this.offlineEventListener=()=>{this.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",this.offlineEventListener,!1))),this.open()}createTransport(e){const t=Object.assign({},this.opts.query);t.EIO=4,t.transport=e,this.id&&(t.sid=this.id);const s=Object.assign({},this.opts.transportOptions[e],this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return new ms[e](s)}open(){let e;if(this.opts.rememberUpgrade&&Es.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(e){return this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}setTransport(e){this.transport&&this.transport.removeAllListeners(),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(e=>this.onClose("transport close",e)))}probe(e){let t=this.createTransport(e),s=!1;Es.priorWebsocketSuccess=!1;const r=()=>{s||(t.send([{type:"ping",data:"probe"}]),t.once("packet",(e=>{if(!s)if("pong"===e.type&&"probe"===e.data){if(this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;Es.priorWebsocketSuccess="websocket"===t.name,this.transport.pause((()=>{s||"closed"!==this.readyState&&(c(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())}))}else{const e=new Error("probe error");e.transport=t.name,this.emitReserved("upgradeError",e)}})))};function i(){s||(s=!0,c(),t.close(),t=null)}const n=e=>{const s=new Error("probe error: "+e);s.transport=t.name,i(),this.emitReserved("upgradeError",s)};function o(){n("transport closed")}function a(){n("socket closed")}function h(e){t&&e.name!==t.name&&i()}const c=()=>{t.removeListener("open",r),t.removeListener("error",n),t.removeListener("close",o),this.off("close",a),this.off("upgrading",h)};t.once("open",r),t.once("error",n),t.once("close",o),this.once("close",a),this.once("upgrading",h),t.open()}onOpen(){if(this.readyState="open",Es.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade&&this.transport.pause){let e=0;const t=this.upgrades.length;for(;e{this.onClose("ping timeout")}),this.pingInterval+this.pingTimeout),this.opts.autoUnref&&this.pingTimeoutTimer.unref()}onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBufferLen=0,0===this.writeBuffer.length?this.emitReserved("drain"):this.flush()}flush(){if("closed"!==this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this.getWritablePackets();this.transport.send(e),this.prevBufferLen=e.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let e=1;for(let s=0;s=57344?s+=3:(r++,s+=4);return s}(t):Math.ceil(1.33*(t.byteLength||t.size))),s>0&&e>this.maxPayload)return this.writeBuffer.slice(0,s);e+=2}var t;return this.writeBuffer}write(e,t,s){return this.sendPacket("message",e,t,s),this}send(e,t,s){return this.sendPacket("message",e,t,s),this}sendPacket(e,t,s,r){if("function"==typeof t&&(r=t,t=void 0),"function"==typeof s&&(r=s,s=null),"closing"===this.readyState||"closed"===this.readyState)return;(s=s||{}).compress=!1!==s.compress;const i={type:e,data:t,options:s};this.emitReserved("packetCreate",i),this.writeBuffer.push(i),r&&this.once("flush",r),this.flush()}close(){const e=()=>{this.onClose("forced close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},s=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?s():e()})):this.upgrading?s():e()),this}onError(e){Es.priorWebsocketSuccess=!1,this.emitReserved("error",e),this.onClose("transport error",e)}onClose(e,t){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&removeEventListener("offline",this.offlineEventListener,!1),this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(e){const t=[];let s=0;const r=e.length;for(;s"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e.buffer instanceof ArrayBuffer)(e))||ks&&e instanceof Blob||xs&&e instanceof File}function Ts(e,t){if(!e||"object"!=typeof e)return!1;if(Array.isArray(e)){for(let t=0,s=e.length;t0;case As.ACK:case As.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&this.reconstructor.finishedReconstruction()}}class Ps{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){const e=Cs(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}var Is=Object.freeze({__proto__:null,protocol:5,get PacketType(){return As},Encoder:class{constructor(e){this.replacer=e}encode(e){return e.type!==As.EVENT&&e.type!==As.ACK||!Ts(e)?[this.encodeAsString(e)]:(e.type=e.type===As.EVENT?As.BINARY_EVENT:As.BINARY_ACK,this.encodeAsBinary(e))}encodeAsString(e){let t=""+e.type;return e.type!==As.BINARY_EVENT&&e.type!==As.BINARY_ACK||(t+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(t+=e.nsp+","),null!=e.id&&(t+=e.id),null!=e.data&&(t+=JSON.stringify(e.data,this.replacer)),t}encodeAsBinary(e){const t=Ns(e),s=this.encodeAsString(t.packet),r=t.buffers;return r.unshift(s),r}},Decoder:Bs});function Ds(e,t,s){return e.on(t,s),function(){e.off(t,s)}}const Us=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class qs extends P{constructor(e,t,s){super(),this.connected=!1,this.receiveBuffer=[],this.sendBuffer=[],this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,s&&s.auth&&(this.auth=s.auth),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const e=this.io;this.subs=[Ds(e,"open",this.onopen.bind(this)),Ds(e,"packet",this.onpacket.bind(this)),Ds(e,"error",this.onerror.bind(this)),Ds(e,"close",this.onclose.bind(this))]}get active(){return!!this.subs}connect(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){if(Us.hasOwnProperty(e))throw new Error('"'+e+'" is a reserved event name');t.unshift(e);const s={type:As.EVENT,data:t,options:{}};if(s.options.compress=!1!==this.flags.compress,"function"==typeof t[t.length-1]){const e=this.ids++,r=t.pop();this._registerAckCallback(e,r),s.id=e}const r=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return this.flags.volatile&&(!r||!this.connected)||(this.connected?(this.notifyOutgoingListeners(s),this.packet(s)):this.sendBuffer.push(s)),this.flags={},this}_registerAckCallback(e,t){const s=this.flags.timeout;if(void 0===s)return void(this.acks[e]=t);const r=this.io.setTimeoutFn((()=>{delete this.acks[e];for(let t=0;t{this.io.clearTimeoutFn(r),t.apply(this,[null,...e])}}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){"function"==typeof this.auth?this.auth((e=>{this.packet({type:As.CONNECT,data:e})})):this.packet({type:As.CONNECT,data:this.auth})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t)}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case As.CONNECT:if(e.data&&e.data.sid){const t=e.data.sid;this.onconnect(t)}else this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case As.EVENT:case As.BINARY_EVENT:this.onevent(e);break;case As.ACK:case As.BINARY_ACK:this.onack(e);break;case As.DISCONNECT:this.ondisconnect();break;case As.CONNECT_ERROR:this.destroy();const t=new Error(e.data.message);t.data=e.data.data,this.emitReserved("connect_error",t)}}onevent(e){const t=e.data||[];null!=e.id&&t.push(this.ack(e.id)),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const s of t)s.apply(this,e)}super.emit.apply(this,e)}ack(e){const t=this;let s=!1;return function(...r){s||(s=!0,t.packet({type:As.ACK,id:e,data:r}))}}onack(e){const t=this.acks[e.id];"function"==typeof t&&(t.apply(this,e.data),delete this.acks[e.id])}onconnect(e){this.id=e,this.connected=!0,this.emitBuffered(),this.emitReserved("connect")}emitBuffered(){this.receiveBuffer.forEach((e=>this.emitEvent(e))),this.receiveBuffer=[],this.sendBuffer.forEach((e=>{this.notifyOutgoingListeners(e),this.packet(e)})),this.sendBuffer=[]}ondisconnect(){this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((e=>e())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&this.packet({type:As.DISCONNECT}),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let s=0;s0&&e.jitter<=1?e.jitter:0,this.attempts=0}js.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),s=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-s:e+s}return 0|Math.min(e,this.max)},js.prototype.reset=function(){this.attempts=0},js.prototype.setMin=function(e){this.ms=e},js.prototype.setMax=function(e){this.max=e},js.prototype.setJitter=function(e){this.jitter=e};class Fs extends P{constructor(e,t){var s;super(),this.nsps={},this.subs=[],e&&"object"==typeof e&&(t=e,e=void 0),(t=t||{}).path=t.path||"/socket.io",this.opts=t,j(this,t),this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(s=t.randomizationFactor)&&void 0!==s?s:.5),this.backoff=new js({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this._readyState="closed",this.uri=e;const r=t.parser||Is;this.encoder=new r.Encoder,this.decoder=new r.Decoder,this._autoConnect=!1!==t.autoConnect,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,this):this._reconnection}reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(this._reconnectionDelay=e,null===(t=this.backoff)||void 0===t||t.setMin(e),this)}randomizationFactor(e){var t;return void 0===e?this._randomizationFactor:(this._randomizationFactor=e,null===(t=this.backoff)||void 0===t||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,null===(t=this.backoff)||void 0===t||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(e){if(~this._readyState.indexOf("open"))return this;this.engine=new Es(this.uri,this.opts);const t=this.engine,s=this;this._readyState="opening",this.skipReconnect=!1;const r=Ds(t,"open",(function(){s.onopen(),e&&e()})),i=Ds(t,"error",(t=>{s.cleanup(),s._readyState="closed",this.emitReserved("error",t),e?e(t):s.maybeReconnectOnOpen()}));if(!1!==this._timeout){const e=this._timeout;0===e&&r();const s=this.setTimeoutFn((()=>{r(),t.close(),t.emit("error",new Error("timeout"))}),e);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}return this.subs.push(r),this.subs.push(i),this}connect(e){return this.open(e)}onopen(){this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(Ds(e,"ping",this.onping.bind(this)),Ds(e,"data",this.ondata.bind(this)),Ds(e,"error",this.onerror.bind(this)),Ds(e,"close",this.onclose.bind(this)),Ds(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){this.decoder.add(e)}ondecoded(e){this.emitReserved("packet",e)}onerror(e){this.emitReserved("error",e)}socket(e,t){let s=this.nsps[e];return s||(s=new qs(this,e,t),this.nsps[e]=s),s}_destroy(e){const t=Object.keys(this.nsps);for(const e of t){if(this.nsps[e].active)return}this._close()}_packet(e){const t=this.encoder.encode(e);for(let s=0;se())),this.subs.length=0,this.decoder.destroy()}_close(){this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(e,t){this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();this._reconnecting=!0;const s=this.setTimeoutFn((()=>{e.skipReconnect||(this.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((t=>{t?(e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",t)):e.onreconnect()})))}),t);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}const Ms={};function Ws(e,t){"object"==typeof e&&(t=e,e=void 0);const s=function(e,t="",s){let r=e;s=s||"undefined"!=typeof location&&location,null==e&&(e=s.protocol+"//"+s.host),"string"==typeof e&&("/"===e.charAt(0)&&(e="/"===e.charAt(1)?s.protocol+e:s.host+e),/^(https?|wss?):\/\//.test(e)||(e=void 0!==s?s.protocol+"//"+e:"https://"+e),r=vs(e)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";const i=-1!==r.host.indexOf(":")?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+i+":"+r.port+t,r.href=r.protocol+"://"+i+(s&&s.port===r.port?"":":"+r.port),r}(e,(t=t||{}).path||"/socket.io"),r=s.source,i=s.id,n=s.path,o=Ms[i]&&n in Ms[i].nsps;let a;return t.forceNew||t["force new connection"]||!1===t.multiplex||o?a=new Fs(r,t):(Ms[i]||(Ms[i]=new Fs(r,t)),a=Ms[i]),s.query&&!t.query&&(t.query=s.queryKey),a.socket(s.path,t)}Object.assign(Ws,{Manager:Fs,Socket:qs,io:Ws,connect:Ws});var Vs="e";var $s="jr",Gs="jc";const Hs=process.argv.slice(2),zs=Hs[0],Ys=Hs[1],Ks=Hs.slice(2),Xs={id:Ys,command:Ks},Js=new class{constructor(e,t,s={}){this.url=e,this.job=t,this.mode=Vs,this.buf={},this.buf.e="",this.buf.o="",this.spawn=s.spawn??this.spawn.bind(this),this.report=s.report??this.report.bind(this),this.onProcClose=s.onProcClose??this.onProcClose.bind(this),this.onClose=s.onClose??this.onClose.bind(this)}spawn(){const e=this.job.command,t=e.shift();this.proc=_.default.spawn(t,e),this.proc.stdout.setEncoding("utf8"),this.proc.stderr.setEncoding("utf8"),this.proc.stdout.on("data",(e=>this.report(e.toString(),"o"))),this.proc.stderr.on("data",(e=>this.report(e.toString(),"e"))),this.proc.on("close",this.onProcClose)}runJob(){const e=new Fs(this.url,{query:{mode:this.mode,jobId:this.job.id}});this.socket=e.socket("/"),this.socket.on("connect",this.spawn),this.socket.on("disconnect",this.onClose)}onClose(){console.log("Server disconnected, terminating process."),this.proc.kill("SIGINT")}onProcClose(e){this.socket.emit(Gs,e),console.log(`Process finished with code ${e}`),this.socket.disconnect()}report(e,t){this.buf[t]+=e,this.buf[t].includes("\n")&&(this.buf[t].endsWith("\n")&&(this.buf[t]=this.buf[t].slice(0,-1)),this.socket.emit($s,this.buf[t]),"e"===t?console.error(`err: ${this.buf[t]}`):console.log(`out: ${this.buf[t]}`),this.buf[t]="")}}(zs,Xs,Ks);Js.runJob(); +var X = p.default, + J = f.default, + Q = _.default.spawn, + Z = ee; +function ee(e) { + e = e || {}; + var t, + s, + r = this, + i = y.default, + n = m.default, + o = {}, + a = !1, + h = { "User-Agent": "node-XMLHttpRequest", Accept: "*/*" }, + c = Object.assign({}, h), + l = [ + "accept-charset", + "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", + "content-length", + "content-transfer-encoding", + "cookie", + "cookie2", + "date", + "expect", + "host", + "keep-alive", + "origin", + "referer", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "via", + ], + d = ["TRACE", "TRACK", "CONNECT"], + u = !1, + p = !1, + f = !1, + _ = {}; + (this.UNSENT = 0), + (this.OPENED = 1), + (this.HEADERS_RECEIVED = 2), + (this.LOADING = 3), + (this.DONE = 4), + (this.readyState = this.UNSENT), + (this.onreadystatechange = null), + (this.responseText = ""), + (this.responseXML = ""), + (this.status = null), + (this.statusText = null); + (this.open = function (e, t, s, r, i) { + if ( + (this.abort(), + (p = !1), + (f = !1), + !(function (e) { + return e && -1 === d.indexOf(e); + })(e)) + ) + throw new Error("SecurityError: Request method not allowed"); + (o = { + method: e, + url: t.toString(), + async: "boolean" != typeof s || s, + user: r || null, + password: i || null, + }), + g(this.OPENED); + }), + (this.setDisableHeaderCheck = function (e) { + a = e; + }), + (this.setRequestHeader = function (e, t) { + if (this.readyState != this.OPENED) + throw new Error( + "INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN" + ); + if ( + !(function (e) { + return a || (e && -1 === l.indexOf(e.toLowerCase())); + })(e) + ) + return console.warn('Refused to set unsafe header "' + e + '"'), !1; + if (u) throw new Error("INVALID_STATE_ERR: send flag is true"); + return (c[e] = t), !0; + }), + (this.getResponseHeader = function (e) { + return "string" == typeof e && + this.readyState > this.OPENED && + s.headers[e.toLowerCase()] && + !p + ? s.headers[e.toLowerCase()] + : null; + }), + (this.getAllResponseHeaders = function () { + if (this.readyState < this.HEADERS_RECEIVED || p) return ""; + var e = ""; + for (var t in s.headers) + "set-cookie" !== t && + "set-cookie2" !== t && + (e += t + ": " + s.headers[t] + "\r\n"); + return e.substr(0, e.length - 2); + }), + (this.getRequestHeader = function (e) { + return "string" == typeof e && c[e] ? c[e] : ""; + }), + (this.send = function (a) { + if (this.readyState != this.OPENED) + throw new Error( + "INVALID_STATE_ERR: connection must be opened before send() is called" + ); + if (u) throw new Error("INVALID_STATE_ERR: send has already been called"); + var h, + l = !1, + d = !1, + f = J.parse(o.url); + switch (f.protocol) { + case "https:": + l = !0; + case "http:": + h = f.hostname; + break; + case "file:": + d = !0; + break; + case void 0: + case "": + h = "localhost"; + break; + default: + throw new Error("Protocol not supported."); + } + if (d) { + if ("GET" !== o.method) + throw new Error("XMLHttpRequest: Only GET method is supported"); + if (o.async) + X.readFile(unescape(f.pathname), "utf8", function (e, t) { + e + ? r.handleError(e, e.errno || -1) + : ((r.status = 200), (r.responseText = t), g(r.DONE)); + }); + else + try { + (this.responseText = X.readFileSync(unescape(f.pathname), "utf8")), + (this.status = 200), + g(r.DONE); + } catch (e) { + this.handleError(e, e.errno || -1); + } + } else { + var _ = f.port || (l ? 443 : 80), + y = f.pathname + (f.search ? f.search : ""); + if ( + ((c.Host = h), + (l && 443 === _) || 80 === _ || (c.Host += ":" + f.port), + o.user) + ) { + void 0 === o.password && (o.password = ""); + var m = new Buffer(o.user + ":" + o.password); + c.Authorization = "Basic " + m.toString("base64"); + } + "GET" === o.method || "HEAD" === o.method + ? (a = null) + : a + ? ((c["Content-Length"] = Buffer.isBuffer(a) + ? a.length + : Buffer.byteLength(a)), + c["Content-Type"] || + (c["Content-Type"] = "text/plain;charset=UTF-8")) + : "POST" === o.method && (c["Content-Length"] = 0); + var b = e.agent || !1, + v = { + host: h, + port: _, + path: y, + method: o.method, + headers: c, + agent: b, + }; + if ( + (l && + ((v.pfx = e.pfx), + (v.key = e.key), + (v.passphrase = e.passphrase), + (v.cert = e.cert), + (v.ca = e.ca), + (v.ciphers = e.ciphers), + (v.rejectUnauthorized = !1 !== e.rejectUnauthorized)), + (p = !1), + o.async) + ) { + var E = l ? n.request : i.request; + (u = !0), r.dispatchEvent("readystatechange"); + var w = function (i) { + if ( + 302 === (s = i).statusCode || + 303 === s.statusCode || + 307 === s.statusCode + ) { + o.url = s.headers.location; + var n = J.parse(o.url); + h = n.hostname; + var a = { + hostname: n.hostname, + port: n.port, + path: n.path, + method: 303 === s.statusCode ? "GET" : o.method, + headers: c, + }; + return ( + l && + ((a.pfx = e.pfx), + (a.key = e.key), + (a.passphrase = e.passphrase), + (a.cert = e.cert), + (a.ca = e.ca), + (a.ciphers = e.ciphers), + (a.rejectUnauthorized = !1 !== e.rejectUnauthorized)), + void (t = E(a, w).on("error", S)).end() + ); + } + s && s.setEncoding && s.setEncoding("utf8"), + g(r.HEADERS_RECEIVED), + (r.status = s.statusCode), + s.on("data", function (e) { + e && (r.responseText += e), u && g(r.LOADING); + }), + s.on("end", function () { + u && ((u = !1), g(r.DONE)); + }), + s.on("error", function (e) { + r.handleError(e); + }); + }, + S = function (e) { + r.handleError(e); + }; + (t = E(v, w).on("error", S)), + e.autoUnref && + t.on("socket", (e) => { + e.unref(); + }), + a && t.write(a), + t.end(), + r.dispatchEvent("loadstart"); + } else { + var k = ".node-xmlhttprequest-content-" + process.pid, + x = ".node-xmlhttprequest-sync-" + process.pid; + X.writeFileSync(x, "", "utf8"); + for ( + var O = + "var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http" + + (l ? "s" : "") + + ".request;var options = " + + JSON.stringify(v) + + ";var responseText = '';var req = doRequest(options, function(response) {response.setEncoding('utf8');response.on('data', function(chunk) { responseText += chunk;});response.on('end', function() {fs.writeFileSync('" + + k + + "', 'NODE-XMLHTTPREQUEST-STATUS:' + response.statusCode + ',' + responseText, 'utf8');fs.unlinkSync('" + + x + + "');});response.on('error', function(error) {fs.writeFileSync('" + + k + + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + + x + + "');});}).on('error', function(error) {fs.writeFileSync('" + + k + + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + + x + + "');});" + + (a + ? "req.write('" + + JSON.stringify(a).slice(1, -1).replace(/'/g, "\\'") + + "');" + : "") + + "req.end();", + T = Q(process.argv[0], ["-e", O]); + X.existsSync(x); + + ); + if ( + ((r.responseText = X.readFileSync(k, "utf8")), + T.stdin.end(), + X.unlinkSync(k), + r.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)) + ) { + var N = r.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/, ""); + r.handleError(N, 503); + } else + (r.status = r.responseText.replace( + /^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/, + "$1" + )), + (r.responseText = r.responseText.replace( + /^NODE-XMLHTTPREQUEST-STATUS:[0-9]*,(.*)/, + "$1" + )), + g(r.DONE); + } + } + }), + (this.handleError = function (e, t) { + (this.status = t || 0), + (this.statusText = e), + (this.responseText = e.stack), + (p = !0), + g(this.DONE); + }), + (this.abort = function () { + t && (t.abort(), (t = null)), + (c = Object.assign({}, h)), + (this.responseText = ""), + (this.responseXML = ""), + (p = f = !0), + this.readyState === this.UNSENT || + (this.readyState === this.OPENED && !u) || + this.readyState === this.DONE || + ((u = !1), g(this.DONE)), + (this.readyState = this.UNSENT); + }), + (this.addEventListener = function (e, t) { + e in _ || (_[e] = []), _[e].push(t); + }), + (this.removeEventListener = function (e, t) { + e in _ && + (_[e] = _[e].filter(function (e) { + return e !== t; + })); + }), + (this.dispatchEvent = function (e) { + if ( + ("function" == typeof r["on" + e] && + (this.readyState === this.DONE + ? setImmediate(function () { + r["on" + e](); + }) + : r["on" + e]()), + e in _) + ) + for (let t = 0, s = _[e].length; t < s; t++) + this.readyState === this.DONE + ? setImmediate(function () { + _[e][t].call(r); + }) + : _[e][t].call(r); + }); + var g = function (e) { + if ( + !(r.readyState === e || (r.readyState === r.UNSENT && f)) && + ((r.readyState = e), + (o.async || r.readyState < r.OPENED || r.readyState === r.DONE) && + r.dispatchEvent("readystatechange"), + r.readyState === r.DONE) + ) { + let e; + (e = f ? "abort" : p ? "error" : "load"), + r.dispatchEvent(e), + r.dispatchEvent("loadend"); + } + }; +} +ee.XMLHttpRequest = ee; +const te = Z || u({ __proto__: null, default: Z }, [Z]); +function se() {} +const re = null != new te({ xdomain: !1 }).responseType; +class ie extends P { + constructor(e, t) { + super(), + j(this, t), + (this.opts = t), + (this.method = t.method || "GET"), + (this.uri = e), + (this.async = !1 !== t.async), + (this.data = void 0 !== t.data ? t.data : null), + this.create(); + } + create() { + const e = D( + this.opts, + "agent", + "pfx", + "key", + "passphrase", + "cert", + "ca", + "ciphers", + "rejectUnauthorized", + "autoUnref" + ); + (e.xdomain = !!this.opts.xd), (e.xscheme = !!this.opts.xs); + const t = (this.xhr = new te(e)); + try { + t.open(this.method, this.uri, this.async); + try { + if (this.opts.extraHeaders) { + t.setDisableHeaderCheck && t.setDisableHeaderCheck(!0); + for (let e in this.opts.extraHeaders) + this.opts.extraHeaders.hasOwnProperty(e) && + t.setRequestHeader(e, this.opts.extraHeaders[e]); + } + } catch (e) {} + if ("POST" === this.method) + try { + t.setRequestHeader("Content-type", "text/plain;charset=UTF-8"); + } catch (e) {} + try { + t.setRequestHeader("Accept", "*/*"); + } catch (e) {} + "withCredentials" in t && (t.withCredentials = this.opts.withCredentials), + this.opts.requestTimeout && (t.timeout = this.opts.requestTimeout), + (t.onreadystatechange = () => { + 4 === t.readyState && + (200 === t.status || 1223 === t.status + ? this.onLoad() + : this.setTimeoutFn(() => { + this.onError("number" == typeof t.status ? t.status : 0); + }, 0)); + }), + t.send(this.data); + } catch (e) { + return void this.setTimeoutFn(() => { + this.onError(e); + }, 0); + } + "undefined" != typeof document && + ((this.index = ie.requestsCount++), (ie.requests[this.index] = this)); + } + onError(e) { + this.emitReserved("error", e, this.xhr), this.cleanup(!0); + } + cleanup(e) { + if (void 0 !== this.xhr && null !== this.xhr) { + if (((this.xhr.onreadystatechange = se), e)) + try { + this.xhr.abort(); + } catch (e) {} + "undefined" != typeof document && delete ie.requests[this.index], + (this.xhr = null); + } + } + onLoad() { + const e = this.xhr.responseText; + null !== e && + (this.emitReserved("data", e), + this.emitReserved("success"), + this.cleanup()); + } + abort() { + this.cleanup(); + } +} +if ( + ((ie.requestsCount = 0), (ie.requests = {}), "undefined" != typeof document) +) + if ("function" == typeof attachEvent) attachEvent("onunload", ne); + else if ("function" == typeof addEventListener) { + addEventListener("onpagehide" in I ? "pagehide" : "unload", ne, !1); + } +function ne() { + for (let e in ie.requests) + ie.requests.hasOwnProperty(e) && ie.requests[e].abort(); +} +var oe = { exports: {} }, + ae = { + BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], + EMPTY_BUFFER: Buffer.alloc(0), + GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", + kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), + kListener: Symbol("kListener"), + kStatusCode: Symbol("status-code"), + kWebSocket: Symbol("websocket"), + NOOP: () => {}, + }; +const { EMPTY_BUFFER: he } = ae; +function ce(e, t) { + if (0 === e.length) return he; + if (1 === e.length) return e[0]; + const s = Buffer.allocUnsafe(t); + let r = 0; + for (let t = 0; t < e.length; t++) { + const i = e[t]; + s.set(i, r), (r += i.length); + } + return r < t ? s.slice(0, r) : s; +} +function le(e, t, s, r, i) { + for (let n = 0; n < i; n++) s[r + n] = e[n] ^ t[3 & n]; +} +function de(e, t) { + for (let s = 0; s < e.length; s++) e[s] ^= t[3 & s]; +} +function ue(e) { + return e.byteLength === e.buffer.byteLength + ? e.buffer + : e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength); +} +function pe(e) { + if (((pe.readOnly = !0), Buffer.isBuffer(e))) return e; + let t; + return ( + e instanceof ArrayBuffer + ? (t = Buffer.from(e)) + : ArrayBuffer.isView(e) + ? (t = Buffer.from(e.buffer, e.byteOffset, e.byteLength)) + : ((t = Buffer.from(e)), (pe.readOnly = !1)), + t + ); +} +try { + const e = require("bufferutil"); + oe.exports = { + concat: ce, + mask(t, s, r, i, n) { + n < 48 ? le(t, s, r, i, n) : e.mask(t, s, r, i, n); + }, + toArrayBuffer: ue, + toBuffer: pe, + unmask(t, s) { + t.length < 32 ? de(t, s) : e.unmask(t, s); + }, + }; +} catch (e) { + oe.exports = { + concat: ce, + mask: le, + toArrayBuffer: ue, + toBuffer: pe, + unmask: de, + }; +} +const fe = Symbol("kDone"), + _e = Symbol("kRun"); +var ye = class { + constructor(e) { + (this[fe] = () => { + this.pending--, this[_e](); + }), + (this.concurrency = e || 1 / 0), + (this.jobs = []), + (this.pending = 0); + } + add(e) { + this.jobs.push(e), this[_e](); + } + [_e]() { + if (this.pending !== this.concurrency && this.jobs.length) { + const e = this.jobs.shift(); + this.pending++, e(this[fe]); + } + } +}; +const me = b.default, + ge = oe.exports, + be = ye, + { kStatusCode: ve } = ae, + Ee = Buffer.from([0, 0, 255, 255]), + we = Symbol("permessage-deflate"), + Se = Symbol("total-length"), + ke = Symbol("callback"), + xe = Symbol("buffers"), + Oe = Symbol("error"); +let Te; +var Ne = class { + constructor(e, t, s) { + if ( + ((this._maxPayload = 0 | s), + (this._options = e || {}), + (this._threshold = + void 0 !== this._options.threshold ? this._options.threshold : 1024), + (this._isServer = !!t), + (this._deflate = null), + (this._inflate = null), + (this.params = null), + !Te) + ) { + const e = + void 0 !== this._options.concurrencyLimit + ? this._options.concurrencyLimit + : 10; + Te = new be(e); + } + } + static get extensionName() { + return "permessage-deflate"; + } + offer() { + const e = {}; + return ( + this._options.serverNoContextTakeover && + (e.server_no_context_takeover = !0), + this._options.clientNoContextTakeover && + (e.client_no_context_takeover = !0), + this._options.serverMaxWindowBits && + (e.server_max_window_bits = this._options.serverMaxWindowBits), + this._options.clientMaxWindowBits + ? (e.client_max_window_bits = this._options.clientMaxWindowBits) + : null == this._options.clientMaxWindowBits && + (e.client_max_window_bits = !0), + e + ); + } + accept(e) { + return ( + (e = this.normalizeParams(e)), + (this.params = this._isServer + ? this.acceptAsServer(e) + : this.acceptAsClient(e)), + this.params + ); + } + cleanup() { + if ( + (this._inflate && (this._inflate.close(), (this._inflate = null)), + this._deflate) + ) { + const e = this._deflate[ke]; + this._deflate.close(), + (this._deflate = null), + e && + e( + new Error( + "The deflate stream was closed while data was being processed" + ) + ); + } + } + acceptAsServer(e) { + const t = this._options, + s = e.find( + (e) => + !( + (!1 === t.serverNoContextTakeover && + e.server_no_context_takeover) || + (e.server_max_window_bits && + (!1 === t.serverMaxWindowBits || + ("number" == typeof t.serverMaxWindowBits && + t.serverMaxWindowBits > e.server_max_window_bits))) || + ("number" == typeof t.clientMaxWindowBits && + !e.client_max_window_bits) + ) + ); + if (!s) throw new Error("None of the extension offers can be accepted"); + return ( + t.serverNoContextTakeover && (s.server_no_context_takeover = !0), + t.clientNoContextTakeover && (s.client_no_context_takeover = !0), + "number" == typeof t.serverMaxWindowBits && + (s.server_max_window_bits = t.serverMaxWindowBits), + "number" == typeof t.clientMaxWindowBits + ? (s.client_max_window_bits = t.clientMaxWindowBits) + : (!0 !== s.client_max_window_bits && !1 !== t.clientMaxWindowBits) || + delete s.client_max_window_bits, + s + ); + } + acceptAsClient(e) { + const t = e[0]; + if ( + !1 === this._options.clientNoContextTakeover && + t.client_no_context_takeover + ) + throw new Error('Unexpected parameter "client_no_context_takeover"'); + if (t.client_max_window_bits) { + if ( + !1 === this._options.clientMaxWindowBits || + ("number" == typeof this._options.clientMaxWindowBits && + t.client_max_window_bits > this._options.clientMaxWindowBits) + ) + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); + } else + "number" == typeof this._options.clientMaxWindowBits && + (t.client_max_window_bits = this._options.clientMaxWindowBits); + return t; + } + normalizeParams(e) { + return ( + e.forEach((e) => { + Object.keys(e).forEach((t) => { + let s = e[t]; + if (s.length > 1) + throw new Error(`Parameter "${t}" must have only a single value`); + if (((s = s[0]), "client_max_window_bits" === t)) { + if (!0 !== s) { + const e = +s; + if (!Number.isInteger(e) || e < 8 || e > 15) + throw new TypeError(`Invalid value for parameter "${t}": ${s}`); + s = e; + } else if (!this._isServer) + throw new TypeError(`Invalid value for parameter "${t}": ${s}`); + } else if ("server_max_window_bits" === t) { + const e = +s; + if (!Number.isInteger(e) || e < 8 || e > 15) + throw new TypeError(`Invalid value for parameter "${t}": ${s}`); + s = e; + } else { + if ( + "client_no_context_takeover" !== t && + "server_no_context_takeover" !== t + ) + throw new Error(`Unknown parameter "${t}"`); + if (!0 !== s) + throw new TypeError(`Invalid value for parameter "${t}": ${s}`); + } + e[t] = s; + }); + }), + e + ); + } + decompress(e, t, s) { + Te.add((r) => { + this._decompress(e, t, (e, t) => { + r(), s(e, t); + }); + }); + } + compress(e, t, s) { + Te.add((r) => { + this._compress(e, t, (e, t) => { + r(), s(e, t); + }); + }); + } + _decompress(e, t, s) { + const r = this._isServer ? "client" : "server"; + if (!this._inflate) { + const e = `${r}_max_window_bits`, + t = + "number" != typeof this.params[e] + ? me.Z_DEFAULT_WINDOWBITS + : this.params[e]; + (this._inflate = me.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits: t, + })), + (this._inflate[we] = this), + (this._inflate[Se] = 0), + (this._inflate[xe] = []), + this._inflate.on("error", Le), + this._inflate.on("data", Ce); + } + (this._inflate[ke] = s), + this._inflate.write(e), + t && this._inflate.write(Ee), + this._inflate.flush(() => { + const e = this._inflate[Oe]; + if (e) return this._inflate.close(), (this._inflate = null), void s(e); + const i = ge.concat(this._inflate[xe], this._inflate[Se]); + this._inflate._readableState.endEmitted + ? (this._inflate.close(), (this._inflate = null)) + : ((this._inflate[Se] = 0), + (this._inflate[xe] = []), + t && + this.params[`${r}_no_context_takeover`] && + this._inflate.reset()), + s(null, i); + }); + } + _compress(e, t, s) { + const r = this._isServer ? "server" : "client"; + if (!this._deflate) { + const e = `${r}_max_window_bits`, + t = + "number" != typeof this.params[e] + ? me.Z_DEFAULT_WINDOWBITS + : this.params[e]; + (this._deflate = me.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits: t, + })), + (this._deflate[Se] = 0), + (this._deflate[xe] = []), + this._deflate.on("data", Re); + } + (this._deflate[ke] = s), + this._deflate.write(e), + this._deflate.flush(me.Z_SYNC_FLUSH, () => { + if (!this._deflate) return; + let e = ge.concat(this._deflate[xe], this._deflate[Se]); + t && (e = e.slice(0, e.length - 4)), + (this._deflate[ke] = null), + (this._deflate[Se] = 0), + (this._deflate[xe] = []), + t && this.params[`${r}_no_context_takeover`] && this._deflate.reset(), + s(null, e); + }); + } +}; +function Re(e) { + this[xe].push(e), (this[Se] += e.length); +} +function Ce(e) { + (this[Se] += e.length), + this[we]._maxPayload < 1 || this[Se] <= this[we]._maxPayload + ? this[xe].push(e) + : ((this[Oe] = new RangeError("Max payload size exceeded")), + (this[Oe].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"), + (this[Oe][ve] = 1009), + this.removeListener("data", Ce), + this.reset()); +} +function Le(e) { + (this[we]._inflate = null), (e[ve] = 1007), this[ke](e); +} +var Ae = { exports: {} }; +const Be = [ + 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, +]; +function Pe(e) { + return ( + (e >= 1e3 && e <= 1014 && 1004 !== e && 1005 !== e && 1006 !== e) || + (e >= 3e3 && e <= 4999) + ); +} +function Ie(e) { + const t = e.length; + let s = 0; + for (; s < t; ) + if (0 == (128 & e[s])) s++; + else if (192 == (224 & e[s])) { + if (s + 1 === t || 128 != (192 & e[s + 1]) || 192 == (254 & e[s])) + return !1; + s += 2; + } else if (224 == (240 & e[s])) { + if ( + s + 2 >= t || + 128 != (192 & e[s + 1]) || + 128 != (192 & e[s + 2]) || + (224 === e[s] && 128 == (224 & e[s + 1])) || + (237 === e[s] && 160 == (224 & e[s + 1])) + ) + return !1; + s += 3; + } else { + if (240 != (248 & e[s])) return !1; + if ( + s + 3 >= t || + 128 != (192 & e[s + 1]) || + 128 != (192 & e[s + 2]) || + 128 != (192 & e[s + 3]) || + (240 === e[s] && 128 == (240 & e[s + 1])) || + (244 === e[s] && e[s + 1] > 143) || + e[s] > 244 + ) + return !1; + s += 4; + } + return !0; +} +try { + const e = require("utf-8-validate"); + Ae.exports = { + isValidStatusCode: Pe, + isValidUTF8: (t) => (t.length < 150 ? Ie(t) : e(t)), + tokenChars: Be, + }; +} catch (e) { + Ae.exports = { isValidStatusCode: Pe, isValidUTF8: Ie, tokenChars: Be }; +} +const { Writable: De } = g.default, + Ue = Ne, + { BINARY_TYPES: qe, EMPTY_BUFFER: je, kStatusCode: Fe, kWebSocket: Me } = ae, + { concat: We, toArrayBuffer: Ve, unmask: $e } = oe.exports, + { isValidStatusCode: Ge, isValidUTF8: He } = Ae.exports; +var ze = class extends De { + constructor(e = {}) { + super(), + (this._binaryType = e.binaryType || qe[0]), + (this._extensions = e.extensions || {}), + (this._isServer = !!e.isServer), + (this._maxPayload = 0 | e.maxPayload), + (this._skipUTF8Validation = !!e.skipUTF8Validation), + (this[Me] = void 0), + (this._bufferedBytes = 0), + (this._buffers = []), + (this._compressed = !1), + (this._payloadLength = 0), + (this._mask = void 0), + (this._fragmented = 0), + (this._masked = !1), + (this._fin = !1), + (this._opcode = 0), + (this._totalPayloadLength = 0), + (this._messageLength = 0), + (this._fragments = []), + (this._state = 0), + (this._loop = !1); + } + _write(e, t, s) { + if (8 === this._opcode && 0 == this._state) return s(); + (this._bufferedBytes += e.length), this._buffers.push(e), this.startLoop(s); + } + consume(e) { + if (((this._bufferedBytes -= e), e === this._buffers[0].length)) + return this._buffers.shift(); + if (e < this._buffers[0].length) { + const t = this._buffers[0]; + return (this._buffers[0] = t.slice(e)), t.slice(0, e); + } + const t = Buffer.allocUnsafe(e); + do { + const s = this._buffers[0], + r = t.length - e; + e >= s.length + ? t.set(this._buffers.shift(), r) + : (t.set(new Uint8Array(s.buffer, s.byteOffset, e), r), + (this._buffers[0] = s.slice(e))), + (e -= s.length); + } while (e > 0); + return t; + } + startLoop(e) { + let t; + this._loop = !0; + do { + switch (this._state) { + case 0: + t = this.getInfo(); + break; + case 1: + t = this.getPayloadLength16(); + break; + case 2: + t = this.getPayloadLength64(); + break; + case 3: + this.getMask(); + break; + case 4: + t = this.getData(e); + break; + default: + return void (this._loop = !1); + } + } while (this._loop); + e(t); + } + getInfo() { + if (this._bufferedBytes < 2) return void (this._loop = !1); + const e = this.consume(2); + if (0 != (48 & e[0])) + return ( + (this._loop = !1), + Ye( + RangeError, + "RSV2 and RSV3 must be clear", + !0, + 1002, + "WS_ERR_UNEXPECTED_RSV_2_3" + ) + ); + const t = 64 == (64 & e[0]); + if (t && !this._extensions[Ue.extensionName]) + return ( + (this._loop = !1), + Ye( + RangeError, + "RSV1 must be clear", + !0, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ) + ); + if ( + ((this._fin = 128 == (128 & e[0])), + (this._opcode = 15 & e[0]), + (this._payloadLength = 127 & e[1]), + 0 === this._opcode) + ) { + if (t) + return ( + (this._loop = !1), + Ye( + RangeError, + "RSV1 must be clear", + !0, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ) + ); + if (!this._fragmented) + return ( + (this._loop = !1), + Ye(RangeError, "invalid opcode 0", !0, 1002, "WS_ERR_INVALID_OPCODE") + ); + this._opcode = this._fragmented; + } else if (1 === this._opcode || 2 === this._opcode) { + if (this._fragmented) + return ( + (this._loop = !1), + Ye( + RangeError, + `invalid opcode ${this._opcode}`, + !0, + 1002, + "WS_ERR_INVALID_OPCODE" + ) + ); + this._compressed = t; + } else { + if (!(this._opcode > 7 && this._opcode < 11)) + return ( + (this._loop = !1), + Ye( + RangeError, + `invalid opcode ${this._opcode}`, + !0, + 1002, + "WS_ERR_INVALID_OPCODE" + ) + ); + if (!this._fin) + return ( + (this._loop = !1), + Ye(RangeError, "FIN must be set", !0, 1002, "WS_ERR_EXPECTED_FIN") + ); + if (t) + return ( + (this._loop = !1), + Ye( + RangeError, + "RSV1 must be clear", + !0, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ) + ); + if (this._payloadLength > 125) + return ( + (this._loop = !1), + Ye( + RangeError, + `invalid payload length ${this._payloadLength}`, + !0, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ) + ); + } + if ( + (this._fin || this._fragmented || (this._fragmented = this._opcode), + (this._masked = 128 == (128 & e[1])), + this._isServer) + ) { + if (!this._masked) + return ( + (this._loop = !1), + Ye(RangeError, "MASK must be set", !0, 1002, "WS_ERR_EXPECTED_MASK") + ); + } else if (this._masked) + return ( + (this._loop = !1), + Ye(RangeError, "MASK must be clear", !0, 1002, "WS_ERR_UNEXPECTED_MASK") + ); + if (126 === this._payloadLength) this._state = 1; + else { + if (127 !== this._payloadLength) return this.haveLength(); + this._state = 2; + } + } + getPayloadLength16() { + if (!(this._bufferedBytes < 2)) + return ( + (this._payloadLength = this.consume(2).readUInt16BE(0)), + this.haveLength() + ); + this._loop = !1; + } + getPayloadLength64() { + if (this._bufferedBytes < 8) return void (this._loop = !1); + const e = this.consume(8), + t = e.readUInt32BE(0); + return t > Math.pow(2, 21) - 1 + ? ((this._loop = !1), + Ye( + RangeError, + "Unsupported WebSocket frame: payload length > 2^53 - 1", + !1, + 1009, + "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" + )) + : ((this._payloadLength = t * Math.pow(2, 32) + e.readUInt32BE(4)), + this.haveLength()); + } + haveLength() { + if ( + this._payloadLength && + this._opcode < 8 && + ((this._totalPayloadLength += this._payloadLength), + this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) + ) + return ( + (this._loop = !1), + Ye( + RangeError, + "Max payload size exceeded", + !1, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ) + ); + this._masked ? (this._state = 3) : (this._state = 4); + } + getMask() { + this._bufferedBytes < 4 + ? (this._loop = !1) + : ((this._mask = this.consume(4)), (this._state = 4)); + } + getData(e) { + let t = je; + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) + return void (this._loop = !1); + (t = this.consume(this._payloadLength)), + this._masked && $e(t, this._mask); + } + return this._opcode > 7 + ? this.controlMessage(t) + : this._compressed + ? ((this._state = 5), void this.decompress(t, e)) + : (t.length && + ((this._messageLength = this._totalPayloadLength), + this._fragments.push(t)), + this.dataMessage()); + } + decompress(e, t) { + this._extensions[Ue.extensionName].decompress(e, this._fin, (e, s) => { + if (e) return t(e); + if (s.length) { + if ( + ((this._messageLength += s.length), + this._messageLength > this._maxPayload && this._maxPayload > 0) + ) + return t( + Ye( + RangeError, + "Max payload size exceeded", + !1, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ) + ); + this._fragments.push(s); + } + const r = this.dataMessage(); + if (r) return t(r); + this.startLoop(t); + }); + } + dataMessage() { + if (this._fin) { + const e = this._messageLength, + t = this._fragments; + if ( + ((this._totalPayloadLength = 0), + (this._messageLength = 0), + (this._fragmented = 0), + (this._fragments = []), + 2 === this._opcode) + ) { + let s; + (s = + "nodebuffer" === this._binaryType + ? We(t, e) + : "arraybuffer" === this._binaryType + ? Ve(We(t, e)) + : t), + this.emit("message", s, !0); + } else { + const s = We(t, e); + if (!this._skipUTF8Validation && !He(s)) + return ( + (this._loop = !1), + Ye(Error, "invalid UTF-8 sequence", !0, 1007, "WS_ERR_INVALID_UTF8") + ); + this.emit("message", s, !1); + } + } + this._state = 0; + } + controlMessage(e) { + if (8 === this._opcode) + if (((this._loop = !1), 0 === e.length)) + this.emit("conclude", 1005, je), this.end(); + else { + if (1 === e.length) + return Ye( + RangeError, + "invalid payload length 1", + !0, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ); + { + const t = e.readUInt16BE(0); + if (!Ge(t)) + return Ye( + RangeError, + `invalid status code ${t}`, + !0, + 1002, + "WS_ERR_INVALID_CLOSE_CODE" + ); + const s = e.slice(2); + if (!this._skipUTF8Validation && !He(s)) + return Ye( + Error, + "invalid UTF-8 sequence", + !0, + 1007, + "WS_ERR_INVALID_UTF8" + ); + this.emit("conclude", t, s), this.end(); + } + } + else 9 === this._opcode ? this.emit("ping", e) : this.emit("pong", e); + this._state = 0; + } +}; +function Ye(e, t, s, r, i) { + const n = new e(s ? `Invalid WebSocket frame: ${t}` : t); + return Error.captureStackTrace(n, Ye), (n.code = i), (n[Fe] = r), n; +} +const { randomFillSync: Ke } = w.default, + Xe = Ne, + { EMPTY_BUFFER: Je } = ae, + { isValidStatusCode: Qe } = Ae.exports, + { mask: Ze, toBuffer: et } = oe.exports, + tt = Buffer.alloc(4); +class st { + constructor(e, t) { + (this._extensions = t || {}), + (this._socket = e), + (this._firstFragment = !0), + (this._compress = !1), + (this._bufferedBytes = 0), + (this._deflating = !1), + (this._queue = []); + } + static frame(e, t) { + const s = t.mask && t.readOnly; + let r = t.mask ? 6 : 2, + i = e.length; + e.length >= 65536 + ? ((r += 8), (i = 127)) + : e.length > 125 && ((r += 2), (i = 126)); + const n = Buffer.allocUnsafe(s ? e.length + r : r); + return ( + (n[0] = t.fin ? 128 | t.opcode : t.opcode), + t.rsv1 && (n[0] |= 64), + (n[1] = i), + 126 === i + ? n.writeUInt16BE(e.length, 2) + : 127 === i && (n.writeUInt32BE(0, 2), n.writeUInt32BE(e.length, 6)), + t.mask + ? (Ke(tt, 0, 4), + (n[1] |= 128), + (n[r - 4] = tt[0]), + (n[r - 3] = tt[1]), + (n[r - 2] = tt[2]), + (n[r - 1] = tt[3]), + s + ? (Ze(e, tt, n, r, e.length), [n]) + : (Ze(e, tt, e, 0, e.length), [n, e])) + : [n, e] + ); + } + close(e, t, s, r) { + let i; + if (void 0 === e) i = Je; + else { + if ("number" != typeof e || !Qe(e)) + throw new TypeError("First argument must be a valid error code number"); + if (void 0 !== t && t.length) { + const s = Buffer.byteLength(t); + if (s > 123) + throw new RangeError( + "The message must not be greater than 123 bytes" + ); + (i = Buffer.allocUnsafe(2 + s)), + i.writeUInt16BE(e, 0), + "string" == typeof t ? i.write(t, 2) : i.set(t, 2); + } else (i = Buffer.allocUnsafe(2)), i.writeUInt16BE(e, 0); + } + this._deflating + ? this.enqueue([this.doClose, i, s, r]) + : this.doClose(i, s, r); + } + doClose(e, t, s) { + this.sendFrame( + st.frame(e, { fin: !0, rsv1: !1, opcode: 8, mask: t, readOnly: !1 }), + s + ); + } + ping(e, t, s) { + const r = et(e); + if (r.length > 125) + throw new RangeError("The data size must not be greater than 125 bytes"); + this._deflating + ? this.enqueue([this.doPing, r, t, et.readOnly, s]) + : this.doPing(r, t, et.readOnly, s); + } + doPing(e, t, s, r) { + this.sendFrame( + st.frame(e, { fin: !0, rsv1: !1, opcode: 9, mask: t, readOnly: s }), + r + ); + } + pong(e, t, s) { + const r = et(e); + if (r.length > 125) + throw new RangeError("The data size must not be greater than 125 bytes"); + this._deflating + ? this.enqueue([this.doPong, r, t, et.readOnly, s]) + : this.doPong(r, t, et.readOnly, s); + } + doPong(e, t, s, r) { + this.sendFrame( + st.frame(e, { fin: !0, rsv1: !1, opcode: 10, mask: t, readOnly: s }), + r + ); + } + send(e, t, s) { + const r = et(e), + i = this._extensions[Xe.extensionName]; + let n = t.binary ? 2 : 1, + o = t.compress; + if ( + (this._firstFragment + ? ((this._firstFragment = !1), + o && + i && + i.params[ + i._isServer + ? "server_no_context_takeover" + : "client_no_context_takeover" + ] && + (o = r.length >= i._threshold), + (this._compress = o)) + : ((o = !1), (n = 0)), + t.fin && (this._firstFragment = !0), + i) + ) { + const e = { + fin: t.fin, + rsv1: o, + opcode: n, + mask: t.mask, + readOnly: et.readOnly, + }; + this._deflating + ? this.enqueue([this.dispatch, r, this._compress, e, s]) + : this.dispatch(r, this._compress, e, s); + } else + this.sendFrame( + st.frame(r, { + fin: t.fin, + rsv1: !1, + opcode: n, + mask: t.mask, + readOnly: et.readOnly, + }), + s + ); + } + dispatch(e, t, s, r) { + if (!t) return void this.sendFrame(st.frame(e, s), r); + const i = this._extensions[Xe.extensionName]; + (this._bufferedBytes += e.length), + (this._deflating = !0), + i.compress(e, s.fin, (t, i) => { + if (this._socket.destroyed) { + const e = new Error( + "The socket was closed while data was being compressed" + ); + "function" == typeof r && r(e); + for (let t = 0; t < this._queue.length; t++) { + const s = this._queue[t][4]; + "function" == typeof s && s(e); + } + } else + (this._bufferedBytes -= e.length), + (this._deflating = !1), + (s.readOnly = !1), + this.sendFrame(st.frame(i, s), r), + this.dequeue(); + }); + } + dequeue() { + for (; !this._deflating && this._queue.length; ) { + const e = this._queue.shift(); + (this._bufferedBytes -= e[1].length), + Reflect.apply(e[0], this, e.slice(1)); + } + } + enqueue(e) { + (this._bufferedBytes += e[1].length), this._queue.push(e); + } + sendFrame(e, t) { + 2 === e.length + ? (this._socket.cork(), + this._socket.write(e[0]), + this._socket.write(e[1], t), + this._socket.uncork()) + : this._socket.write(e[0], t); + } +} +var rt = st; +const { kForOnEventAttribute: it, kListener: nt } = ae, + ot = Symbol("kCode"), + at = Symbol("kData"), + ht = Symbol("kError"), + ct = Symbol("kMessage"), + lt = Symbol("kReason"), + dt = Symbol("kTarget"), + ut = Symbol("kType"), + pt = Symbol("kWasClean"); +class ft { + constructor(e) { + (this[dt] = null), (this[ut] = e); + } + get target() { + return this[dt]; + } + get type() { + return this[ut]; + } +} +Object.defineProperty(ft.prototype, "target", { enumerable: !0 }), + Object.defineProperty(ft.prototype, "type", { enumerable: !0 }); +class _t extends ft { + constructor(e, t = {}) { + super(e), + (this[ot] = void 0 === t.code ? 0 : t.code), + (this[lt] = void 0 === t.reason ? "" : t.reason), + (this[pt] = void 0 !== t.wasClean && t.wasClean); + } + get code() { + return this[ot]; + } + get reason() { + return this[lt]; + } + get wasClean() { + return this[pt]; + } +} +Object.defineProperty(_t.prototype, "code", { enumerable: !0 }), + Object.defineProperty(_t.prototype, "reason", { enumerable: !0 }), + Object.defineProperty(_t.prototype, "wasClean", { enumerable: !0 }); +class yt extends ft { + constructor(e, t = {}) { + super(e), + (this[ht] = void 0 === t.error ? null : t.error), + (this[ct] = void 0 === t.message ? "" : t.message); + } + get error() { + return this[ht]; + } + get message() { + return this[ct]; + } +} +Object.defineProperty(yt.prototype, "error", { enumerable: !0 }), + Object.defineProperty(yt.prototype, "message", { enumerable: !0 }); +class mt extends ft { + constructor(e, t = {}) { + super(e), (this[at] = void 0 === t.data ? null : t.data); + } + get data() { + return this[at]; + } +} +Object.defineProperty(mt.prototype, "data", { enumerable: !0 }); +const gt = { + addEventListener(e, t, s = {}) { + let r; + if ("message" === e) + r = function (e, s) { + const r = new mt("message", { data: s ? e : e.toString() }); + (r[dt] = this), t.call(this, r); + }; + else if ("close" === e) + r = function (e, s) { + const r = new _t("close", { + code: e, + reason: s.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent, + }); + (r[dt] = this), t.call(this, r); + }; + else if ("error" === e) + r = function (e) { + const s = new yt("error", { error: e, message: e.message }); + (s[dt] = this), t.call(this, s); + }; + else { + if ("open" !== e) return; + r = function () { + const e = new ft("open"); + (e[dt] = this), t.call(this, e); + }; + } + (r[it] = !!s[it]), (r[nt] = t), s.once ? this.once(e, r) : this.on(e, r); + }, + removeEventListener(e, t) { + for (const s of this.listeners(e)) + if (s[nt] === t && !s[it]) { + this.removeListener(e, s); + break; + } + }, +}; +var bt = { + CloseEvent: _t, + ErrorEvent: yt, + Event: ft, + EventTarget: gt, + MessageEvent: mt, +}; +const { tokenChars: vt } = Ae.exports; +function Et(e, t, s) { + void 0 === e[t] ? (e[t] = [s]) : e[t].push(s); +} +var wt = { + format: function (e) { + return Object.keys(e) + .map((t) => { + let s = e[t]; + return ( + Array.isArray(s) || (s = [s]), + s + .map((e) => + [t] + .concat( + Object.keys(e).map((t) => { + let s = e[t]; + return ( + Array.isArray(s) || (s = [s]), + s.map((e) => (!0 === e ? t : `${t}=${e}`)).join("; ") + ); + }) + ) + .join("; ") + ) + .join(", ") + ); + }) + .join(", "); + }, + parse: function (e) { + const t = Object.create(null); + let s, + r, + i = Object.create(null), + n = !1, + o = !1, + a = !1, + h = -1, + c = -1, + l = -1, + d = 0; + for (; d < e.length; d++) + if (((c = e.charCodeAt(d)), void 0 === s)) + if (-1 === l && 1 === vt[c]) -1 === h && (h = d); + else if (0 === d || (32 !== c && 9 !== c)) { + if (59 !== c && 44 !== c) + throw new SyntaxError(`Unexpected character at index ${d}`); + { + if (-1 === h) + throw new SyntaxError(`Unexpected character at index ${d}`); + -1 === l && (l = d); + const r = e.slice(h, l); + 44 === c ? (Et(t, r, i), (i = Object.create(null))) : (s = r), + (h = l = -1); + } + } else -1 === l && -1 !== h && (l = d); + else if (void 0 === r) + if (-1 === l && 1 === vt[c]) -1 === h && (h = d); + else if (32 === c || 9 === c) -1 === l && -1 !== h && (l = d); + else if (59 === c || 44 === c) { + if (-1 === h) + throw new SyntaxError(`Unexpected character at index ${d}`); + -1 === l && (l = d), + Et(i, e.slice(h, l), !0), + 44 === c && (Et(t, s, i), (i = Object.create(null)), (s = void 0)), + (h = l = -1); + } else { + if (61 !== c || -1 === h || -1 !== l) + throw new SyntaxError(`Unexpected character at index ${d}`); + (r = e.slice(h, d)), (h = l = -1); + } + else if (o) { + if (1 !== vt[c]) + throw new SyntaxError(`Unexpected character at index ${d}`); + -1 === h ? (h = d) : n || (n = !0), (o = !1); + } else if (a) + if (1 === vt[c]) -1 === h && (h = d); + else if (34 === c && -1 !== h) (a = !1), (l = d); + else { + if (92 !== c) + throw new SyntaxError(`Unexpected character at index ${d}`); + o = !0; + } + else if (34 === c && 61 === e.charCodeAt(d - 1)) a = !0; + else if (-1 === l && 1 === vt[c]) -1 === h && (h = d); + else if (-1 === h || (32 !== c && 9 !== c)) { + if (59 !== c && 44 !== c) + throw new SyntaxError(`Unexpected character at index ${d}`); + { + if (-1 === h) + throw new SyntaxError(`Unexpected character at index ${d}`); + -1 === l && (l = d); + let o = e.slice(h, l); + n && ((o = o.replace(/\\/g, "")), (n = !1)), + Et(i, r, o), + 44 === c && (Et(t, s, i), (i = Object.create(null)), (s = void 0)), + (r = void 0), + (h = l = -1); + } + } else -1 === l && (l = d); + if (-1 === h || a || 32 === c || 9 === c) + throw new SyntaxError("Unexpected end of input"); + -1 === l && (l = d); + const u = e.slice(h, l); + return ( + void 0 === s + ? Et(t, u, i) + : (void 0 === r ? Et(i, u, !0) : Et(i, r, n ? u.replace(/\\/g, "") : u), + Et(t, s, i)), + t + ); + }, +}; +const St = S.default, + kt = m.default, + xt = y.default, + Ot = v.default, + Tt = E.default, + { randomBytes: Nt, createHash: Rt } = w.default, + { URL: Ct } = f.default, + Lt = Ne, + At = ze, + Bt = rt, + { + BINARY_TYPES: Pt, + EMPTY_BUFFER: It, + GUID: Dt, + kForOnEventAttribute: Ut, + kListener: qt, + kStatusCode: jt, + kWebSocket: Ft, + NOOP: Mt, + } = ae, + { + EventTarget: { addEventListener: Wt, removeEventListener: Vt }, + } = bt, + { format: $t, parse: Gt } = wt, + { toBuffer: Ht } = oe.exports, + zt = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"], + Yt = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/, + Kt = [8, 13]; +class Xt extends St { + constructor(e, t, s) { + super(), + (this._binaryType = Pt[0]), + (this._closeCode = 1006), + (this._closeFrameReceived = !1), + (this._closeFrameSent = !1), + (this._closeMessage = It), + (this._closeTimer = null), + (this._extensions = {}), + (this._protocol = ""), + (this._readyState = Xt.CONNECTING), + (this._receiver = null), + (this._sender = null), + (this._socket = null), + null !== e + ? ((this._bufferedAmount = 0), + (this._isServer = !1), + (this._redirects = 0), + void 0 === t + ? (t = []) + : Array.isArray(t) || + ("object" == typeof t && null !== t + ? ((s = t), (t = [])) + : (t = [t])), + Jt(this, e, t, s)) + : (this._isServer = !0); + } + get binaryType() { + return this._binaryType; + } + set binaryType(e) { + Pt.includes(e) && + ((this._binaryType = e), + this._receiver && (this._receiver._binaryType = e)); + } + get bufferedAmount() { + return this._socket + ? this._socket._writableState.length + this._sender._bufferedBytes + : this._bufferedAmount; + } + get extensions() { + return Object.keys(this._extensions).join(); + } + get onclose() { + return null; + } + get onerror() { + return null; + } + get onopen() { + return null; + } + get onmessage() { + return null; + } + get protocol() { + return this._protocol; + } + get readyState() { + return this._readyState; + } + get url() { + return this._url; + } + setSocket(e, t, s) { + const r = new At({ + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxPayload: s.maxPayload, + skipUTF8Validation: s.skipUTF8Validation, + }); + (this._sender = new Bt(e, this._extensions)), + (this._receiver = r), + (this._socket = e), + (r[Ft] = this), + (e[Ft] = this), + r.on("conclude", ss), + r.on("drain", rs), + r.on("error", is), + r.on("message", os), + r.on("ping", as), + r.on("pong", hs), + e.setTimeout(0), + e.setNoDelay(), + t.length > 0 && e.unshift(t), + e.on("close", ls), + e.on("data", ds), + e.on("end", us), + e.on("error", ps), + (this._readyState = Xt.OPEN), + this.emit("open"); + } + emitClose() { + if (!this._socket) + return ( + (this._readyState = Xt.CLOSED), + void this.emit("close", this._closeCode, this._closeMessage) + ); + this._extensions[Lt.extensionName] && + this._extensions[Lt.extensionName].cleanup(), + this._receiver.removeAllListeners(), + (this._readyState = Xt.CLOSED), + this.emit("close", this._closeCode, this._closeMessage); + } + close(e, t) { + if (this.readyState !== Xt.CLOSED) { + if (this.readyState === Xt.CONNECTING) { + const e = "WebSocket was closed before the connection was established"; + return es(this, this._req, e); + } + this.readyState !== Xt.CLOSING + ? ((this._readyState = Xt.CLOSING), + this._sender.close(e, t, !this._isServer, (e) => { + e || + ((this._closeFrameSent = !0), + (this._closeFrameReceived || + this._receiver._writableState.errorEmitted) && + this._socket.end()); + }), + (this._closeTimer = setTimeout( + this._socket.destroy.bind(this._socket), + 3e4 + ))) + : this._closeFrameSent && + (this._closeFrameReceived || + this._receiver._writableState.errorEmitted) && + this._socket.end(); + } + } + ping(e, t, s) { + if (this.readyState === Xt.CONNECTING) + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + "function" == typeof e + ? ((s = e), (e = t = void 0)) + : "function" == typeof t && ((s = t), (t = void 0)), + "number" == typeof e && (e = e.toString()), + this.readyState === Xt.OPEN + ? (void 0 === t && (t = !this._isServer), + this._sender.ping(e || It, t, s)) + : ts(this, e, s); + } + pong(e, t, s) { + if (this.readyState === Xt.CONNECTING) + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + "function" == typeof e + ? ((s = e), (e = t = void 0)) + : "function" == typeof t && ((s = t), (t = void 0)), + "number" == typeof e && (e = e.toString()), + this.readyState === Xt.OPEN + ? (void 0 === t && (t = !this._isServer), + this._sender.pong(e || It, t, s)) + : ts(this, e, s); + } + send(e, t, s) { + if (this.readyState === Xt.CONNECTING) + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + if ( + ("function" == typeof t && ((s = t), (t = {})), + "number" == typeof e && (e = e.toString()), + this.readyState !== Xt.OPEN) + ) + return void ts(this, e, s); + const r = { + binary: "string" != typeof e, + mask: !this._isServer, + compress: !0, + fin: !0, + ...t, + }; + this._extensions[Lt.extensionName] || (r.compress = !1), + this._sender.send(e || It, r, s); + } + terminate() { + if (this.readyState !== Xt.CLOSED) { + if (this.readyState === Xt.CONNECTING) { + const e = "WebSocket was closed before the connection was established"; + return es(this, this._req, e); + } + this._socket && ((this._readyState = Xt.CLOSING), this._socket.destroy()); + } + } +} +function Jt(e, t, s, r) { + const i = { + protocolVersion: Kt[1], + maxPayload: 104857600, + skipUTF8Validation: !1, + perMessageDeflate: !0, + followRedirects: !1, + maxRedirects: 10, + ...r, + createConnection: void 0, + socketPath: void 0, + hostname: void 0, + protocol: void 0, + timeout: void 0, + method: void 0, + host: void 0, + path: void 0, + port: void 0, + }; + if (!Kt.includes(i.protocolVersion)) + throw new RangeError( + `Unsupported protocol version: ${ + i.protocolVersion + } (supported versions: ${Kt.join(", ")})` + ); + let n; + if (t instanceof Ct) (n = t), (e._url = t.href); + else { + try { + n = new Ct(t); + } catch (e) { + throw new SyntaxError(`Invalid URL: ${t}`); + } + e._url = t; + } + const o = "wss:" === n.protocol, + a = "ws+unix:" === n.protocol; + if ("ws:" !== n.protocol && !o && !a) + throw new SyntaxError( + 'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"' + ); + if (a && !n.pathname) throw new SyntaxError("The URL's pathname is empty"); + if (n.hash) throw new SyntaxError("The URL contains a fragment identifier"); + const h = o ? 443 : 80, + c = Nt(16).toString("base64"), + l = o ? kt.get : xt.get, + d = new Set(); + let u; + if ( + ((i.createConnection = o ? Zt : Qt), + (i.defaultPort = i.defaultPort || h), + (i.port = n.port || h), + (i.host = n.hostname.startsWith("[") + ? n.hostname.slice(1, -1) + : n.hostname), + (i.headers = { + "Sec-WebSocket-Version": i.protocolVersion, + "Sec-WebSocket-Key": c, + Connection: "Upgrade", + Upgrade: "websocket", + ...i.headers, + }), + (i.path = n.pathname + n.search), + (i.timeout = i.handshakeTimeout), + i.perMessageDeflate && + ((u = new Lt( + !0 !== i.perMessageDeflate ? i.perMessageDeflate : {}, + !1, + i.maxPayload + )), + (i.headers["Sec-WebSocket-Extensions"] = $t({ + [Lt.extensionName]: u.offer(), + }))), + s.length) + ) { + for (const e of s) { + if ("string" != typeof e || !Yt.test(e) || d.has(e)) + throw new SyntaxError( + "An invalid or duplicated subprotocol was specified" + ); + d.add(e); + } + i.headers["Sec-WebSocket-Protocol"] = s.join(","); + } + if ( + (i.origin && + (i.protocolVersion < 13 + ? (i.headers["Sec-WebSocket-Origin"] = i.origin) + : (i.headers.Origin = i.origin)), + (n.username || n.password) && (i.auth = `${n.username}:${n.password}`), + a) + ) { + const e = i.path.split(":"); + (i.socketPath = e[0]), (i.path = e[1]); + } + let p = (e._req = l(i)); + i.timeout && + p.on("timeout", () => { + es(e, p, "Opening handshake has timed out"); + }), + p.on("error", (t) => { + null === p || + p.aborted || + ((p = e._req = null), + (e._readyState = Xt.CLOSING), + e.emit("error", t), + e.emitClose()); + }), + p.on("response", (n) => { + const o = n.headers.location, + a = n.statusCode; + if (o && i.followRedirects && a >= 300 && a < 400) { + if (++e._redirects > i.maxRedirects) + return void es(e, p, "Maximum redirects exceeded"); + p.abort(); + const n = new Ct(o, t); + Jt(e, n, s, r); + } else + e.emit("unexpected-response", p, n) || + es(e, p, `Unexpected server response: ${n.statusCode}`); + }), + p.on("upgrade", (t, s, r) => { + if ((e.emit("upgrade", t), e.readyState !== Xt.CONNECTING)) return; + p = e._req = null; + const n = Rt("sha1") + .update(c + Dt) + .digest("base64"); + if (t.headers["sec-websocket-accept"] !== n) + return void es(e, s, "Invalid Sec-WebSocket-Accept header"); + const o = t.headers["sec-websocket-protocol"]; + let a; + if ( + (void 0 !== o + ? d.size + ? d.has(o) || (a = "Server sent an invalid subprotocol") + : (a = "Server sent a subprotocol but none was requested") + : d.size && (a = "Server sent no subprotocol"), + a) + ) + return void es(e, s, a); + o && (e._protocol = o); + const h = t.headers["sec-websocket-extensions"]; + if (void 0 !== h) { + if (!u) { + return void es( + e, + s, + "Server sent a Sec-WebSocket-Extensions header but no extension was requested" + ); + } + let t; + try { + t = Gt(h); + } catch (t) { + return void es(e, s, "Invalid Sec-WebSocket-Extensions header"); + } + const r = Object.keys(t); + if (1 !== r.length || r[0] !== Lt.extensionName) { + return void es( + e, + s, + "Server indicated an extension that was not requested" + ); + } + try { + u.accept(t[Lt.extensionName]); + } catch (t) { + return void es(e, s, "Invalid Sec-WebSocket-Extensions header"); + } + e._extensions[Lt.extensionName] = u; + } + e.setSocket(s, r, { + maxPayload: i.maxPayload, + skipUTF8Validation: i.skipUTF8Validation, + }); + }); +} +function Qt(e) { + return (e.path = e.socketPath), Ot.connect(e); +} +function Zt(e) { + return ( + (e.path = void 0), + e.servername || + "" === e.servername || + (e.servername = Ot.isIP(e.host) ? "" : e.host), + Tt.connect(e) + ); +} +function es(e, t, s) { + e._readyState = Xt.CLOSING; + const r = new Error(s); + Error.captureStackTrace(r, es), + t.setHeader + ? (t.abort(), + t.socket && !t.socket.destroyed && t.socket.destroy(), + t.once("abort", e.emitClose.bind(e)), + e.emit("error", r)) + : (t.destroy(r), + t.once("error", e.emit.bind(e, "error")), + t.once("close", e.emitClose.bind(e))); +} +function ts(e, t, s) { + if (t) { + const s = Ht(t).length; + e._socket ? (e._sender._bufferedBytes += s) : (e._bufferedAmount += s); + } + if (s) { + s( + new Error( + `WebSocket is not open: readyState ${e.readyState} (${ + zt[e.readyState] + })` + ) + ); + } +} +function ss(e, t) { + const s = this[Ft]; + (s._closeFrameReceived = !0), + (s._closeMessage = t), + (s._closeCode = e), + void 0 !== s._socket[Ft] && + (s._socket.removeListener("data", ds), + process.nextTick(cs, s._socket), + 1005 === e ? s.close() : s.close(e, t)); +} +function rs() { + this[Ft]._socket.resume(); +} +function is(e) { + const t = this[Ft]; + void 0 !== t._socket[Ft] && + (t._socket.removeListener("data", ds), + process.nextTick(cs, t._socket), + t.close(e[jt])), + t.emit("error", e); +} +function ns() { + this[Ft].emitClose(); +} +function os(e, t) { + this[Ft].emit("message", e, t); +} +function as(e) { + const t = this[Ft]; + t.pong(e, !t._isServer, Mt), t.emit("ping", e); +} +function hs(e) { + this[Ft].emit("pong", e); +} +function cs(e) { + e.resume(); +} +function ls() { + const e = this[Ft]; + let t; + this.removeListener("close", ls), + this.removeListener("data", ds), + this.removeListener("end", us), + (e._readyState = Xt.CLOSING), + this._readableState.endEmitted || + e._closeFrameReceived || + e._receiver._writableState.errorEmitted || + null === (t = e._socket.read()) || + e._receiver.write(t), + e._receiver.end(), + (this[Ft] = void 0), + clearTimeout(e._closeTimer), + e._receiver._writableState.finished || + e._receiver._writableState.errorEmitted + ? e.emitClose() + : (e._receiver.on("error", ns), e._receiver.on("finish", ns)); +} +function ds(e) { + this[Ft]._receiver.write(e) || this.pause(); +} +function us() { + const e = this[Ft]; + (e._readyState = Xt.CLOSING), e._receiver.end(), this.end(); +} +function ps() { + const e = this[Ft]; + this.removeListener("error", ps), + this.on("error", Mt), + e && ((e._readyState = Xt.CLOSING), this.destroy()); +} +Object.defineProperty(Xt, "CONNECTING", { + enumerable: !0, + value: zt.indexOf("CONNECTING"), +}), + Object.defineProperty(Xt.prototype, "CONNECTING", { + enumerable: !0, + value: zt.indexOf("CONNECTING"), + }), + Object.defineProperty(Xt, "OPEN", { + enumerable: !0, + value: zt.indexOf("OPEN"), + }), + Object.defineProperty(Xt.prototype, "OPEN", { + enumerable: !0, + value: zt.indexOf("OPEN"), + }), + Object.defineProperty(Xt, "CLOSING", { + enumerable: !0, + value: zt.indexOf("CLOSING"), + }), + Object.defineProperty(Xt.prototype, "CLOSING", { + enumerable: !0, + value: zt.indexOf("CLOSING"), + }), + Object.defineProperty(Xt, "CLOSED", { + enumerable: !0, + value: zt.indexOf("CLOSED"), + }), + Object.defineProperty(Xt.prototype, "CLOSED", { + enumerable: !0, + value: zt.indexOf("CLOSED"), + }), + [ + "binaryType", + "bufferedAmount", + "extensions", + "protocol", + "readyState", + "url", + ].forEach((e) => { + Object.defineProperty(Xt.prototype, e, { enumerable: !0 }); + }), + ["open", "error", "close", "message"].forEach((e) => { + Object.defineProperty(Xt.prototype, `on${e}`, { + enumerable: !0, + get() { + for (const t of this.listeners(e)) if (t[Ut]) return t[qt]; + return null; + }, + set(t) { + for (const t of this.listeners(e)) + if (t[Ut]) { + this.removeListener(e, t); + break; + } + "function" == typeof t && this.addEventListener(e, t, { [Ut]: !0 }); + }, + }); + }), + (Xt.prototype.addEventListener = Wt), + (Xt.prototype.removeEventListener = Vt); +const fs = Xt, + _s = process.nextTick, + ys = + "undefined" != typeof navigator && + "string" == typeof navigator.product && + "reactnative" === navigator.product.toLowerCase(); +const ms = { + websocket: class extends M { + constructor(e) { + super(e), (this.supportsBinary = !e.forceBase64); + } + get name() { + return "websocket"; + } + doOpen() { + if (!this.check()) return; + const e = this.uri(), + t = this.opts.protocols, + s = ys + ? {} + : D( + this.opts, + "agent", + "perMessageDeflate", + "pfx", + "key", + "passphrase", + "cert", + "ca", + "ciphers", + "rejectUnauthorized", + "localAddress", + "protocolVersion", + "origin", + "maxPayload", + "family", + "checkServerIdentity" + ); + this.opts.extraHeaders && (s.headers = this.opts.extraHeaders); + try { + this.ws = new fs(e, t, s); + } catch (e) { + return this.emitReserved("error", e); + } + (this.ws.binaryType = this.socket.binaryType || "nodebuffer"), + this.addEventListeners(); + } + addEventListeners() { + (this.ws.onopen = () => { + this.opts.autoUnref && this.ws._socket.unref(), this.onOpen(); + }), + (this.ws.onclose = (e) => + this.onClose({ + description: "websocket connection closed", + context: e, + })), + (this.ws.onmessage = (e) => this.onData(e.data)), + (this.ws.onerror = (e) => this.onError("websocket error", e)); + } + write(e) { + this.writable = !1; + for (let t = 0; t < e.length; t++) { + const s = e[t], + r = t === e.length - 1; + T(s, this.supportsBinary, (e) => { + const t = {}; + if ( + (s.options && (t.compress = s.options.compress), + this.opts.perMessageDeflate) + ) { + ("string" == typeof e ? Buffer.byteLength(e) : e.length) < + this.opts.perMessageDeflate.threshold && (t.compress = !1); + } + try { + this.ws.send(e, t); + } catch (e) {} + r && + _s(() => { + (this.writable = !0), this.emitReserved("drain"); + }, this.setTimeoutFn); + }); + } + } + doClose() { + void 0 !== this.ws && (this.ws.close(), (this.ws = null)); + } + uri() { + let e = this.query || {}; + const t = this.opts.secure ? "wss" : "ws"; + let s = ""; + this.opts.port && + (("wss" === t && 443 !== Number(this.opts.port)) || + ("ws" === t && 80 !== Number(this.opts.port))) && + (s = ":" + this.opts.port), + this.opts.timestampRequests && (e[this.opts.timestampParam] = Y()), + this.supportsBinary || (e.b64 = 1); + const r = K(e); + return ( + t + + "://" + + (-1 !== this.opts.hostname.indexOf(":") + ? "[" + this.opts.hostname + "]" + : this.opts.hostname) + + s + + this.opts.path + + (r.length ? "?" + r : "") + ); + } + check() { + return !!fs; + } + }, + polling: class extends M { + constructor(e) { + if ((super(e), (this.polling = !1), "undefined" != typeof location)) { + const t = "https:" === location.protocol; + let s = location.port; + s || (s = t ? "443" : "80"), + (this.xd = + ("undefined" != typeof location && + e.hostname !== location.hostname) || + s !== e.port), + (this.xs = e.secure !== t); + } + const t = e && e.forceBase64; + this.supportsBinary = re && !t; + } + get name() { + return "polling"; + } + doOpen() { + this.poll(); + } + pause(e) { + this.readyState = "pausing"; + const t = () => { + (this.readyState = "paused"), e(); + }; + if (this.polling || !this.writable) { + let e = 0; + this.polling && + (e++, + this.once("pollComplete", function () { + --e || t(); + })), + this.writable || + (e++, + this.once("drain", function () { + --e || t(); + })); + } else t(); + } + poll() { + (this.polling = !0), this.doPoll(), this.emitReserved("poll"); + } + onData(e) { + ((e, t) => { + const s = e.split(B), + r = []; + for (let e = 0; e < s.length; e++) { + const i = C(s[e], t); + if ((r.push(i), "error" === i.type)) break; + } + return r; + })(e, this.socket.binaryType).forEach((e) => { + if ( + ("opening" === this.readyState && + "open" === e.type && + this.onOpen(), + "close" === e.type) + ) + return ( + this.onClose({ description: "transport closed by the server" }), + !1 + ); + this.onPacket(e); + }), + "closed" !== this.readyState && + ((this.polling = !1), + this.emitReserved("pollComplete"), + "open" === this.readyState && this.poll()); + } + doClose() { + const e = () => { + this.write([{ type: "close" }]); + }; + "open" === this.readyState ? e() : this.once("open", e); + } + write(e) { + (this.writable = !1), + ((e, t) => { + const s = e.length, + r = new Array(s); + let i = 0; + e.forEach((e, n) => { + T(e, !1, (e) => { + (r[n] = e), ++i === s && t(r.join(B)); + }); + }); + })(e, (e) => { + this.doWrite(e, () => { + (this.writable = !0), this.emitReserved("drain"); + }); + }); + } + uri() { + let e = this.query || {}; + const t = this.opts.secure ? "https" : "http"; + let s = ""; + !1 !== this.opts.timestampRequests && + (e[this.opts.timestampParam] = Y()), + this.supportsBinary || e.sid || (e.b64 = 1), + this.opts.port && + (("https" === t && 443 !== Number(this.opts.port)) || + ("http" === t && 80 !== Number(this.opts.port))) && + (s = ":" + this.opts.port); + const r = K(e); + return ( + t + + "://" + + (-1 !== this.opts.hostname.indexOf(":") + ? "[" + this.opts.hostname + "]" + : this.opts.hostname) + + s + + this.opts.path + + (r.length ? "?" + r : "") + ); + } + request(e = {}) { + return ( + Object.assign(e, { xd: this.xd, xs: this.xs }, this.opts), + new ie(this.uri(), e) + ); + } + doWrite(e, t) { + const s = this.request({ method: "POST", data: e }); + s.on("success", t), + s.on("error", (e, t) => { + this.onError("xhr post error", e, t); + }); + } + doPoll() { + const e = this.request(); + e.on("data", this.onData.bind(this)), + e.on("error", (e, t) => { + this.onError("xhr poll error", e, t); + }), + (this.pollXhr = e); + } + }, + }, + gs = + /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/, + bs = [ + "source", + "protocol", + "authority", + "userInfo", + "user", + "password", + "host", + "port", + "relative", + "path", + "directory", + "file", + "query", + "anchor", + ]; +function vs(e) { + const t = e, + s = e.indexOf("["), + r = e.indexOf("]"); + -1 != s && + -1 != r && + (e = + e.substring(0, s) + + e.substring(s, r).replace(/:/g, ";") + + e.substring(r, e.length)); + let i = gs.exec(e || ""), + n = {}, + o = 14; + for (; o--; ) n[bs[o]] = i[o] || ""; + return ( + -1 != s && + -1 != r && + ((n.source = t), + (n.host = n.host.substring(1, n.host.length - 1).replace(/;/g, ":")), + (n.authority = n.authority + .replace("[", "") + .replace("]", "") + .replace(/;/g, ":")), + (n.ipv6uri = !0)), + (n.pathNames = (function (e, t) { + const s = /\/{2,9}/g, + r = t.replace(s, "/").split("/"); + ("/" != t.substr(0, 1) && 0 !== t.length) || r.splice(0, 1); + "/" == t.substr(t.length - 1, 1) && r.splice(r.length - 1, 1); + return r; + })(0, n.path)), + (n.queryKey = (function (e, t) { + const s = {}; + return ( + t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function (e, t, r) { + t && (s[t] = r); + }), + s + ); + })(0, n.query)), + n + ); +} +class Es extends P { + constructor(e, t = {}) { + super(), + e && "object" == typeof e && ((t = e), (e = null)), + e + ? ((e = vs(e)), + (t.hostname = e.host), + (t.secure = "https" === e.protocol || "wss" === e.protocol), + (t.port = e.port), + e.query && (t.query = e.query)) + : t.host && (t.hostname = vs(t.host).host), + j(this, t), + (this.secure = + null != t.secure + ? t.secure + : "undefined" != typeof location && "https:" === location.protocol), + t.hostname && !t.port && (t.port = this.secure ? "443" : "80"), + (this.hostname = + t.hostname || + ("undefined" != typeof location ? location.hostname : "localhost")), + (this.port = + t.port || + ("undefined" != typeof location && location.port + ? location.port + : this.secure + ? "443" + : "80")), + (this.transports = t.transports || ["polling", "websocket"]), + (this.readyState = ""), + (this.writeBuffer = []), + (this.prevBufferLen = 0), + (this.opts = Object.assign( + { + path: "/engine.io", + agent: !1, + withCredentials: !1, + upgrade: !0, + timestampParam: "t", + rememberUpgrade: !1, + rejectUnauthorized: !0, + perMessageDeflate: { threshold: 1024 }, + transportOptions: {}, + closeOnBeforeunload: !0, + }, + t + )), + (this.opts.path = this.opts.path.replace(/\/$/, "") + "/"), + "string" == typeof this.opts.query && + (this.opts.query = (function (e) { + let t = {}, + s = e.split("&"); + for (let e = 0, r = s.length; e < r; e++) { + let r = s[e].split("="); + t[decodeURIComponent(r[0])] = decodeURIComponent(r[1]); + } + return t; + })(this.opts.query)), + (this.id = null), + (this.upgrades = null), + (this.pingInterval = null), + (this.pingTimeout = null), + (this.pingTimeoutTimer = null), + "function" == typeof addEventListener && + (this.opts.closeOnBeforeunload && + addEventListener( + "beforeunload", + () => { + this.transport && + (this.transport.removeAllListeners(), this.transport.close()); + }, + !1 + ), + "localhost" !== this.hostname && + ((this.offlineEventListener = () => { + this.onClose("transport close", { + description: "network connection lost", + }); + }), + addEventListener("offline", this.offlineEventListener, !1))), + this.open(); + } + createTransport(e) { + const t = Object.assign({}, this.opts.query); + (t.EIO = 4), (t.transport = e), this.id && (t.sid = this.id); + const s = Object.assign({}, this.opts.transportOptions[e], this.opts, { + query: t, + socket: this, + hostname: this.hostname, + secure: this.secure, + port: this.port, + }); + return new ms[e](s); + } + open() { + let e; + if ( + this.opts.rememberUpgrade && + Es.priorWebsocketSuccess && + -1 !== this.transports.indexOf("websocket") + ) + e = "websocket"; + else { + if (0 === this.transports.length) + return void this.setTimeoutFn(() => { + this.emitReserved("error", "No transports available"); + }, 0); + e = this.transports[0]; + } + this.readyState = "opening"; + try { + e = this.createTransport(e); + } catch (e) { + return this.transports.shift(), void this.open(); + } + e.open(), this.setTransport(e); + } + setTransport(e) { + this.transport && this.transport.removeAllListeners(), + (this.transport = e), + e + .on("drain", this.onDrain.bind(this)) + .on("packet", this.onPacket.bind(this)) + .on("error", this.onError.bind(this)) + .on("close", (e) => this.onClose("transport close", e)); + } + probe(e) { + let t = this.createTransport(e), + s = !1; + Es.priorWebsocketSuccess = !1; + const r = () => { + s || + (t.send([{ type: "ping", data: "probe" }]), + t.once("packet", (e) => { + if (!s) + if ("pong" === e.type && "probe" === e.data) { + if ( + ((this.upgrading = !0), this.emitReserved("upgrading", t), !t) + ) + return; + (Es.priorWebsocketSuccess = "websocket" === t.name), + this.transport.pause(() => { + s || + ("closed" !== this.readyState && + (c(), + this.setTransport(t), + t.send([{ type: "upgrade" }]), + this.emitReserved("upgrade", t), + (t = null), + (this.upgrading = !1), + this.flush())); + }); + } else { + const e = new Error("probe error"); + (e.transport = t.name), this.emitReserved("upgradeError", e); + } + })); + }; + function i() { + s || ((s = !0), c(), t.close(), (t = null)); + } + const n = (e) => { + const s = new Error("probe error: " + e); + (s.transport = t.name), i(), this.emitReserved("upgradeError", s); + }; + function o() { + n("transport closed"); + } + function a() { + n("socket closed"); + } + function h(e) { + t && e.name !== t.name && i(); + } + const c = () => { + t.removeListener("open", r), + t.removeListener("error", n), + t.removeListener("close", o), + this.off("close", a), + this.off("upgrading", h); + }; + t.once("open", r), + t.once("error", n), + t.once("close", o), + this.once("close", a), + this.once("upgrading", h), + t.open(); + } + onOpen() { + if ( + ((this.readyState = "open"), + (Es.priorWebsocketSuccess = "websocket" === this.transport.name), + this.emitReserved("open"), + this.flush(), + "open" === this.readyState && this.opts.upgrade && this.transport.pause) + ) { + let e = 0; + const t = this.upgrades.length; + for (; e < t; e++) this.probe(this.upgrades[e]); + } + } + onPacket(e) { + if ( + "opening" === this.readyState || + "open" === this.readyState || + "closing" === this.readyState + ) + switch ( + (this.emitReserved("packet", e), this.emitReserved("heartbeat"), e.type) + ) { + case "open": + this.onHandshake(JSON.parse(e.data)); + break; + case "ping": + this.resetPingTimeout(), + this.sendPacket("pong"), + this.emitReserved("ping"), + this.emitReserved("pong"); + break; + case "error": + const t = new Error("server error"); + (t.code = e.data), this.onError(t); + break; + case "message": + this.emitReserved("data", e.data), + this.emitReserved("message", e.data); + } + } + onHandshake(e) { + this.emitReserved("handshake", e), + (this.id = e.sid), + (this.transport.query.sid = e.sid), + (this.upgrades = this.filterUpgrades(e.upgrades)), + (this.pingInterval = e.pingInterval), + (this.pingTimeout = e.pingTimeout), + (this.maxPayload = e.maxPayload), + this.onOpen(), + "closed" !== this.readyState && this.resetPingTimeout(); + } + resetPingTimeout() { + this.clearTimeoutFn(this.pingTimeoutTimer), + (this.pingTimeoutTimer = this.setTimeoutFn(() => { + this.onClose("ping timeout"); + }, this.pingInterval + this.pingTimeout)), + this.opts.autoUnref && this.pingTimeoutTimer.unref(); + } + onDrain() { + this.writeBuffer.splice(0, this.prevBufferLen), + (this.prevBufferLen = 0), + 0 === this.writeBuffer.length ? this.emitReserved("drain") : this.flush(); + } + flush() { + if ( + "closed" !== this.readyState && + this.transport.writable && + !this.upgrading && + this.writeBuffer.length + ) { + const e = this.getWritablePackets(); + this.transport.send(e), + (this.prevBufferLen = e.length), + this.emitReserved("flush"); + } + } + getWritablePackets() { + if ( + !( + this.maxPayload && + "polling" === this.transport.name && + this.writeBuffer.length > 1 + ) + ) + return this.writeBuffer; + let e = 1; + for (let s = 0; s < this.writeBuffer.length; s++) { + const r = this.writeBuffer[s].data; + if ( + (r && + (e += + "string" == typeof (t = r) + ? (function (e) { + let t = 0, + s = 0; + for (let r = 0, i = e.length; r < i; r++) + (t = e.charCodeAt(r)), + t < 128 + ? (s += 1) + : t < 2048 + ? (s += 2) + : t < 55296 || t >= 57344 + ? (s += 3) + : (r++, (s += 4)); + return s; + })(t) + : Math.ceil(1.33 * (t.byteLength || t.size))), + s > 0 && e > this.maxPayload) + ) + return this.writeBuffer.slice(0, s); + e += 2; + } + var t; + return this.writeBuffer; + } + write(e, t, s) { + return this.sendPacket("message", e, t, s), this; + } + send(e, t, s) { + return this.sendPacket("message", e, t, s), this; + } + sendPacket(e, t, s, r) { + if ( + ("function" == typeof t && ((r = t), (t = void 0)), + "function" == typeof s && ((r = s), (s = null)), + "closing" === this.readyState || "closed" === this.readyState) + ) + return; + (s = s || {}).compress = !1 !== s.compress; + const i = { type: e, data: t, options: s }; + this.emitReserved("packetCreate", i), + this.writeBuffer.push(i), + r && this.once("flush", r), + this.flush(); + } + close() { + const e = () => { + this.onClose("forced close"), this.transport.close(); + }, + t = () => { + this.off("upgrade", t), this.off("upgradeError", t), e(); + }, + s = () => { + this.once("upgrade", t), this.once("upgradeError", t); + }; + return ( + ("opening" !== this.readyState && "open" !== this.readyState) || + ((this.readyState = "closing"), + this.writeBuffer.length + ? this.once("drain", () => { + this.upgrading ? s() : e(); + }) + : this.upgrading + ? s() + : e()), + this + ); + } + onError(e) { + (Es.priorWebsocketSuccess = !1), + this.emitReserved("error", e), + this.onClose("transport error", e); + } + onClose(e, t) { + ("opening" !== this.readyState && + "open" !== this.readyState && + "closing" !== this.readyState) || + (this.clearTimeoutFn(this.pingTimeoutTimer), + this.transport.removeAllListeners("close"), + this.transport.close(), + this.transport.removeAllListeners(), + "function" == typeof removeEventListener && + removeEventListener("offline", this.offlineEventListener, !1), + (this.readyState = "closed"), + (this.id = null), + this.emitReserved("close", e, t), + (this.writeBuffer = []), + (this.prevBufferLen = 0)); + } + filterUpgrades(e) { + const t = []; + let s = 0; + const r = e.length; + for (; s < r; s++) ~this.transports.indexOf(e[s]) && t.push(e[s]); + return t; + } +} +Es.protocol = 4; +const ws = "function" == typeof ArrayBuffer, + Ss = Object.prototype.toString, + ks = + "function" == typeof Blob || + ("undefined" != typeof Blob && + "[object BlobConstructor]" === Ss.call(Blob)), + xs = + "function" == typeof File || + ("undefined" != typeof File && + "[object FileConstructor]" === Ss.call(File)); +function Os(e) { + return ( + (ws && + (e instanceof ArrayBuffer || + ((e) => + "function" == typeof ArrayBuffer.isView + ? ArrayBuffer.isView(e) + : e.buffer instanceof ArrayBuffer)(e))) || + (ks && e instanceof Blob) || + (xs && e instanceof File) + ); +} +function Ts(e, t) { + if (!e || "object" != typeof e) return !1; + if (Array.isArray(e)) { + for (let t = 0, s = e.length; t < s; t++) if (Ts(e[t])) return !0; + return !1; + } + if (Os(e)) return !0; + if (e.toJSON && "function" == typeof e.toJSON && 1 === arguments.length) + return Ts(e.toJSON(), !0); + for (const t in e) + if (Object.prototype.hasOwnProperty.call(e, t) && Ts(e[t])) return !0; + return !1; +} +function Ns(e) { + const t = [], + s = e.data, + r = e; + return ( + (r.data = Rs(s, t)), (r.attachments = t.length), { packet: r, buffers: t } + ); +} +function Rs(e, t) { + if (!e) return e; + if (Os(e)) { + const s = { _placeholder: !0, num: t.length }; + return t.push(e), s; + } + if (Array.isArray(e)) { + const s = new Array(e.length); + for (let r = 0; r < e.length; r++) s[r] = Rs(e[r], t); + return s; + } + if ("object" == typeof e && !(e instanceof Date)) { + const s = {}; + for (const r in e) + Object.prototype.hasOwnProperty.call(e, r) && (s[r] = Rs(e[r], t)); + return s; + } + return e; +} +function Cs(e, t) { + return (e.data = Ls(e.data, t)), (e.attachments = void 0), e; +} +function Ls(e, t) { + if (!e) return e; + if (e && e._placeholder) return t[e.num]; + if (Array.isArray(e)) for (let s = 0; s < e.length; s++) e[s] = Ls(e[s], t); + else if ("object" == typeof e) + for (const s in e) + Object.prototype.hasOwnProperty.call(e, s) && (e[s] = Ls(e[s], t)); + return e; +} +var As; +!(function (e) { + (e[(e.CONNECT = 0)] = "CONNECT"), + (e[(e.DISCONNECT = 1)] = "DISCONNECT"), + (e[(e.EVENT = 2)] = "EVENT"), + (e[(e.ACK = 3)] = "ACK"), + (e[(e.CONNECT_ERROR = 4)] = "CONNECT_ERROR"), + (e[(e.BINARY_EVENT = 5)] = "BINARY_EVENT"), + (e[(e.BINARY_ACK = 6)] = "BINARY_ACK"); +})(As || (As = {})); +class Bs extends P { + constructor(e) { + super(), (this.reviver = e); + } + add(e) { + let t; + if ("string" == typeof e) + (t = this.decodeString(e)), + t.type === As.BINARY_EVENT || t.type === As.BINARY_ACK + ? ((this.reconstructor = new Ps(t)), + 0 === t.attachments && super.emitReserved("decoded", t)) + : super.emitReserved("decoded", t); + else { + if (!Os(e) && !e.base64) throw new Error("Unknown type: " + e); + if (!this.reconstructor) + throw new Error("got binary data when not reconstructing a packet"); + (t = this.reconstructor.takeBinaryData(e)), + t && ((this.reconstructor = null), super.emitReserved("decoded", t)); + } + } + decodeString(e) { + let t = 0; + const s = { type: Number(e.charAt(0)) }; + if (void 0 === As[s.type]) throw new Error("unknown packet type " + s.type); + if (s.type === As.BINARY_EVENT || s.type === As.BINARY_ACK) { + const r = t + 1; + for (; "-" !== e.charAt(++t) && t != e.length; ); + const i = e.substring(r, t); + if (i != Number(i) || "-" !== e.charAt(t)) + throw new Error("Illegal attachments"); + s.attachments = Number(i); + } + if ("/" === e.charAt(t + 1)) { + const r = t + 1; + for (; ++t; ) { + if ("," === e.charAt(t)) break; + if (t === e.length) break; + } + s.nsp = e.substring(r, t); + } else s.nsp = "/"; + const r = e.charAt(t + 1); + if ("" !== r && Number(r) == r) { + const r = t + 1; + for (; ++t; ) { + const s = e.charAt(t); + if (null == s || Number(s) != s) { + --t; + break; + } + if (t === e.length) break; + } + s.id = Number(e.substring(r, t + 1)); + } + if (e.charAt(++t)) { + const r = this.tryParse(e.substr(t)); + if (!Bs.isPayloadValid(s.type, r)) throw new Error("invalid payload"); + s.data = r; + } + return s; + } + tryParse(e) { + try { + return JSON.parse(e, this.reviver); + } catch (e) { + return !1; + } + } + static isPayloadValid(e, t) { + switch (e) { + case As.CONNECT: + return "object" == typeof t; + case As.DISCONNECT: + return void 0 === t; + case As.CONNECT_ERROR: + return "string" == typeof t || "object" == typeof t; + case As.EVENT: + case As.BINARY_EVENT: + return Array.isArray(t) && t.length > 0; + case As.ACK: + case As.BINARY_ACK: + return Array.isArray(t); + } + } + destroy() { + this.reconstructor && this.reconstructor.finishedReconstruction(); + } +} +class Ps { + constructor(e) { + (this.packet = e), (this.buffers = []), (this.reconPack = e); + } + takeBinaryData(e) { + if ( + (this.buffers.push(e), this.buffers.length === this.reconPack.attachments) + ) { + const e = Cs(this.reconPack, this.buffers); + return this.finishedReconstruction(), e; + } + return null; + } + finishedReconstruction() { + (this.reconPack = null), (this.buffers = []); + } +} +var Is = Object.freeze({ + __proto__: null, + protocol: 5, + get PacketType() { + return As; + }, + Encoder: class { + constructor(e) { + this.replacer = e; + } + encode(e) { + return (e.type !== As.EVENT && e.type !== As.ACK) || !Ts(e) + ? [this.encodeAsString(e)] + : ((e.type = e.type === As.EVENT ? As.BINARY_EVENT : As.BINARY_ACK), + this.encodeAsBinary(e)); + } + encodeAsString(e) { + let t = "" + e.type; + return ( + (e.type !== As.BINARY_EVENT && e.type !== As.BINARY_ACK) || + (t += e.attachments + "-"), + e.nsp && "/" !== e.nsp && (t += e.nsp + ","), + null != e.id && (t += e.id), + null != e.data && (t += JSON.stringify(e.data, this.replacer)), + t + ); + } + encodeAsBinary(e) { + const t = Ns(e), + s = this.encodeAsString(t.packet), + r = t.buffers; + return r.unshift(s), r; + } + }, + Decoder: Bs, +}); +function Ds(e, t, s) { + return ( + e.on(t, s), + function () { + e.off(t, s); + } + ); +} +const Us = Object.freeze({ + connect: 1, + connect_error: 1, + disconnect: 1, + disconnecting: 1, + newListener: 1, + removeListener: 1, +}); +class qs extends P { + constructor(e, t, s) { + super(), + (this.connected = !1), + (this.receiveBuffer = []), + (this.sendBuffer = []), + (this.ids = 0), + (this.acks = {}), + (this.flags = {}), + (this.io = e), + (this.nsp = t), + s && s.auth && (this.auth = s.auth), + this.io._autoConnect && this.open(); + } + get disconnected() { + return !this.connected; + } + subEvents() { + if (this.subs) return; + const e = this.io; + this.subs = [ + Ds(e, "open", this.onopen.bind(this)), + Ds(e, "packet", this.onpacket.bind(this)), + Ds(e, "error", this.onerror.bind(this)), + Ds(e, "close", this.onclose.bind(this)), + ]; + } + get active() { + return !!this.subs; + } + connect() { + return ( + this.connected || + (this.subEvents(), + this.io._reconnecting || this.io.open(), + "open" === this.io._readyState && this.onopen()), + this + ); + } + open() { + return this.connect(); + } + send(...e) { + return e.unshift("message"), this.emit.apply(this, e), this; + } + emit(e, ...t) { + if (Us.hasOwnProperty(e)) + throw new Error('"' + e + '" is a reserved event name'); + t.unshift(e); + const s = { type: As.EVENT, data: t, options: {} }; + if ( + ((s.options.compress = !1 !== this.flags.compress), + "function" == typeof t[t.length - 1]) + ) { + const e = this.ids++, + r = t.pop(); + this._registerAckCallback(e, r), (s.id = e); + } + const r = + this.io.engine && + this.io.engine.transport && + this.io.engine.transport.writable; + return ( + (this.flags.volatile && (!r || !this.connected)) || + (this.connected + ? (this.notifyOutgoingListeners(s), this.packet(s)) + : this.sendBuffer.push(s)), + (this.flags = {}), + this + ); + } + _registerAckCallback(e, t) { + const s = this.flags.timeout; + if (void 0 === s) return void (this.acks[e] = t); + const r = this.io.setTimeoutFn(() => { + delete this.acks[e]; + for (let t = 0; t < this.sendBuffer.length; t++) + this.sendBuffer[t].id === e && this.sendBuffer.splice(t, 1); + t.call(this, new Error("operation has timed out")); + }, s); + this.acks[e] = (...e) => { + this.io.clearTimeoutFn(r), t.apply(this, [null, ...e]); + }; + } + packet(e) { + (e.nsp = this.nsp), this.io._packet(e); + } + onopen() { + "function" == typeof this.auth + ? this.auth((e) => { + this.packet({ type: As.CONNECT, data: e }); + }) + : this.packet({ type: As.CONNECT, data: this.auth }); + } + onerror(e) { + this.connected || this.emitReserved("connect_error", e); + } + onclose(e, t) { + (this.connected = !1), + delete this.id, + this.emitReserved("disconnect", e, t); + } + onpacket(e) { + if (e.nsp === this.nsp) + switch (e.type) { + case As.CONNECT: + if (e.data && e.data.sid) { + const t = e.data.sid; + this.onconnect(t); + } else + this.emitReserved( + "connect_error", + new Error( + "It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)" + ) + ); + break; + case As.EVENT: + case As.BINARY_EVENT: + this.onevent(e); + break; + case As.ACK: + case As.BINARY_ACK: + this.onack(e); + break; + case As.DISCONNECT: + this.ondisconnect(); + break; + case As.CONNECT_ERROR: + this.destroy(); + const t = new Error(e.data.message); + (t.data = e.data.data), this.emitReserved("connect_error", t); + } + } + onevent(e) { + const t = e.data || []; + null != e.id && t.push(this.ack(e.id)), + this.connected + ? this.emitEvent(t) + : this.receiveBuffer.push(Object.freeze(t)); + } + emitEvent(e) { + if (this._anyListeners && this._anyListeners.length) { + const t = this._anyListeners.slice(); + for (const s of t) s.apply(this, e); + } + super.emit.apply(this, e); + } + ack(e) { + const t = this; + let s = !1; + return function (...r) { + s || ((s = !0), t.packet({ type: As.ACK, id: e, data: r })); + }; + } + onack(e) { + const t = this.acks[e.id]; + "function" == typeof t && (t.apply(this, e.data), delete this.acks[e.id]); + } + onconnect(e) { + (this.id = e), + (this.connected = !0), + this.emitBuffered(), + this.emitReserved("connect"); + } + emitBuffered() { + this.receiveBuffer.forEach((e) => this.emitEvent(e)), + (this.receiveBuffer = []), + this.sendBuffer.forEach((e) => { + this.notifyOutgoingListeners(e), this.packet(e); + }), + (this.sendBuffer = []); + } + ondisconnect() { + this.destroy(), this.onclose("io server disconnect"); + } + destroy() { + this.subs && (this.subs.forEach((e) => e()), (this.subs = void 0)), + this.io._destroy(this); + } + disconnect() { + return ( + this.connected && this.packet({ type: As.DISCONNECT }), + this.destroy(), + this.connected && this.onclose("io client disconnect"), + this + ); + } + close() { + return this.disconnect(); + } + compress(e) { + return (this.flags.compress = e), this; + } + get volatile() { + return (this.flags.volatile = !0), this; + } + timeout(e) { + return (this.flags.timeout = e), this; + } + onAny(e) { + return ( + (this._anyListeners = this._anyListeners || []), + this._anyListeners.push(e), + this + ); + } + prependAny(e) { + return ( + (this._anyListeners = this._anyListeners || []), + this._anyListeners.unshift(e), + this + ); + } + offAny(e) { + if (!this._anyListeners) return this; + if (e) { + const t = this._anyListeners; + for (let s = 0; s < t.length; s++) + if (e === t[s]) return t.splice(s, 1), this; + } else this._anyListeners = []; + return this; + } + listenersAny() { + return this._anyListeners || []; + } + onAnyOutgoing(e) { + return ( + (this._anyOutgoingListeners = this._anyOutgoingListeners || []), + this._anyOutgoingListeners.push(e), + this + ); + } + prependAnyOutgoing(e) { + return ( + (this._anyOutgoingListeners = this._anyOutgoingListeners || []), + this._anyOutgoingListeners.unshift(e), + this + ); + } + offAnyOutgoing(e) { + if (!this._anyOutgoingListeners) return this; + if (e) { + const t = this._anyOutgoingListeners; + for (let s = 0; s < t.length; s++) + if (e === t[s]) return t.splice(s, 1), this; + } else this._anyOutgoingListeners = []; + return this; + } + listenersAnyOutgoing() { + return this._anyOutgoingListeners || []; + } + notifyOutgoingListeners(e) { + if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) { + const t = this._anyOutgoingListeners.slice(); + for (const s of t) s.apply(this, e.data); + } + } +} +function js(e) { + (e = e || {}), + (this.ms = e.min || 100), + (this.max = e.max || 1e4), + (this.factor = e.factor || 2), + (this.jitter = e.jitter > 0 && e.jitter <= 1 ? e.jitter : 0), + (this.attempts = 0); +} +(js.prototype.duration = function () { + var e = this.ms * Math.pow(this.factor, this.attempts++); + if (this.jitter) { + var t = Math.random(), + s = Math.floor(t * this.jitter * e); + e = 0 == (1 & Math.floor(10 * t)) ? e - s : e + s; + } + return 0 | Math.min(e, this.max); +}), + (js.prototype.reset = function () { + this.attempts = 0; + }), + (js.prototype.setMin = function (e) { + this.ms = e; + }), + (js.prototype.setMax = function (e) { + this.max = e; + }), + (js.prototype.setJitter = function (e) { + this.jitter = e; + }); +class Fs extends P { + constructor(e, t) { + var s; + super(), + (this.nsps = {}), + (this.subs = []), + e && "object" == typeof e && ((t = e), (e = void 0)), + ((t = t || {}).path = t.path || "/socket.io"), + (this.opts = t), + j(this, t), + this.reconnection(!1 !== t.reconnection), + this.reconnectionAttempts(t.reconnectionAttempts || 1 / 0), + this.reconnectionDelay(t.reconnectionDelay || 1e3), + this.reconnectionDelayMax(t.reconnectionDelayMax || 5e3), + this.randomizationFactor( + null !== (s = t.randomizationFactor) && void 0 !== s ? s : 0.5 + ), + (this.backoff = new js({ + min: this.reconnectionDelay(), + max: this.reconnectionDelayMax(), + jitter: this.randomizationFactor(), + })), + this.timeout(null == t.timeout ? 2e4 : t.timeout), + (this._readyState = "closed"), + (this.uri = e); + const r = t.parser || Is; + (this.encoder = new r.Encoder()), + (this.decoder = new r.Decoder()), + (this._autoConnect = !1 !== t.autoConnect), + this._autoConnect && this.open(); + } + reconnection(e) { + return arguments.length + ? ((this._reconnection = !!e), this) + : this._reconnection; + } + reconnectionAttempts(e) { + return void 0 === e + ? this._reconnectionAttempts + : ((this._reconnectionAttempts = e), this); + } + reconnectionDelay(e) { + var t; + return void 0 === e + ? this._reconnectionDelay + : ((this._reconnectionDelay = e), + null === (t = this.backoff) || void 0 === t || t.setMin(e), + this); + } + randomizationFactor(e) { + var t; + return void 0 === e + ? this._randomizationFactor + : ((this._randomizationFactor = e), + null === (t = this.backoff) || void 0 === t || t.setJitter(e), + this); + } + reconnectionDelayMax(e) { + var t; + return void 0 === e + ? this._reconnectionDelayMax + : ((this._reconnectionDelayMax = e), + null === (t = this.backoff) || void 0 === t || t.setMax(e), + this); + } + timeout(e) { + return arguments.length ? ((this._timeout = e), this) : this._timeout; + } + maybeReconnectOnOpen() { + !this._reconnecting && + this._reconnection && + 0 === this.backoff.attempts && + this.reconnect(); + } + open(e) { + if (~this._readyState.indexOf("open")) return this; + this.engine = new Es(this.uri, this.opts); + const t = this.engine, + s = this; + (this._readyState = "opening"), (this.skipReconnect = !1); + const r = Ds(t, "open", function () { + s.onopen(), e && e(); + }), + i = Ds(t, "error", (t) => { + s.cleanup(), + (s._readyState = "closed"), + this.emitReserved("error", t), + e ? e(t) : s.maybeReconnectOnOpen(); + }); + if (!1 !== this._timeout) { + const e = this._timeout; + 0 === e && r(); + const s = this.setTimeoutFn(() => { + r(), t.close(), t.emit("error", new Error("timeout")); + }, e); + this.opts.autoUnref && s.unref(), + this.subs.push(function () { + clearTimeout(s); + }); + } + return this.subs.push(r), this.subs.push(i), this; + } + connect(e) { + return this.open(e); + } + onopen() { + this.cleanup(), (this._readyState = "open"), this.emitReserved("open"); + const e = this.engine; + this.subs.push( + Ds(e, "ping", this.onping.bind(this)), + Ds(e, "data", this.ondata.bind(this)), + Ds(e, "error", this.onerror.bind(this)), + Ds(e, "close", this.onclose.bind(this)), + Ds(this.decoder, "decoded", this.ondecoded.bind(this)) + ); + } + onping() { + this.emitReserved("ping"); + } + ondata(e) { + this.decoder.add(e); + } + ondecoded(e) { + this.emitReserved("packet", e); + } + onerror(e) { + this.emitReserved("error", e); + } + socket(e, t) { + let s = this.nsps[e]; + return s || ((s = new qs(this, e, t)), (this.nsps[e] = s)), s; + } + _destroy(e) { + const t = Object.keys(this.nsps); + for (const e of t) { + if (this.nsps[e].active) return; + } + this._close(); + } + _packet(e) { + const t = this.encoder.encode(e); + for (let s = 0; s < t.length; s++) this.engine.write(t[s], e.options); + } + cleanup() { + this.subs.forEach((e) => e()), + (this.subs.length = 0), + this.decoder.destroy(); + } + _close() { + (this.skipReconnect = !0), + (this._reconnecting = !1), + this.onclose("forced close"), + this.engine && this.engine.close(); + } + disconnect() { + return this._close(); + } + onclose(e, t) { + this.cleanup(), + this.backoff.reset(), + (this._readyState = "closed"), + this.emitReserved("close", e, t), + this._reconnection && !this.skipReconnect && this.reconnect(); + } + reconnect() { + if (this._reconnecting || this.skipReconnect) return this; + const e = this; + if (this.backoff.attempts >= this._reconnectionAttempts) + this.backoff.reset(), + this.emitReserved("reconnect_failed"), + (this._reconnecting = !1); + else { + const t = this.backoff.duration(); + this._reconnecting = !0; + const s = this.setTimeoutFn(() => { + e.skipReconnect || + (this.emitReserved("reconnect_attempt", e.backoff.attempts), + e.skipReconnect || + e.open((t) => { + t + ? ((e._reconnecting = !1), + e.reconnect(), + this.emitReserved("reconnect_error", t)) + : e.onreconnect(); + })); + }, t); + this.opts.autoUnref && s.unref(), + this.subs.push(function () { + clearTimeout(s); + }); + } + } + onreconnect() { + const e = this.backoff.attempts; + (this._reconnecting = !1), + this.backoff.reset(), + this.emitReserved("reconnect", e); + } +} +const Ms = {}; +function Ws(e, t) { + "object" == typeof e && ((t = e), (e = void 0)); + const s = (function (e, t = "", s) { + let r = e; + (s = s || ("undefined" != typeof location && location)), + null == e && (e = s.protocol + "//" + s.host), + "string" == typeof e && + ("/" === e.charAt(0) && + (e = "/" === e.charAt(1) ? s.protocol + e : s.host + e), + /^(https?|wss?):\/\//.test(e) || + (e = void 0 !== s ? s.protocol + "//" + e : "https://" + e), + (r = vs(e))), + r.port || + (/^(http|ws)$/.test(r.protocol) + ? (r.port = "80") + : /^(http|ws)s$/.test(r.protocol) && (r.port = "443")), + (r.path = r.path || "/"); + const i = -1 !== r.host.indexOf(":") ? "[" + r.host + "]" : r.host; + return ( + (r.id = r.protocol + "://" + i + ":" + r.port + t), + (r.href = + r.protocol + + "://" + + i + + (s && s.port === r.port ? "" : ":" + r.port)), + r + ); + })(e, (t = t || {}).path || "/socket.io"), + r = s.source, + i = s.id, + n = s.path, + o = Ms[i] && n in Ms[i].nsps; + let a; + return ( + t.forceNew || t["force new connection"] || !1 === t.multiplex || o + ? (a = new Fs(r, t)) + : (Ms[i] || (Ms[i] = new Fs(r, t)), (a = Ms[i])), + s.query && !t.query && (t.query = s.queryKey), + a.socket(s.path, t) + ); +} +Object.assign(Ws, { Manager: Fs, Socket: qs, io: Ws, connect: Ws }); +var Vs = "e"; +var $s = "jr", + Gs = "jc"; +const Hs = process.argv.slice(2), + zs = Hs[0], + Ys = Hs[1], + Ks = Hs.slice(2), + Xs = { id: Ys, command: Ks }, + Js = new (class { + constructor(e, t, s = {}) { + (this.url = e), + (this.job = t), + (this.mode = Vs), + (this.buf = {}), + (this.buf.e = ""), + (this.buf.o = ""), + (this.spawn = s.spawn ?? this.spawn.bind(this)), + (this.report = s.report ?? this.report.bind(this)), + (this.onProcClose = s.onProcClose ?? this.onProcClose.bind(this)), + (this.onClose = s.onClose ?? this.onClose.bind(this)); + } + spawn() { + const e = this.job.command, + t = e.shift(); + (this.proc = _.default.spawn(t, e)), + this.proc.stdout.setEncoding("utf8"), + this.proc.stderr.setEncoding("utf8"), + this.proc.stdout.on("data", (e) => this.report(e.toString(), "o")), + this.proc.stderr.on("data", (e) => this.report(e.toString(), "e")), + this.proc.on("close", this.onProcClose); + } + runJob() { + const e = new Fs(this.url, { + query: { mode: this.mode, jobId: this.job.id }, + }); + (this.socket = e.socket("/")), + this.socket.on("connect", this.spawn), + this.socket.on("disconnect", this.onClose); + } + onClose() { + console.log("Server disconnected, terminating process."), + this.proc.kill("SIGINT"); + } + onProcClose(e) { + this.socket.emit(Gs, e), + console.log(`Process finished with code ${e}`), + this.socket.disconnect(); + } + report(e, t) { + (this.buf[t] += e), + this.buf[t].includes("\n") && + (this.buf[t].endsWith("\n") && + (this.buf[t] = this.buf[t].slice(0, -1)), + this.socket.emit($s, this.buf[t]), + "e" === t + ? console.error(`err: ${this.buf[t]}`) + : console.log(`out: ${this.buf[t]}`), + (this.buf[t] = "")); + } + })(zs, Xs, Ks); +Js.runJob(); diff --git a/lib/core/internal-deploy.js b/lib/core/internal-deploy.js index 90ad3e0..3590aed 100644 --- a/lib/core/internal-deploy.js +++ b/lib/core/internal-deploy.js @@ -6,11 +6,10 @@ const jobStr = process.argv.slice(2)[0]; const job = JSON.parse(jobStr); const { command } = job.spec.template.spec.containers[0]; INFO("EXEC", "Internal Executor Starting!"); -cp.exec(command, (error, stdout, stderr)=>{ -if(error) ERR("EXEC", error); -//if(stdout) VERB("EXEC-STDOUT", stdout); -//if(stderr) VERB("EXEC-STDERR", stderr); -OK("EXEC", "Internal Executor Finished!"); -process.exit(error? 1 : 0 ); +cp.exec(command, (error, stdout, stderr) => { + if (error) ERR("EXEC", error); + //if(stdout) VERB("EXEC-STDOUT", stdout); + //if(stderr) VERB("EXEC-STDERR", stderr); + OK("EXEC", "Internal Executor Finished!"); + process.exit(error ? 1 : 0); }); - diff --git a/lib/core/kubernetes.js b/lib/core/kubernetes.js index 3b466d8..e0767c5 100644 --- a/lib/core/kubernetes.js +++ b/lib/core/kubernetes.js @@ -5,9 +5,11 @@ import path from "path"; const internalDeploy = process.env.INTERNAL_DEPLOY === "true"; const executorUrl = process.env.EXECUTOR_URL; const executorScriptOnly = process.env.EXECUTOR_SCRIPT_ONLY === "true"; -const executorBin = process.env.EXECUTOR_BIN ?? `qltr-executor${executorScriptOnly ? ".js": ""}`; +const executorBin = + process.env.EXECUTOR_BIN ?? `qltr-executor${executorScriptOnly ? ".js" : ""}`; -const qualiteerUrl = process.env.QUALITEER_URL ?? "file:///home/runner/Qualiteer/bin/executor"; +const qualiteerUrl = + process.env.QUALITEER_URL ?? "file:///home/runner/Qualiteer/bin/executor"; const kubCmd = "kubectl apply -f"; const jobsDir = "jobs/"; @@ -16,11 +18,15 @@ const defaults = JSON.parse( ); const wrapCommand = (jobId, command) => { - const bin = executorScriptOnly ? `node ${executorBin}`:`chmod +x ${executorBin} && ./${executorBin}`; - const cmd = command.map((arg)=>JSON.stringify(arg)) - const curlCmd = `curl -o qltr-executor ${executorUrl} && ${bin} ${qualiteerUrl} ${jobId} ${cmd.join(" ")}`; + const bin = executorScriptOnly + ? `node ${executorBin}` + : `chmod +x ${executorBin} && ./${executorBin}`; + const cmd = command.map((arg) => JSON.stringify(arg)); + const curlCmd = `curl -o qltr-executor ${executorUrl} && ${bin} ${qualiteerUrl} ${jobId} ${cmd.join( + " " + )}`; return curlCmd; -} +}; const createFile = (job) => { const { name } = job.metadata; diff --git a/lib/core/server.js b/lib/core/server.js index 8ebddbb..de78cf1 100644 --- a/lib/core/server.js +++ b/lib/core/server.js @@ -5,11 +5,15 @@ import express from "express"; import results from "../routes/results-route.js"; import alerting from "../routes/alerting-route.js"; import react from "../routes/react-route.js"; -import tests from "../routes/tests-route.js"; +import catalog from "../routes/catalog-route.js"; import jobs from "../routes/jobs-route.js"; +import mock from "../routes/mock-route.js"; + const app = express(); +// Special Routes app.all("/", (req, res) => res.redirect("/qualiteer")); +if (process.env.MOCK_ROUTES === "true") app.use(mock); // Middlewares @@ -17,7 +21,7 @@ app.all("/", (req, res) => res.redirect("/qualiteer")); app.use(react); // Static Build Route app.use("/api/results", results); app.use("/api/alerting", alerting); -app.use("/api/tests", tests); +app.use("/api/catalog", catalog); app.use("/api/jobs", jobs); export default app; diff --git a/lib/database/TABLES.md b/lib/database/TABLES.md index d128ade..048e05d 100644 --- a/lib/database/TABLES.md +++ b/lib/database/TABLES.md @@ -1,32 +1,34 @@ CREATE SEQUENCE test_results_id_seq; CREATE TABLE test_results ( - id bigint NOT NULL DEFAULT nextval('test_results_seq') PRIMARY KEY, - test_name varchar(255) DEFAULT NULL, - test_class varchar(255) DEFAULT NULL, - test_method varchar(255) DEFAULT NULL, - test_path varchar(255) DEFAULT NULL, - test_type varchar(32) DEFAULT NULL, - test_timestamp timestamptz NOT NULL DEFAULT now(), - test_retry BOOLEAN DEFAULT FALSE, - origin varchar(255) DEFAULT NULL, - failed BOOLEAN DEFAULT FALSE, - failed_message varchar(2047) DEFAULT NULL, - screenshot_url varchar(255) DEFAULT NULL, - weblog_url varchar(255) DEFAULT NULL, +id bigint NOT NULL DEFAULT nextval('test_results_seq') PRIMARY KEY, +test_name varchar(255) DEFAULT NULL, +test_class varchar(255) DEFAULT NULL, +test_method varchar(255) DEFAULT NULL, +test_path varchar(255) DEFAULT NULL, +test_type varchar(32) DEFAULT NULL, +test_timestamp timestamptz NOT NULL DEFAULT now(), +test_retry BOOLEAN DEFAULT FALSE, +origin varchar(255) DEFAULT NULL, +failed BOOLEAN DEFAULT FALSE, +failed_message varchar(2047) DEFAULT NULL, +screenshot_url varchar(255) DEFAULT NULL, +weblog_url varchar(255) DEFAULT NULL, ); ALTER SEQUENCE test_results_id_seq OWNED BY test_results.id; # Tables + PG Database Tables Mapped Out -## ```test_results``` +## `test_results` + | id | test_name | test_class | test_method | test_path | test_type | test_timestamp | test_retry | origin | failed | failed_message | screenshot_url | weblog_url | | int | string | string | string | string | string | timestamp | boolean | string | boolean | string | string | string | | 1 | My Test | My Test Class | My Failing Test Method | My Test Class Path | API | Date.now() | false | Test Suite A | true | Some Failure Messsage | screenshotUrl | weblogUrl | - id Automatically Generated - test_name\* Name of test -- test_class\* Name of class +- test_class\* Name of class - test_method Name of failed method if failed else null - test_path Path to test class - test_type API/UI/Mobile @@ -35,8 +37,5 @@ PG Database Tables Mapped Out - origin Test Suite test belongs to - failed Indicates if the test failed or not - failed_message Failure Message of test or null -- screenshot_url Screenshot of failure +- screenshot_url Screenshot of failure - weblog_url Log from the web console - - - diff --git a/lib/database/migrations/1_create_test_results_table.sql b/lib/database/migrations/1_create_test_results_table.sql index bd65e86..eef75b4 100644 --- a/lib/database/migrations/1_create_test_results_table.sql +++ b/lib/database/migrations/1_create_test_results_table.sql @@ -1,19 +1,14 @@ CREATE SEQUENCE test_results_id_seq; CREATE TABLE test_results ( - id bigint NOT NULL DEFAULT nextval('test_results_seq') PRIMARY KEY, - test_name varchar(255) DEFAULT NULL, - test_class varchar(255) DEFAULT NULL, - test_method varchar(255) DEFAULT NULL, - test_path varchar(255) DEFAULT NULL, - test_type varchar(32) DEFAULT NULL, - test_timestamp timestamptz NOT NULL DEFAULT now(), - test_retry BOOLEAN DEFAULT FALSE, - origin varchar(255) DEFAULT NULL, + id bigint NOT NULL DEFAULT nextval('test_results_id_seq') PRIMARY KEY, + name varchar(255) DEFAULT NULL, + "method" varchar(255) DEFAULT NULL, + env varchar(31) DEFAULT NULL, + "timestamp" TIMESTAMP NOT NULL DEFAULT now(), + retry BOOLEAN DEFAULT FALSE, failed BOOLEAN DEFAULT FALSE, failed_message varchar(2047) DEFAULT NULL, - screenshot_url varchar(255) DEFAULT NULL, - weblog_url varchar(255) DEFAULT NULL, + screenshot varchar(255) DEFAULT NULL, + weblog varchar(255) DEFAULT NULL ); -ALTER SEQUENCE test_results_id_seq OWNED BY test_results.id; - - +ALTER SEQUENCE test_results_id_seq OWNED BY test_results.id; \ No newline at end of file diff --git a/lib/database/migrations/2_create_catalog_table.sql b/lib/database/migrations/2_create_catalog_table.sql new file mode 100644 index 0000000..4a42d7c --- /dev/null +++ b/lib/database/migrations/2_create_catalog_table.sql @@ -0,0 +1,18 @@ +CREATE SEQUENCE test_catalog_id_seq; +CREATE TABLE test_catalog ( + id bigint NOT NULL DEFAULT nextval('test_catalog_id_seq') PRIMARY KEY, + name varchar(255) DEFAULT NULL, + class varchar(255) DEFAULT NULL, + compound BOOLEAN DEFAULT FALSE, + type varchar(31) DEFAULT NULL, + markers varchar(255)[] DEFAULT NULL, + ignored BOOLEAN DEFAULT FALSE, + comment varchar(1023) DEFAULT NULL, + coverage varchar(255)[] DEFAULT NULL, + env varchar(31)[] DEFAULT NULL, + "path" varchar(255) DEFAULT NULL, + regions varchar(15)[] DEFAULT NULL, + origin varchar(255) DEFAULT NULL, + cron varchar(127) DEFAULT NULL +); +ALTER SEQUENCE test_catalog_id_seq OWNED BY test_catalog.id; \ No newline at end of file diff --git a/lib/database/postgres.js b/lib/database/postgres.js index 4326bf3..ea1ecae 100644 --- a/lib/database/postgres.js +++ b/lib/database/postgres.js @@ -2,7 +2,7 @@ import { migrate } from "postgres-migrations"; import createPgp from "pg-promise"; import moment from "moment"; -import { WARN } from "../util/logging.js"; +import { INFO, WARN } from "../util/logging.js"; // Environment Variables const { POSTGRES_DATABASE: database, diff --git a/lib/database/queries/silenced_tests.js b/lib/database/queries/alerting.js similarity index 99% rename from lib/database/queries/silenced_tests.js rename to lib/database/queries/alerting.js index bf1049e..bcbf806 100644 --- a/lib/database/queries/silenced_tests.js +++ b/lib/database/queries/alerting.js @@ -12,4 +12,3 @@ export const getSilencedTests = () => { const query = `SELECT * from ${table}`; return pg.query(query); }; - diff --git a/lib/database/queries/tests.js b/lib/database/queries/catalog.js similarity index 99% rename from lib/database/queries/tests.js rename to lib/database/queries/catalog.js index 82ce5dd..e0c27e1 100644 --- a/lib/database/queries/tests.js +++ b/lib/database/queries/catalog.js @@ -12,4 +12,3 @@ export const getTests = () => { const query = `SELECT * from ${table}`; return pg.query(query); }; - diff --git a/lib/database/queries/results.js b/lib/database/queries/results.js new file mode 100644 index 0000000..1cb0b99 --- /dev/null +++ b/lib/database/queries/results.js @@ -0,0 +1,64 @@ +import pg from "../postgres.js"; +// Imports +import { + insertQuery, + selectWhereAnyQuery, + selectWhereAllQuery, + updateWhereAnyQuery, +} from "../pg-query.js"; +// Constants +const table = "test_results"; +// Queries +export const insertTestResult = (testResult) => { + const { + test_name, + test_class, + test_method, + test_path, + test_type, + test_timestamp, + test_retry, + origin, + failed, + failed_message, + screenshot_url, + expected_screenshot_url, + weblog_url, + } = testResult; + + var query = insertQuery(table, { + test_name, + test_class, + test_method, + test_path, + test_type, + test_timestamp, + test_retry, + origin, + failed, + failed_message, + screenshot_url, + expected_screenshot_url, + weblog_url, + }); + + query += "\n RETURNING *"; + return pg.query(query); +}; + +export const getCurrentlyFailing = () => { + const query = `WITH recent as (SELECT * FROM test_results WHERE (timestamp BETWEEN NOW() - INTERVAL '24 HOURS' AND NOW()) AND NOT(failed AND retry)) SELECT * FROM recent WHERE timestamp = (SELECT MAX(timestamp) FROM recent r2 WHERE recent.name = r2.name) AND failed; +`; + return pg.query(query); + + /*SELECT * FROM test_results WHERE "timestamp" BETWEEN NOW() - INTERVAL '24 HOURS' AND NOW(); <-- Last 24 hours all runs*/ + + /* SELECT * FROM test_results tr1 WHERE timestamp BETWEEN NOW() - INTERVAL '24 HOURS' AND NOW() AND timestamp = (SELECT MAX(timestamp) FROM test_results tr2 WHERE tr1.name = tr2.name); <-- Last 24 hours only most recent + */ +}; + +export const getCurrentlyFailingFull = (env) => { + const query = `WITH recent AS (SELECT * FROM test_results WHERE (timestamp BETWEEN NOW() - INTERVAL '24 HOURS' AND NOW()) AND NOT(failed AND retry) AND env='prod') SELECT * FROM recent INNER JOIN test_catalog USING(name) WHERE timestamp = (SELECT MAX(timestamp) FROM recent r2 WHERE recent.name = r2.name) AND failed; +;`; + return pg.query(query); +}; diff --git a/lib/database/queries/test_results.js b/lib/database/queries/test_results.js deleted file mode 100644 index 64d48f4..0000000 --- a/lib/database/queries/test_results.js +++ /dev/null @@ -1,51 +0,0 @@ -import pg from "../postgres.js"; -// Imports -import { - insertQuery, - selectWhereAnyQuery, - updateWhereAnyQuery, -} from "../pg-query.js"; -// Constants -const table = "test_results"; -// Queries -export const insertTestResult = (testResult) => { - const { - test_name, - test_class, - test_method, - test_path, - test_type, - test_timestamp, - test_retry, - origin, - failed, - failed_message, - screenshot_url, - expected_screenshot_url, - weblog_url, - } = testResult; - - var query = insertQuery(table, { - test_name, - test_class, - test_method, - test_path, - test_type, - test_timestamp, - test_retry, - origin, - failed, - failed_message, - screenshot_url, - expected_screenshot_url, - weblog_url, - }); - - query += "\n RETURNING *"; - return pg.query(query); -}; - -export const getCurrentlyFailing = () => { - const query = "SELECT *"; - return pg.query(query); -}; diff --git a/lib/routes/alerting-route.js b/lib/routes/alerting-route.js index f328235..31d9b90 100644 --- a/lib/routes/alerting-route.js +++ b/lib/routes/alerting-route.js @@ -1,5 +1,5 @@ import { Router, json as jsonMiddleware } from "express"; -import { getSilencedTests } from "../database/queries/silenced_tests.js"; +import { getSilencedTests } from "../database/queries/alerting.js"; const router = Router(); // Apply Middlewares @@ -11,8 +11,8 @@ router.get("/silenced", (req, res) => { }); // Post Routes -router.post("/silence", (req,res)=>{ - res.sendStatus(200); +router.post("/silence", (req, res) => { + res.sendStatus(200); }); export default router; diff --git a/lib/routes/tests-route.js b/lib/routes/catalog-route.js similarity index 70% rename from lib/routes/tests-route.js rename to lib/routes/catalog-route.js index 2cb1d38..a2f5b41 100644 --- a/lib/routes/tests-route.js +++ b/lib/routes/catalog-route.js @@ -1,11 +1,11 @@ import { Router, json as jsonMiddleware } from "express"; -import { getTests } from "../database/queries/tests.js"; +import { getTests } from "../database/queries/catalog.js"; const router = Router(); const maxSize = 1024 * 1024 * 100; // 100MB // Apply Middlewares -router.use(jsonMiddleware({limit: maxSize})); +router.use(jsonMiddleware({ limit: maxSize })); // Get Routes router.get("/tests", async (req, res) => { @@ -14,7 +14,7 @@ router.get("/tests", async (req, res) => { }); // Post Routes -router.post("/update", (req,res)=>{ +router.post("/update", (req, res) => { // Update All Tests res.sendStatus(200); }); diff --git a/lib/routes/jobs-route.js b/lib/routes/jobs-route.js index b007a19..c5149e8 100644 --- a/lib/routes/jobs-route.js +++ b/lib/routes/jobs-route.js @@ -4,9 +4,9 @@ import jobs from "../core/JobManager.js"; const router = Router(); router.get("/jobs", (req, res) => { - const { clients } = jobs; + const { clients } = jobs; const allJobs = []; - for(var c of clients) allJobs.push(...c.jobs); + for (var c of clients) allJobs.push(...c.jobs); res.json(allJobs); }); export default router; diff --git a/lib/routes/mock-route.js b/lib/routes/mock-route.js new file mode 100644 index 0000000..a88bf2f --- /dev/null +++ b/lib/routes/mock-route.js @@ -0,0 +1,37 @@ +import { Router } from "express"; +import { readFileSync } from "fs"; + +const router = Router(); + +const catalog = "lib/routes/mocks/catalog.json"; +const alerting = "lib/routes/mocks/alerting.json"; +const results = "lib/routes/mocks/results.json"; + +const query = async (mock) => JSON.parse(readFileSync(mock)); + +// Queries +router.get("/api/catalog/tests", (req, res) => { + query(catalog).then((catalog) => { + res.json(req.get("full") ? catalog["tests:full"] : catalog.tests); + }); +}); + +router.get("/api/results/failing", async (req, res) => { + query(results).then(async (results) => { + if (req.get("count")) res.json({ failing: results.results.length }); + else if (!req.get("full")) res.json(results.results); + else + query(catalog).then((catalog) => { + res.json( + results.results.map((r) => ({ + ...catalog["tests:full"].find((t) => t.name === r.name), + ...r, + })) + ); + }); + }); +}); + +// Mutations + +export default router; diff --git a/lib/routes/mocks/alerting.json b/lib/routes/mocks/alerting.json new file mode 100644 index 0000000..f98f5cc --- /dev/null +++ b/lib/routes/mocks/alerting.json @@ -0,0 +1,32 @@ +{ + "silenced": [ + { + "name": "Test1", + "class": "TestClass1", + "method": "TestMethod1", + "regions": ["us"], + "alerting": "MyUtcDate" + }, + { + "name": "Test2", + "class": null, + "method": "TestMethod1", + "regions": [], + "alerting": "MyUtcDate" + }, + { + "name": "*", + "class": "*", + "method": "TestMethod1", + "regions": [], + "alerting": "MyUtcDate" + }, + { + "name": "Test3", + "class": "TestClass3", + "method": "*", + "regions": ["us", "au"], + "alerting": "MyUtcDate" + } + ] +} diff --git a/lib/routes/mocks/catalog.json b/lib/routes/mocks/catalog.json new file mode 100644 index 0000000..bf89bf3 --- /dev/null +++ b/lib/routes/mocks/catalog.json @@ -0,0 +1,92 @@ +{ + "tests": [ + { + "name": "Test 1", + "class": "Test Class 1", + "compound": false, + "type": "api" + }, + { + "name": "Test 2", + "class": "Test Class 2", + "compound": false, + "type": "ui" + }, + { + "name": "Test Primary", + "class": "Test Class Primary", + "compound": true, + "type": "api" + }, + { + "name": "Test Secondary", + "class": "Test Class Secondary", + "compound": true, + "type": "ui" + } + ], + "tests:full": [ + { + "name": "Test1", + "class": "TestClass1", + "compound": false, + "type": "api", + "markers": ["Service1"], + "ignored": false, + "comment": "This Comment Is Part Of Test 1", + "coverage": ["/api/test1", "/api/test2"], + "env": ["prod", "ci"], + "path": "tests/api/test1.js", + "regions": ["us", "ca"], + "origin": "Repo1", + "cron": "1hour" + }, + { + "name": "Test2", + "class": "TestClass2", + "compound": false, + "type": "ui", + "markers": ["Service2"], + "ignored": false, + "comment": "Comment belonging to Test2", + "coverage": ["Page1/FeatureA"], + "env": ["prod"], + "path": "tests/ui/test2.js", + "regions": [], + "origin": "Repo2", + "cron": "30min" + }, + { + "name": "TestPrimary", + "class": "TestClassPrimary", + "compound": true, + "type": "api", + "markers": [ + "ServiceComplex", + "compound_Repo2!TestClassSecondary#TestSecondary" + ], + "ignored": false, + "comment": "Comment belonging to Test Primary", + "coverage": ["/api/compound"], + "env": ["ci"], + "path": "tests/api/primary.js", + "regions": [], + "origin": "Repo1", + "cron": "2hour" + }, + { + "name": "TestSecondary", + "class": "TestClassSecondary", + "compound": true, + "type": "ui", + "markers": ["ServiceComplex"], + "ignored": false, + "coverage": ["PageComplex/FeatureA"], + "env": ["ci"], + "path": "tests/ui/secondary.js", + "regions": [], + "origin": "Repo2", + "cron": "2hour" + } + ] +} diff --git a/lib/routes/mocks/results.json b/lib/routes/mocks/results.json new file mode 100644 index 0000000..c0ddf9c --- /dev/null +++ b/lib/routes/mocks/results.json @@ -0,0 +1,48 @@ +{ + "results": [ + { + "name": "Test1", + "method": "Test1Method", + "env": "prod", + "timestamp": "2022-05-10T16:35:27.220Z", + "retry": false, + "failed": true, + "failed_message": "Some failure message", + "screenshot": "https://example.com", + "weblog": "https://example.com" + }, + { + "name": "Test2", + "method": "Test2Method", + "env": "prod", + "timestamp": "2022-05-10T16:35:31.682Z", + "retry": false, + "failed": true, + "failed_message": "Some failure message 2", + "screenshot": "https://example.com", + "weblog": "https://example.com" + }, + { + "name": "Test1", + "method": null, + "env": "prod", + "timestamp": "2022-05-10T16:35:33.810Z", + "retry": false, + "failed": false, + "failed_message": null, + "screenshot": "https://example.com", + "weblog": "https://example.com" + }, + { + "name": "Test1", + "method": null, + "env": "ci", + "timestamp": "2022-05-10T16:35:33.810Z", + "retry": false, + "failed": false, + "failed_message": null, + "screenshot": "https://example.com", + "weblog": "https://example.com" + } + ] +} diff --git a/lib/routes/results-route.js b/lib/routes/results-route.js index 8675d09..025b8ff 100644 --- a/lib/routes/results-route.js +++ b/lib/routes/results-route.js @@ -1,5 +1,5 @@ import { Router, json as jsonMiddleware } from "express"; -import { getCurrentlyFailing } from "../database/queries/test_results.js"; +import { getCurrentlyFailing } from "../database/queries/results.js"; const router = Router(); // Apply Middlewares @@ -11,8 +11,8 @@ router.get("/failing", (req, res) => { }); // Post Routes -router.post("/history", (req,res)=>{ - res.send([]); +router.post("/history", (req, res) => { + res.send([]); }); export default router; diff --git a/lib/sockets/clients/Executor.js b/lib/sockets/clients/Executor.js index 88bb68e..b1db3ca 100644 --- a/lib/sockets/clients/Executor.js +++ b/lib/sockets/clients/Executor.js @@ -67,7 +67,8 @@ export default class Executor { report(d, dType) { this.buf[dType] += d; if (!this.buf[dType].includes("\n")) return; - if(this.buf[dType].endsWith("\n")) this.buf[dType] = this.buf[dType].slice(0, -1); + if (this.buf[dType].endsWith("\n")) + this.buf[dType] = this.buf[dType].slice(0, -1); this.socket.emit(events.JOB_REP, this.buf[dType]); if (dType === ERR) console.error(`err: ${this.buf[dType]}`); else console.log(`out: ${this.buf[dType]}`); diff --git a/package-lock.json b/package-lock.json index 05edad5..1479e7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "qualiteer", - "version": "1.0.0", + "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "qualiteer", - "version": "1.0.0", + "version": "0.0.1", "license": "LGPL-2.1-only", "dependencies": { "amqplib": "^0.8.0", @@ -18,12 +18,13 @@ "path": "^0.12.7", "pg-promise": "^10.11.1", "postgres-migrations": "^5.3.0", + "react-router-dom": "^6.3.0", "socket.io": "^4.4.1", "socket.io-client": "^4.4.1", "uuid": "^8.3.2" }, "bin": { - "qualiteer": "bin/app.js" + "qualiteer": "dist/app.js" }, "devDependencies": { "@emotion/react": "^11.9.0", @@ -33,6 +34,7 @@ "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-replace": "^4.0.0", + "axios": "^0.27.2", "caxa": "^2.1.0", "nodemon": "^2.0.15", "react": "^18.1.0", @@ -1904,7 +1906,6 @@ "version": "7.17.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -5160,6 +5161,30 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -9674,6 +9699,14 @@ "he": "bin/he" } }, + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -12764,8 +12797,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -13173,7 +13205,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -15814,7 +15845,6 @@ "version": "18.1.0", "resolved": "https://registry.npmjs.org/react/-/react-18.1.0.tgz", "integrity": "sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -16012,7 +16042,6 @@ "version": "18.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.1.0.tgz", "integrity": "sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.22.0" @@ -16042,6 +16071,30 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", + "integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==", + "dependencies": { + "history": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz", + "integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==", + "dependencies": { + "history": "^5.2.0", + "react-router": "6.3.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -16407,8 +16460,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -16913,7 +16965,6 @@ "version": "0.22.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz", "integrity": "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -21090,7 +21141,6 @@ "version": "7.17.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } @@ -23495,6 +23545,29 @@ "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", "dev": true }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -26887,6 +26960,14 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "requires": { + "@babel/runtime": "^7.7.6" + } + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -29151,8 +29232,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -29495,7 +29575,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -31312,7 +31391,6 @@ "version": "18.1.0", "resolved": "https://registry.npmjs.org/react/-/react-18.1.0.tgz", "integrity": "sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -31455,7 +31533,6 @@ "version": "18.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.1.0.tgz", "integrity": "sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==", - "dev": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.22.0" @@ -31479,6 +31556,23 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "dev": true }, + "react-router": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", + "integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==", + "requires": { + "history": "^5.2.0" + } + }, + "react-router-dom": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz", + "integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==", + "requires": { + "history": "^5.2.0", + "react-router": "6.3.0" + } + }, "react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -31727,8 +31821,7 @@ "regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "regenerator-transform": { "version": "0.15.0", @@ -32072,7 +32165,6 @@ "version": "0.22.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz", "integrity": "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } diff --git a/package.json b/package.json index aaf16d4..f027423 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "start:react": "react-scripts start", "start:react:replit": "DANGEROUSLY_DISABLE_HOST_CHECK=true npm run start:react", "test": "node tests/index.js", + "test:api": "node tests/api.js", "test:dev": "nodemon tests/index.js" }, "browserslist": { @@ -49,6 +50,7 @@ "path": "^0.12.7", "pg-promise": "^10.11.1", "postgres-migrations": "^5.3.0", + "react-router-dom": "^6.3.0", "socket.io": "^4.4.1", "socket.io-client": "^4.4.1", "uuid": "^8.3.2" @@ -61,6 +63,7 @@ "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-replace": "^4.0.0", + "axios": "^0.27.2", "caxa": "^2.1.0", "nodemon": "^2.0.15", "react": "^18.1.0", diff --git a/public/assets/QA.jpg b/public/assets/QA.jpg deleted file mode 100644 index 519c194231cf5cabb3a62579b24a37f582224ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18707 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 diff --git a/public/assets/QA.png b/public/assets/QA.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7813c04fdd107add127abacadf16c532c565ac GIT binary patch literal 58887 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 Q+u?TH7d-CP&VbbLpAz- - + - + diff --git a/src/Views.jsx b/src/Views.jsx index 1e70e6e..7c4e3d1 100644 --- a/src/Views.jsx +++ b/src/Views.jsx @@ -1,21 +1,23 @@ import { useContext, useState } from "react"; -import ViewContext from "./ctx/ViewContext.jsx"; - import * as React from "react"; +import { + Routes, + Route, + Link, + BrowserRouter, + Navigate, + useLocation, +} from "react-router-dom"; import AppBar from "@mui/material/AppBar"; +import Badge, { BadgeProps } from "@mui/material/Badge"; +import { styled } from "@mui/material/styles"; import Box from "@mui/material/Box"; import Toolbar from "@mui/material/Toolbar"; import IconButton from "@mui/material/IconButton"; import Typography from "@mui/material/Typography"; -import Menu from "@mui/material/Menu"; import MenuIcon from "@mui/icons-material/Menu"; -import Container from "@mui/material/Container"; import Avatar from "@mui/material/Avatar"; -import Button from "@mui/material/Button"; -import Tooltip from "@mui/material/Tooltip"; -import MenuItem from "@mui/material/MenuItem"; import Drawer from "@mui/material/Drawer"; -import ListItem from "@mui/material/ListItem"; import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText from "@mui/material/ListItemText"; import List from "@mui/material/List"; @@ -24,79 +26,124 @@ import NotificationsIcon from "@mui/icons-material/Notifications"; import WorkIcon from "@mui/icons-material/Work"; import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted"; import SettingsIcon from "@mui/icons-material/Settings"; -import ErrorIcon from "@mui/icons-material/Error"; +import WarningIcon from "@mui/icons-material/Warning"; +import InfoIcon from "@mui/icons-material/Info"; +// Import Pages +import Failing from "./views/Failing.jsx"; +import Alerting from "./views/Alerting.jsx"; +import Jobs from "./views/Jobs.jsx"; +import Catalog from "./views/Catalog.jsx"; +import Settings from "./views/Settings.jsx"; +import About from "./views/About.jsx"; -const pages = ["failing", "alerting", "jobs", "tests", "settings"]; +const pages = ["failing", "alerting", "jobs", "catalog", "settings", "about"]; const icons = [ - ErrorIcon, - NotificationsIcon, - WorkIcon, - FormatListBulletedIcon, - SettingsIcon, + + + , + , + + + , + , + , + , ]; +const drawerWidth = 240; + export default function Views() { - const [view, setView] = useState(pages[0]); + const location = useLocation(); const [drawerOpen, setDrawer] = React.useState(false); const toggleDrawer = () => setDrawer(!drawerOpen); const closeDrawer = () => setDrawer(false); - const openPage = (e) => setView(e.target.outerText.toLowerCase()); + + const reloadPage = () => window.location.reload(false); + + const SideBadge = styled(Badge)(({ theme }) => ({ + "& .MuiBadge-badge": { + right: -6, + top: 10, + padding: "0 4px", + }, + })); + + const navHeader = () => { + const pathStr = + location.pathname.charAt(1).toUpperCase() + location.pathname.slice(2); + if (location.pathname !== "/failing") return pathStr; + return ( + + {pathStr} + + ); + }; return ( - - - - - {" "} - - - {pages.map((text, index) => ( - - {/*icons[index]*/} - - - ))} - - - - - - - - {view.charAt(0).toUpperCase() + view.slice(1)} - - - {view.charAt(0).toUpperCase() + view.slice(1)} - - - - - - - +
+ theme.zIndex.drawer + 1 }} + > + + + + + + + + + + {pages.map((text, index) => ( + + {icons[index]} + + + ))} + + + + + {navHeader()} + + + + + + + + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + +
); } diff --git a/src/ctx/JobContext.jsx b/src/ctx/JobContext.jsx index 010b4c4..10a8d73 100644 --- a/src/ctx/JobContext.jsx +++ b/src/ctx/JobContext.jsx @@ -36,16 +36,32 @@ const reducer = (state, action) => { } }; + + export const JobProvider = ({ children }) => { const [state, dispatch] = useReducer(reducer, initialState); + const jobUpdate = (job, jobId) => dispatch({ type: ACTIONS.UPDATE, jobId, job }); + const jobCreate = (job) => + dispatch({ type: ACTIONS.CREATE, job: { ...job, log: [] } }); + const jobDelete = (jobId) => dispatch({ type: ACTIONS.DELETE, jobId }); + + function retryAll(failing){ + // Query Full Locator + console.log("Would retry all failing tests!"); +} + +function jobBuilder(){ + +} + const context = { state, dispatch, - jobUpdate: (job, jobId) => dispatch({ type: ACTIONS.UPDATE, jobId, job }), - jobCreate: (job) => - dispatch({ type: ACTIONS.CREATE, job: { ...job, log: [] } }), - jobDelete: (jobId) => dispatch({ type: ACTIONS.DELETE, jobId }), + jobUpdate, + jobCreate, + jobDelete, + retryAll }; const contextValue = useMemo(() => context, [state, dispatch]); diff --git a/src/ctx/StoreContext.jsx b/src/ctx/StoreContext.jsx index 9ed8246..ff71176 100644 --- a/src/ctx/StoreContext.jsx +++ b/src/ctx/StoreContext.jsx @@ -5,9 +5,18 @@ const ACTIONS = { UPDATE: "u", }; -const initialState = {}; +const initialState = { + intervals: [], + failing: [], + regions: [], + focusJob: false, + simplifiedControls: false, + defaultRegion: "us", // Local Store + defaultPage: "failing", // Local Store +}; const reducer = (state, action) => { + const { store } = action; // Actions switch (action.type) { case ACTIONS.UPDATE: @@ -23,7 +32,7 @@ export const StoreProvider = ({ children }) => { const context = { state, dispatch, - updateStore: (store) => dispatch(state, { type: ACTIONS.UPDATE, store }), + updateStore: (store) => dispatch({ type: ACTIONS.UPDATE, store }), }; const contextValue = useMemo(() => context, [state, dispatch]); diff --git a/src/ctx/ViewContext.jsx b/src/ctx/ViewContext.jsx deleted file mode 100644 index b1519d1..0000000 --- a/src/ctx/ViewContext.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { useReducer, createContext, useMemo } from "react"; -const ViewContext = createContext(); - -const ACTIONS = { - UPDATE: "u", -}; - -const initialState = { - activePage: "Home", -}; - -const reducer = (state, action) => { - // Actions - switch (action.type) { - case ACTIONS.UPDATE: - return { ...state }; - default: - return state; - } -}; - -export const ViewProvider = ({ children }) => { - const [state, dispatch] = useReducer(reducer, initialState); - - const contextValue = useMemo(() => ({ state, dispatch }), [state, dispatch]); - - return ( - {children} - ); -}; - -export default ViewContext; diff --git a/src/views/About.jsx b/src/views/About.jsx new file mode 100644 index 0000000..98f28bb --- /dev/null +++ b/src/views/About.jsx @@ -0,0 +1,32 @@ +import Typography from "@mui/material/Typography"; +import Link from "@mui/material/Link"; +import Container from "@mui/material/Container"; +import Box from "@mui/material/Box"; + +const memeUrl = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; +const repoUrl = "https://gitlab.com/dunemask/Qualiteer"; + +export default function About() { + return ( +
+ + + Why? + + + Qualiteer was designed to solve the issue of "on call". A state of being in which QA tests will fail, stiring everyone into a frenzy of what is broken in production! 🤯 + Qualiteer gives users power to resolve and reattempt failing tests, run a particular suite of tests, and mute pesky alerts reminding you the navbar's color changed... 🤦‍♂️ + +
+ + {"Repository: "} + {repoUrl} + +
+
+ Qualiteer +
+
+
+ ); +} diff --git a/src/views/Alerting.jsx b/src/views/Alerting.jsx new file mode 100644 index 0000000..55dce25 --- /dev/null +++ b/src/views/Alerting.jsx @@ -0,0 +1,61 @@ +import { useState, useContext } from "react"; +import StoreContext from "../ctx/StoreContext.jsx"; + +import SpeedDial from '@mui/material/SpeedDial'; +import SpeedDialAction from '@mui/material/SpeedDialAction'; +import SpeedDialIcon from '@mui/material/SpeedDialIcon'; + +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; + +export default function Alerting() { + const { state: store, updateStore } = useContext(StoreContext); + + const [alertDialogOpen, setAlertDialogOpen] = useState(false); + const quickAlertClick = () => setAlertDialogOpen(!alertDialogOpen); + + function silenceAlert(){ + + } + const handleClose = (confirmed) => () => { + quickAlertClick(); + if(!confirmed) return; + silenceAlert(); + } + + return ( +
+ + + Silence Alert + + + + + + + + + + + } + onClick={quickAlertClick} + open={false} + /> +
+ ); +} diff --git a/src/views/Catalog.jsx b/src/views/Catalog.jsx new file mode 100644 index 0000000..69c8d99 --- /dev/null +++ b/src/views/Catalog.jsx @@ -0,0 +1,29 @@ +import { useContext } from "react"; +import StoreContext from "../ctx/StoreContext.jsx"; +import JobContext from "../ctx/JobContext.jsx"; + +import TextField from "@mui/material/TextField"; + +import CatalogSearch from "./components/CatalogSearch.jsx"; + +export default function Catalog() { + const { + state: jobState, + dispatch: jobDispatch, + jobUpdate, + jobCreate, + } = useContext(JobContext); + + const { state: store, updateStore } = useContext(StoreContext); + + return ( +
+ + +
+ ); +} diff --git a/src/views/Failing.jsx b/src/views/Failing.jsx new file mode 100644 index 0000000..e1b7bab --- /dev/null +++ b/src/views/Failing.jsx @@ -0,0 +1,70 @@ +import { useState, useContext } from "react"; +import StoreContext from "../ctx/StoreContext.jsx"; +import JobContext from "../ctx/JobContext.jsx"; + +import SpeedDial from '@mui/material/SpeedDial'; +import SpeedDialAction from '@mui/material/SpeedDialAction'; +import SpeedDialIcon from '@mui/material/SpeedDialIcon'; + +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; + +import ReplayIcon from '@mui/icons-material/Replay'; + +export default function Failing() { + const { + state: jobState, + retryAll + } = useContext(JobContext); + + const { state: store, updateStore } = useContext(StoreContext); + + const [retryAllOpen, setRetryAllOpen] = useState(false); + const retryAllClick = () => setRetryAllOpen(!retryAllOpen); + const handleClose = (confirmed) => ()=> { + retryAllClick(); + if(!confirmed) return; + retryAll(store.failing); + } + + return ( +
+ + + + + Retry all failing tests? + + + + This will create x jobs and run y tests + + + + + + + + + } + onClick={retryAllClick} + open={false} + /> + +
+ ); +} diff --git a/src/views/Jobs.jsx b/src/views/Jobs.jsx new file mode 100644 index 0000000..0ab6a26 --- /dev/null +++ b/src/views/Jobs.jsx @@ -0,0 +1,55 @@ +import { useState, useContext } from "react"; +import StoreContext from "../ctx/StoreContext.jsx"; +import JobContext from "../ctx/JobContext.jsx"; + + +import ClickAwayListener from '@mui/material/ClickAwayListener'; +import SpeedDial from '@mui/material/SpeedDial'; +import SpeedDialAction from '@mui/material/SpeedDialAction'; +import SpeedDialIcon from '@mui/material/SpeedDialIcon'; + +import PageviewIcon from '@mui/icons-material/Pageview'; +import ViewColumnIcon from '@mui/icons-material/ViewColumn'; +import ViewCarouselIcon from '@mui/icons-material/ViewCarousel'; + +export default function Jobs() { + const { + state: jobState, + dispatch: jobDispatch, + jobUpdate, + jobCreate, + } = useContext(JobContext); + + const { state: store, updateStore } = useContext(StoreContext); + + const [quickOpen, setQuickOpen] = useState(false); + + const quickOpenClick = () => setQuickOpen(!quickOpen); + const quickOpenClose = () => setQuickOpen(false); + + const actions = [ + {name: "Suite", icon: }, {name: "Compound", icon: }, {name: "Manual", icon: } + ] + + return ( +
+ + } + onClick={quickOpenClick} + open={quickOpen} + > + {actions.map((action) => ( + + ))} + + +
+ ); +} diff --git a/src/views/Settings.jsx b/src/views/Settings.jsx new file mode 100644 index 0000000..fee6ce2 --- /dev/null +++ b/src/views/Settings.jsx @@ -0,0 +1,124 @@ +import { useContext, useState, useEffect } from "react"; +import StoreContext from "../ctx/StoreContext.jsx"; + +import MultiOptionDialog from "./components/MultiOptionDialog.jsx"; + +import * as React from 'react'; +import PropTypes from 'prop-types'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemText from '@mui/material/ListItemText'; +import Switch from "@mui/material/Switch"; +import SummarizeIcon from '@mui/icons-material/Summarize'; +import Typography from "@mui/material/Typography"; + + +export default function Settings(props) { + + const { state: store, updateStore } = useContext(StoreContext); + const { regions } = store; + const { pages } = props; + +const defaultDialog = {title: "", options: [], current: null, onSelect: null, open: false}; + const [dialog, setDialog] = React.useState(defaultDialog); + + const optionSettings = {region: { + title: "Region", + options: ["us", "au"], + current: store.defaultRegion, + onSelect: (r) => updateStore({defaultRegion: r}) +}, + defaultPage: { + title: "Default Page", + options: ["failing", "alerting"], + current: store.defaultPage, + onSelect: (p) => updateStore({defaultPage: p}) +}} + + const handleOptionsMenu = (s) => { + setDialog({...s, open:true}); + }; + + const handleClose = (newValue, onSelect) => { + setDialog({...dialog, open:false}) + if (!newValue) return; + onSelect(newValue); + }; + + const handleToggle = (booleanSetting) => ()=> { + const storeUpdate = {}; + storeUpdate[booleanSetting] = !store[booleanSetting]; + updateStore(storeUpdate) + } + + function MultiOptionSubtext(props){ + return( + + {props.value} + + ) + } + + + return ( + + + + handleOptionsMenu(optionSettings.defaultPage)} + > + + }/> + + + handleOptionsMenu(optionSettings.region)} + > + } /> + + + + + + + + + + + + + + + + ); +} diff --git a/src/views/components/CatalogSearch.jsx b/src/views/components/CatalogSearch.jsx new file mode 100644 index 0000000..220f50a --- /dev/null +++ b/src/views/components/CatalogSearch.jsx @@ -0,0 +1,31 @@ +import * as React from 'react'; +import Paper from '@mui/material/Paper'; +import InputBase from '@mui/material/InputBase'; +import Divider from '@mui/material/Divider'; +import IconButton from '@mui/material/IconButton'; +import MenuIcon from '@mui/icons-material/Menu'; +import SearchIcon from '@mui/icons-material/Search'; +import DirectionsIcon from '@mui/icons-material/Directions'; + import ClearOutlinedIcon from "@mui/icons-material/ClearOutlined"; + +export default function SearchBar(props) { + return ( + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/src/views/components/MultiOptionDialog.jsx b/src/views/components/MultiOptionDialog.jsx new file mode 100644 index 0000000..63e1789 --- /dev/null +++ b/src/views/components/MultiOptionDialog.jsx @@ -0,0 +1,73 @@ +import {useState, useRef, useEffect} from "react"; + +import Button from "@mui/material/Button" +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import DialogActions from '@mui/material/DialogActions'; +import Dialog from '@mui/material/Dialog'; +import RadioGroup from '@mui/material/RadioGroup'; +import Radio from '@mui/material/Radio'; +import FormControlLabel from '@mui/material/FormControlLabel'; + + +export default function MultiOptionDialog(props) { + + const { dialog: dialogProp, onClose, open, ...other } = props; + const [value, setValue] = useState(dialogProp.current); + const [dialog, setDialog] = useState(dialogProp); + + const radioGroupRef = useRef(null); + + useEffect(() => { + setDialog(dialogProp); + setValue(dialogProp.current); + }, [dialogProp, open]); + + const handleEntering = () => { + if (radioGroupRef.current != null) radioGroupRef.current.focus(); + }; + + const handleCancel = () => onClose(); + + const handleOk = () => onClose(value, dialog.onSelect); + + + const handleChange = (e) =>{ setValue(e.target.value); + } + + return ( + + {dialog.title} + + + {dialog.options.map((option) => ( + } + label={option} + /> + ))} + + + + + + + + ); +} diff --git a/tests/api.js b/tests/api.js new file mode 100644 index 0000000..1f2c29f --- /dev/null +++ b/tests/api.js @@ -0,0 +1,22 @@ +#!/usr/bin/env node +import "dotenv/config"; // Load Envars +import Qualiteer from "qualiteer"; +import axios from "axios"; + +// Start server +const qltr = new Qualiteer(); +await qltr.start(); + +const url = "https://Qualiteer.elijahparker3.repl.co"; + +const testsUrl = "/api/catalog/tests"; +const resultsUrl = "/api/results/failing"; + +const get = (...args) => axios.get(`${url}/${args[0]}`, args[1]); + +var res = await get(resultsUrl); +console.log(res.data); + +res = await get(resultsUrl, { headers: { count: true } }); + +console.log(res.data); diff --git a/tests/index.js b/tests/index.js index 4733a71..ba875dc 100644 --- a/tests/index.js +++ b/tests/index.js @@ -11,7 +11,11 @@ const url = "https://Qualiteer.elijahparker3.repl.co"; // Create an initiator and make a job request const primary = new Initiator(url); -const job = { command: ["node", "dev/other.js"], name: "testing", image: "node" }; +const job = { + command: ["node", "dev/other.js"], + name: "testing", + image: "node", +}; await primary.newJob(job, null, () => console.log("Primary Job Concluded")); /*const { clients } = qltr.jobs;