From 7c2fc90ed6da31980fa7b4279235ab6eb744ec9a Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 18 Feb 2022 00:09:48 +0100 Subject: [PATCH 001/101] feat(utilities): WS redis --- utilities/package-lock.json | 272 +++++++++++++++++++++++++++++++++ utilities/package.json | 2 + utilities/servers/websocket.js | 90 +++++++---- 3 files changed, 337 insertions(+), 27 deletions(-) diff --git a/utilities/package-lock.json b/utilities/package-lock.json index 8fe161f1a..bafdf340f 100644 --- a/utilities/package-lock.json +++ b/utilities/package-lock.json @@ -10,9 +10,11 @@ "license": "MIT", "dependencies": { "@maxmind/geoip2-node": "^3.4.0", + "@socket.io/redis-adapter": "^7.1.0", "aws-sdk": "^2.992.0", "express": "^4.17.1", "peer": "^0.6.1", + "redis": "^4.0.3", "socket.io": "^4.4.1", "source-map": "^0.7.3", "ua-parser-js": "^1.0.2", @@ -30,6 +32,60 @@ "maxmind": "^4.2.0" } }, + "node_modules/@node-redis/bloom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", + "integrity": "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/client": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", + "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", + "dependencies": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "redis-parser": "3.0.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@node-redis/graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@node-redis/graph/-/graph-1.0.0.tgz", + "integrity": "sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/json/-/json-1.0.2.tgz", + "integrity": "sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/search": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", + "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/time-series": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", + "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, "node_modules/@socket.io/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -38,6 +94,41 @@ "node": ">= 0.6.0" } }, + "node_modules/@socket.io/redis-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", + "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", + "dependencies": { + "debug": "~4.3.1", + "notepack.io": "~2.2.0", + "socket.io-adapter": "~2.3.0", + "uid2": "0.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@socket.io/redis-adapter/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@socket.io/redis-adapter/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -305,6 +396,14 @@ "wrap-ansi": "^6.2.0" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -616,6 +715,14 @@ "node": ">= 0.6" } }, + "node_modules/generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -830,6 +937,11 @@ "node": ">= 0.6" } }, + "node_modules/notepack.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", + "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1001,6 +1113,38 @@ "node": ">= 0.8" } }, + "node_modules/redis": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", + "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", + "dependencies": { + "@node-redis/bloom": "1.0.1", + "@node-redis/client": "1.0.3", + "@node-redis/graph": "1.0.0", + "@node-redis/json": "1.0.2", + "@node-redis/search": "1.0.2", + "@node-redis/time-series": "1.0.1" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1254,6 +1398,11 @@ "node": "*" } }, + "node_modules/uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1373,6 +1522,11 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", @@ -1419,11 +1573,78 @@ "maxmind": "^4.2.0" } }, + "@node-redis/bloom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", + "integrity": "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==", + "requires": {} + }, + "@node-redis/client": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", + "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", + "requires": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "redis-parser": "3.0.0", + "yallist": "4.0.0" + } + }, + "@node-redis/graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@node-redis/graph/-/graph-1.0.0.tgz", + "integrity": "sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==", + "requires": {} + }, + "@node-redis/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/json/-/json-1.0.2.tgz", + "integrity": "sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==", + "requires": {} + }, + "@node-redis/search": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", + "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", + "requires": {} + }, + "@node-redis/time-series": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", + "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", + "requires": {} + }, "@socket.io/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" }, + "@socket.io/redis-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", + "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", + "requires": { + "debug": "~4.3.1", + "notepack.io": "~2.2.0", + "socket.io-adapter": "~2.3.0", + "uid2": "0.0.3" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -1637,6 +1858,11 @@ "wrap-ansi": "^6.2.0" } }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1871,6 +2097,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==" + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2026,6 +2257,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "notepack.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", + "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2143,6 +2379,32 @@ "unpipe": "1.0.0" } }, + "redis": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", + "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", + "requires": { + "@node-redis/bloom": "1.0.1", + "@node-redis/client": "1.0.3", + "@node-redis/graph": "1.0.0", + "@node-redis/json": "1.0.2", + "@node-redis/search": "1.0.2", + "@node-redis/time-series": "1.0.1" + } + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2331,6 +2593,11 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==" }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2414,6 +2681,11 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", diff --git a/utilities/package.json b/utilities/package.json index 79c8513a4..87e1d1596 100644 --- a/utilities/package.json +++ b/utilities/package.json @@ -19,9 +19,11 @@ "homepage": "https://github.com/openreplay/openreplay#readme", "dependencies": { "@maxmind/geoip2-node": "^3.4.0", + "@socket.io/redis-adapter": "^7.1.0", "aws-sdk": "^2.992.0", "express": "^4.17.1", "peer": "^0.6.1", + "redis": "^4.0.3", "socket.io": "^4.4.1", "source-map": "^0.7.3", "ua-parser-js": "^1.0.2", diff --git a/utilities/servers/websocket.js b/utilities/servers/websocket.js index ab6a2c4d5..5811c4d13 100644 --- a/utilities/servers/websocket.js +++ b/utilities/servers/websocket.js @@ -2,7 +2,10 @@ const _io = require('socket.io'); const express = require('express'); const uaParser = require('ua-parser-js'); const geoip2Reader = require('@maxmind/geoip2-node').Reader; -var {extractPeerId} = require('./peerjs-server'); +const {extractPeerId} = require('./peerjs-server'); +const {createAdapter} = require("@socket.io/redis-adapter"); +const {createClient} = require("redis"); + var wsRouter = express.Router(); const IDENTITIES = {agent: 'agent', session: 'session'}; const NEW_AGENT = "NEW_AGENT"; @@ -14,11 +17,28 @@ const SESSION_ALREADY_CONNECTED = "SESSION_ALREADY_CONNECTED"; // const wsReconnectionTimeout = process.env.wsReconnectionTimeout | 10 * 1000; let io; -let debug = process.env.debug === "1" || false; -wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, function (req, res) { +const debug = process.env.debug === "1" || false; +const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379"; + +const pubClient = createClient({url: REDIS_URL}); +const subClient = pubClient.duplicate(); + +const uniqueSessions = function (data) { + let resArr = []; + let resArrIDS = []; + for (let item of data) { + if (resArrIDS.indexOf(item.sessionID) < 0) { + resArr.push(item); + resArrIDS.push(item.sessionID); + } + } + return resArr; +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, async function (req, res) { debug && console.log("[WS]looking for all available sessions"); let liveSessions = {}; - for (let peerId of io.sockets.adapter.rooms.keys()) { + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey !== undefined) { liveSessions[projectKey] = liveSessions[projectKey] || []; @@ -29,10 +49,11 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, function (req, res) { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions})); }); -wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, function (req, res) { +wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, async function (req, res) { debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); let liveSessions = {}; - for (let peerId of io.sockets.adapter.rooms.keys()) { + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey === req.params.projectKey) { liveSessions[projectKey] = liveSessions[projectKey] || []; @@ -47,7 +68,8 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, function (req, r wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { debug && console.log("[WS]looking for all available LIVE sessions"); let liveSessions = {}; - for (let peerId of io.sockets.adapter.rooms.keys()) { + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey !== undefined) { let connected_sockets = await io.in(peerId).fetchSockets(); @@ -57,6 +79,7 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { liveSessions[projectKey].push(item.handshake.query.sessionInfo); } } + liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); } } @@ -67,7 +90,8 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function (req, res) { debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); let liveSessions = {}; - for (let peerId of io.sockets.adapter.rooms.keys()) { + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey === req.params.projectKey) { let connected_sockets = await io.in(peerId).fetchSockets(); @@ -77,6 +101,7 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function ( liveSessions[projectKey].push(item.handshake.query.sessionInfo); } } + liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); } } res.statusCode = 200; @@ -96,7 +121,8 @@ const findSessionSocketId = async (io, peerId) => { async function sessions_agents_count(io, socket) { let c_sessions = 0, c_agents = 0; - if (io.sockets.adapter.rooms.get(socket.peerId)) { + let rooms = await io.of('/').adapter.allRooms(); + if (rooms.has(socket.peerId)) { const connected_sockets = await io.in(socket.peerId).fetchSockets(); for (let item of connected_sockets) { @@ -115,7 +141,8 @@ async function sessions_agents_count(io, socket) { async function get_all_agents_ids(io, socket) { let agents = []; - if (io.sockets.adapter.rooms.get(socket.peerId)) { + let rooms = await io.of('/').adapter.allRooms(); + if (rooms.has(socket.peerId)) { const connected_sockets = await io.in(socket.peerId).fetchSockets(); for (let item of connected_sockets) { if (item.handshake.query.identity === IDENTITIES.agent) { @@ -173,7 +200,7 @@ module.exports = { debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`); socket.peerId = socket.handshake.query.peerId; socket.identity = socket.handshake.query.identity; - const {projectKey, sessionId} = extractPeerId(socket.peerId); + let {projectKey, sessionId} = extractPeerId(socket.peerId); socket.sessionId = sessionId; socket.projectKey = projectKey; socket.lastMessageReceivedAt = Date.now(); @@ -196,8 +223,10 @@ module.exports = { io.to(socket.id).emit(NO_SESSIONS); } socket.join(socket.peerId); - if (io.sockets.adapter.rooms.get(socket.peerId)) { - debug && console.log(`${socket.id} joined room:${socket.peerId}, as:${socket.identity}, members:${io.sockets.adapter.rooms.get(socket.peerId).size}`); + let rooms = await io.of('/').adapter.allRooms(); + if (rooms.has(socket.peerId)) { + let connectedSockets = await io.in(socket.peerId).fetchSockets(); + debug && console.log(`${socket.id} joined room:${socket.peerId}, as:${socket.identity}, members:${connectedSockets.length}`); } if (socket.identity === IDENTITIES.agent) { if (socket.handshake.query.agentInfo !== undefined) { @@ -229,10 +258,10 @@ module.exports = { socket.onAny(async (eventName, ...args) => { socket.lastMessageReceivedAt = Date.now(); if (socket.identity === IDENTITIES.session) { - debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to room:${socket.peerId}, members: ${io.sockets.adapter.rooms.get(socket.peerId).size}`); + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to room:${socket.peerId}`); socket.to(socket.peerId).emit(eventName, args[0]); } else { - debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to session of room:${socket.peerId}, members:${io.sockets.adapter.rooms.get(socket.peerId).size}`); + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to session of room:${socket.peerId}`); let socketId = await findSessionSocketId(io, socket.peerId); if (socketId === null) { debug && console.log(`session not found for:${socket.peerId}`); @@ -246,27 +275,34 @@ module.exports = { }); console.log("WS server started") - setInterval((io) => { + setInterval(async (io) => { try { - let count = 0; - console.log(` ====== Rooms: ${io.sockets.adapter.rooms.size} ====== `); - const arr = Array.from(io.sockets.adapter.rooms) - const filtered = arr.filter(room => !room[1].has(room[0])) - for (let i of filtered) { - let {projectKey, sessionId} = extractPeerId(i[0]); - if (projectKey !== null && sessionId !== null) { - count++; + let rooms = await io.of('/').adapter.allRooms(); + let validRooms = []; + console.log(` ====== Rooms: ${rooms.size} ====== `); + const arr = Array.from(rooms) + // const filtered = arr.filter(room => !room[1].has(room[0])) + for (let i of rooms) { + let {projectKey, sessionId} = extractPeerId(i); + if (projectKey !== undefined && sessionId !== undefined) { + validRooms.push(i); } } - console.log(` ====== Valid Rooms: ${count} ====== `); + console.log(` ====== Valid Rooms: ${validRooms.length} ====== `); if (debug) { - for (let item of filtered) { - console.log(`Room: ${item[0]} connected: ${item[1].size}`) + for (let item of validRooms) { + let connectedSockets = await io.in(item).fetchSockets(); + console.log(`Room: ${item} connected: ${connectedSockets.length}`) } } } catch (e) { console.error(e); } }, 20000, io); + Promise.all([pubClient.connect(), subClient.connect()]).then(() => { + io.adapter(createAdapter(pubClient, subClient)); + console.log("> redis connected."); + // io.listen(3000); + }); } }; \ No newline at end of file From 10e187c98a17bd05bfe0db2ae522697ffa358090 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 22 Feb 2022 21:04:50 +0100 Subject: [PATCH 002/101] feat(utilities): EE custom code --- ee/utilities/.gitignore | 13 + ee/utilities/package-lock.json | 2708 +++++++++++++++++++++ ee/utilities/package.json | 31 + ee/utilities/server.js | 58 + ee/utilities/servers/websocket-cluster.js | 308 +++ utilities/package-lock.json | 283 +-- utilities/package.json | 5 +- utilities/servers/websocket.js | 90 +- 8 files changed, 3147 insertions(+), 349 deletions(-) create mode 100644 ee/utilities/.gitignore create mode 100644 ee/utilities/package-lock.json create mode 100644 ee/utilities/package.json create mode 100644 ee/utilities/server.js create mode 100644 ee/utilities/servers/websocket-cluster.js diff --git a/ee/utilities/.gitignore b/ee/utilities/.gitignore new file mode 100644 index 000000000..84f619088 --- /dev/null +++ b/ee/utilities/.gitignore @@ -0,0 +1,13 @@ +.idea +node_modules +npm-debug.log +.cache +test.html +build.sh + + + +servers/peerjs-server.js +servers/sourcemaps-handler.js +servers/sourcemaps-server.js +servers/websocket.js \ No newline at end of file diff --git a/ee/utilities/package-lock.json b/ee/utilities/package-lock.json new file mode 100644 index 000000000..0255b7ce1 --- /dev/null +++ b/ee/utilities/package-lock.json @@ -0,0 +1,2708 @@ +{ + "name": "utilities_server", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "utilities_server", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@maxmind/geoip2-node": "^3.4.0", + "@socket.io/redis-adapter": "^7.1.0", + "aws-sdk": "^2.992.0", + "express": "^4.17.1", + "peer": "^0.6.1", + "redis": "^4.0.3", + "socket.io": "^4.4.1", + "source-map": "^0.7.3", + "ua-parser-js": "^1.0.2" + } + }, + "node_modules/@maxmind/geoip2-node": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@maxmind/geoip2-node/-/geoip2-node-3.4.0.tgz", + "integrity": "sha512-XBB+IJSXQRXXHBvwULZu2nOYAPuC0pc77xw/xkDo0cWkBO/L2rUMr+xKGZwj47mFBEiG6tnTMBzxJajEJTrKAg==", + "dependencies": { + "camelcase-keys": "^7.0.0", + "ip6addr": "^0.2.5", + "lodash.set": "^4.3.2", + "maxmind": "^4.2.0" + } + }, + "node_modules/@node-redis/bloom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", + "integrity": "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/client": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", + "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", + "dependencies": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "redis-parser": "3.0.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@node-redis/graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@node-redis/graph/-/graph-1.0.0.tgz", + "integrity": "sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/json/-/json-1.0.2.tgz", + "integrity": "sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/search": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", + "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@node-redis/time-series": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", + "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } + }, + "node_modules/@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/@socket.io/redis-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", + "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", + "dependencies": { + "debug": "~4.3.1", + "notepack.io": "~2.2.0", + "socket.io-adapter": "~2.3.0", + "uid2": "0.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@socket.io/redis-adapter/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@socket.io/redis-adapter/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/component-emitter": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", + "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.26", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", + "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "node_modules/@types/node": { + "version": "16.11.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz", + "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/aws-sdk": { + "version": "2.1043.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1043.0.tgz", + "integrity": "sha512-WysMTSLfi8ZCj6QAAitJkxObxOzGLhcu6FxoKHiEnrefvfQtSvwqUq7BbT/pIfijnF9dE/7e9XwjW8Dz/hqF4Q==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dependencies": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", + "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "dependencies": { + "@socket.io/base64-arraybuffer": "~1.0.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ip6addr": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz", + "integrity": "sha512-9RGGSB6Zc9Ox5DpDGFnJdIeF0AsqXzdH+FspCfPPaU/L/4tI6P+5lIoFUFm9JXs9IrJv1boqAaNCQmoDADTSKQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/maxmind": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.5.tgz", + "integrity": "sha512-ak0TABuO664C5zXyQH5u13WmtdTwxxXLGOy1e51ZRrp/cEH9xfOcG20F51TcNhVyDos13Ys94kxN8/elg9Ri4Q==", + "dependencies": { + "mmdb-lib": "2.0.2", + "tiny-lru": "7.0.6" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mmdb-lib": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", + "integrity": "sha512-shi1I+fCPQonhTi7qyb6hr7hi87R7YS69FlfJiMFuJ12+grx0JyL56gLNzGTYXPU7EhAPkMLliGeyHer0K+AVA==", + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/notepack.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", + "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/peer": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/peer/-/peer-0.6.1.tgz", + "integrity": "sha512-zPJSPoZvo+83sPJNrW8o93QTktx7dKk67965RRDDNAIelWw1ZwE6ZmmhsvRrdNRlK0knQb3rR8GBdZlbWzCYJw==", + "dependencies": { + "@types/cors": "^2.8.6", + "@types/express": "^4.17.3", + "@types/ws": "^7.2.3", + "body-parser": "^1.19.0", + "cors": "^2.8.5", + "express": "^4.17.1", + "uuid": "^3.4.0", + "ws": "^7.2.3", + "yargs": "^15.3.1" + }, + "bin": { + "peerjs": "bin/peerjs" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/peer/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/redis": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", + "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", + "dependencies": { + "@node-redis/bloom": "1.0.1", + "@node-redis/client": "1.0.3", + "@node-redis/graph": "1.0.0", + "@node-redis/json": "1.0.2", + "@node-redis/search": "1.0.2", + "@node-redis/time-series": "1.0.1" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/socket.io": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", + "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.1.0", + "socket.io-adapter": "~2.3.3", + "socket.io-parser": "~4.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", + "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + }, + "node_modules/socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "dependencies": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tiny-lru": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz", + "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==", + "engines": { + "node": ">=6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", + "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@maxmind/geoip2-node": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@maxmind/geoip2-node/-/geoip2-node-3.4.0.tgz", + "integrity": "sha512-XBB+IJSXQRXXHBvwULZu2nOYAPuC0pc77xw/xkDo0cWkBO/L2rUMr+xKGZwj47mFBEiG6tnTMBzxJajEJTrKAg==", + "requires": { + "camelcase-keys": "^7.0.0", + "ip6addr": "^0.2.5", + "lodash.set": "^4.3.2", + "maxmind": "^4.2.0" + } + }, + "@node-redis/bloom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", + "integrity": "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==", + "requires": {} + }, + "@node-redis/client": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", + "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", + "requires": { + "cluster-key-slot": "1.1.0", + "generic-pool": "3.8.2", + "redis-parser": "3.0.0", + "yallist": "4.0.0" + } + }, + "@node-redis/graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@node-redis/graph/-/graph-1.0.0.tgz", + "integrity": "sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==", + "requires": {} + }, + "@node-redis/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/json/-/json-1.0.2.tgz", + "integrity": "sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==", + "requires": {} + }, + "@node-redis/search": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", + "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", + "requires": {} + }, + "@node-redis/time-series": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", + "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", + "requires": {} + }, + "@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" + }, + "@socket.io/redis-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", + "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", + "requires": { + "debug": "~4.3.1", + "notepack.io": "~2.2.0", + "socket.io-adapter": "~2.3.0", + "uid2": "0.0.3" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/component-emitter": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", + "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.26", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", + "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/node": { + "version": "16.11.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz", + "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "requires": { + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "aws-sdk": { + "version": "2.1043.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1043.0.tgz", + "integrity": "sha512-WysMTSLfi8ZCj6QAAitJkxObxOzGLhcu6FxoKHiEnrefvfQtSvwqUq7BbT/pIfijnF9dE/7e9XwjW8Dz/hqF4Q==", + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "requires": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + } + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", + "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "ws": "~8.2.3" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "requires": { + "@socket.io/base64-arraybuffer": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "generic-pool": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", + "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ip6addr": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz", + "integrity": "sha512-9RGGSB6Zc9Ox5DpDGFnJdIeF0AsqXzdH+FspCfPPaU/L/4tI6P+5lIoFUFm9JXs9IrJv1boqAaNCQmoDADTSKQ==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==" + }, + "maxmind": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.5.tgz", + "integrity": "sha512-ak0TABuO664C5zXyQH5u13WmtdTwxxXLGOy1e51ZRrp/cEH9xfOcG20F51TcNhVyDos13Ys94kxN8/elg9Ri4Q==", + "requires": { + "mmdb-lib": "2.0.2", + "tiny-lru": "7.0.6" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "mmdb-lib": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", + "integrity": "sha512-shi1I+fCPQonhTi7qyb6hr7hi87R7YS69FlfJiMFuJ12+grx0JyL56gLNzGTYXPU7EhAPkMLliGeyHer0K+AVA==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "notepack.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", + "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "peer": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/peer/-/peer-0.6.1.tgz", + "integrity": "sha512-zPJSPoZvo+83sPJNrW8o93QTktx7dKk67965RRDDNAIelWw1ZwE6ZmmhsvRrdNRlK0knQb3rR8GBdZlbWzCYJw==", + "requires": { + "@types/cors": "^2.8.6", + "@types/express": "^4.17.3", + "@types/ws": "^7.2.3", + "body-parser": "^1.19.0", + "cors": "^2.8.5", + "express": "^4.17.1", + "uuid": "^3.4.0", + "ws": "^7.2.3", + "yargs": "^15.3.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "redis": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", + "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", + "requires": { + "@node-redis/bloom": "1.0.1", + "@node-redis/client": "1.0.3", + "@node-redis/graph": "1.0.0", + "@node-redis/json": "1.0.2", + "@node-redis/search": "1.0.2", + "@node-redis/time-series": "1.0.1" + } + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "socket.io": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", + "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.1.0", + "socket.io-adapter": "~2.3.3", + "socket.io-parser": "~4.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "socket.io-adapter": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", + "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + }, + "socket.io-parser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", + "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==", + "requires": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "tiny-lru": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz", + "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "ua-parser-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", + "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==" + }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "ws": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "requires": {} + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/ee/utilities/package.json b/ee/utilities/package.json new file mode 100644 index 000000000..76b7d2013 --- /dev/null +++ b/ee/utilities/package.json @@ -0,0 +1,31 @@ +{ + "name": "utilities_server", + "version": "1.0.0", + "description": "assist server to get live sessions & sourcemaps reader to get stack trace", + "main": "peerjs-server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/openreplay/openreplay.git" + }, + "author": "KRAIEM Taha Yassine ", + "license": "MIT", + "bugs": { + "url": "https://github.com/openreplay/openreplay/issues" + }, + "homepage": "https://github.com/openreplay/openreplay#readme", + "dependencies": { + "@maxmind/geoip2-node": "^3.4.0", + "@socket.io/redis-adapter": "^7.1.0", + "aws-sdk": "^2.992.0", + "express": "^4.17.1", + "peer": "^0.6.1", + "redis": "^4.0.3", + "socket.io": "^4.4.1", + "source-map": "^0.7.3", + "ua-parser-js": "^1.0.2" + } +} diff --git a/ee/utilities/server.js b/ee/utilities/server.js new file mode 100644 index 000000000..1d9a680b8 --- /dev/null +++ b/ee/utilities/server.js @@ -0,0 +1,58 @@ +var sourcemapsReaderServer = require('./servers/sourcemaps-server'); +var {peerRouter, peerConnection, peerDisconnect, peerError} = require('./servers/peerjs-server'); +var express = require('express'); +const {ExpressPeerServer} = require('peer'); +var socket; +if (process.env.cluster === "true") { + socket = require("./servers/websocket-cluster"); +} else { + socket = require("./servers/websocket"); +} + +const HOST = '0.0.0.0'; +const PORT = 9000; + +var app = express(); +var wsapp = express(); +let debug = process.env.debug === "1" || false; +const request_logger = (identity) => { + return (req, res, next) => { + debug && console.log(identity, new Date().toTimeString(), 'REQUEST', req.method, req.originalUrl); + res.on('finish', function () { + if (this.statusCode !== 200 || debug) { + console.log(new Date().toTimeString(), 'RESPONSE', req.method, req.originalUrl, this.statusCode); + } + }) + + next(); + } +}; +app.use(request_logger("[app]")); +wsapp.use(request_logger("[wsapp]")); + +app.use('/sourcemaps', sourcemapsReaderServer); +app.use('/assist', peerRouter); +wsapp.use('/assist', socket.wsRouter); + +const server = app.listen(PORT, HOST, () => { + console.log(`App listening on http://${HOST}:${PORT}`); + console.log('Press Ctrl+C to quit.'); +}); +const wsserver = wsapp.listen(PORT + 1, HOST, () => { + console.log(`WS App listening on http://${HOST}:${PORT + 1}`); + console.log('Press Ctrl+C to quit.'); +}); +const peerServer = ExpressPeerServer(server, { + debug: true, + path: '/', + proxied: true, + allow_discovery: false +}); +peerServer.on('connection', peerConnection); +peerServer.on('disconnect', peerDisconnect); +peerServer.on('error', peerError); +app.use('/', peerServer); +app.enable('trust proxy'); +wsapp.enable('trust proxy'); +socket.start(wsserver); +module.exports = {wsserver, server}; diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js new file mode 100644 index 000000000..5811c4d13 --- /dev/null +++ b/ee/utilities/servers/websocket-cluster.js @@ -0,0 +1,308 @@ +const _io = require('socket.io'); +const express = require('express'); +const uaParser = require('ua-parser-js'); +const geoip2Reader = require('@maxmind/geoip2-node').Reader; +const {extractPeerId} = require('./peerjs-server'); +const {createAdapter} = require("@socket.io/redis-adapter"); +const {createClient} = require("redis"); + +var wsRouter = express.Router(); +const IDENTITIES = {agent: 'agent', session: 'session'}; +const NEW_AGENT = "NEW_AGENT"; +const NO_AGENTS = "NO_AGENT"; +const AGENT_DISCONNECT = "AGENT_DISCONNECTED"; +const AGENTS_CONNECTED = "AGENTS_CONNECTED"; +const NO_SESSIONS = "SESSION_DISCONNECTED"; +const SESSION_ALREADY_CONNECTED = "SESSION_ALREADY_CONNECTED"; +// const wsReconnectionTimeout = process.env.wsReconnectionTimeout | 10 * 1000; + +let io; +const debug = process.env.debug === "1" || false; +const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379"; + +const pubClient = createClient({url: REDIS_URL}); +const subClient = pubClient.duplicate(); + +const uniqueSessions = function (data) { + let resArr = []; + let resArrIDS = []; + for (let item of data) { + if (resArrIDS.indexOf(item.sessionID) < 0) { + resArr.push(item); + resArrIDS.push(item.sessionID); + } + } + return resArr; +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, async function (req, res) { + debug && console.log("[WS]looking for all available sessions"); + let liveSessions = {}; + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey !== undefined) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(sessionId); + } + } + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions})); +}); +wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, async function (req, res) { + debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); + let liveSessions = {}; + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey === req.params.projectKey) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(sessionId); + } + } + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); +}); + +wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { + debug && console.log("[WS]looking for all available LIVE sessions"); + let liveSessions = {}; + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey !== undefined) { + let connected_sockets = await io.in(peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(item.handshake.query.sessionInfo); + } + } + liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); + } + } + + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions})); +}); +wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function (req, res) { + debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); + let liveSessions = {}; + let rooms = await io.of('/').adapter.allRooms(); + for (let peerId of rooms) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey === req.params.projectKey) { + let connected_sockets = await io.in(peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(item.handshake.query.sessionInfo); + } + } + liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); + } + } + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); +}); + +const findSessionSocketId = async (io, peerId) => { + const connected_sockets = await io.in(peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + return item.id; + } + } + return null; +}; + +async function sessions_agents_count(io, socket) { + let c_sessions = 0, c_agents = 0; + let rooms = await io.of('/').adapter.allRooms(); + if (rooms.has(socket.peerId)) { + const connected_sockets = await io.in(socket.peerId).fetchSockets(); + + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + c_sessions++; + } else { + c_agents++; + } + } + } else { + c_agents = -1; + c_sessions = -1; + } + return {c_sessions, c_agents}; +} + +async function get_all_agents_ids(io, socket) { + let agents = []; + let rooms = await io.of('/').adapter.allRooms(); + if (rooms.has(socket.peerId)) { + const connected_sockets = await io.in(socket.peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.agent) { + agents.push(item.id); + } + } + } + return agents; +} + +function extractSessionInfo(socket) { + if (socket.handshake.query.sessionInfo !== undefined) { + debug && console.log("received headers"); + debug && console.log(socket.handshake.headers); + socket.handshake.query.sessionInfo = JSON.parse(socket.handshake.query.sessionInfo); + + let ua = uaParser(socket.handshake.headers['user-agent']); + socket.handshake.query.sessionInfo.userOs = ua.os.name || null; + socket.handshake.query.sessionInfo.userBrowser = ua.browser.name || null; + socket.handshake.query.sessionInfo.userBrowserVersion = ua.browser.version || null; + socket.handshake.query.sessionInfo.userDevice = ua.device.model || null; + socket.handshake.query.sessionInfo.userDeviceType = ua.device.type || 'desktop'; + socket.handshake.query.sessionInfo.userCountry = null; + + const options = { + // you can use options like `cache` or `watchForUpdates` + }; + // console.log("Looking for MMDB file in " + process.env.MAXMINDDB_FILE); + geoip2Reader.open(process.env.MAXMINDDB_FILE, options) + .then(reader => { + debug && console.log("looking for location of "); + debug && console.log(socket.handshake.headers['x-forwarded-for'] || socket.handshake.address); + let country = reader.country(socket.handshake.headers['x-forwarded-for'] || socket.handshake.address); + socket.handshake.query.sessionInfo.userCountry = country.country.isoCode; + }) + .catch(error => { + console.error(error); + }); + } +} + +module.exports = { + wsRouter, + start: (server) => { + io = _io(server, { + maxHttpBufferSize: 1e6, + cors: { + origin: "*", + methods: ["GET", "POST", "PUT"] + }, + path: '/socket' + }); + + io.on('connection', async (socket) => { + debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`); + socket.peerId = socket.handshake.query.peerId; + socket.identity = socket.handshake.query.identity; + let {projectKey, sessionId} = extractPeerId(socket.peerId); + socket.sessionId = sessionId; + socket.projectKey = projectKey; + socket.lastMessageReceivedAt = Date.now(); + let {c_sessions, c_agents} = await sessions_agents_count(io, socket); + if (socket.identity === IDENTITIES.session) { + if (c_sessions > 0) { + debug && console.log(`session already connected, refusing new connexion`); + io.to(socket.id).emit(SESSION_ALREADY_CONNECTED); + return socket.disconnect(); + } + extractSessionInfo(socket); + if (c_agents > 0) { + debug && console.log(`notifying new session about agent-existence`); + let agents_ids = await get_all_agents_ids(io, socket); + io.to(socket.id).emit(AGENTS_CONNECTED, agents_ids); + } + + } else if (c_sessions <= 0) { + debug && console.log(`notifying new agent about no SESSIONS`); + io.to(socket.id).emit(NO_SESSIONS); + } + socket.join(socket.peerId); + let rooms = await io.of('/').adapter.allRooms(); + if (rooms.has(socket.peerId)) { + let connectedSockets = await io.in(socket.peerId).fetchSockets(); + debug && console.log(`${socket.id} joined room:${socket.peerId}, as:${socket.identity}, members:${connectedSockets.length}`); + } + if (socket.identity === IDENTITIES.agent) { + if (socket.handshake.query.agentInfo !== undefined) { + socket.handshake.query.agentInfo = JSON.parse(socket.handshake.query.agentInfo); + } + socket.to(socket.peerId).emit(NEW_AGENT, socket.id, socket.handshake.query.agentInfo); + } + + socket.on('disconnect', async () => { + debug && console.log(`${socket.id} disconnected from ${socket.peerId}`); + if (socket.identity === IDENTITIES.agent) { + socket.to(socket.peerId).emit(AGENT_DISCONNECT, socket.id); + } + debug && console.log("checking for number of connected agents and sessions"); + let {c_sessions, c_agents} = await sessions_agents_count(io, socket); + if (c_sessions === -1 && c_agents === -1) { + debug && console.log(`room not found: ${socket.peerId}`); + } + if (c_sessions === 0) { + debug && console.log(`notifying everyone in ${socket.peerId} about no SESSIONS`); + socket.to(socket.peerId).emit(NO_SESSIONS); + } + if (c_agents === 0) { + debug && console.log(`notifying everyone in ${socket.peerId} about no AGENTS`); + socket.to(socket.peerId).emit(NO_AGENTS); + } + }); + + socket.onAny(async (eventName, ...args) => { + socket.lastMessageReceivedAt = Date.now(); + if (socket.identity === IDENTITIES.session) { + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to room:${socket.peerId}`); + socket.to(socket.peerId).emit(eventName, args[0]); + } else { + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to session of room:${socket.peerId}`); + let socketId = await findSessionSocketId(io, socket.peerId); + if (socketId === null) { + debug && console.log(`session not found for:${socket.peerId}`); + io.to(socket.id).emit(NO_SESSIONS); + } else { + debug && console.log("message sent"); + io.to(socketId).emit(eventName, socket.id, args[0]); + } + } + }); + + }); + console.log("WS server started") + setInterval(async (io) => { + try { + let rooms = await io.of('/').adapter.allRooms(); + let validRooms = []; + console.log(` ====== Rooms: ${rooms.size} ====== `); + const arr = Array.from(rooms) + // const filtered = arr.filter(room => !room[1].has(room[0])) + for (let i of rooms) { + let {projectKey, sessionId} = extractPeerId(i); + if (projectKey !== undefined && sessionId !== undefined) { + validRooms.push(i); + } + } + console.log(` ====== Valid Rooms: ${validRooms.length} ====== `); + if (debug) { + for (let item of validRooms) { + let connectedSockets = await io.in(item).fetchSockets(); + console.log(`Room: ${item} connected: ${connectedSockets.length}`) + } + } + } catch (e) { + console.error(e); + } + }, 20000, io); + Promise.all([pubClient.connect(), subClient.connect()]).then(() => { + io.adapter(createAdapter(pubClient, subClient)); + console.log("> redis connected."); + // io.listen(3000); + }); + } +}; \ No newline at end of file diff --git a/utilities/package-lock.json b/utilities/package-lock.json index bafdf340f..5ff7612c2 100644 --- a/utilities/package-lock.json +++ b/utilities/package-lock.json @@ -10,15 +10,12 @@ "license": "MIT", "dependencies": { "@maxmind/geoip2-node": "^3.4.0", - "@socket.io/redis-adapter": "^7.1.0", "aws-sdk": "^2.992.0", "express": "^4.17.1", "peer": "^0.6.1", - "redis": "^4.0.3", "socket.io": "^4.4.1", "source-map": "^0.7.3", - "ua-parser-js": "^1.0.2", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.6.0" + "ua-parser-js": "^1.0.2" } }, "node_modules/@maxmind/geoip2-node": { @@ -32,60 +29,6 @@ "maxmind": "^4.2.0" } }, - "node_modules/@node-redis/bloom": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", - "integrity": "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==", - "peerDependencies": { - "@node-redis/client": "^1.0.0" - } - }, - "node_modules/@node-redis/client": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", - "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", - "dependencies": { - "cluster-key-slot": "1.1.0", - "generic-pool": "3.8.2", - "redis-parser": "3.0.0", - "yallist": "4.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@node-redis/graph": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@node-redis/graph/-/graph-1.0.0.tgz", - "integrity": "sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==", - "peerDependencies": { - "@node-redis/client": "^1.0.0" - } - }, - "node_modules/@node-redis/json": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@node-redis/json/-/json-1.0.2.tgz", - "integrity": "sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==", - "peerDependencies": { - "@node-redis/client": "^1.0.0" - } - }, - "node_modules/@node-redis/search": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", - "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", - "peerDependencies": { - "@node-redis/client": "^1.0.0" - } - }, - "node_modules/@node-redis/time-series": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", - "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", - "peerDependencies": { - "@node-redis/client": "^1.0.0" - } - }, "node_modules/@socket.io/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -94,41 +37,6 @@ "node": ">= 0.6.0" } }, - "node_modules/@socket.io/redis-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", - "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", - "dependencies": { - "debug": "~4.3.1", - "notepack.io": "~2.2.0", - "socket.io-adapter": "~2.3.0", - "uid2": "0.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@socket.io/redis-adapter/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@socket.io/redis-adapter/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -396,14 +304,6 @@ "wrap-ansi": "^6.2.0" } }, - "node_modules/cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -715,14 +615,6 @@ "node": ">= 0.6" } }, - "node_modules/generic-pool": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", - "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", - "engines": { - "node": ">= 4" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -937,11 +829,6 @@ "node": ">= 0.6" } }, - "node_modules/notepack.io": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", - "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1113,38 +1000,6 @@ "node": ">= 0.8" } }, - "node_modules/redis": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", - "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", - "dependencies": { - "@node-redis/bloom": "1.0.1", - "@node-redis/client": "1.0.3", - "@node-redis/graph": "1.0.0", - "@node-redis/json": "1.0.2", - "@node-redis/search": "1.0.2", - "@node-redis/time-series": "1.0.1" - } - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1398,11 +1253,6 @@ "node": "*" } }, - "node_modules/uid2": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", - "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1437,10 +1287,6 @@ "uuid": "bin/uuid" } }, - "node_modules/uWebSockets.js": { - "version": "20.6.0", - "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#a58e810e47a23696410f6073c8c905dc38f75da5" - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1522,11 +1368,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", @@ -1573,78 +1414,11 @@ "maxmind": "^4.2.0" } }, - "@node-redis/bloom": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", - "integrity": "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==", - "requires": {} - }, - "@node-redis/client": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", - "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", - "requires": { - "cluster-key-slot": "1.1.0", - "generic-pool": "3.8.2", - "redis-parser": "3.0.0", - "yallist": "4.0.0" - } - }, - "@node-redis/graph": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@node-redis/graph/-/graph-1.0.0.tgz", - "integrity": "sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==", - "requires": {} - }, - "@node-redis/json": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@node-redis/json/-/json-1.0.2.tgz", - "integrity": "sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==", - "requires": {} - }, - "@node-redis/search": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", - "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", - "requires": {} - }, - "@node-redis/time-series": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", - "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", - "requires": {} - }, "@socket.io/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" }, - "@socket.io/redis-adapter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/redis-adapter/-/redis-adapter-7.1.0.tgz", - "integrity": "sha512-vbsNJKUQgtVHcOqNL2ac8kSemTVNKHRzYPldqQJt0eFKvlAtAviuAMzBP0WmOp5OoRLQMjhVsVvgMzzMsVsK5g==", - "requires": { - "debug": "~4.3.1", - "notepack.io": "~2.2.0", - "socket.io-adapter": "~2.3.0", - "uid2": "0.0.3" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -1858,11 +1632,6 @@ "wrap-ansi": "^6.2.0" } }, - "cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2097,11 +1866,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, - "generic-pool": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", - "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==" - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2257,11 +2021,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, - "notepack.io": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.2.0.tgz", - "integrity": "sha512-9b5w3t5VSH6ZPosoYnyDONnUTF8o0UkBw7JLA6eBlYJWyGT1Q3vQa8Hmuj1/X6RYvHjjygBDgw6fJhe0JEojfw==" - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2379,32 +2138,6 @@ "unpipe": "1.0.0" } }, - "redis": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", - "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", - "requires": { - "@node-redis/bloom": "1.0.1", - "@node-redis/client": "1.0.3", - "@node-redis/graph": "1.0.0", - "@node-redis/json": "1.0.2", - "@node-redis/search": "1.0.2", - "@node-redis/time-series": "1.0.1" - } - }, - "redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" - }, - "redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", - "requires": { - "redis-errors": "^1.0.0" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2593,11 +2326,6 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==" }, - "uid2": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", - "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2622,10 +2350,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, - "uWebSockets.js": { - "version": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#a58e810e47a23696410f6073c8c905dc38f75da5", - "from": "uWebSockets.js@github:uNetworking/uWebSockets.js#v20.6.0" - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2681,11 +2405,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", diff --git a/utilities/package.json b/utilities/package.json index 87e1d1596..452c3fe00 100644 --- a/utilities/package.json +++ b/utilities/package.json @@ -19,14 +19,11 @@ "homepage": "https://github.com/openreplay/openreplay#readme", "dependencies": { "@maxmind/geoip2-node": "^3.4.0", - "@socket.io/redis-adapter": "^7.1.0", "aws-sdk": "^2.992.0", "express": "^4.17.1", "peer": "^0.6.1", - "redis": "^4.0.3", "socket.io": "^4.4.1", "source-map": "^0.7.3", - "ua-parser-js": "^1.0.2", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.6.0" + "ua-parser-js": "^1.0.2" } } diff --git a/utilities/servers/websocket.js b/utilities/servers/websocket.js index 5811c4d13..ab6a2c4d5 100644 --- a/utilities/servers/websocket.js +++ b/utilities/servers/websocket.js @@ -2,10 +2,7 @@ const _io = require('socket.io'); const express = require('express'); const uaParser = require('ua-parser-js'); const geoip2Reader = require('@maxmind/geoip2-node').Reader; -const {extractPeerId} = require('./peerjs-server'); -const {createAdapter} = require("@socket.io/redis-adapter"); -const {createClient} = require("redis"); - +var {extractPeerId} = require('./peerjs-server'); var wsRouter = express.Router(); const IDENTITIES = {agent: 'agent', session: 'session'}; const NEW_AGENT = "NEW_AGENT"; @@ -17,28 +14,11 @@ const SESSION_ALREADY_CONNECTED = "SESSION_ALREADY_CONNECTED"; // const wsReconnectionTimeout = process.env.wsReconnectionTimeout | 10 * 1000; let io; -const debug = process.env.debug === "1" || false; -const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379"; - -const pubClient = createClient({url: REDIS_URL}); -const subClient = pubClient.duplicate(); - -const uniqueSessions = function (data) { - let resArr = []; - let resArrIDS = []; - for (let item of data) { - if (resArrIDS.indexOf(item.sessionID) < 0) { - resArr.push(item); - resArrIDS.push(item.sessionID); - } - } - return resArr; -} -wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, async function (req, res) { +let debug = process.env.debug === "1" || false; +wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, function (req, res) { debug && console.log("[WS]looking for all available sessions"); let liveSessions = {}; - let rooms = await io.of('/').adapter.allRooms(); - for (let peerId of rooms) { + for (let peerId of io.sockets.adapter.rooms.keys()) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey !== undefined) { liveSessions[projectKey] = liveSessions[projectKey] || []; @@ -49,11 +29,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, async function (req, res) { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions})); }); -wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, async function (req, res) { +wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, function (req, res) { debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); let liveSessions = {}; - let rooms = await io.of('/').adapter.allRooms(); - for (let peerId of rooms) { + for (let peerId of io.sockets.adapter.rooms.keys()) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey === req.params.projectKey) { liveSessions[projectKey] = liveSessions[projectKey] || []; @@ -68,8 +47,7 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, async function ( wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { debug && console.log("[WS]looking for all available LIVE sessions"); let liveSessions = {}; - let rooms = await io.of('/').adapter.allRooms(); - for (let peerId of rooms) { + for (let peerId of io.sockets.adapter.rooms.keys()) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey !== undefined) { let connected_sockets = await io.in(peerId).fetchSockets(); @@ -79,7 +57,6 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { liveSessions[projectKey].push(item.handshake.query.sessionInfo); } } - liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); } } @@ -90,8 +67,7 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function (req, res) { debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); let liveSessions = {}; - let rooms = await io.of('/').adapter.allRooms(); - for (let peerId of rooms) { + for (let peerId of io.sockets.adapter.rooms.keys()) { let {projectKey, sessionId} = extractPeerId(peerId); if (projectKey === req.params.projectKey) { let connected_sockets = await io.in(peerId).fetchSockets(); @@ -101,7 +77,6 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function ( liveSessions[projectKey].push(item.handshake.query.sessionInfo); } } - liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); } } res.statusCode = 200; @@ -121,8 +96,7 @@ const findSessionSocketId = async (io, peerId) => { async function sessions_agents_count(io, socket) { let c_sessions = 0, c_agents = 0; - let rooms = await io.of('/').adapter.allRooms(); - if (rooms.has(socket.peerId)) { + if (io.sockets.adapter.rooms.get(socket.peerId)) { const connected_sockets = await io.in(socket.peerId).fetchSockets(); for (let item of connected_sockets) { @@ -141,8 +115,7 @@ async function sessions_agents_count(io, socket) { async function get_all_agents_ids(io, socket) { let agents = []; - let rooms = await io.of('/').adapter.allRooms(); - if (rooms.has(socket.peerId)) { + if (io.sockets.adapter.rooms.get(socket.peerId)) { const connected_sockets = await io.in(socket.peerId).fetchSockets(); for (let item of connected_sockets) { if (item.handshake.query.identity === IDENTITIES.agent) { @@ -200,7 +173,7 @@ module.exports = { debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`); socket.peerId = socket.handshake.query.peerId; socket.identity = socket.handshake.query.identity; - let {projectKey, sessionId} = extractPeerId(socket.peerId); + const {projectKey, sessionId} = extractPeerId(socket.peerId); socket.sessionId = sessionId; socket.projectKey = projectKey; socket.lastMessageReceivedAt = Date.now(); @@ -223,10 +196,8 @@ module.exports = { io.to(socket.id).emit(NO_SESSIONS); } socket.join(socket.peerId); - let rooms = await io.of('/').adapter.allRooms(); - if (rooms.has(socket.peerId)) { - let connectedSockets = await io.in(socket.peerId).fetchSockets(); - debug && console.log(`${socket.id} joined room:${socket.peerId}, as:${socket.identity}, members:${connectedSockets.length}`); + if (io.sockets.adapter.rooms.get(socket.peerId)) { + debug && console.log(`${socket.id} joined room:${socket.peerId}, as:${socket.identity}, members:${io.sockets.adapter.rooms.get(socket.peerId).size}`); } if (socket.identity === IDENTITIES.agent) { if (socket.handshake.query.agentInfo !== undefined) { @@ -258,10 +229,10 @@ module.exports = { socket.onAny(async (eventName, ...args) => { socket.lastMessageReceivedAt = Date.now(); if (socket.identity === IDENTITIES.session) { - debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to room:${socket.peerId}`); + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to room:${socket.peerId}, members: ${io.sockets.adapter.rooms.get(socket.peerId).size}`); socket.to(socket.peerId).emit(eventName, args[0]); } else { - debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to session of room:${socket.peerId}`); + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to session of room:${socket.peerId}, members:${io.sockets.adapter.rooms.get(socket.peerId).size}`); let socketId = await findSessionSocketId(io, socket.peerId); if (socketId === null) { debug && console.log(`session not found for:${socket.peerId}`); @@ -275,34 +246,27 @@ module.exports = { }); console.log("WS server started") - setInterval(async (io) => { + setInterval((io) => { try { - let rooms = await io.of('/').adapter.allRooms(); - let validRooms = []; - console.log(` ====== Rooms: ${rooms.size} ====== `); - const arr = Array.from(rooms) - // const filtered = arr.filter(room => !room[1].has(room[0])) - for (let i of rooms) { - let {projectKey, sessionId} = extractPeerId(i); - if (projectKey !== undefined && sessionId !== undefined) { - validRooms.push(i); + let count = 0; + console.log(` ====== Rooms: ${io.sockets.adapter.rooms.size} ====== `); + const arr = Array.from(io.sockets.adapter.rooms) + const filtered = arr.filter(room => !room[1].has(room[0])) + for (let i of filtered) { + let {projectKey, sessionId} = extractPeerId(i[0]); + if (projectKey !== null && sessionId !== null) { + count++; } } - console.log(` ====== Valid Rooms: ${validRooms.length} ====== `); + console.log(` ====== Valid Rooms: ${count} ====== `); if (debug) { - for (let item of validRooms) { - let connectedSockets = await io.in(item).fetchSockets(); - console.log(`Room: ${item} connected: ${connectedSockets.length}`) + for (let item of filtered) { + console.log(`Room: ${item[0]} connected: ${item[1].size}`) } } } catch (e) { console.error(e); } }, 20000, io); - Promise.all([pubClient.connect(), subClient.connect()]).then(() => { - io.adapter(createAdapter(pubClient, subClient)); - console.log("> redis connected."); - // io.listen(3000); - }); } }; \ No newline at end of file From 07ca75bb2dafb218b4be174b7b927525b6afce0a Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 22 Feb 2022 21:14:12 +0100 Subject: [PATCH 003/101] feat(utilities): redis-remote-join --- ee/utilities/servers/websocket-cluster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index 5811c4d13..8d8eec061 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -222,7 +222,7 @@ module.exports = { debug && console.log(`notifying new agent about no SESSIONS`); io.to(socket.id).emit(NO_SESSIONS); } - socket.join(socket.peerId); + io.adapter.remoteJoin(socket.peerId); let rooms = await io.of('/').adapter.allRooms(); if (rooms.has(socket.peerId)) { let connectedSockets = await io.in(socket.peerId).fetchSockets(); From 5cbc366d1105d54ba02c8b16bee4bc4bf42cfe6e Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Wed, 23 Feb 2022 13:01:26 +0100 Subject: [PATCH 004/101] chore(websocket): enabling consistent hashing for sticky load balancing Signed-off-by: rjshrjndrn --- .../nginx-ingress/templates/configMap.yaml | 15 ++++++++------ .../charts/utilities/templates/service.yaml | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/configMap.yaml b/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/configMap.yaml index f5b7699cd..f6ba1842f 100644 --- a/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/configMap.yaml +++ b/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/configMap.yaml @@ -82,7 +82,7 @@ data: proxy_set_header Host $host; proxy_set_header X-Forwarded-For $origin_forwarded_ip; proxy_set_header X-Real-IP $real_ip; - proxy_pass http://utilities-openreplay.app.svc.cluster.local:9001; + proxy_pass http://utilities-pool; } location /assets/ { rewrite ^/assets/(.*) /sessions-assets/$1 break; @@ -139,7 +139,7 @@ data: # Need real ip address for flags in replay. # Some LBs will forward real ips as x-forwarded-for # So making that as priority - map $http_x_forwarded_for $real_ip { + map $http_x_forwarded_for $origin_forwarded_ip { ~^(\d+\.\d+\.\d+\.\d+) $1; default $remote_addr; } @@ -151,10 +151,6 @@ data: default $http_x_forwarded_proto; '' $scheme; } - map $http_x_forwarded_for $origin_forwarded_ip { - default $http_x_forwarded_for; - '' $remote_addr; - } # Default server for helath check server { listen 80 default_server; @@ -163,6 +159,13 @@ data: return 200 'OK'; } } + + upstream utilities-pool { + server utilities-openreplay-headless.app:9001; + # enable sticky session with either "hash" (uses the complete IP address) + hash $origin_forwarded_ip consistent; + } + server { listen 80; listen [::]:80; diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/service.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/service.yaml index 9ec9f18cf..8b1dc8753 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/service.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/service.yaml @@ -15,3 +15,23 @@ spec: {{- end}} selector: {{- include "utilities.selectorLabels" . | nindent 4 }} + +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "utilities.fullname" . }}-headless + labels: + {{- include "utilities.labels" . | nindent 4 }} +spec: + type: ClusterIP + clusterIP: None + ports: + {{- range $key, $val := .Values.service.ports }} + - port: {{ $val }} + targetPort: {{ $key }} + protocol: TCP + name: {{ $key }} + {{- end}} + selector: + {{- include "utilities.selectorLabels" . | nindent 4 }} From 108452d05cb910b67980207a6c41bee9365c4cd7 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 23 Feb 2022 14:18:12 +0100 Subject: [PATCH 005/101] feat(utilities): fixed redis-remote-join --- ee/utilities/servers/websocket-cluster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index 8d8eec061..fbbed93e6 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -222,7 +222,7 @@ module.exports = { debug && console.log(`notifying new agent about no SESSIONS`); io.to(socket.id).emit(NO_SESSIONS); } - io.adapter.remoteJoin(socket.peerId); + await io.of('/').adapter.remoteJoin(socket.id, socket.peerId); let rooms = await io.of('/').adapter.allRooms(); if (rooms.has(socket.peerId)) { let connectedSockets = await io.in(socket.peerId).fetchSockets(); From 207638fca2bd97fd0db23a77474b91cbe36d7091 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 23 Feb 2022 14:32:45 +0100 Subject: [PATCH 006/101] feat(utilities): changed extractPeerId to validate project_key length --- utilities/servers/peerjs-server.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/utilities/servers/peerjs-server.js b/utilities/servers/peerjs-server.js index b139e0104..434e5f4bc 100644 --- a/utilities/servers/peerjs-server.js +++ b/utilities/servers/peerjs-server.js @@ -1,11 +1,16 @@ var express = require('express'); var peerRouter = express.Router(); - +let PROJECT_KEY_LENGTH = parseInt(process.env.PROJECT_KEY_LENGTH) || 20; +let debug = process.env.debug === "1" || false; const extractPeerId = (peerId) => { let splited = peerId.split("-"); if (splited.length !== 2) { - console.error(`cannot split peerId: ${peerId}`); + debug && console.error(`cannot split peerId: ${peerId}`); + return {}; + } + if (PROJECT_KEY_LENGTH > 0 && splited[0].length !== PROJECT_KEY_LENGTH) { + debug && console.error(`wrong project key length for peerId: ${peerId}`); return {}; } return {projectKey: splited[0], sessionId: splited[1]}; @@ -13,30 +18,30 @@ const extractPeerId = (peerId) => { const connectedPeers = {}; const peerConnection = (client) => { - console.log(`initiating ${client.id}`); + debug && console.log(`initiating ${client.id}`); const {projectKey, sessionId} = extractPeerId(client.id); if (projectKey === undefined || sessionId === undefined) { return; } connectedPeers[projectKey] = connectedPeers[projectKey] || []; if (connectedPeers[projectKey].indexOf(sessionId) === -1) { - console.log(`new connexion ${client.id}`); + debug && console.log(`new connexion ${client.id}`); connectedPeers[projectKey].push(sessionId); } else { - console.log(`reconnecting peer ${client.id}`); + debug && console.log(`reconnecting peer ${client.id}`); } }; const peerDisconnect = (client) => { - console.log(`disconnect ${client.id}`); + debug && console.log(`disconnect ${client.id}`); const {projectKey, sessionId} = extractPeerId(client.id); if (projectKey === undefined || sessionId === undefined) { return; } const i = (connectedPeers[projectKey] || []).indexOf(sessionId); if (i === -1) { - console.log(`session not found ${client.id}`); + debug && console.log(`session not found ${client.id}`); } else { connectedPeers[projectKey].splice(i, 1); } @@ -49,13 +54,13 @@ const peerError = (error) => { peerRouter.get(`/${process.env.S3_KEY}/peers`, function (req, res) { - console.log("looking for all available sessions"); + debug && console.log("looking for all available sessions"); res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": connectedPeers})); }); peerRouter.get(`/${process.env.S3_KEY}/peers/:projectKey`, function (req, res) { - console.log(`looking for available sessions for ${req.params.projectKey}`); + debug && console.log(`looking for available sessions for ${req.params.projectKey}`); res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": connectedPeers[req.params.projectKey] || []})); From 2ce6ffbd9665a68ffd1df12d35ccdd526491ce76 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 23 Feb 2022 14:36:12 +0100 Subject: [PATCH 007/101] feat(utilities): WS configurable maxHttpBufferSize --- ee/utilities/servers/websocket-cluster.js | 2 +- utilities/servers/websocket.js | 2 +- utilities/servers/websocket_back.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index fbbed93e6..ef16241a9 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -188,7 +188,7 @@ module.exports = { wsRouter, start: (server) => { io = _io(server, { - maxHttpBufferSize: 1e6, + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 1) * 1e6, cors: { origin: "*", methods: ["GET", "POST", "PUT"] diff --git a/utilities/servers/websocket.js b/utilities/servers/websocket.js index ab6a2c4d5..28d2626a6 100644 --- a/utilities/servers/websocket.js +++ b/utilities/servers/websocket.js @@ -161,7 +161,7 @@ module.exports = { wsRouter, start: (server) => { io = _io(server, { - maxHttpBufferSize: 1e6, + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 1) * 1e6, cors: { origin: "*", methods: ["GET", "POST", "PUT"] diff --git a/utilities/servers/websocket_back.js b/utilities/servers/websocket_back.js index ab6a2c4d5..28d2626a6 100644 --- a/utilities/servers/websocket_back.js +++ b/utilities/servers/websocket_back.js @@ -161,7 +161,7 @@ module.exports = { wsRouter, start: (server) => { io = _io(server, { - maxHttpBufferSize: 1e6, + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 1) * 1e6, cors: { origin: "*", methods: ["GET", "POST", "PUT"] From 29d3e130b683a44a9cc86a0022558859bfdac6ce Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 23 Feb 2022 16:31:10 +0100 Subject: [PATCH 008/101] feat(utilities): changed default maxHttpBufferSize --- ee/utilities/servers/websocket-cluster.js | 2 +- utilities/servers/websocket.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index ef16241a9..175c0bab1 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -188,7 +188,7 @@ module.exports = { wsRouter, start: (server) => { io = _io(server, { - maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 1) * 1e6, + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, cors: { origin: "*", methods: ["GET", "POST", "PUT"] diff --git a/utilities/servers/websocket.js b/utilities/servers/websocket.js index 28d2626a6..1941611f9 100644 --- a/utilities/servers/websocket.js +++ b/utilities/servers/websocket.js @@ -161,7 +161,7 @@ module.exports = { wsRouter, start: (server) => { io = _io(server, { - maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 1) * 1e6, + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, cors: { origin: "*", methods: ["GET", "POST", "PUT"] From 3281c4ecacfd848693c14781538c8a44d1021afd Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 24 Feb 2022 20:32:07 +0100 Subject: [PATCH 009/101] feat(api): definition of metric_type feat(db): definition of metric_type --- api/schemas.py | 13 ++++++++++ .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 26 +++++++++++++++++++ .../db/init_dbs/postgresql/init_schema.sql | 18 +++++++------ .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 26 +++++++++++++++++++ .../db/init_dbs/postgresql/init_schema.sql | 19 +++++++------- 5 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql create mode 100644 scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql diff --git a/api/schemas.py b/api/schemas.py index 400dd94cc..e78f6054a 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -702,6 +702,17 @@ class MetricViewType(str, Enum): progress = "progress" +class MetricType(str, Enum): + timeseries = "timeseries" + table = "table" + + +# class MetricTypeTableGroupField(str, Enum): +# users = "USERS" +# click_rage = IssueType.click_rage +# dead_click = IssueType.dead_click + + class CustomMetricRawPayloadSchema(BaseModel): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) @@ -719,6 +730,8 @@ class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): endDate: int = Field(TimeUTC.now()) density: int = Field(7) viewType: MetricViewType = Field(MetricViewType.line_chart) + metricType: MetricType = Field(MetricType.timeseries) + groupField: Optional[Union[FilterType]] = Field(None) class CustomMetricChartPayloadSchema2(CustomMetricChartPayloadSchema): diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql new file mode 100644 index 000000000..bb24fae51 --- /dev/null +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -0,0 +1,26 @@ +BEGIN; +CREATE OR REPLACE FUNCTION openreplay_version() + RETURNS text AS +$$ +SELECT 'v1.5.X-ee' +$$ LANGUAGE sql IMMUTABLE; + +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE nsp.nspname = current_schema() + AND typ.typname = 'metric_type') THEN + CREATE TYPE metric_type AS ENUM ('timeseries','table'); + END IF; + END; +$$ +LANGUAGE plpgsql; + +ALTER TABLE metrics + ADD COLUMN IF NOT EXISTS + metric_type metric_type NOT NULL DEFAULT 'timeseries'; +COMMIT; \ No newline at end of file diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index b64376d10..00b533f16 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -770,16 +770,18 @@ $$ CREATE INDEX IF NOT EXISTS traces_user_id_idx ON traces (user_id); CREATE INDEX IF NOT EXISTS traces_tenant_id_idx ON traces (tenant_id); + CREATE TYPE metric_type AS ENUM ('timeseries','table'); CREATE TABLE IF NOT EXISTS metrics ( - metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, - project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, - user_id integer REFERENCES users (user_id) ON DELETE SET NULL, - name text NOT NULL, - is_public boolean NOT NULL DEFAULT FALSE, - active boolean NOT NULL DEFAULT TRUE, - created_at timestamp default timezone('utc'::text, now()) not null, - deleted_at timestamp + metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, + project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, + user_id integer REFERENCES users (user_id) ON DELETE SET NULL, + name text NOT NULL, + is_public boolean NOT NULL DEFAULT FALSE, + active boolean NOT NULL DEFAULT TRUE, + created_at timestamp default timezone('utc'::text, now()) not null, + deleted_at timestamp, + metric_type metric_type NOT NULL DEFAULT 'timeseries' ); CREATE INDEX IF NOT EXISTS metrics_user_id_is_public_idx ON public.metrics (user_id, is_public); CREATE TABLE IF NOT EXISTS metric_series diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql new file mode 100644 index 000000000..9c5878fd4 --- /dev/null +++ b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -0,0 +1,26 @@ +BEGIN; +CREATE OR REPLACE FUNCTION openreplay_version() + RETURNS text AS +$$ +SELECT 'v1.5.X' +$$ LANGUAGE sql IMMUTABLE; + +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE nsp.nspname = current_schema() + AND typ.typname = 'metric_type') THEN + CREATE TYPE metric_type AS ENUM ('timeseries','table'); + END IF; + END; +$$ +LANGUAGE plpgsql; + +ALTER TABLE metrics + ADD COLUMN IF NOT EXISTS + metric_type metric_type NOT NULL DEFAULT 'timeseries'; +COMMIT; \ No newline at end of file diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index e053063c2..14a495ada 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -881,7 +881,6 @@ $$ CREATE INDEX autocomplete_type_idx ON public.autocomplete (type); CREATE INDEX autocomplete_value_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops); --- --- jobs.sql --- CREATE TYPE job_status AS ENUM ('scheduled','running','cancelled','failed','completed'); CREATE TYPE job_action AS ENUM ('delete_user_data'); CREATE TABLE jobs @@ -901,16 +900,18 @@ $$ CREATE INDEX jobs_start_at_idx ON jobs (start_at); CREATE INDEX jobs_project_id_idx ON jobs (project_id); + CREATE TYPE metric_type AS ENUM ('timeseries','table'); CREATE TABLE metrics ( - metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, - project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, - user_id integer REFERENCES users (user_id) ON DELETE SET NULL, - name text NOT NULL, - is_public boolean NOT NULL DEFAULT FALSE, - active boolean NOT NULL DEFAULT TRUE, - created_at timestamp default timezone('utc'::text, now()) not null, - deleted_at timestamp + metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, + project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, + user_id integer REFERENCES users (user_id) ON DELETE SET NULL, + name text NOT NULL, + is_public boolean NOT NULL DEFAULT FALSE, + active boolean NOT NULL DEFAULT TRUE, + created_at timestamp default timezone('utc'::text, now()) not null, + deleted_at timestamp, + metric_type metric_type NOT NULL DEFAULT 'timeseries' ); CREATE INDEX metrics_user_id_is_public_idx ON public.metrics (user_id, is_public); CREATE TABLE metric_series From 1a55f9a897e0b075e8656933a3ed1702b091e414 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 25 Feb 2022 15:19:24 +0100 Subject: [PATCH 010/101] feat(ui) - subfilters - wip --- .../FilterAutoComplete/FilterAutoComplete.tsx | 20 ++++--- .../shared/Filters/FilterItem/FilterItem.tsx | 55 ++++++++++++++++--- .../Filters/SubFilterItem/SubFilterItem.tsx | 34 ++++++++++++ .../shared/Filters/SubFilterItem/index.ts | 1 + .../shared/FunnelSearch/FunnelSearch.tsx | 6 -- .../shared/SessionSearch/SessionSearch.tsx | 6 -- frontend/app/duck/filters.js | 14 +---- frontend/app/duck/search.js | 6 +- frontend/app/types/filter/filterType.ts | 5 ++ frontend/app/types/filter/index.js | 20 +------ frontend/app/types/filter/newFilter.js | 35 ++++++------ 11 files changed, 123 insertions(+), 79 deletions(-) create mode 100644 frontend/app/components/shared/Filters/SubFilterItem/SubFilterItem.tsx create mode 100644 frontend/app/components/shared/Filters/SubFilterItem/index.ts diff --git a/frontend/app/components/shared/Filters/FilterAutoComplete/FilterAutoComplete.tsx b/frontend/app/components/shared/Filters/FilterAutoComplete/FilterAutoComplete.tsx index 333188b3e..92baa3d51 100644 --- a/frontend/app/components/shared/Filters/FilterAutoComplete/FilterAutoComplete.tsx +++ b/frontend/app/components/shared/Filters/FilterAutoComplete/FilterAutoComplete.tsx @@ -47,15 +47,17 @@ function FilterAutoComplete(props: Props) { const requestValues = (q) => { setLoading(true); - return new APIClient()[method?.toLowerCase()](endpoint, { ...params, q }) - .then(response => response.json()) - .then(({ errors, data }) => { - if (errors) { - // this.setError(); - } else { - setOptions(data); - } - }).finally(() => setLoading(false)); + return new APIClient()[method?.toLocaleLowerCase()](endpoint, { ...params, q }) + .then(response => { + if (response.ok) { + return response.json(); + } + throw new Error(response.statusText); + }) + .then(({ data }) => { + setOptions(data); + }) + .finally(() => setLoading(false)); } const debouncedRequestValues = React.useCallback(debounce(requestValues, 300), []); diff --git a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx index db0bedf32..f01fefcd8 100644 --- a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx +++ b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx @@ -4,6 +4,8 @@ import FilterSelection from '../FilterSelection'; import FilterValue from '../FilterValue'; import { Icon } from 'UI'; import FilterSource from '../FilterSource'; +import { FilterType } from 'App/types/filter/filterType'; +import SubFilterItem from '../SubFilterItem'; interface Props { filterIndex: number; @@ -15,9 +17,14 @@ interface Props { function FilterItem(props: Props) { const { isFilter = false, filterIndex, filter } = props; const canShowValues = !(filter.operator === "isAny" || filter.operator === "onAny" || filter.operator === "isUndefined"); + const isSubFilter = filter.type === FilterType.SUB_FILTERS; const replaceFilter = (filter) => { - props.onUpdate({ ...filter, value: [""]}); + props.onUpdate({ + ...filter, + value: [""], + subFilters: filter.subFilters ? filter.subFilters.map(i => ({ ...i, value: [""] })) : [] + }); }; const onOperatorChange = (e, { name, value }) => { @@ -28,6 +35,19 @@ function FilterItem(props: Props) { props.onUpdate({ ...filter, sourceOperator: value }) } + const onUpdateSubFilter = (subFilter, subFilterIndex) => { + props.onUpdate({ + ...filter, + subFilters: filter.subFilters.map((i, index) => { + if (index === subFilterIndex) { + return subFilter; + } + return i; + }) + }); + }; + + return (
@@ -48,14 +68,31 @@ function FilterItem(props: Props) { )} {/* Filter values */} - - { canShowValues && () } - + { !isSubFilter && ( + <> + + { canShowValues && () } + + )} + + {/* SubFilters */} + {isSubFilter && ( +
+ {filter.subFilters.map((subFilter, subFilterIndex) => ( + onUpdateSubFilter(f, subFilterIndex)} + onRemoveFilter={props.onRemoveFilter} + /> + ))} +
+ )}
void; + onRemoveFilter: () => void; + isFilter?: boolean; +} +export default function SubFilterItem(props: Props) { + const { isFilter = false, filterIndex, filter } = props; + const canShowValues = !(filter.operator === "isAny" || filter.operator === "onAny" || filter.operator === "isUndefined"); + + const onOperatorChange = (e, { name, value }) => { + props.onUpdate({ ...filter, operator: value }) + } + + return ( +
+
{filter.label}
+ + + { canShowValues && () } +
+ ) +} diff --git a/frontend/app/components/shared/Filters/SubFilterItem/index.ts b/frontend/app/components/shared/Filters/SubFilterItem/index.ts new file mode 100644 index 000000000..0877700cc --- /dev/null +++ b/frontend/app/components/shared/Filters/SubFilterItem/index.ts @@ -0,0 +1 @@ +export { default } from './SubFilterItem'; \ No newline at end of file diff --git a/frontend/app/components/shared/FunnelSearch/FunnelSearch.tsx b/frontend/app/components/shared/FunnelSearch/FunnelSearch.tsx index 809eb739f..19a3b7ceb 100644 --- a/frontend/app/components/shared/FunnelSearch/FunnelSearch.tsx +++ b/frontend/app/components/shared/FunnelSearch/FunnelSearch.tsx @@ -18,12 +18,6 @@ function FunnelSearch(props: Props) { const onAddFilter = (filter) => { props.addFilter(filter); - // filter.value = [""] - // const newFilters = appliedFilter.filters.concat(filter); - // props.edit({ - // ...appliedFilter.filter, - // filters: newFilters, - // }); } const onUpdateFilter = (filterIndex, filter) => { diff --git a/frontend/app/components/shared/SessionSearch/SessionSearch.tsx b/frontend/app/components/shared/SessionSearch/SessionSearch.tsx index 264786fff..17904c1ba 100644 --- a/frontend/app/components/shared/SessionSearch/SessionSearch.tsx +++ b/frontend/app/components/shared/SessionSearch/SessionSearch.tsx @@ -19,12 +19,6 @@ function SessionSearch(props: Props) { const onAddFilter = (filter) => { props.addFilter(filter); - // filter.value = [""] - // const newFilters = appliedFilter.filters.concat(filter); - // props.edit({ - // ...appliedFilter.filter, - // filters: newFilters, - // }); } const onUpdateFilter = (filterIndex, filter) => { diff --git a/frontend/app/duck/filters.js b/frontend/app/duck/filters.js index 132996797..16c16aa5e 100644 --- a/frontend/app/duck/filters.js +++ b/frontend/app/duck/filters.js @@ -1,4 +1,4 @@ -import { fromJS, List, Map, Set } from 'immutable'; +import { List, Map, Set } from 'immutable'; import { errors as errorsRoute, isRoute } from "App/routes"; import Filter from 'Types/filter'; import SavedFilter from 'Types/filter/savedFilter'; @@ -8,15 +8,6 @@ import withRequestState, { RequestTypes } from './requestStateCreator'; import { fetchList as fetchSessionList } from './sessions'; import { fetchList as fetchErrorsList } from './errors'; import { fetchListType, fetchType, saveType, editType, initType, removeType } from './funcTools/crud/types'; -import logger from 'App/logger'; - -import { newFiltersList } from 'Types/filter' -import NewFilter, { filtersMap } from 'Types/filter/newFilter'; - - -// for (var i = 0; i < newFiltersList.length; i++) { -// filterOptions[newFiltersList[i].category] = newFiltersList.filter(filter => filter.category === newFiltersList[i].category) -// } const ERRORS_ROUTE = errorsRoute(); @@ -44,11 +35,8 @@ const ADD_ATTRIBUTE = 'filters/ADD_ATTRIBUTE'; const EDIT_ATTRIBUTE = 'filters/EDIT_ATTRIBUTE'; const REMOVE_ATTRIBUTE = 'filters/REMOVE_ATTRIBUTE'; const SET_ACTIVE_FLOW = 'filters/SET_ACTIVE_FLOW'; - const UPDATE_VALUE = 'filters/UPDATE_VALUE'; -const REFRESH_FILTER_OPTIONS = 'filters/REFRESH_FILTER_OPTIONS'; - const initialState = Map({ instance: Filter(), activeFilter: null, diff --git a/frontend/app/duck/search.js b/frontend/app/duck/search.js index ad4ea944c..00799e5d7 100644 --- a/frontend/app/duck/search.js +++ b/frontend/app/duck/search.js @@ -161,7 +161,7 @@ export const applySavedSearch = (filter) => (dispatch, getState) => { export const fetchSessions = (filter) => (dispatch, getState) => { const _filter = filter ? filter : getState().getIn([ 'search', 'instance']); - return dispatch(applyFilter(_filter)); + // return dispatch(applyFilter(_filter)); // TODO uncomment this line }; export const updateSeries = (index, series) => ({ @@ -233,6 +233,10 @@ export const hasFilterApplied = (filters, filter) => { export const addFilter = (filter) => (dispatch, getState) => { filter.value = checkFilterValue(filter.value); + filter.subFilters = filter.subFilters ? filter.subFilters.map(subFilter => ({ + ...subFilter, + value: checkFilterValue(subFilter.value), + })) : null; const instance = getState().getIn([ 'search', 'instance']); if (hasFilterApplied(instance.filters, filter)) { diff --git a/frontend/app/types/filter/filterType.ts b/frontend/app/types/filter/filterType.ts index 16f128975..655681796 100644 --- a/frontend/app/types/filter/filterType.ts +++ b/frontend/app/types/filter/filterType.ts @@ -15,6 +15,7 @@ export enum FilterType { NUMBER = "NUMBER", DURATION = "DURATION", MULTIPLE = "MULTIPLE", + SUB_FILTERS = "SUB_FILTERS", COUNTRY = "COUNTRY", DROPDOWN = "DROPDOWN", MULTIPLE_DROPDOWN = "MULTIPLE_DROPDOWN", @@ -61,4 +62,8 @@ export enum FilterKey { AVG_CPU_LOAD = "AVG_CPU_LOAD", AVG_MEMORY_USAGE = "AVG_MEMORY_USAGE", FETCH_FAILED = "FETCH_FAILED", + FETCH = "FETCH", + FETCH_URL = "FETCH_URL", + FETCH_STATUS = "FETCH_STATUS", + FETCH_METHOD = "FETCH_METHOD", } \ No newline at end of file diff --git a/frontend/app/types/filter/index.js b/frontend/app/types/filter/index.js index 957e1dfb8..386ea96a0 100644 --- a/frontend/app/types/filter/index.js +++ b/frontend/app/types/filter/index.js @@ -236,22 +236,4 @@ export const operatorOptions = (filter) => { case KEYS.CLICK_RAGE: return [{ key: 'onAnything', text: 'on anything', value: 'true' }] } -} - -const NewFilterType = (key, category, label, icon, isEvent = false) => { - return { - key: key, - category: category, - label: label, - icon: icon, - isEvent: isEvent, - operators: operatorOptions({ key }), - value: [""] - } -} - -export const newFiltersList = [ - NewFilterType(TYPES.CLICK, 'Gear', 'Click', 'filters/click', true), - NewFilterType(TYPES.CLICK, 'Gear', 'Input', 'filters/click', true), - NewFilterType(TYPES.CONSOLE, 'Other', 'Console', 'filters/click', true), -]; \ No newline at end of file +} \ No newline at end of file diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index d4cb905a1..99726b4a6 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -48,6 +48,11 @@ export const filtersMap = { [FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'User AnonymousId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' }, // PERFORMANCE + [FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.SUB_FILTERS, category: FilterCategory.PERFORMANCE, label: 'Fetch Request', subFilters: [ + { key: FilterKey.FETCH_URL, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with URL', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, + { key: FilterKey.FETCH_STATUS, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with status code', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, + { key: FilterKey.FETCH_METHOD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with method', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, + ], icon: 'filters/fetch-failed', isEvent: true }, [FilterKey.DOM_COMPLETE]: { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'DOM Complete', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/dom-complete', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, [FilterKey.LARGEST_CONTENTFUL_PAINT_TIME]: { key: FilterKey.LARGEST_CONTENTFUL_PAINT_TIME, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Largest Contentful Paint', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/lcpt', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, [FilterKey.TTFB]: { key: FilterKey.TTFB, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Time to First Byte', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/ttfb', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, @@ -121,17 +126,19 @@ export default Record({ isEvent: false, index: 0, options: [], + + subFilters: [], }, { keyKey: "_key", fromJS: ({ value, key, type, ...filter }) => { - // const _filter = filtersMap[key] || filtersMap[type] || {}; const _filter = filtersMap[type]; return { ...filter, ..._filter, key: _filter.key, type: _filter.type, // camelCased(filter.type.toLowerCase()), - value: value.length === 0 ? [""] : value, // make sure there an empty value + value: value.length === 0 ? [""] : value, + // subFilters: filter.subFilters.map(this), } }, }) @@ -142,33 +149,29 @@ export default Record({ * @returns */ export const generateFilterOptions = (map) => { - const _options = {}; + const filterSection = {}; Object.keys(map).forEach(key => { const filter = map[key]; - if (_options.hasOwnProperty(filter.category)) { - _options[filter.category].push(filter); + if (filterSection.hasOwnProperty(filter.category)) { + filterSection[filter.category].push(filter); } else { - _options[filter.category] = [filter]; + filterSection[filter.category] = [filter]; } }); - return _options; + return filterSection; } export const generateLiveFilterOptions = (map) => { - const _options = {}; + const filterSection = {}; Object.keys(map).filter(i => map[i].isLive).forEach(key => { const filter = map[key]; filter.operator = 'contains'; - // filter.type = FilterType.STRING; - // filter.type = FilterType.AUTOCOMPLETE_LOCAL; - // filter.options = countryOptions; - // filter.operatorOptions = [{ key: 'contains', text: 'contains', value: 'contains' }] - if (_options.hasOwnProperty(filter.category)) { - _options[filter.category].push(filter); + if (filterSection.hasOwnProperty(filter.category)) { + filterSection[filter.category].push(filter); } else { - _options[filter.category] = [filter]; + filterSection[filter.category] = [filter]; } }); - return _options; + return filterSection; } \ No newline at end of file From df5772d487376eec6a8df8a543169aed756c433a Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 25 Feb 2022 18:09:47 +0100 Subject: [PATCH 011/101] feat(api): custom metrics for user_os, user_browser, user_device, user_country, user_id --- api/chalicelib/core/custom_metrics.py | 14 +++-- api/chalicelib/core/sessions.py | 88 +++++++++++++++++++-------- api/schemas.py | 10 ++- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index eb918b222..c0370083f 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -6,20 +6,22 @@ from chalicelib.utils import helper, pg_client from chalicelib.utils.TimeUTC import TimeUTC -def try_live(project_id, data: schemas.TryCustomMetricsSchema): +def __try_live(project_id, data: schemas.TryCustomMetricsSchema): results = [] for i, s in enumerate(data.series): s.filter.startDate = data.startDate s.filter.endDate = data.endDate results.append(sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, - view_type=data.viewType)) + view_type=data.viewType, metric_type=data.metricType, + metric_of=data.metricOf)) if data.viewType == schemas.MetricViewType.progress: r = {"count": results[-1]} diff = s.filter.endDate - s.filter.startDate s.filter.startDate = data.endDate s.filter.endDate = data.endDate - diff r["previousCount"] = sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, - view_type=data.viewType) + view_type=data.viewType, metric_type=data.metricType, + metric_of=data.metricOf) r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) r["seriesName"] = s.name if s.name else i + 1 r["seriesId"] = s.series_id if s.series_id else None @@ -28,8 +30,8 @@ def try_live(project_id, data: schemas.TryCustomMetricsSchema): def merged_live(project_id, data: schemas.TryCustomMetricsSchema): - series_charts = try_live(project_id=project_id, data=data) - if data.viewType == schemas.MetricViewType.progress: + series_charts = __try_live(project_id=project_id, data=data) + if data.viewType == schemas.MetricViewType.progress or data.metricType == schemas.MetricType.table: return series_charts results = [{}] * len(series_charts[0]) for i in range(len(results)): @@ -44,7 +46,7 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa if metric is None: return None metric: schemas.TryCustomMetricsSchema = schemas.TryCustomMetricsSchema.parse_obj({**data.dict(), **metric}) - series_charts = try_live(project_id=project_id, data=metric) + series_charts = __try_live(project_id=project_id, data=metric) if data.viewType == schemas.MetricViewType.progress: return series_charts results = [{}] * len(series_charts[0]) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index d180cccc7..bedabe70e 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -198,7 +198,7 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f ROW_NUMBER() OVER (ORDER BY count(full_sessions) DESC) AS rn FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY start_ts DESC) AS rn FROM (SELECT DISTINCT ON(s.session_id) {SESSION_PROJECTION_COLS} - {"," if len(meta_keys)>0 else ""}{",".join([f'metadata_{m["index"]}' for m in meta_keys])} + {"," if len(meta_keys) > 0 else ""}{",".join([f'metadata_{m["index"]}' for m in meta_keys])} {query_part} ORDER BY s.session_id desc) AS filtred_sessions ORDER BY favorite DESC, issue_score DESC, {sort} {data.order}) AS full_sessions @@ -210,7 +210,7 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f main_query = cur.mogrify(f"""SELECT COUNT(full_sessions) AS count, COALESCE(JSONB_AGG(full_sessions) FILTER (WHERE rn <= 200), '[]'::JSONB) AS sessions FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY favorite DESC, issue_score DESC, session_id desc, start_ts desc) AS rn FROM (SELECT DISTINCT ON(s.session_id) {SESSION_PROJECTION_COLS} - {"," if len(meta_keys)>0 else ""}{",".join([f'metadata_{m["index"]}' for m in meta_keys])} + {"," if len(meta_keys) > 0 else ""}{",".join([f'metadata_{m["index"]}' for m in meta_keys])} {query_part} ORDER BY s.session_id desc) AS filtred_sessions ORDER BY favorite DESC, issue_score DESC, {sort} {data.order}) AS full_sessions;""", @@ -264,40 +264,74 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f } -@dev.timed def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, density: int, - view_type: schemas.MetricViewType): + view_type: schemas.MetricViewType, metric_type: schemas.MetricType, metric_of: schemas.MetricOfType): step_size = int(metrics_helper.__get_step_size(endTimestamp=data.endDate, startTimestamp=data.startDate, density=density, factor=1, decimal=True)) full_args, query_part, sort = search_query_parts(data=data, error_status=None, errors_only=False, favorite_only=False, issue=None, project_id=project_id, user_id=None) full_args["step_size"] = step_size + sessions = [] with pg_client.PostgresClient() as cur: - if view_type == schemas.MetricViewType.line_chart: - main_query = cur.mogrify(f"""WITH full_sessions AS (SELECT DISTINCT ON(s.session_id) s.session_id, s.start_ts - {query_part}) - SELECT generated_timestamp AS timestamp, - COUNT(s) AS count - FROM generate_series(%(startDate)s, %(endDate)s, %(step_size)s) AS generated_timestamp - LEFT JOIN LATERAL ( SELECT 1 AS s - FROM full_sessions - WHERE start_ts >= generated_timestamp - AND start_ts <= generated_timestamp + %(step_size)s) AS sessions ON (TRUE) - GROUP BY generated_timestamp - ORDER BY generated_timestamp;""", full_args) - else: - main_query = cur.mogrify(f"""SELECT count(DISTINCT s.session_id) AS count - {query_part};""", full_args) + if metric_type == schemas.MetricType.timeseries: + if view_type == schemas.MetricViewType.line_chart: + main_query = cur.mogrify(f"""WITH full_sessions AS (SELECT DISTINCT ON(s.session_id) s.session_id, s.start_ts + {query_part}) + SELECT generated_timestamp AS timestamp, + COUNT(s) AS count + FROM generate_series(%(startDate)s, %(endDate)s, %(step_size)s) AS generated_timestamp + LEFT JOIN LATERAL ( SELECT 1 AS s + FROM full_sessions + WHERE start_ts >= generated_timestamp + AND start_ts <= generated_timestamp + %(step_size)s) AS sessions ON (TRUE) + GROUP BY generated_timestamp + ORDER BY generated_timestamp;""", full_args) + else: + main_query = cur.mogrify(f"""SELECT count(DISTINCT s.session_id) AS count + {query_part};""", full_args) + + # print("--------------------") + # print(main_query) + cur.execute(main_query) + # print("--------------------") + if view_type == schemas.MetricViewType.line_chart: + sessions = cur.fetchall() + else: + sessions = cur.fetchone()["count"] + elif metric_type == schemas.MetricType.table: + if isinstance(metric_of, schemas.MetricOfType): + main_col = "user_id" + if metric_of == schemas.MetricOfType.user_country: + main_col = "user_country" + elif metric_of == schemas.MetricOfType.user_device: + main_col = "user_device" + elif metric_of == schemas.MetricOfType.user_browser: + main_col = "user_browser" + main_query = cur.mogrify(f"""SELECT COUNT(*) AS count, COALESCE(JSONB_AGG(users_sessions) FILTER ( WHERE rn <= 200 ), '[]'::JSONB) AS values + FROM (SELECT {main_col} AS name, + count(full_sessions) AS session_count, + ROW_NUMBER() OVER (ORDER BY count(full_sessions) DESC) AS rn + FROM (SELECT * + FROM (SELECT DISTINCT ON(s.session_id) s.session_id, s.user_uuid, + s.user_id, s.user_os, + s.user_browser, s.user_device, + s.user_device_type, s.user_country + {query_part} + ORDER BY s.session_id desc) AS filtred_sessions + ) AS full_sessions + GROUP BY {main_col} + ORDER BY session_count DESC) AS users_sessions;""", + full_args) + # print("--------------------") + # print(main_query) + # print("--------------------") + cur.execute(main_query) + sessions = cur.fetchone() + for s in sessions["values"]: + s.pop("rn") + sessions["values"] = helper.list_to_camel_case(sessions["values"]) - # print("--------------------") - # print(main_query) - cur.execute(main_query) - # print("--------------------") - if view_type == schemas.MetricViewType.line_chart: - sessions = cur.fetchall() - else: - sessions = cur.fetchone()["count"] return sessions diff --git a/api/schemas.py b/api/schemas.py index e78f6054a..812dca5cd 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -725,13 +725,21 @@ class CustomMetricRawPayloadSchema2(CustomMetricRawPayloadSchema): metric_id: int = Field(...) +class MetricOfType(str, Enum): + user_os = FilterType.user_os + user_browser = FilterType.user_browser + user_device = FilterType.user_device + user_country = FilterType.user_country + user_id = FilterType.user_id + + class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) density: int = Field(7) viewType: MetricViewType = Field(MetricViewType.line_chart) metricType: MetricType = Field(MetricType.timeseries) - groupField: Optional[Union[FilterType]] = Field(None) + metricOf: MetricOfType = Field(MetricOfType.user_id) class CustomMetricChartPayloadSchema2(CustomMetricChartPayloadSchema): From e35f3a7b9f564f8729789a7eaaf5bde190f743d3 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 25 Feb 2022 19:58:23 +0100 Subject: [PATCH 012/101] feat(api): custom metrics for issues --- api/chalicelib/core/sessions.py | 6 +++++- api/schemas.py | 11 ++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index bedabe70e..caedc4ff7 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -302,12 +302,16 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d elif metric_type == schemas.MetricType.table: if isinstance(metric_of, schemas.MetricOfType): main_col = "user_id" + extra_col = "" if metric_of == schemas.MetricOfType.user_country: main_col = "user_country" elif metric_of == schemas.MetricOfType.user_device: main_col = "user_device" elif metric_of == schemas.MetricOfType.user_browser: main_col = "user_browser" + elif metric_of == schemas.MetricOfType.issues: + main_col = "issue" + extra_col = f", UNNEST(s.issue_types) AS {main_col}" main_query = cur.mogrify(f"""SELECT COUNT(*) AS count, COALESCE(JSONB_AGG(users_sessions) FILTER ( WHERE rn <= 200 ), '[]'::JSONB) AS values FROM (SELECT {main_col} AS name, count(full_sessions) AS session_count, @@ -316,7 +320,7 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d FROM (SELECT DISTINCT ON(s.session_id) s.session_id, s.user_uuid, s.user_id, s.user_os, s.user_browser, s.user_device, - s.user_device_type, s.user_country + s.user_device_type, s.user_country, s.issue_types{extra_col} {query_part} ORDER BY s.session_id desc) AS filtred_sessions ) AS full_sessions diff --git a/api/schemas.py b/api/schemas.py index 812dca5cd..780bd0191 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -726,11 +726,12 @@ class CustomMetricRawPayloadSchema2(CustomMetricRawPayloadSchema): class MetricOfType(str, Enum): - user_os = FilterType.user_os - user_browser = FilterType.user_browser - user_device = FilterType.user_device - user_country = FilterType.user_country - user_id = FilterType.user_id + user_os = FilterType.user_os.value + user_browser = FilterType.user_browser.value + user_device = FilterType.user_device.value + user_country = FilterType.user_country.value + user_id = FilterType.user_id.value + issues = FilterType.issue.value class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): From 5b84ada80967c93bdb4e7e5ff4483d7b5d0a3210 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 25 Feb 2022 21:53:35 +0100 Subject: [PATCH 013/101] feat(api): custom metrics table for VISITED_URL --- api/chalicelib/core/sessions.py | 29 +++++++++++++++++++++++------ api/schemas.py | 3 +++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index caedc4ff7..0beec7aae 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -268,9 +268,12 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d view_type: schemas.MetricViewType, metric_type: schemas.MetricType, metric_of: schemas.MetricOfType): step_size = int(metrics_helper.__get_step_size(endTimestamp=data.endDate, startTimestamp=data.startDate, density=density, factor=1, decimal=True)) + extra_event = None + if metric_of == schemas.MetricOfType.visited_url: + extra_event = "events.pages" full_args, query_part, sort = search_query_parts(data=data, error_status=None, errors_only=False, favorite_only=False, issue=None, project_id=project_id, - user_id=None) + user_id=None, extra_event=extra_event) full_args["step_size"] = step_size sessions = [] with pg_client.PostgresClient() as cur: @@ -303,6 +306,7 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d if isinstance(metric_of, schemas.MetricOfType): main_col = "user_id" extra_col = "" + pre_query = "" if metric_of == schemas.MetricOfType.user_country: main_col = "user_country" elif metric_of == schemas.MetricOfType.user_device: @@ -312,7 +316,14 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d elif metric_of == schemas.MetricOfType.issues: main_col = "issue" extra_col = f", UNNEST(s.issue_types) AS {main_col}" - main_query = cur.mogrify(f"""SELECT COUNT(*) AS count, COALESCE(JSONB_AGG(users_sessions) FILTER ( WHERE rn <= 200 ), '[]'::JSONB) AS values + elif metric_of == schemas.MetricOfType.visited_url: + main_col = "base_path" + extra_col = ", base_path" + # elif metric_of == schemas.MetricOfType.initial_page_load_time: + # main_col = "issue" + # extra_col = f", UNNEST(s.issue_types) AS {main_col}" + main_query = cur.mogrify(f"""{pre_query} + SELECT COUNT(*) AS count, COALESCE(JSONB_AGG(users_sessions) FILTER ( WHERE rn <= 200 ), '[]'::JSONB) AS values FROM (SELECT {main_col} AS name, count(full_sessions) AS session_count, ROW_NUMBER() OVER (ORDER BY count(full_sessions) DESC) AS rn @@ -321,15 +332,17 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d s.user_id, s.user_os, s.user_browser, s.user_device, s.user_device_type, s.user_country, s.issue_types{extra_col} + ----------------- {query_part} + ----------------- ORDER BY s.session_id desc) AS filtred_sessions ) AS full_sessions GROUP BY {main_col} ORDER BY session_count DESC) AS users_sessions;""", full_args) - # print("--------------------") - # print(main_query) - # print("--------------------") + print("--------------------") + print(main_query) + print("--------------------") cur.execute(main_query) sessions = cur.fetchone() for s in sessions["values"]: @@ -339,7 +352,7 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d return sessions -def search_query_parts(data, error_status, errors_only, favorite_only, issue, project_id, user_id): +def search_query_parts(data, error_status, errors_only, favorite_only, issue, project_id, user_id, extra_event=None): ss_constraints = [] full_args = {"project_id": project_id, "startDate": data.startDate, "endDate": data.endDate, "projectId": project_id, "userId": user_id} @@ -894,6 +907,10 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr """ full_args["issue_contextString"] = issue["contextString"] full_args["issue_type"] = issue["type"] + if extra_event: + extra_join += f"""INNER JOIN {extra_event} AS ev USING(session_id)""" + extra_constraints.append("ev.timestamp>=%(startDate)s") + extra_constraints.append("ev.timestamp<=%(endDate)s") query_part = f"""\ FROM {f"({events_query_part}) AS f" if len(events_query_part) > 0 else "public.sessions AS s"} {extra_join} diff --git a/api/schemas.py b/api/schemas.py index 780bd0191..b341a45fb 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -732,6 +732,8 @@ class MetricOfType(str, Enum): user_country = FilterType.user_country.value user_id = FilterType.user_id.value issues = FilterType.issue.value + initial_page_load_time = "INITIAL_PAGE_LOAD_TIME" + visited_url = "VISITED_URL" class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): @@ -741,6 +743,7 @@ class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): viewType: MetricViewType = Field(MetricViewType.line_chart) metricType: MetricType = Field(MetricType.timeseries) metricOf: MetricOfType = Field(MetricOfType.user_id) + metricFraction: float = Field(None, gt=0, lt=1) class CustomMetricChartPayloadSchema2(CustomMetricChartPayloadSchema): From 0791744de770cd6256d20fa1b70a2603a6036c76 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Sun, 27 Feb 2022 12:15:51 +0100 Subject: [PATCH 014/101] feat(ui) - custommetrics - wip --- .../CustomMetricForm/CustomMetricForm.tsx | 32 +++++++++++++++++-- .../shared/DropdownPlain/DropdownPlain.tsx | 7 ++-- frontend/app/constants/filterOptions.js | 16 ++++++++++ frontend/app/types/customMetric.js | 4 ++- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index 7700a7a29..fd95cd5c6 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -7,6 +7,8 @@ import CustomMetricWidgetPreview from 'App/components/Dashboard/Widgets/CustomMe import { confirm } from 'UI/Confirmation'; import { toast } from 'react-toastify'; import cn from 'classnames'; +import DropdownPlain from '../../DropdownPlain'; +import { metricTypes, metricOf } from 'App/constants/filterOptions'; interface Props { metric: any; @@ -21,6 +23,7 @@ interface Props { function CustomMetricForm(props: Props) { const { metric, loading } = props; + const metricOfOptions = metricOf.filter(i => i.key === metric.metricType); const addSeries = () => { props.addSeries(); @@ -30,7 +33,8 @@ function CustomMetricForm(props: Props) { props.removeSeries(index); } - const write = ({ target: { value, name } }) => props.editMetric({ ...metric, [ name ]: value }, false); + const write = ({ target: { value, name } }) => props.editMetric({ [ name ]: value }, false); + const writeOption = (e, { value, name }) => props.editMetric({ [ name ]: value }, false); const changeConditionTab = (e, { name, value }) => { props.editMetric({[ 'viewType' ]: value }); @@ -79,6 +83,30 @@ function CustomMetricForm(props: Props) {
+ + of + + showing + +
+ {/*
Timeseries of
@@ -95,7 +123,7 @@ function CustomMetricForm(props: Props) { ]} />
-
+
*/}
diff --git a/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx b/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx index f4f21b1c8..d3313ac3e 100644 --- a/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx +++ b/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx @@ -3,6 +3,7 @@ import stl from './DropdownPlain.css'; import { Dropdown, Icon } from 'UI'; interface Props { + name?: string; options: any[]; onChange: (e, { name, value }) => void; icon?: string; @@ -11,17 +12,19 @@ interface Props { } export default function DropdownPlain(props: Props) { - const { value, options, icon = "chevron-down", direction = "left" } = props; + const { name = "sort", value, options, icon = "chevron-down", direction = "left" } = props; return (
: null } /> diff --git a/frontend/app/constants/filterOptions.js b/frontend/app/constants/filterOptions.js index 868379e86..215832c1a 100644 --- a/frontend/app/constants/filterOptions.js +++ b/frontend/app/constants/filterOptions.js @@ -54,6 +54,20 @@ export const customOperators = [ { key: '>=', text: '>=', value: '>=' }, ] +export const metricTypes = [ + { text: 'Timeseries', value: 'timeseries' }, + { text: 'Table', value: 'table' }, +]; + +export const metricOf = [ + { text: 'Session Count', value: 'sessionCount', key: 'timeseries' }, + { text: 'Users', value: 'users', key: 'table' }, + { text: 'Rage Click', value: 'rageClick', key: 'table' }, + { text: 'Dead Click', value: 'deadClick', key: 'table' }, + { text: 'Browser', value: 'browser', key: 'table' }, + { text: 'Device', value: 'device', key: 'table' }, +] + export default { options, baseOperators, @@ -62,4 +76,6 @@ export default { booleanOperators, customOperators, getOperatorsByKeys, + metricTypes, + metricOf, } \ No newline at end of file diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index d5238a0aa..902c10a23 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -27,7 +27,9 @@ export const FilterSeries = Record({ export default Record({ metricId: undefined, name: 'Series', - viewType: 'lineChart', + metricType: 'timeseries', + metricOf: 'sessionCount', + viewType: 'sessionCount', series: List(), isPublic: true, startDate: '', From 33e000efc6fefdc990b75a8c8af64b045b7e7f51 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 27 Feb 2022 21:35:09 +0100 Subject: [PATCH 015/101] fix (tracker-assist): 3.5.2: resume action-control on a new page --- tracker/tracker-assist/package-lock.json | 2 +- tracker/tracker-assist/package.json | 2 +- tracker/tracker-assist/src/Assist.ts | 41 +++++++++++++++++------- tracker/tracker-assist/tsconfig.json | 2 +- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/tracker/tracker-assist/package-lock.json b/tracker/tracker-assist/package-lock.json index 45f467ba7..db1a0b7e2 100644 --- a/tracker/tracker-assist/package-lock.json +++ b/tracker/tracker-assist/package-lock.json @@ -1,6 +1,6 @@ { "name": "@openreplay/tracker-assist", - "version": "3.5.0", + "version": "3.5.1-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tracker/tracker-assist/package.json b/tracker/tracker-assist/package.json index bb2edd4ab..358bc3b40 100644 --- a/tracker/tracker-assist/package.json +++ b/tracker/tracker-assist/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker-assist", "description": "Tracker plugin for screen assistance through the WebRTC", - "version": "3.5.0", + "version": "3.5.2", "keywords": [ "WebRTC", "assistance", diff --git a/tracker/tracker-assist/src/Assist.ts b/tracker/tracker-assist/src/Assist.ts index f9e010559..96f3f1997 100644 --- a/tracker/tracker-assist/src/Assist.ts +++ b/tracker/tracker-assist/src/Assist.ts @@ -18,6 +18,7 @@ export interface Options { onAgentConnect: () => ((()=>{}) | void), onCallStart: () => ((()=>{}) | void), session_calling_peer_key: string, + session_control_peer_key: string, callConfirm: ConfirmOptions, controlConfirm: ConfirmOptions, @@ -58,6 +59,7 @@ export default class Assist { ) { this.options = Object.assign({ session_calling_peer_key: "__openreplay_calling_peer", + session_control_peer_key: "__openreplay_control_peer", config: null, onCallStart: ()=>{}, onAgentConnect: ()=>{}, @@ -103,7 +105,8 @@ export default class Assist { "peerId": peerID, "identity": "session", "sessionInfo": JSON.stringify(this.app.getSessionInfo()), - } + }, + transports: ["websocket"], }) socket.onAny((...args) => app.debug.log("Socket:", ...args)) @@ -125,37 +128,53 @@ export default class Assist { this.assistDemandedRestart = true this.app.stop(); this.app.start().then(() => { this.assistDemandedRestart = false }) + const storedControllingAgent = sessionStorage.getItem(this.options.session_control_peer_key) + if (storedControllingAgent !== null && ids.includes(storedControllingAgent)) { + grantControl(storedControllingAgent) + socket.emit("control_granted", storedControllingAgent) + } else { + sessionStorage.removeItem(this.options.session_control_peer_key) + } }) let confirmRC: ConfirmWindow | null = null const mouse = new Mouse() // TODO: lazy init let controllingAgent: string | null = null - function releaseControl() { - confirmRC?.remove() - mouse.remove() - controllingAgent = null - } - socket.on("request_control", (id: string) => { + const requestControl = (id: string) => { if (controllingAgent !== null) { socket.emit("control_rejected", id) return } - controllingAgent = id + controllingAgent = id // TODO: more explicit pending state confirmRC = new ConfirmWindow(controlConfirmDefault(this.options.controlConfirm)) confirmRC.mount().then(allowed => { - if (allowed) { // TODO: per agent id - mouse.mount() + if (allowed) { + grantControl(id) socket.emit("control_granted", id) } else { releaseControl() socket.emit("control_rejected", id) } }).catch() - }) + } + const grantControl = (id: string) => { + controllingAgent = id + mouse.mount() + sessionStorage.setItem(this.options.session_control_peer_key, id) + } + const releaseControl = () => { + confirmRC?.remove() + mouse.remove() + controllingAgent = null + sessionStorage.removeItem(this.options.session_control_peer_key) + } + socket.on("request_control", requestControl) socket.on("release_control", (id: string) => { if (controllingAgent !== id) { return } releaseControl() }) + + socket.on("scroll", (id, d) => { id === controllingAgent && mouse.scroll(d) }) socket.on("click", (id, xy) => { id === controllingAgent && mouse.click(xy) }) socket.on("move", (id, xy) => { id === controllingAgent && mouse.move(xy) }) diff --git a/tracker/tracker-assist/tsconfig.json b/tracker/tracker-assist/tsconfig.json index 95d4f9408..bb8f6a4c4 100644 --- a/tracker/tracker-assist/tsconfig.json +++ b/tracker/tracker-assist/tsconfig.json @@ -5,7 +5,7 @@ "alwaysStrict": true, "target": "es6", "module": "es6", - "moduleResolution": "nodenext", + "moduleResolution": "node", "allowSyntheticDefaultImports": true, "declaration": true, "outDir": "./lib" From 172f5c5211413bb5c2edafb90d301013290f9560 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 27 Feb 2022 21:56:00 +0100 Subject: [PATCH 016/101] feat (tracker-assist): 3.5.3:onRemoteControlStart --- tracker/tracker-assist/package.json | 2 +- tracker/tracker-assist/src/Assist.ts | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tracker/tracker-assist/package.json b/tracker/tracker-assist/package.json index 358bc3b40..63eb23944 100644 --- a/tracker/tracker-assist/package.json +++ b/tracker/tracker-assist/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker-assist", "description": "Tracker plugin for screen assistance through the WebRTC", - "version": "3.5.2", + "version": "3.5.3", "keywords": [ "WebRTC", "assistance", diff --git a/tracker/tracker-assist/src/Assist.ts b/tracker/tracker-assist/src/Assist.ts index 96f3f1997..55ace11a4 100644 --- a/tracker/tracker-assist/src/Assist.ts +++ b/tracker/tracker-assist/src/Assist.ts @@ -14,9 +14,12 @@ import type { Options as ConfirmOptions } from './ConfirmWindow.js'; //@ts-ignore peerjs hack for webpack5 (?!) TODO: ES/node modules; Peer = Peer.default || Peer; +type BehinEndCallback = () => ((()=>{}) | void) + export interface Options { - onAgentConnect: () => ((()=>{}) | void), - onCallStart: () => ((()=>{}) | void), + onAgentConnect: BehinEndCallback, + onCallStart: BehinEndCallback, + onRemoteControlStart: BehinEndCallback, session_calling_peer_key: string, session_control_peer_key: string, callConfirm: ConfirmOptions, @@ -63,6 +66,7 @@ export default class Assist { config: null, onCallStart: ()=>{}, onAgentConnect: ()=>{}, + onRemoteControlStart: ()=>{}, callConfirm: {}, controlConfirm: {}, // TODO: clear options passing/merging/overriting }, @@ -157,12 +161,16 @@ export default class Assist { } }).catch() } + let onRemoteControlStop: (()=>void) | null = null const grantControl = (id: string) => { controllingAgent = id mouse.mount() + onRemoteControlStop = this.options.onRemoteControlStart() || null sessionStorage.setItem(this.options.session_control_peer_key, id) } const releaseControl = () => { + typeof onRemoteControlStop === 'function' && onRemoteControlStop() + onRemoteControlStop = null confirmRC?.remove() mouse.remove() controllingAgent = null From d6039aa9c646287c44f3a3caf620efe1201a3730 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Mon, 28 Feb 2022 15:54:57 +0100 Subject: [PATCH 017/101] feat(tracker-fetch):3.5.1: request & response sanitizers --- tracker/tracker-fetch/package.json | 2 +- tracker/tracker-fetch/src/index.ts | 68 +++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/tracker/tracker-fetch/package.json b/tracker/tracker-fetch/package.json index 1d650bf6e..11e7bf6ff 100644 --- a/tracker/tracker-fetch/package.json +++ b/tracker/tracker-fetch/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker-fetch", "description": "Tracker plugin for fetch requests recording ", - "version": "3.4.1", + "version": "3.5.1", "keywords": [ "fetch", "logging", diff --git a/tracker/tracker-fetch/src/index.ts b/tracker/tracker-fetch/src/index.ts index fbce7ac31..910d20ec7 100644 --- a/tracker/tracker-fetch/src/index.ts +++ b/tracker/tracker-fetch/src/index.ts @@ -1,10 +1,25 @@ import { App, Messages } from '@openreplay/tracker'; +interface Request { + url: string, + body: string | Object, + headers: Record, +} + +interface Response { + url: string, + status: number, + body: string, + headers: Record, +} + export interface Options { sessionTokenHeader?: string; replaceDefault: boolean; // overrideDefault ? failuresOnly: boolean; ignoreHeaders: Array | boolean; + requestSanitizer: ((Request) => Request | null) | null; + responseSanitizer: ((Response) => Response | null) | null; } export default function(opts: Partial = {}) { @@ -13,10 +28,11 @@ export default function(opts: Partial = {}) { replaceDefault: false, failuresOnly: false, ignoreHeaders: [ 'Cookie', 'Set-Cookie', 'Authorization' ], + requestSanitizer: null, + responseSanitizer: null, }, opts, ); - return (app: App | null) => { if (app === null) { return window.fetch; @@ -55,6 +71,7 @@ export default function(opts: Partial = {}) { const r = response.clone(); r.text().then(text => { + // Headers prepearing const reqHs: Record = {} const resHs: Record = {} if (ihOpt !== true) { @@ -71,20 +88,57 @@ export default function(opts: Partial = {}) { r.headers.forEach((v, n) => { if (!isHIgnoring(n)) resHs[n] = v }) } - const req = JSON.stringify({ + + // Request forming + let reqBody = '' + if (typeof init.body === 'string') { + reqBody = init.body + } else if (typeof init.body === 'object') { + try { + reqBody = JSON.stringify(init.body) + } catch {} + } + let req: Request | null = { + url: input, headers: reqHs, - body: typeof init.body === 'string' ? init.body : '', - }) - const res = JSON.stringify({ + body: reqBody, + } + if (options.requestSanitizer !== null) { + req = options.requestSanitizer(req) + if (!req) { + return + } + } + + // Response forming + let res: Response | null = { + url: input, + status: r.status, headers: resHs, body: text, + } + if (options.responseSanitizer !== null) { + res = options.responseSanitizer(res) + if (!res) { + return + } + } + + const reqStr = JSON.stringify({ + headers: req.headers, + body: req.body, }) + const resStr = JSON.stringify({ + headers: res.headers, + body: res.body, + }) + app.send( Messages.Fetch( typeof init.method === 'string' ? init.method.toUpperCase() : 'GET', input, - req, - res, + reqStr, + resStr, r.status, startTime + performance.timing.navigationStart, duration, From 5673b8d8edbf0ef336391a2602d2fb233f1ce863 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Mon, 28 Feb 2022 21:36:23 +0100 Subject: [PATCH 018/101] feat(api): search by request_details 1/2 --- api/chalicelib/core/sessions.py | 54 +++++++++++-------- api/schemas.py | 42 +++++++++++++-- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 38 +++++++++++++ 3 files changed, 110 insertions(+), 24 deletions(-) create mode 100644 scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index 0beec7aae..74b7f7cfa 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -223,11 +223,11 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f # ORDER BY favorite DESC, issue_score DESC, {sort} {order};""", # full_args) - # print("--------------------") - # print(main_query) - + print("--------------------") + print(main_query) + print("--------------------") cur.execute(main_query) - # print("--------------------") + if count_only: return helper.dict_to_camel_case(cur.fetchone()) sessions = cur.fetchone() @@ -319,9 +319,6 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d elif metric_of == schemas.MetricOfType.visited_url: main_col = "base_path" extra_col = ", base_path" - # elif metric_of == schemas.MetricOfType.initial_page_load_time: - # main_col = "issue" - # extra_col = f", UNNEST(s.issue_types) AS {main_col}" main_query = cur.mogrify(f"""{pre_query} SELECT COUNT(*) AS count, COALESCE(JSONB_AGG(users_sessions) FILTER ( WHERE rn <= 200 ), '[]'::JSONB) AS values FROM (SELECT {main_col} AS name, @@ -332,17 +329,15 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d s.user_id, s.user_os, s.user_browser, s.user_device, s.user_device_type, s.user_country, s.issue_types{extra_col} - ----------------- {query_part} - ----------------- ORDER BY s.session_id desc) AS filtred_sessions ) AS full_sessions GROUP BY {main_col} ORDER BY session_count DESC) AS users_sessions;""", full_args) - print("--------------------") - print(main_query) - print("--------------------") + # print("--------------------") + # print(main_query) + # print("--------------------") cur.execute(main_query) sessions = cur.fetchone() for s in sessions["values"]: @@ -788,15 +783,19 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr event_where += ["main2.timestamp >= %(startDate)s", "main2.timestamp <= %(endDate)s"] if event_index > 0 and not or_events: event_where.append("main2.session_id=event_0.session_id") - event_where.append( - _multiple_conditions( - f"main.{getattr(events.event_type, event.value[0].type).column} {s_op} %({e_k1})s", - event.value[0].value, value_key=e_k1)) + is_any = _isAny_opreator(event.value[0].operator) + if not is_any: + event_where.append( + _multiple_conditions( + f"main.{getattr(events.event_type, event.value[0].type).column} {s_op} %({e_k1})s", + event.value[0].value, value_key=e_k1)) s_op = __get_sql_operator(event.value[1].operator) - event_where.append( - _multiple_conditions( - f"main2.{getattr(events.event_type, event.value[1].type).column} {s_op} %({e_k2})s", - event.value[1].value, value_key=e_k2)) + is_any = _isAny_opreator(event.value[1].operator) + if not is_any: + event_where.append( + _multiple_conditions( + f"main2.{getattr(events.event_type, event.value[1].type).column} {s_op} %({e_k2})s", + event.value[1].value, value_key=e_k2)) e_k += "_custom" full_args = {**full_args, **_multiple_values(event.source, value_key=e_k)} @@ -804,7 +803,20 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr _multiple_conditions(f"main2.timestamp - main.timestamp {event.sourceOperator} %({e_k})s", event.source, value_key=e_k)) - + elif event_type==schemas.EventType.request_details: + event_from = event_from % f"{events.event_type.REQUEST.table} AS main " + if len(event.value[0].url_value)>0 and not _isAny_opreator(event.value[0].url_operator): + event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].url_value,value_key=e_k)) + if len(event.value[0].status_code_value)>0 and not _isAny_opreator(event.value[0].status_code_operator): + event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].status_code_value,value_key=e_k)) + if len(event.value[0].method_value)>0 and not _isAny_opreator(event.value[0].method_operator): + event_where.append(_multiple_conditions(f"main.method {op} %({e_k})s", event.value[0].method_value,value_key=e_k)) + if len(event.value[0].duration_value)>0 and not _isAny_opreator(event.value[0].duration_operator): + event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].duration_value,value_key=e_k)) + if len(event.value[0].request_value)>0 and not _isAny_opreator(event.value[0].request_operator): + event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].request_value,value_key=e_k)) + if len(event.value[0].response_value)>0 and not _isAny_opreator(event.value[0].response_operator): + event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].response_value,value_key=e_k)) else: continue if event_index == 0 or or_events: diff --git a/api/schemas.py b/api/schemas.py index b341a45fb..f35125ae5 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -384,6 +384,7 @@ class EventType(str, Enum): location = "LOCATION" custom = "CUSTOM" request = "REQUEST" + request_details = "REQUEST_DETAILS" graphql = "GRAPHQL" state_action = "STATEACTION" error = "ERROR" @@ -480,7 +481,8 @@ class __MixedSearchFilter(BaseModel): @root_validator(pre=True) def remove_duplicate_values(cls, values): if values.get("value") is not None: - if len(values["value"]) > 0 and isinstance(values["value"][0], int): + if len(values["value"]) > 0 \ + and (isinstance(values["value"][0], int) or isinstance(values["value"][0], dict)): return values values["value"] = list(set(values["value"])) return values @@ -489,6 +491,36 @@ class __MixedSearchFilter(BaseModel): alias_generator = attribute_to_camel_case +class HttpMethod(str, Enum): + _get = 'GET' + _head = 'HEAD' + _post = 'POST' + _put = 'PUT' + _delete = 'DELETE' + _connect = 'CONNECT' + _option = 'OPTIONS' + _trace = 'TRACE' + _patch = 'PATCH' + + +class RequestDetailsSchema(BaseModel): + url_value: List[str] = Field([]) + url_operator: SearchEventOperator = Field(SearchEventOperator._is_any) + status_code_value: List[int] = Field(None) + status_code_operator: MathOperator = Field(None) + method_value: List[HttpMethod] = Field([]) + method_operator: SearchEventOperator = Field(None) + duration_value: List[int] = Field(None) + duration_operator: MathOperator = Field(None) + request_value: List[str] = Field([]) + request_operator: SearchEventOperator = Field(None) + response_value: List[str] = Field([]) + response_operator: SearchEventOperator = Field(None) + + class Config: + alias_generator = attribute_to_camel_case + + class _SessionSearchEventRaw(__MixedSearchFilter): is_event: bool = Field(default=True, const=True) value: List[str] = Field(...) @@ -513,17 +545,22 @@ class _SessionSearchEventRaw(__MixedSearchFilter): assert isinstance(values["value"][0], _SessionSearchEventRaw) \ and isinstance(values["value"][1], _SessionSearchEventRaw), \ f"event should be of type _SessionSearchEventRaw for {PerformanceEventType.time_between_events}" + assert len(values["source"]) > 0 and isinstance(values["source"][0], int), \ + f"source of type int if required for {PerformanceEventType.time_between_events}" else: for c in values["source"]: assert isinstance(c, int), f"source value should be of type int for {values.get('type')}" elif values.get("type") == EventType.error and values.get("source") is None: values["source"] = [ErrorSource.js_exception] + elif values.get("type") == EventType.request_details: + assert len(values.get("value", [])) == 1 and isinstance(values["value"][0], RequestDetailsSchema), \ + f"event should be of type RequestDetailsSchema for {EventType.request_details}" return values class _SessionSearchEventSchema(_SessionSearchEventRaw): - value: Union[List[_SessionSearchEventRaw], str, List[str]] = Field(...) + value: Union[List[Union[RequestDetailsSchema, _SessionSearchEventRaw, str]], str] = Field(...) class _SessionSearchFilterSchema(__MixedSearchFilter): @@ -732,7 +769,6 @@ class MetricOfType(str, Enum): user_country = FilterType.user_country.value user_id = FilterType.user_id.value issues = FilterType.issue.value - initial_page_load_time = "INITIAL_PAGE_LOAD_TIME" visited_url = "VISITED_URL" diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql new file mode 100644 index 000000000..0b9a1d3b5 --- /dev/null +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -0,0 +1,38 @@ +BEGIN; +CREATE OR REPLACE FUNCTION openreplay_version() + RETURNS text AS +$$ +SELECT 'v1.5.X' +$$ LANGUAGE sql IMMUTABLE; + + +-- Split requests-URL: +UPDATE events_common.requests +SET schema=SUBSTRING(url, 1, POSITION('://' IN url) - 1), + host=CASE + WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( + SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, + POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) + ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, + base_path=CASE + WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN + CASE + WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN + SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), + POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, + POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - + POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) + ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), + POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + + 1) END + ELSE '' END, + query_string=CASE + WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( + SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), + POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1) + END; + + + + +COMMIT; \ No newline at end of file From a9583db20f134a4c16e6c4c23fabedc026a4198e Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Mon, 28 Feb 2022 22:07:35 +0100 Subject: [PATCH 019/101] feat(DB): changed update script --- .../helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql index 0b9a1d3b5..c8efda38c 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -1,3 +1,5 @@ +-- !!!!NOT IN CREATE DB YET + BEGIN; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS @@ -8,13 +10,19 @@ $$ LANGUAGE sql IMMUTABLE; -- Split requests-URL: UPDATE events_common.requests -SET schema=SUBSTRING(url, 1, POSITION('://' IN url) - 1), +SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, host=CASE + WHEN POSITION('://' IN url) = 0 THEN NULL WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, base_path=CASE + WHEN POSITION('://' IN url) = 0 THEN + CASE + WHEN POSITION('?' IN url) > 0 THEN + SUBSTRING(url, 1, POSITION('?' IN url) - 1) + ELSE url END WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN CASE WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN @@ -25,14 +33,11 @@ SET schema=SUBSTRING(url, 1, POSITION('://' IN url) - 1), ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1) END - ELSE '' END, + END, query_string=CASE - WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( - SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), - POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1) + WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) END; - COMMIT; \ No newline at end of file From 82e572b9d1337cf8a8b5b13db245e3cbd6d5d4f1 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Tue, 1 Mar 2022 13:29:20 +0100 Subject: [PATCH 020/101] feat(ui) - custom metrics - wip --- .../CustomMetriLineChart.tsx | 56 +++++++++++++ .../CustomMetriLineChart/index.ts | 1 + .../CustomMetriPercentage.tsx | 16 ++++ .../CustomMetriPercentage/index.ts | 1 + .../CustomMetricPieChart.css | 6 ++ .../CustomMetricPieChart.tsx | 16 ++++ .../CustomMetricPieChart/index.ts | 1 + .../CustomMetricTable/CustomMetricTable.css | 6 ++ .../CustomMetricTable/CustomMetricTable.tsx | 44 ++++++++++ .../CustomMetricTable/index.ts | 1 + .../CustomMetricWidgetPreview.tsx | 81 ++++++++++--------- .../Dashboard/Widgets/common/Table.js | 12 +-- .../CustomMetricForm/CustomMetricForm.tsx | 68 ++++++++++++---- .../shared/DropdownPlain/DropdownPlain.css | 2 + .../shared/DropdownPlain/DropdownPlain.tsx | 4 +- .../ui/SegmentSelection/SegmentSelection.js | 4 +- .../ui/SegmentSelection/segmentSelection.css | 5 +- frontend/app/constants/filterOptions.js | 2 +- frontend/app/svg/icons/graph-up-arrow.svg | 3 + frontend/app/svg/icons/hash.svg | 3 + frontend/app/types/customMetric.js | 6 +- 21 files changed, 266 insertions(+), 72 deletions(-) create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/CustomMetriPercentage.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.css create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.css create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/index.ts create mode 100644 frontend/app/svg/icons/graph-up-arrow.svg create mode 100644 frontend/app/svg/icons/hash.svg diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx new file mode 100644 index 000000000..9f68abf3a --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx @@ -0,0 +1,56 @@ +import React from 'react' +import { Styles } from '../../common'; +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import { LineChart, Line, Legend } from 'recharts'; + +interface Props { + data: any; + params: any; + seriesMap: any; + colors: any; +} +function CustomMetriLineChart(props: Props) { + const { data, params, seriesMap, colors } = props; + return ( + + + + + + + + { seriesMap.map((key, index) => ( + + ))} + + + ) +} + +export default CustomMetriLineChart diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/index.ts b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/index.ts new file mode 100644 index 000000000..f05a16274 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/index.ts @@ -0,0 +1 @@ +export { default } from './CustomMetriLineChart'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/CustomMetriPercentage.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/CustomMetriPercentage.tsx new file mode 100644 index 000000000..7138f2b1c --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/CustomMetriPercentage.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +interface Props { + data: any; +} +function CustomMetriPercentage(props: Props) { + const { data } = props; + return ( +
+
0%
+
0 ( 0.0% ) from previous hour
+
+ ) +} + +export default CustomMetriPercentage; diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/index.ts b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/index.ts new file mode 100644 index 000000000..a36f4ae23 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/index.ts @@ -0,0 +1 @@ +export { default } from './CustomMetriPercentage'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.css b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.css new file mode 100644 index 000000000..1d1ef3ee4 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.css @@ -0,0 +1,6 @@ +.wrapper { + background-color: white; + /* border: solid thin $gray-medium; */ + border-radius: 3px; + padding: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx new file mode 100644 index 000000000..a771a0f45 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +interface Props { + data: any; +} +function CustomMetricPieChart(props: Props) { + const { data } = props; + return ( +
+
0%
+
0 ( 0.0% ) from previous hour
+
+ ) +} + +export default CustomMetricPieChart; diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/index.ts b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/index.ts new file mode 100644 index 000000000..6bdaf2270 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/index.ts @@ -0,0 +1 @@ +export { default } from './CustomMetricPieChart'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.css b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.css new file mode 100644 index 000000000..1d1ef3ee4 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.css @@ -0,0 +1,6 @@ +.wrapper { + background-color: white; + /* border: solid thin $gray-medium; */ + border-radius: 3px; + padding: 10px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx new file mode 100644 index 000000000..9ab0d72eb --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx @@ -0,0 +1,44 @@ +import React from 'react' +import { Table } from '../../common'; +import { List } from 'immutable'; + +const cols = [ + { + key: 'name', + title: 'Resource', + toText: name => name, + width: '70%', + }, + { + key: 'sessions', + title: 'Sessions', + toText: sessions => sessions, + width: '30%', + }, +]; + +interface Props { + data: any; +} +function CustomMetriTable(props: Props) { + const { data } = props; + const rows = List([ + { name: 'one', sessions: 2 }, + { name: 'two', sessions: 3 }, + { name: 'three', sessions: 4 }, + { name: 'four', sessions: 1 }, + { name: 'five', sessions: 6 }, + ]) + return ( +
+ + + ) +} + +export default CustomMetriTable; diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/index.ts b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/index.ts new file mode 100644 index 000000000..dc43c93b4 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/index.ts @@ -0,0 +1 @@ +export { default } from './CustomMetricTable'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index 8af9784d5..f0ca8aa80 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState, useRef } from 'react'; import { connect } from 'react-redux'; -import { Loader, NoContent, Icon } from 'UI'; +import { Loader, NoContent, SegmentSelection, Icon } from 'UI'; import { Styles } from '../../common'; import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, LineChart, Line, Legend } from 'recharts'; import Period, { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; @@ -9,6 +9,9 @@ import { getChartFormatter } from 'Types/dashboard/helper'; import { remove } from 'Duck/customMetrics'; import DateRange from 'Shared/DateRange'; import { edit } from 'Duck/customMetrics'; +import CustomMetriLineChart from '../CustomMetriLineChart'; +import CustomMetriPercentage from '../CustomMetriPercentage'; +import CustomMetricTable from '../CustomMetricTable'; import APIClient from 'App/api_client'; @@ -83,11 +86,28 @@ function CustomMetricWidget(props: Props) { props.edit({ ...changedDates, rangeName: changedDates.rangeValue }); } + const chagneViewType = (e, { name, value }) => { + props.edit({ [ name ]: value }); + } + return (
Preview
-
+
+ +
+ Time Range - - - - - - - - { seriesMap.map((key, index) => ( - + { metric.viewType === 'percent' && ( + + )} + { metric.viewType === 'chart' && ( + - ))} - - + )} + + )} + + { metric.metricType === 'table' && ( +
+ +
+ )}
diff --git a/frontend/app/components/Dashboard/Widgets/common/Table.js b/frontend/app/components/Dashboard/Widgets/common/Table.js index 0aecca5ea..73192a501 100644 --- a/frontend/app/components/Dashboard/Widgets/common/Table.js +++ b/frontend/app/components/Dashboard/Widgets/common/Table.js @@ -16,7 +16,8 @@ export default class Table extends React.PureComponent { rowProps, rowClass = '', small = false, - compare = false + compare = false, + maxHeight = 200, } = this.props; const { showAll } = this.state; @@ -30,7 +31,7 @@ export default class Table extends React.PureComponent {
{ title }
) }
-
+
{ rows.take(showAll ? 10 : (small ? 3 : 5)).map(row => (
{ cols.map(({ cellClass = '', className = '', Component, key, toText = t => t, width }) => ( @@ -41,9 +42,9 @@ export default class Table extends React.PureComponent {
)) }
- )) } - - { rows.size > (small ? 3 : 5) && !showAll && + )) } +
+ { rows.size > (small ? 3 : 5) && !showAll &&
} -
); } diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index fd95cd5c6..754af89e2 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -24,6 +24,8 @@ interface Props { function CustomMetricForm(props: Props) { const { metric, loading } = props; const metricOfOptions = metricOf.filter(i => i.key === metric.metricType); + const timeseriesOptions = metricOf.filter(i => i.key === 'timeseries'); + const tableOptions = metricOf.filter(i => i.key === 'table'); const addSeries = () => { props.addSeries(); @@ -34,7 +36,17 @@ function CustomMetricForm(props: Props) { } const write = ({ target: { value, name } }) => props.editMetric({ [ name ]: value }, false); - const writeOption = (e, { value, name }) => props.editMetric({ [ name ]: value }, false); + const writeOption = (e, { value, name }) => { + props.editMetric({ [ name ]: value }, false); + + if (name === 'metricType') { + if (value === 'timeseries') { + props.editMetric({ metricOf: timeseriesOptions[0].value }, false); + } else if (value === 'table') { + props.editMetric({ metricOf: tableOptions[0].value }, false); + } + } + }; const changeConditionTab = (e, { name, value }) => { props.editMetric({[ 'viewType' ]: value }); @@ -89,22 +101,44 @@ function CustomMetricForm(props: Props) { value={ metric.metricType } onChange={ writeOption } /> - of - - showing - + + {metric.metricType === 'timeseries' && ( + <> + of + + + )} + + {metric.metricType === 'table' && ( + <> + of + + + )} + + {metric.metricType === 'table' && ( + <> + showing + + + )}
{/*
Timeseries diff --git a/frontend/app/components/shared/DropdownPlain/DropdownPlain.css b/frontend/app/components/shared/DropdownPlain/DropdownPlain.css index 87e26bc68..1bf3e305c 100644 --- a/frontend/app/components/shared/DropdownPlain/DropdownPlain.css +++ b/frontend/app/components/shared/DropdownPlain/DropdownPlain.css @@ -4,6 +4,8 @@ border-radius: 3px; color: $gray-darkest; font-weight: 500; + background-color: white; + border: solid thin $gray-light; &:hover { background-color: $gray-light; } diff --git a/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx b/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx index d3313ac3e..07d64aa5d 100644 --- a/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx +++ b/frontend/app/components/shared/DropdownPlain/DropdownPlain.tsx @@ -12,7 +12,7 @@ interface Props { } export default function DropdownPlain(props: Props) { - const { name = "sort", value, options, icon = "chevron-down", direction = "left" } = props; + const { name = "sort", value, options, icon = "chevron-down", direction = "right" } = props; return (
{ list.map(item => ( @@ -27,7 +27,7 @@ class SegmentSelection extends React.Component { data-active={ this.props.value && this.props.value.value === item.value } onClick={ () => !item.disabled && this.setActiveItem(item) } > - { item.icon && } + { item.icon && }
{ item.name }
} diff --git a/frontend/app/components/ui/SegmentSelection/segmentSelection.css b/frontend/app/components/ui/SegmentSelection/segmentSelection.css index 20007b010..197627c9f 100644 --- a/frontend/app/components/ui/SegmentSelection/segmentSelection.css +++ b/frontend/app/components/ui/SegmentSelection/segmentSelection.css @@ -12,13 +12,13 @@ padding: 10px; flex: 1; text-align: center; - border-right: solid thin $teal; cursor: pointer; background-color: $gray-lightest; display: flex; align-items: center; justify-content: center; white-space: nowrap; + border-right: solid thin $gray-light; & span svg { fill: $gray-medium; @@ -53,6 +53,7 @@ & .item { color: $teal; background-color: white; + border-right: solid thin $teal; &[data-active=true] { background-color: $teal; color: white; @@ -65,6 +66,6 @@ } .extraSmall .item { - padding: 0 4px; + padding: 6px !important; font-size: 12px; } \ No newline at end of file diff --git a/frontend/app/constants/filterOptions.js b/frontend/app/constants/filterOptions.js index 215832c1a..9884d7851 100644 --- a/frontend/app/constants/filterOptions.js +++ b/frontend/app/constants/filterOptions.js @@ -61,7 +61,7 @@ export const metricTypes = [ export const metricOf = [ { text: 'Session Count', value: 'sessionCount', key: 'timeseries' }, - { text: 'Users', value: 'users', key: 'table' }, + { text: 'Users', value: 'USERID', key: 'table' }, { text: 'Rage Click', value: 'rageClick', key: 'table' }, { text: 'Dead Click', value: 'deadClick', key: 'table' }, { text: 'Browser', value: 'browser', key: 'table' }, diff --git a/frontend/app/svg/icons/graph-up-arrow.svg b/frontend/app/svg/icons/graph-up-arrow.svg new file mode 100644 index 000000000..fd582e467 --- /dev/null +++ b/frontend/app/svg/icons/graph-up-arrow.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/hash.svg b/frontend/app/svg/icons/hash.svg new file mode 100644 index 000000000..4621b1dac --- /dev/null +++ b/frontend/app/svg/icons/hash.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index 902c10a23..9b3585be1 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -27,9 +27,9 @@ export const FilterSeries = Record({ export default Record({ metricId: undefined, name: 'Series', - metricType: 'timeseries', - metricOf: 'sessionCount', - viewType: 'sessionCount', + metricType: 'table', + metricOf: 'USERID', + viewType: 'lineChart', series: List(), isPublic: true, startDate: '', From b587252bb54d905c9539c84d9907fd9da847a286 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 1 Mar 2022 16:31:07 +0100 Subject: [PATCH 021/101] feat(api): request changes --- api/chalicelib/core/sessions.py | 49 ++++++++++++++++++++++----------- api/schemas.py | 36 ++++++++++++------------ 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index 74b7f7cfa..3c766b74c 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -567,7 +567,6 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr value_key=f_k)) # --------------------------------------------------------------------------- if len(data.events) > 0: - # ss_constraints = [s.decode('UTF-8') for s in ss_constraints] events_query_from = [] event_index = 0 or_events = data.events_order == schemas.SearchEventOrder._or @@ -578,13 +577,15 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr is_any = _isAny_opreator(event.operator) if not isinstance(event.value, list): event.value = [event.value] - if not is_any and len(event.value) == 0 \ + if not is_any and len(event.value) == 0 and event_type not in [schemas.EventType.request_details] \ or event_type in [schemas.PerformanceEventType.location_dom_complete, schemas.PerformanceEventType.location_largest_contentful_paint_time, schemas.PerformanceEventType.location_ttfb, schemas.PerformanceEventType.location_avg_cpu_load, schemas.PerformanceEventType.location_avg_memory_usage - ] and (event.source is None or len(event.source) == 0): + ] and (event.source is None or len(event.source) == 0) \ + or event_type in [schemas.EventType.request_details] and ( + event.filters is None or len(event.filters) == 0): continue op = __get_sql_operator(event.operator) is_not = False @@ -803,20 +804,36 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr _multiple_conditions(f"main2.timestamp - main.timestamp {event.sourceOperator} %({e_k})s", event.source, value_key=e_k)) - elif event_type==schemas.EventType.request_details: + elif event_type == schemas.EventType.request_details: event_from = event_from % f"{events.event_type.REQUEST.table} AS main " - if len(event.value[0].url_value)>0 and not _isAny_opreator(event.value[0].url_operator): - event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].url_value,value_key=e_k)) - if len(event.value[0].status_code_value)>0 and not _isAny_opreator(event.value[0].status_code_operator): - event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].status_code_value,value_key=e_k)) - if len(event.value[0].method_value)>0 and not _isAny_opreator(event.value[0].method_operator): - event_where.append(_multiple_conditions(f"main.method {op} %({e_k})s", event.value[0].method_value,value_key=e_k)) - if len(event.value[0].duration_value)>0 and not _isAny_opreator(event.value[0].duration_operator): - event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].duration_value,value_key=e_k)) - if len(event.value[0].request_value)>0 and not _isAny_opreator(event.value[0].request_operator): - event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].request_value,value_key=e_k)) - if len(event.value[0].response_value)>0 and not _isAny_opreator(event.value[0].response_operator): - event_where.append(_multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k})s", event.value[0].response_value,value_key=e_k)) + for j, f in enumerate(event.filters): + is_any = _isAny_opreator(f.operator) + if is_any or len(f.value) == 0: + continue + op = __get_sql_operator(f.operator) + e_k_f = e_k + f"_fetch{j}" + full_args = {**full_args, **_multiple_values(f.value, value_key=e_k_f)} + if f.type == schemas.FetchFilterType._url: + event_where.append( + _multiple_conditions(f"main.{events.event_type.REQUEST.column} {op} %({e_k_f})s", f.value, + value_key=e_k_f)) + elif f.type == schemas.FetchFilterType._status_code: + event_where.append( + _multiple_conditions(f"main.status_code {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.FetchFilterType._method: + event_where.append( + _multiple_conditions(f"main.method {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.FetchFilterType._duration: + event_where.append( + _multiple_conditions(f"main.duration {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.FetchFilterType._request_body: + event_where.append( + _multiple_conditions(f"main.request_body {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.FetchFilterType._response_body: + event_where.append( + _multiple_conditions(f"main.response_body {op} %({e_k_f})s", f.value, value_key=e_k_f)) + else: + print(f"undefined fetch filter: {f.type}") else: continue if event_index == 0 or or_events: diff --git a/api/schemas.py b/api/schemas.py index f35125ae5..6e59bdafd 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -384,7 +384,7 @@ class EventType(str, Enum): location = "LOCATION" custom = "CUSTOM" request = "REQUEST" - request_details = "REQUEST_DETAILS" + request_details = "FETCH" graphql = "GRAPHQL" state_action = "STATEACTION" error = "ERROR" @@ -503,22 +503,19 @@ class HttpMethod(str, Enum): _patch = 'PATCH' -class RequestDetailsSchema(BaseModel): - url_value: List[str] = Field([]) - url_operator: SearchEventOperator = Field(SearchEventOperator._is_any) - status_code_value: List[int] = Field(None) - status_code_operator: MathOperator = Field(None) - method_value: List[HttpMethod] = Field([]) - method_operator: SearchEventOperator = Field(None) - duration_value: List[int] = Field(None) - duration_operator: MathOperator = Field(None) - request_value: List[str] = Field([]) - request_operator: SearchEventOperator = Field(None) - response_value: List[str] = Field([]) - response_operator: SearchEventOperator = Field(None) +class FetchFilterType(str, Enum): + _url = "FETCH_URL" + _status_code = "FETCH_STATUS_CODE" + _method = "FETCH_METHOD" + _duration = "FETCH_DURATION" + _request_body = "FETCH_REQUEST_BODY" + _response_body = "FETCH_RESPONSE_BODY" - class Config: - alias_generator = attribute_to_camel_case + +class RequestFilterSchema(BaseModel): + type: FetchFilterType = Field(...) + value: List[Union[int, str]] = Field(...) + operator: Union[SearchEventOperator, MathOperator] = Field(...) class _SessionSearchEventRaw(__MixedSearchFilter): @@ -528,6 +525,7 @@ class _SessionSearchEventRaw(__MixedSearchFilter): operator: SearchEventOperator = Field(...) source: Optional[List[Union[ErrorSource, int, str]]] = Field(None) sourceOperator: Optional[MathOperator] = Field(None) + filters: Optional[List[RequestFilterSchema]] = Field(None) @root_validator def event_validator(cls, values): @@ -553,14 +551,14 @@ class _SessionSearchEventRaw(__MixedSearchFilter): elif values.get("type") == EventType.error and values.get("source") is None: values["source"] = [ErrorSource.js_exception] elif values.get("type") == EventType.request_details: - assert len(values.get("value", [])) == 1 and isinstance(values["value"][0], RequestDetailsSchema), \ - f"event should be of type RequestDetailsSchema for {EventType.request_details}" + assert isinstance(values.get("filters"), List) and len(values.get("filters", [])) > 0, \ + f"filters should be defined for {EventType.request_details}" return values class _SessionSearchEventSchema(_SessionSearchEventRaw): - value: Union[List[Union[RequestDetailsSchema, _SessionSearchEventRaw, str]], str] = Field(...) + value: Union[List[Union[_SessionSearchEventRaw, str]], str] = Field(...) class _SessionSearchFilterSchema(__MixedSearchFilter): From ee2983e7ed3471f060f1c074cb5574de1b06c23c Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 1 Mar 2022 17:01:55 +0100 Subject: [PATCH 022/101] feat(DB): delta file for request --- scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql index c8efda38c..6cbb1a2e2 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -7,6 +7,17 @@ $$ SELECT 'v1.5.X' $$ LANGUAGE sql IMMUTABLE; +CREATE TYPE events_common.http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL, + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL; -- Split requests-URL: UPDATE events_common.requests From bc87d0302579b151924d56b2fbf026eae211945c Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 1 Mar 2022 17:13:44 +0100 Subject: [PATCH 023/101] feat(DB): changed delta file for request --- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql index 6cbb1a2e2..b774c4bea 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -10,45 +10,44 @@ $$ LANGUAGE sql IMMUTABLE; CREATE TYPE events_common.http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); ALTER TABLE events_common.requests - ADD COLUMN IF NOT EXISTS schema text NULL, - ADD COLUMN IF NOT EXISTS host text NULL, - ADD COLUMN IF NOT EXISTS base_path text NULL, - ADD COLUMN IF NOT EXISTS query_string text NULL, - ADD COLUMN IF NOT EXISTS request_body text NULL, - ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code text NULL, - ADD COLUMN IF NOT EXISTS method http_method NULL; - --- Split requests-URL: -UPDATE events_common.requests -SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, - host=CASE - WHEN POSITION('://' IN url) = 0 THEN NULL - WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( - SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, - POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) - ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, - base_path=CASE - WHEN POSITION('://' IN url) = 0 THEN - CASE - WHEN POSITION('?' IN url) > 0 THEN - SUBSTRING(url, 1, POSITION('?' IN url) - 1) - ELSE url END - WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN - CASE - WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN - SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), - POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, - POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - - POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) - ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), - POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + - 1) END - END, - query_string=CASE - WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) - END; + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL, + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS method events_common.http_method NULL; +-- Split requests-URL: Takes too long to use +-- UPDATE events_common.requests +-- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, +-- host=CASE +-- WHEN POSITION('://' IN url) = 0 THEN NULL +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( +-- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, +-- base_path=CASE +-- WHEN POSITION('://' IN url) = 0 THEN +-- CASE +-- WHEN POSITION('?' IN url) > 0 THEN +-- SUBSTRING(url, 1, POSITION('?' IN url) - 1) +-- ELSE url END +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- CASE +-- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, +-- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + +-- 1) END +-- END, +-- query_string=CASE +-- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) +-- END; COMMIT; \ No newline at end of file From 6a82b323f437bbcf5d768940cb63b7d9d39e050e Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 1 Mar 2022 17:58:42 +0100 Subject: [PATCH 024/101] feat(api): allow metricOf for timeseries --- api/schemas.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/api/schemas.py b/api/schemas.py index 6e59bdafd..c5d6945db 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -742,12 +742,6 @@ class MetricType(str, Enum): table = "table" -# class MetricTypeTableGroupField(str, Enum): -# users = "USERS" -# click_rage = IssueType.click_rage -# dead_click = IssueType.dead_click - - class CustomMetricRawPayloadSchema(BaseModel): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) @@ -760,7 +754,7 @@ class CustomMetricRawPayloadSchema2(CustomMetricRawPayloadSchema): metric_id: int = Field(...) -class MetricOfType(str, Enum): +class TableMetricOfType(str, Enum): user_os = FilterType.user_os.value user_browser = FilterType.user_browser.value user_device = FilterType.user_device.value @@ -770,14 +764,25 @@ class MetricOfType(str, Enum): visited_url = "VISITED_URL" +class TimeseriesMetricOfType(str, Enum): + session_count = "sessionCount" + + class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) density: int = Field(7) viewType: MetricViewType = Field(MetricViewType.line_chart) metricType: MetricType = Field(MetricType.timeseries) - metricOf: MetricOfType = Field(MetricOfType.user_id) - metricFraction: float = Field(None, gt=0, lt=1) + metricOf: Union[TableMetricOfType, TimeseriesMetricOfType] = Field(TableMetricOfType.user_id) + + # metricFraction: float = Field(None, gt=0, lt=1) + @root_validator + def validator(cls, values): + if isinstance(values.get("metricOf"), TimeseriesMetricOfType): + assert values.get("metricType") == MetricType.timeseries, \ + f"Only metricType:{MetricType.timeseries.value} is allowed for metricOf: {values.get('metricOf')}" + return values class CustomMetricChartPayloadSchema2(CustomMetricChartPayloadSchema): From f0d13fde5034d126e13e9e9678d2328fd9b88c5d Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Tue, 1 Mar 2022 18:12:21 +0100 Subject: [PATCH 025/101] feat(api): allow metricOf for timeseries --- api/chalicelib/core/sessions.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index 3c766b74c..e8e778584 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -265,11 +265,11 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, density: int, - view_type: schemas.MetricViewType, metric_type: schemas.MetricType, metric_of: schemas.MetricOfType): + view_type: schemas.MetricViewType, metric_type: schemas.MetricType, metric_of: schemas.TableMetricOfType): step_size = int(metrics_helper.__get_step_size(endTimestamp=data.endDate, startTimestamp=data.startDate, density=density, factor=1, decimal=True)) extra_event = None - if metric_of == schemas.MetricOfType.visited_url: + if metric_of == schemas.TableMetricOfType.visited_url: extra_event = "events.pages" full_args, query_part, sort = search_query_parts(data=data, error_status=None, errors_only=False, favorite_only=False, issue=None, project_id=project_id, @@ -303,20 +303,20 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d else: sessions = cur.fetchone()["count"] elif metric_type == schemas.MetricType.table: - if isinstance(metric_of, schemas.MetricOfType): + if isinstance(metric_of, schemas.TableMetricOfType): main_col = "user_id" extra_col = "" pre_query = "" - if metric_of == schemas.MetricOfType.user_country: + if metric_of == schemas.TableMetricOfType.user_country: main_col = "user_country" - elif metric_of == schemas.MetricOfType.user_device: + elif metric_of == schemas.TableMetricOfType.user_device: main_col = "user_device" - elif metric_of == schemas.MetricOfType.user_browser: + elif metric_of == schemas.TableMetricOfType.user_browser: main_col = "user_browser" - elif metric_of == schemas.MetricOfType.issues: + elif metric_of == schemas.TableMetricOfType.issues: main_col = "issue" extra_col = f", UNNEST(s.issue_types) AS {main_col}" - elif metric_of == schemas.MetricOfType.visited_url: + elif metric_of == schemas.TableMetricOfType.visited_url: main_col = "base_path" extra_col = ", base_path" main_query = cur.mogrify(f"""{pre_query} From 09e3b44914c142af8ab4a120f90018ca3b4ff155 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 2 Mar 2022 10:28:14 +0100 Subject: [PATCH 026/101] feat(ui) - slide modal disable body scroll on open --- .../shared/CustomMetrics/CustomMetrics.tsx | 5 ++++- .../components/ui/SlideModal/SlideModal.js | 22 ++++++++++++++----- frontend/app/constants/filterOptions.js | 9 ++++---- frontend/app/styles/main.css | 6 +++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx index aedd4a097..ae0718aea 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { IconButton } from 'UI'; import { connect } from 'react-redux'; import { edit, init } from 'Duck/customMetrics'; @@ -7,6 +7,9 @@ interface Props { init: (instance?, setDefault?) => void; } function CustomMetrics(props: Props) { + useEffect(() => { // TODO remove this block + props.init() + }, []) return (
props.init()} /> diff --git a/frontend/app/components/ui/SlideModal/SlideModal.js b/frontend/app/components/ui/SlideModal/SlideModal.js index cc329463c..92f8ba710 100644 --- a/frontend/app/components/ui/SlideModal/SlideModal.js +++ b/frontend/app/components/ui/SlideModal/SlideModal.js @@ -1,12 +1,24 @@ import styles from './slideModal.css'; import cn from 'classnames'; export default class SlideModal extends React.PureComponent { - componentDidMount() { - document.addEventListener('keydown', this.keyPressHandler); - } + // componentDidMount() { + // document.addEventListener('keydown', this.keyPressHandler); + // } - componentWillUnmount() { - document.removeEventListener('keydown', this.keyPressHandler); + // componentWillUnmount() { + // document.removeEventListener('keydown', this.keyPressHandler); + // } + + componentDidUpdate(prevProps) { + if (prevProps.isDisplayed !== this.props.isDisplayed) { + if (this.props.isDisplayed) { + document.addEventListener('keydown', this.keyPressHandler); + document.body.classList.add('no-scroll'); + } else { + document.removeEventListener('keydown', this.keyPressHandler); + document.body.classList.remove('no-scroll'); + } + } } keyPressHandler = (e) => { diff --git a/frontend/app/constants/filterOptions.js b/frontend/app/constants/filterOptions.js index 9884d7851..3a497e8cf 100644 --- a/frontend/app/constants/filterOptions.js +++ b/frontend/app/constants/filterOptions.js @@ -62,10 +62,11 @@ export const metricTypes = [ export const metricOf = [ { text: 'Session Count', value: 'sessionCount', key: 'timeseries' }, { text: 'Users', value: 'USERID', key: 'table' }, - { text: 'Rage Click', value: 'rageClick', key: 'table' }, - { text: 'Dead Click', value: 'deadClick', key: 'table' }, - { text: 'Browser', value: 'browser', key: 'table' }, - { text: 'Device', value: 'device', key: 'table' }, + { text: 'Issues', value: 'ISSUES', key: 'table' }, + { text: 'Browser', value: 'USERBROWSER', key: 'table' }, + { text: 'Device', value: 'USERDEVICE', key: 'table' }, + { text: 'Country', value: 'USERCOUNTRY', key: 'table' }, + { text: 'URL', value: 'VISITED_URL', key: 'table' }, ] export default { diff --git a/frontend/app/styles/main.css b/frontend/app/styles/main.css index 81e5ab814..3b7f5fe4b 100644 --- a/frontend/app/styles/main.css +++ b/frontend/app/styles/main.css @@ -141,4 +141,10 @@ margin: 25px 0; background-color: $gray-light; +} + +.no-scroll { + height: 100vh; + overflow-y: hidden; + padding-right: 15px; } \ No newline at end of file From 3356a11ccf64f0f86513df3597867f12a3cac8ec Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Wed, 2 Mar 2022 14:02:31 +0100 Subject: [PATCH 027/101] fix(tracker-assist):3.5.4:csstype dependency --- tracker/tracker-assist/package-lock.json | 4390 +++++++++++++++++++++- tracker/tracker-assist/package.json | 3 +- 2 files changed, 4270 insertions(+), 123 deletions(-) diff --git a/tracker/tracker-assist/package-lock.json b/tracker/tracker-assist/package-lock.json index db1a0b7e2..b0c032a8b 100644 --- a/tracker/tracker-assist/package-lock.json +++ b/tracker/tracker-assist/package-lock.json @@ -1,8 +1,3899 @@ { "name": "@openreplay/tracker-assist", - "version": "3.5.1-beta.1", - "lockfileVersion": 1, + "version": "3.5.3", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@openreplay/tracker-assist", + "version": "3.5.3", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.10", + "npm-dragndrop": "^1.2.0", + "peerjs": "^1.3.2", + "socket.io-client": "^4.4.1" + }, + "devDependencies": { + "@openreplay/tracker": "file:../tracker", + "prettier": "^1.18.2", + "replace-in-files-cli": "^1.0.0", + "typescript": "^4.6.0-dev.20211126" + }, + "peerDependencies": { + "@openreplay/tracker": "^3.5.0" + } + }, + "../tracker": { + "name": "@openreplay/tracker", + "version": "3.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "error-stack-parser": "^2.0.6" + }, + "devDependencies": { + "@babel/core": "^7.10.2", + "@rollup/plugin-babel": "^5.0.3", + "@rollup/plugin-node-resolve": "^8.0.1", + "@typescript-eslint/eslint-plugin": "^2.34.0", + "@typescript-eslint/parser": "^2.34.0", + "eslint": "^6.8.0", + "eslint-plugin-prettier": "^3.1.4", + "prettier": "^2.0.0", + "replace-in-files": "^2.0.3", + "rollup": "^2.17.0", + "rollup-plugin-terser": "^6.1.0", + "semver": "^6.3.0", + "typescript": "^4.6.0-dev.20211126" + }, + "engines": { + "node": ">=12" + } + }, + "../tracker/node_modules/@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.8.3" + } + }, + "../tracker/node_modules/@babel/core": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", + "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.2", + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helpers": "^7.10.1", + "@babel/parser": "^7.10.2", + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "../tracker/node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/core/node_modules/@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "../tracker/node_modules/@babel/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "../tracker/node_modules/@babel/generator": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", + "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.2", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "../tracker/node_modules/@babel/helper-function-name": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", + "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-get-function-arity": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", + "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", + "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-module-imports": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", + "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-module-transforms": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", + "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-simple-access": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1", + "lodash": "^4.17.13" + } + }, + "../tracker/node_modules/@babel/helper-optimise-call-expression": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", + "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-replace-supers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", + "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-simple-access": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", + "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-split-export-declaration": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", + "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "../tracker/node_modules/@babel/helpers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", + "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "dependencies": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "../tracker/node_modules/@babel/parser": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/@babel/template": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", + "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/template/node_modules/@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "../tracker/node_modules/@babel/traverse": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", + "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.1", + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "../tracker/node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.1" + } + }, + "../tracker/node_modules/@babel/traverse/node_modules/@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "../tracker/node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/@babel/types": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", + "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "../tracker/node_modules/@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "../tracker/node_modules/@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "../tracker/node_modules/@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "../tracker/node_modules/@rollup/plugin-babel": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.0.3.tgz", + "integrity": "sha512-NlaPf4E6YFxeOCbqc+A2PTkB1BSy3rfKu6EJuQ1MGhMHpTVvMqKi6Rf0DlwtnEsTNK9LueUgsGEgp5Occ4KDVA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.7.4", + "@rollup/pluginutils": "^3.0.8" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "rollup": "^1.20.0||^2.0.0" + } + }, + "../tracker/node_modules/@rollup/plugin-node-resolve": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.1.tgz", + "integrity": "sha512-KIeAmueDDaYMqMBnUngLVVZhURwxA12nq/YB6nGm5/JpVyOMwI1fCVU3oL/dAnnLBG7oiPXntO5LHOiMrfNXCA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.8", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "deep-freeze": "^0.0.1", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.14.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "../tracker/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "../tracker/node_modules/@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "../tracker/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "../tracker/node_modules/@types/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "../tracker/node_modules/@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, + "../tracker/node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "../tracker/node_modules/@types/node": { + "version": "14.0.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.13.tgz", + "integrity": "sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==", + "dev": true + }, + "../tracker/node_modules/@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "../tracker/node_modules/@typescript-eslint/eslint-plugin": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "2.34.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^2.0.0", + "eslint": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../tracker/node_modules/@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "../tracker/node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "../tracker/node_modules/@typescript-eslint/parser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "dev": true, + "dependencies": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../tracker/node_modules/@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "../tracker/node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "../tracker/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "../tracker/node_modules/acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0" + } + }, + "../tracker/node_modules/ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "../tracker/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../tracker/node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../tracker/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "../tracker/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "../tracker/node_modules/binaryextensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "../tracker/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "../tracker/node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "../tracker/node_modules/builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "../tracker/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "../tracker/node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "../tracker/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "../tracker/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "../tracker/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "../tracker/node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "../tracker/node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "../tracker/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "../tracker/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "../tracker/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "../tracker/node_modules/deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=", + "dev": true + }, + "../tracker/node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "../tracker/node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/editions": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/editions/-/editions-2.3.1.tgz", + "integrity": "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==", + "dev": true, + "dependencies": { + "errlop": "^2.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "../tracker/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "../tracker/node_modules/errlop": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-2.2.0.tgz", + "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "../tracker/node_modules/error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.1.1" + } + }, + "../tracker/node_modules/es6-promisify": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz", + "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==", + "dev": true + }, + "../tracker/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "../tracker/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../tracker/node_modules/eslint-plugin-prettier": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz", + "integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + } + }, + "../tracker/node_modules/eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "../tracker/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/eslint/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "../tracker/node_modules/espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "dependencies": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/esquery": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz", + "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==", + "dev": true, + "dependencies": { + "estraverse": "^4.0.0" + }, + "engines": { + "node": ">=0.6" + } + }, + "../tracker/node_modules/esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "dependencies": { + "estraverse": "^4.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "../tracker/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "../tracker/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "../tracker/node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "../tracker/node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "../tracker/node_modules/fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/fast-glob/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/fast-glob/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/fast-glob/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "../tracker/node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/fast-glob/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "../tracker/node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "../tracker/node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "../tracker/node_modules/fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "../tracker/node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../tracker/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "../tracker/node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "../tracker/node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "../tracker/node_modules/gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "../tracker/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../tracker/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "../tracker/node_modules/globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/globby/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "../tracker/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "../tracker/node_modules/import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "../tracker/node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "../tracker/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "../tracker/node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "../tracker/node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "../tracker/node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "../tracker/node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "../tracker/node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "../tracker/node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/inquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "../tracker/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "../tracker/node_modules/istextorbinary": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.6.0.tgz", + "integrity": "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==", + "dev": true, + "dependencies": { + "binaryextensions": "^2.1.2", + "editions": "^2.2.0", + "textextensions": "^2.5.0" + }, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "../tracker/node_modules/jest-worker": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.0.0.tgz", + "integrity": "sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw==", + "dev": true, + "dependencies": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "../tracker/node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/jest-worker/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/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 + }, + "../tracker/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "../tracker/node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "../tracker/node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "../tracker/node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/json5/node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "../tracker/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../tracker/node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "../tracker/node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "../tracker/node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "../tracker/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "../tracker/node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "../tracker/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "../tracker/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "../tracker/node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "../tracker/node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "../tracker/node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "../tracker/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "../tracker/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../tracker/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../tracker/node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "../tracker/node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "../tracker/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "../tracker/node_modules/prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "../tracker/node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "../tracker/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "../tracker/node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "../tracker/node_modules/replace-in-files": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/replace-in-files/-/replace-in-files-2.0.3.tgz", + "integrity": "sha512-wm9kg+WhKQ10CFaCS9jvUtgw9JnaPilm4TqSRq57H06v5EgX7hTrr/qwgyvq3G+IeNhmr6VTW84LvfnpZfq5/g==", + "dev": true, + "dependencies": { + "co": "^4.6.0", + "es6-promisify": "^6.0.2", + "globby": "^10.0.1", + "istextorbinary": "^2.5.1", + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "../tracker/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "../tracker/node_modules/rollup": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.17.0.tgz", + "integrity": "sha512-4Um68vKyyTLzT+EWClgc+nyxSlunlmx8wgCO16RDicwxvccnyBHguoNqxPaJL/YPAdvuAJkqaFPf/BfDojzEZA==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "../tracker/node_modules/rollup-plugin-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz", + "integrity": "sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "jest-worker": "^26.0.0", + "serialize-javascript": "^3.0.0", + "terser": "^4.7.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "../tracker/node_modules/rollup/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "../tracker/node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "../tracker/node_modules/run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "../tracker/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "../tracker/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "../tracker/node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "../tracker/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "../tracker/node_modules/serialize-javascript": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", + "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "../tracker/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "../tracker/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "../tracker/node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "../tracker/node_modules/stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", + "dev": true + }, + "../tracker/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/table/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "../tracker/node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "../tracker/node_modules/terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "../tracker/node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "../tracker/node_modules/textextensions": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", + "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "../tracker/node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "../tracker/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "../tracker/node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "../tracker/node_modules/tslib": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", + "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==", + "dev": true + }, + "../tracker/node_modules/tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "../tracker/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../tracker/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "../tracker/node_modules/typescript": { + "version": "4.6.0-dev.20211126", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20211126.tgz", + "integrity": "sha512-m+LKstqVv6FYW363aIbO6bm8awsLbeSUCzU6FxPtzUF/WJkFieQfYmdVwEIzigeTpw4E2GETBXnk6P6AixcQJQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "../tracker/node_modules/uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "../tracker/node_modules/v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "../tracker/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "../tracker/node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "../tracker/node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "../tracker/node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@openreplay/tracker": { + "resolved": "../tracker", + "link": true + }, + "node_modules/@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, + "node_modules/@types/minimist": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", + "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/csstype": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "dependencies": { + "@socket.io/base64-arraybuffer": "~1.0.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, + "node_modules/fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "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 + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/map-obj": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", + "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-dragndrop": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/npm-dragndrop/-/npm-dragndrop-1.2.0.tgz", + "integrity": "sha1-bgUkAP7Yay8eP0csU4EPkjcRu7U=" + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "node_modules/parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/peerjs": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.3.2.tgz", + "integrity": "sha512-+PHfmsC7QGUU8Ye3OLi6tKQZGPCNy7QatUVNw4JtE8alkguF3+DdO5W0bzepqP2OtE9FqH/ltXt37qyvHw2CqA==", + "dependencies": { + "@types/node": "^10.14.33", + "eventemitter3": "^3.1.2", + "peerjs-js-binarypack": "1.0.1", + "webrtc-adapter": "^7.7.1" + } + }, + "node_modules/peerjs-js-binarypack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/peerjs-js-binarypack/-/peerjs-js-binarypack-1.0.1.tgz", + "integrity": "sha512-N6aeia3NhdpV7kiGxJV5xQiZZCVEEVjRz2T2C6UZQiBkHWHzUv/oWA4myQLcwBwO8LUoR1KWW5oStvwVesmfCg==" + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/replace-in-files-cli": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-in-files-cli/-/replace-in-files-cli-1.0.0.tgz", + "integrity": "sha512-/HMPLZeCA24CBUQ59ymHji6LyMKM+gEgDZlYsiPvXW6+3PdfOw6SsMCVd9KC2B+KlAEe/8vkJA6gfnexVdF15A==", + "dev": true, + "dependencies": { + "arrify": "^2.0.1", + "escape-string-regexp": "^4.0.0", + "globby": "^11.0.1", + "meow": "^7.1.1", + "normalize-path": "^3.0.0", + "write-file-atomic": "^3.0.0" + }, + "bin": { + "replace-in-files": "cli.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "dependencies": { + "sdp": "^2.6.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io-client": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", + "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.1.tgz", + "integrity": "sha512-USQVLSkDWE5nbcY760ExdKaJxCE65kcsG/8k5FDGZVVxpD1pA7hABYXYkCUvxUuYYh/+uQw0N/fvBzfT8o07KA==", + "dependencies": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.6.0-dev.20211126", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20211126.tgz", + "integrity": "sha512-m+LKstqVv6FYW363aIbO6bm8awsLbeSUCzU6FxPtzUF/WJkFieQfYmdVwEIzigeTpw4E2GETBXnk6P6AixcQJQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/webrtc-adapter": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz", + "integrity": "sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==", + "dependencies": { + "rtcpeerconnection-shim": "^1.2.15", + "sdp": "^2.12.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + }, "dependencies": { "@babel/code-frame": { "version": "7.14.5", @@ -58,15 +3949,28 @@ }, "@openreplay/tracker": { "version": "file:../tracker", - "dev": true, "requires": { - "error-stack-parser": "^2.0.6" + "@babel/core": "^7.10.2", + "@rollup/plugin-babel": "^5.0.3", + "@rollup/plugin-node-resolve": "^8.0.1", + "@typescript-eslint/eslint-plugin": "^2.34.0", + "@typescript-eslint/parser": "^2.34.0", + "error-stack-parser": "^2.0.6", + "eslint": "^6.8.0", + "eslint-plugin-prettier": "^3.1.4", + "prettier": "^2.0.0", + "replace-in-files": "^2.0.3", + "rollup": "^2.17.0", + "rollup-plugin-terser": "^6.1.0", + "semver": "^6.3.0", + "typescript": "^4.6.0-dev.20211126" }, "dependencies": { "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, "requires": { "@babel/highlight": "^7.8.3" } @@ -75,6 +3979,7 @@ "version": "7.10.2", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.1", "@babel/generator": "^7.10.2", @@ -98,6 +4003,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, "requires": { "@babel/highlight": "^7.10.1" } @@ -106,6 +4012,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.1", "chalk": "^2.0.0", @@ -115,7 +4022,8 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -123,6 +4031,7 @@ "version": "7.10.2", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "dev": true, "requires": { "@babel/types": "^7.10.2", "jsesc": "^2.5.1", @@ -134,6 +4043,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.10.1", "@babel/template": "^7.10.1", @@ -144,6 +4054,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "dev": true, "requires": { "@babel/types": "^7.10.1" } @@ -152,6 +4063,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", + "dev": true, "requires": { "@babel/types": "^7.10.1" } @@ -160,6 +4072,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", + "dev": true, "requires": { "@babel/types": "^7.10.1" } @@ -168,6 +4081,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", + "dev": true, "requires": { "@babel/helper-module-imports": "^7.10.1", "@babel/helper-replace-supers": "^7.10.1", @@ -182,6 +4096,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", + "dev": true, "requires": { "@babel/types": "^7.10.1" } @@ -190,6 +4105,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", + "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.10.1", "@babel/helper-optimise-call-expression": "^7.10.1", @@ -201,6 +4117,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", + "dev": true, "requires": { "@babel/template": "^7.10.1", "@babel/types": "^7.10.1" @@ -210,6 +4127,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "dev": true, "requires": { "@babel/types": "^7.10.1" } @@ -217,12 +4135,14 @@ "@babel/helper-validator-identifier": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", - "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==" + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true }, "@babel/helpers": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", + "dev": true, "requires": { "@babel/template": "^7.10.1", "@babel/traverse": "^7.10.1", @@ -233,6 +4153,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -242,12 +4163,14 @@ "@babel/parser": { "version": "7.10.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", - "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==" + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "dev": true }, "@babel/template": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.1", "@babel/parser": "^7.10.1", @@ -258,6 +4181,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, "requires": { "@babel/highlight": "^7.10.1" } @@ -266,6 +4190,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.1", "chalk": "^2.0.0", @@ -278,6 +4203,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.1", "@babel/generator": "^7.10.1", @@ -294,6 +4220,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, "requires": { "@babel/highlight": "^7.10.1" } @@ -302,6 +4229,7 @@ "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.1", "chalk": "^2.0.0", @@ -311,7 +4239,8 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true } } }, @@ -319,6 +4248,7 @@ "version": "7.10.2", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.1", "lodash": "^4.17.13", @@ -329,6 +4259,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, "requires": { "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" @@ -337,12 +4268,14 @@ "@nodelib/fs.stat": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true }, "@nodelib/fs.walk": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" @@ -352,6 +4285,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.0.3.tgz", "integrity": "sha512-NlaPf4E6YFxeOCbqc+A2PTkB1BSy3rfKu6EJuQ1MGhMHpTVvMqKi6Rf0DlwtnEsTNK9LueUgsGEgp5Occ4KDVA==", + "dev": true, "requires": { "@babel/helper-module-imports": "^7.7.4", "@rollup/pluginutils": "^3.0.8" @@ -361,6 +4295,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.1.tgz", "integrity": "sha512-KIeAmueDDaYMqMBnUngLVVZhURwxA12nq/YB6nGm5/JpVyOMwI1fCVU3oL/dAnnLBG7oiPXntO5LHOiMrfNXCA==", + "dev": true, "requires": { "@rollup/pluginutils": "^3.0.8", "@types/resolve": "0.0.8", @@ -375,6 +4310,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, "requires": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", @@ -384,17 +4320,20 @@ "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true }, "@types/estree": { "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true }, "@types/glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==", + "dev": true, "requires": { "@types/minimatch": "*", "@types/node": "*" @@ -403,22 +4342,26 @@ "@types/json-schema": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", - "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==" + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true }, "@types/node": { "version": "14.0.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.13.tgz", - "integrity": "sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==" + "integrity": "sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==", + "dev": true }, "@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, "requires": { "@types/node": "*" } @@ -427,6 +4370,7 @@ "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "dev": true, "requires": { "@typescript-eslint/experimental-utils": "2.34.0", "functional-red-black-tree": "^1.0.1", @@ -438,6 +4382,7 @@ "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, "requires": { "@types/json-schema": "^7.0.3", "@typescript-eslint/typescript-estree": "2.34.0", @@ -449,6 +4394,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" } @@ -459,6 +4405,7 @@ "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", "@typescript-eslint/experimental-utils": "2.34.0", @@ -470,6 +4417,7 @@ "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, "requires": { "debug": "^4.1.1", "eslint-visitor-keys": "^1.1.0", @@ -483,24 +4431,29 @@ "semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true } } }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true }, "acorn-jsx": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", - "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==" + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true, + "requires": {} }, "ajv": { "version": "6.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -512,6 +4465,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, "requires": { "type-fest": "^0.21.3" }, @@ -519,19 +4473,22 @@ "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true } } }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -540,6 +4497,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -547,27 +4505,32 @@ "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "binaryextensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", - "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==" + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -576,22 +4539,26 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true }, "builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==" + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -601,12 +4568,14 @@ "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, "requires": { "restore-cursor": "^3.1.0" } @@ -614,17 +4583,20 @@ "cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -632,22 +4604,26 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -656,6 +4632,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -667,7 +4644,8 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -675,6 +4653,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, "requires": { "ms": "^2.1.1" } @@ -682,22 +4661,26 @@ "deep-freeze": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", - "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=" + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=", + "dev": true }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "requires": { "path-type": "^4.0.0" }, @@ -705,7 +4688,8 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true } } }, @@ -713,6 +4697,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, "requires": { "esutils": "^2.0.2" } @@ -721,6 +4706,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/editions/-/editions-2.3.1.tgz", "integrity": "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==", + "dev": true, "requires": { "errlop": "^2.0.0", "semver": "^6.3.0" @@ -729,12 +4715,14 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "errlop": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/errlop/-/errlop-2.2.0.tgz", - "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==" + "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==", + "dev": true }, "error-stack-parser": { "version": "2.0.6", @@ -748,17 +4736,20 @@ "es6-promisify": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz", - "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==" + "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "eslint": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "ajv": "^6.10.0", @@ -802,7 +4793,8 @@ "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true } } }, @@ -810,6 +4802,7 @@ "version": "3.1.4", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz", "integrity": "sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==", + "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" } @@ -818,6 +4811,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -827,6 +4821,7 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" } @@ -834,12 +4829,14 @@ "eslint-visitor-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true }, "espree": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, "requires": { "acorn": "^7.1.0", "acorn-jsx": "^5.1.0", @@ -849,12 +4846,14 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "esquery": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz", "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==", + "dev": true, "requires": { "estraverse": "^4.0.0" } @@ -863,6 +4862,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, "requires": { "estraverse": "^4.1.0" } @@ -870,22 +4870,26 @@ "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true }, "estree-walker": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, "requires": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -895,17 +4899,20 @@ "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true }, "fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true }, "fast-glob": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -919,6 +4926,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -927,6 +4935,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -934,12 +4943,14 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.0.5" @@ -949,6 +4960,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -958,17 +4970,20 @@ "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, "fastq": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, "requires": { "reusify": "^1.0.4" } @@ -977,6 +4992,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } @@ -985,6 +5001,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, "requires": { "flat-cache": "^2.0.1" } @@ -993,6 +5010,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, "requires": { "flatted": "^2.0.0", "rimraf": "2.6.3", @@ -1002,27 +5020,32 @@ "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true }, "gensync": { "version": "1.0.0-beta.1", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==" + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1036,6 +5059,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -1044,6 +5068,7 @@ "version": "12.3.0", "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, "requires": { "type-fest": "^0.8.1" } @@ -1052,6 +5077,7 @@ "version": "10.0.2", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, "requires": { "@types/glob": "^7.1.1", "array-union": "^2.1.0", @@ -1066,19 +5092,22 @@ "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true } } }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -1086,12 +5115,14 @@ "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1100,12 +5131,14 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1114,12 +5147,14 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, "requires": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.0", @@ -1140,6 +5175,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -1148,6 +5184,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1157,6 +5194,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -1164,17 +5202,20 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -1183,6 +5224,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -1192,17 +5234,20 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -1210,17 +5255,20 @@ "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "istextorbinary": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.6.0.tgz", "integrity": "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==", + "dev": true, "requires": { "binaryextensions": "^2.1.2", "editions": "^2.2.0", @@ -1231,6 +5279,7 @@ "version": "26.0.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.0.0.tgz", "integrity": "sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw==", + "dev": true, "requires": { "merge-stream": "^2.0.0", "supports-color": "^7.0.0" @@ -1239,12 +5288,14 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -1254,12 +5305,14 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1268,22 +5321,26 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, "json5": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, "requires": { "minimist": "^1.2.5" }, @@ -1291,7 +5348,8 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true } } }, @@ -1299,6 +5357,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -1307,27 +5366,32 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1335,12 +5399,14 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -1348,27 +5414,32 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -1377,6 +5448,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -1385,6 +5457,7 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -1397,12 +5470,14 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "requires": { "callsites": "^3.0.0" } @@ -1410,37 +5485,44 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true }, "prettier": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", - "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==" + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, "requires": { "fast-diff": "^1.1.2" } @@ -1448,17 +5530,20 @@ "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -1466,12 +5551,14 @@ "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==" + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true }, "replace-in-files": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/replace-in-files/-/replace-in-files-2.0.3.tgz", "integrity": "sha512-wm9kg+WhKQ10CFaCS9jvUtgw9JnaPilm4TqSRq57H06v5EgX7hTrr/qwgyvq3G+IeNhmr6VTW84LvfnpZfq5/g==", + "dev": true, "requires": { "co": "^4.6.0", "es6-promisify": "^6.0.2", @@ -1484,6 +5571,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -1491,12 +5579,14 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -1505,12 +5595,14 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, "requires": { "glob": "^7.1.3" } @@ -1519,6 +5611,7 @@ "version": "2.17.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.17.0.tgz", "integrity": "sha512-4Um68vKyyTLzT+EWClgc+nyxSlunlmx8wgCO16RDicwxvccnyBHguoNqxPaJL/YPAdvuAJkqaFPf/BfDojzEZA==", + "dev": true, "requires": { "fsevents": "~2.1.2" }, @@ -1527,6 +5620,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, "optional": true } } @@ -1535,6 +5629,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz", "integrity": "sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw==", + "dev": true, "requires": { "@babel/code-frame": "^7.8.3", "jest-worker": "^26.0.0", @@ -1545,17 +5640,20 @@ "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true }, "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, "requires": { "tslib": "^1.9.0" } @@ -1563,22 +5661,26 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true }, "serialize-javascript": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "dev": true, "requires": { "randombytes": "^2.1.0" } @@ -1587,6 +5689,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -1594,22 +5697,26 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true }, "signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", @@ -1619,19 +5726,22 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true } } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true }, "source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -1640,14 +5750,16 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "stackframe": { "version": "1.2.0", @@ -1659,6 +5771,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1669,6 +5782,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -1679,6 +5793,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" }, @@ -1686,19 +5801,22 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true } } }, "strip-json-comments": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -1707,6 +5825,7 @@ "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, "requires": { "ajv": "^6.10.2", "lodash": "^4.17.14", @@ -1717,17 +5836,20 @@ "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -1740,6 +5862,7 @@ "version": "4.8.0", "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -1749,29 +5872,34 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "textextensions": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", - "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==" + "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", + "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, "requires": { "os-tmpdir": "~1.0.2" } @@ -1779,17 +5907,20 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true }, "tslib": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", - "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==" + "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==", + "dev": true }, "tsutils": { "version": "3.17.1", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, "requires": { "tslib": "^1.8.1" } @@ -1798,6 +5929,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -1805,17 +5937,20 @@ "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true }, "typescript": { "version": "4.6.0-dev.20211126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.0-dev.20211126.tgz", - "integrity": "sha512-m+LKstqVv6FYW363aIbO6bm8awsLbeSUCzU6FxPtzUF/WJkFieQfYmdVwEIzigeTpw4E2GETBXnk6P6AixcQJQ==" + "integrity": "sha512-m+LKstqVv6FYW363aIbO6bm8awsLbeSUCzU6FxPtzUF/WJkFieQfYmdVwEIzigeTpw4E2GETBXnk6P6AixcQJQ==", + "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, "requires": { "punycode": "^2.1.0" } @@ -1823,12 +5958,14 @@ "v8-compile-cache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==" + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -1836,17 +5973,20 @@ "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, "requires": { "mkdirp": "^0.5.1" } @@ -1966,6 +6106,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "csstype": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -2712,7 +6857,8 @@ "ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} }, "xmlhttprequest-ssl": { "version": "2.0.0", diff --git a/tracker/tracker-assist/package.json b/tracker/tracker-assist/package.json index 63eb23944..c90a674d3 100644 --- a/tracker/tracker-assist/package.json +++ b/tracker/tracker-assist/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker-assist", "description": "Tracker plugin for screen assistance through the WebRTC", - "version": "3.5.3", + "version": "3.5.4", "keywords": [ "WebRTC", "assistance", @@ -24,6 +24,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { + "csstype": "^3.0.10", "npm-dragndrop": "^1.2.0", "peerjs": "^1.3.2", "socket.io-client": "^4.4.1" From a1402239237e0b8787a8034dad0bf47b263effbf Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 2 Mar 2022 19:07:21 +0100 Subject: [PATCH 028/101] feat(api): cleaned unused custom_metrics endpoints feat(api): custom_metrics support list of issues feat(api): custom_metrics support table-pieChart feat(api): custom_metrics support table-table feat(api): custom_metrics handle redundant series update feat(api): custom_metrics default create-values feat(api): custom_metrics refactored schemas feat(DB): custom_metrics structure changes --- api/chalicelib/core/custom_metrics.py | 61 ++++++-------- api/chalicelib/core/sessions.py | 23 ++++- api/routers/core.py | 44 +++++----- api/schemas.py | 83 ++++++++++--------- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 26 +++++- .../db/init_dbs/postgresql/init_schema.sql | 17 ++-- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 25 +++++- .../db/init_dbs/postgresql/init_schema.sql | 17 ++-- 8 files changed, 179 insertions(+), 117 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index c0370083f..a48723ec5 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -6,22 +6,22 @@ from chalicelib.utils import helper, pg_client from chalicelib.utils.TimeUTC import TimeUTC -def __try_live(project_id, data: schemas.TryCustomMetricsSchema): +def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): results = [] for i, s in enumerate(data.series): s.filter.startDate = data.startDate s.filter.endDate = data.endDate results.append(sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, - view_type=data.viewType, metric_type=data.metricType, - metric_of=data.metricOf)) - if data.viewType == schemas.MetricViewType.progress: + view_type=data.view_type, metric_type=data.metric_type, + metric_of=data.metric_of, metric_value=data.metric_value)) + if data.view_type == schemas.MetricTimeseriesViewType.progress: r = {"count": results[-1]} diff = s.filter.endDate - s.filter.startDate s.filter.startDate = data.endDate s.filter.endDate = data.endDate - diff r["previousCount"] = sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, - view_type=data.viewType, metric_type=data.metricType, - metric_of=data.metricOf) + view_type=data.view_type, metric_type=data.metric_type, + metric_of=data.metric_of, metric_value=data.metric_value) r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) r["seriesName"] = s.name if s.name else i + 1 r["seriesId"] = s.series_id if s.series_id else None @@ -29,9 +29,9 @@ def __try_live(project_id, data: schemas.TryCustomMetricsSchema): return results -def merged_live(project_id, data: schemas.TryCustomMetricsSchema): +def merged_live(project_id, data: schemas.CreateCustomMetricsSchema): series_charts = __try_live(project_id=project_id, data=data) - if data.viewType == schemas.MetricViewType.progress or data.metricType == schemas.MetricType.table: + if data.view_type == schemas.MetricTimeseriesViewType.progress or data.metric_type == schemas.MetricType.table: return series_charts results = [{}] * len(series_charts[0]) for i in range(len(results)): @@ -45,9 +45,9 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) if metric is None: return None - metric: schemas.TryCustomMetricsSchema = schemas.TryCustomMetricsSchema.parse_obj({**data.dict(), **metric}) + metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) series_charts = __try_live(project_id=project_id, data=metric) - if data.viewType == schemas.MetricViewType.progress: + if metric.view_type == schemas.MetricTimeseriesViewType.progress: return series_charts results = [{}] * len(series_charts[0]) for i in range(len(results)): @@ -57,11 +57,12 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa return results -def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricRawPayloadSchema): +def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricSessionsPayloadSchema): metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) if metric is None: return None - metric: schemas.TryCustomMetricsSchema = schemas.TryCustomMetricsSchema.parse_obj({**data.dict(), **metric}) + metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj( + {**data.dict(), **metric}) results = [] for s in metric.series: s.filter.startDate = data.startDate @@ -84,8 +85,9 @@ def create(project_id, user_id, data: schemas.CreateCustomMetricsSchema): data.series = None params = {"user_id": user_id, "project_id": project_id, **data.dict(), **_data} query = cur.mogrify(f"""\ - WITH m AS (INSERT INTO metrics (project_id, user_id, name) - VALUES (%(project_id)s, %(user_id)s, %(name)s) + WITH m AS (INSERT INTO metrics (project_id, user_id, name, is_public, view_type, metric_type, metric_of, metric_value) + VALUES (%(project_id)s, %(user_id)s, %(name)s, %(is_public)s, + %(view_type)s, %(metric_type)s, %(metric_of)s, %(metric_value)s) RETURNING *) INSERT INTO metric_series(metric_id, index, name, filter) @@ -100,32 +102,21 @@ def create(project_id, user_id, data: schemas.CreateCustomMetricsSchema): return {"data": get(metric_id=r["metric_id"], project_id=project_id, user_id=user_id)} -def __get_series_id(metric_id): - with pg_client.PostgresClient() as cur: - cur.execute( - cur.mogrify( - """SELECT series_id - FROM metric_series - WHERE metric_series.metric_id = %(metric_id)s - AND metric_series.deleted_at ISNULL;""", - {"metric_id": metric_id} - ) - ) - rows = cur.fetchall() - return [r["series_id"] for r in rows] - - def update(metric_id, user_id, project_id, data: schemas.UpdateCustomMetricsSchema): - series_ids = __get_series_id(metric_id) + metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) + if metric is None: + return None + series_ids = [r["seriesId"] for r in metric["series"]] n_series = [] d_series_ids = [] u_series = [] u_series_ids = [] params = {"metric_id": metric_id, "is_public": data.is_public, "name": data.name, - "user_id": user_id, "project_id": project_id} + "user_id": user_id, "project_id": project_id, "view_type": data.view_type, + "metric_type": data.metric_type, "metric_of": data.metric_of, "metric_value": data.metric_value} for i, s in enumerate(data.series): prefix = "u_" - if s.series_id is None: + if s.series_id is None or s.series_id not in series_ids: n_series.append({"i": i, "s": s}) prefix = "n_" s.index = i @@ -167,7 +158,9 @@ def update(metric_id, user_id, project_id, data: schemas.UpdateCustomMetricsSche query = cur.mogrify(f"""\ {"WITH " if len(sub_queries) > 0 else ""}{",".join(sub_queries)} UPDATE metrics - SET name = %(name)s, is_public= %(is_public)s + SET name = %(name)s, is_public= %(is_public)s, + view_type= %(view_type)s, metric_type= %(metric_type)s, + metric_of= %(metric_of)s, metric_value= %(metric_value)s WHERE metric_id = %(metric_id)s AND project_id = %(project_id)s AND (user_id = %(user_id)s OR is_public) @@ -226,7 +219,7 @@ def get(metric_id, project_id, user_id, flatten=True): cur.mogrify( """SELECT * FROM metrics - LEFT JOIN LATERAL (SELECT jsonb_agg(metric_series.* ORDER BY index) AS series + LEFT JOIN LATERAL (SELECT COALESCE(jsonb_agg(metric_series.* ORDER BY index),'[]'::jsonb) AS series FROM metric_series WHERE metric_series.metric_id = metrics.metric_id AND metric_series.deleted_at ISNULL diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index e8e778584..0bf3c9366 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -1,3 +1,5 @@ +from typing import List + import schemas from chalicelib.core import events, metadata, events_ios, \ sessions_mobs, issues, projects, errors, resources, assist, performance_event @@ -265,12 +267,16 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, density: int, - view_type: schemas.MetricViewType, metric_type: schemas.MetricType, metric_of: schemas.TableMetricOfType): + view_type: schemas.MetricTimeseriesViewType, metric_type: schemas.MetricType, + metric_of: schemas.TableMetricOfType, metric_value: List): step_size = int(metrics_helper.__get_step_size(endTimestamp=data.endDate, startTimestamp=data.startDate, density=density, factor=1, decimal=True)) extra_event = None if metric_of == schemas.TableMetricOfType.visited_url: extra_event = "events.pages" + elif metric_of == schemas.TableMetricOfType.issues and len(metric_value) > 0: + data.filters.append(schemas.SessionSearchFilterSchema(value=metric_value, type=schemas.FilterType.issue, + operator=schemas.SearchEventOperator._is)) full_args, query_part, sort = search_query_parts(data=data, error_status=None, errors_only=False, favorite_only=False, issue=None, project_id=project_id, user_id=None, extra_event=extra_event) @@ -278,7 +284,7 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d sessions = [] with pg_client.PostgresClient() as cur: if metric_type == schemas.MetricType.timeseries: - if view_type == schemas.MetricViewType.line_chart: + if view_type == schemas.MetricTimeseriesViewType.line_chart: main_query = cur.mogrify(f"""WITH full_sessions AS (SELECT DISTINCT ON(s.session_id) s.session_id, s.start_ts {query_part}) SELECT generated_timestamp AS timestamp, @@ -296,9 +302,9 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d # print("--------------------") # print(main_query) - cur.execute(main_query) # print("--------------------") - if view_type == schemas.MetricViewType.line_chart: + cur.execute(main_query) + if view_type == schemas.MetricTimeseriesViewType.line_chart: sessions = cur.fetchall() else: sessions = cur.fetchone()["count"] @@ -306,6 +312,7 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d if isinstance(metric_of, schemas.TableMetricOfType): main_col = "user_id" extra_col = "" + extra_where = "" pre_query = "" if metric_of == schemas.TableMetricOfType.user_country: main_col = "user_country" @@ -316,6 +323,13 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d elif metric_of == schemas.TableMetricOfType.issues: main_col = "issue" extra_col = f", UNNEST(s.issue_types) AS {main_col}" + if len(metric_value) > 0: + extra_where = [] + for i in range(len(metric_value)): + arg_name = f"selected_issue_{i}" + extra_where.append(f"{main_col} = %({arg_name})s") + full_args[arg_name] = metric_value[i] + extra_where = f"WHERE ({' OR '.join(extra_where)})" elif metric_of == schemas.TableMetricOfType.visited_url: main_col = "base_path" extra_col = ", base_path" @@ -332,6 +346,7 @@ def search2_series(data: schemas.SessionsSearchPayloadSchema, project_id: int, d {query_part} ORDER BY s.session_id desc) AS filtred_sessions ) AS full_sessions + {extra_where} GROUP BY {main_col} ORDER BY session_count DESC) AS users_sessions;""", full_args) diff --git a/api/routers/core.py b/api/routers/core.py index 9af9fec63..9cf9dfd0c 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -1089,27 +1089,12 @@ def change_client_password(data: schemas.EditUserPasswordSchema = Body(...), @app.post('/{projectId}/custom_metrics/try', tags=["customMetrics"]) @app.put('/{projectId}/custom_metrics/try', tags=["customMetrics"]) -def try_custom_metric(projectId: int, data: schemas.TryCustomMetricsSchema = Body(...), +def try_custom_metric(projectId: int, data: schemas.CreateCustomMetricsSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): return {"data": custom_metrics.merged_live (project_id=projectId, data=data)} -@app.post('/{projectId}/custom_metrics/sessions', tags=["customMetrics"]) -def get_custom_metric_sessions(projectId: int, data: schemas.CustomMetricRawPayloadSchema2 = Body(...), - context: schemas.CurrentContext = Depends(OR_context)): - return {"data": custom_metrics.get_sessions(project_id=projectId, user_id=context.user_id, metric_id=data.metric_id, - data=data)} - - -@app.post('/{projectId}/custom_metrics/chart', tags=["customMetrics"]) -@app.put('/{projectId}/custom_metrics/chart', tags=["customMetrics"]) -def get_custom_metric_chart(projectId: int, data: schemas.CustomMetricChartPayloadSchema2 = Body(...), - context: schemas.CurrentContext = Depends(OR_context)): - return {"data": custom_metrics.make_chart(project_id=projectId, user_id=context.user_id, metric_id=data.metric_id, - data=data)} - - @app.post('/{projectId}/custom_metrics', tags=["customMetrics"]) @app.put('/{projectId}/custom_metrics', tags=["customMetrics"]) def add_custom_metric(projectId: int, data: schemas.CreateCustomMetricsSchema = Body(...), @@ -1124,29 +1109,40 @@ def get_custom_metrics(projectId: int, context: schemas.CurrentContext = Depends @app.get('/{projectId}/custom_metrics/{metric_id}', tags=["customMetrics"]) def get_custom_metric(projectId: int, metric_id: int, context: schemas.CurrentContext = Depends(OR_context)): - return {"data": custom_metrics.get(project_id=projectId, user_id=context.user_id, metric_id=metric_id)} + data = custom_metrics.get(project_id=projectId, user_id=context.user_id, metric_id=metric_id) + if data is None: + return {"errors": ["custom metric not found"]} + return {"data": data} @app.post('/{projectId}/custom_metrics/{metric_id}/sessions', tags=["customMetrics"]) -def get_custom_metric_sessions(projectId: int, metric_id: int, data: schemas.CustomMetricRawPayloadSchema = Body(...), +def get_custom_metric_sessions(projectId: int, metric_id: int, + data: schemas.CustomMetricSessionsPayloadSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - return {"data": custom_metrics.get_sessions(project_id=projectId, user_id=context.user_id, metric_id=metric_id, - data=data)} + data = custom_metrics.get_sessions(project_id=projectId, user_id=context.user_id, metric_id=metric_id, data=data) + if data is None: + return {"errors": ["custom metric not found"]} + return {"data": data} @app.post('/{projectId}/custom_metrics/{metric_id}/chart', tags=["customMetrics"]) def get_custom_metric_chart(projectId: int, metric_id: int, data: schemas.CustomMetricChartPayloadSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - return {"data": custom_metrics.make_chart(project_id=projectId, user_id=context.user_id, metric_id=metric_id, - data=data)} + data = custom_metrics.make_chart(project_id=projectId, user_id=context.user_id, metric_id=metric_id, + data=data) + if data is None: + return {"errors": ["custom metric not found"]} + return {"data": data} @app.post('/{projectId}/custom_metrics/{metric_id}', tags=["customMetrics"]) @app.put('/{projectId}/custom_metrics/{metric_id}', tags=["customMetrics"]) def update_custom_metric(projectId: int, metric_id: int, data: schemas.UpdateCustomMetricsSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - return { - "data": custom_metrics.update(project_id=projectId, user_id=context.user_id, metric_id=metric_id, data=data)} + data = custom_metrics.update(project_id=projectId, user_id=context.user_id, metric_id=metric_id, data=data) + if data is None: + return {"errors": ["custom metric not found"]} + return {"data": data} @app.post('/{projectId}/custom_metrics/{metric_id}/status', tags=["customMetrics"]) diff --git a/api/schemas.py b/api/schemas.py index c5d6945db..40cc8e24d 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -561,7 +561,7 @@ class _SessionSearchEventSchema(_SessionSearchEventRaw): value: Union[List[Union[_SessionSearchEventRaw, str]], str] = Field(...) -class _SessionSearchFilterSchema(__MixedSearchFilter): +class SessionSearchFilterSchema(__MixedSearchFilter): is_event: bool = Field(False, const=False) value: Union[Optional[Union[IssueType, PlatformType, int, str]], Optional[List[Union[IssueType, PlatformType, int, str]]]] = Field(...) @@ -594,7 +594,7 @@ class _SessionSearchFilterSchema(__MixedSearchFilter): class SessionsSearchPayloadSchema(BaseModel): events: List[_SessionSearchEventSchema] = Field([]) - filters: List[_SessionSearchFilterSchema] = Field([]) + filters: List[SessionSearchFilterSchema] = Field([]) startDate: int = Field(None) endDate: int = Field(None) sort: str = Field(default="startTs") @@ -608,7 +608,7 @@ class SessionsSearchPayloadSchema(BaseModel): class FlatSessionsSearchPayloadSchema(SessionsSearchPayloadSchema): events: Optional[List[_SessionSearchEventSchema]] = Field([]) - filters: List[Union[_SessionSearchFilterSchema, _SessionSearchEventSchema]] = Field([]) + filters: List[Union[SessionSearchFilterSchema, _SessionSearchEventSchema]] = Field([]) @root_validator(pre=True) def flat_to_original(cls, values): @@ -723,37 +723,21 @@ class CustomMetricCreateSeriesSchema(BaseModel): alias_generator = attribute_to_camel_case -class CreateCustomMetricsSchema(BaseModel): - name: str = Field(...) - series: List[CustomMetricCreateSeriesSchema] = Field(..., min_items=1) - is_public: Optional[bool] = Field(True) - - class Config: - alias_generator = attribute_to_camel_case - - -class MetricViewType(str, Enum): +class MetricTimeseriesViewType(str, Enum): line_chart = "lineChart" progress = "progress" +class MetricTableViewType(str, Enum): + table = "table" + pie_chart = "pieChart" + + class MetricType(str, Enum): timeseries = "timeseries" table = "table" -class CustomMetricRawPayloadSchema(BaseModel): - startDate: int = Field(TimeUTC.now(-7)) - endDate: int = Field(TimeUTC.now()) - - class Config: - alias_generator = attribute_to_camel_case - - -class CustomMetricRawPayloadSchema2(CustomMetricRawPayloadSchema): - metric_id: int = Field(...) - - class TableMetricOfType(str, Enum): user_os = FilterType.user_os.value user_browser = FilterType.user_browser.value @@ -768,29 +752,50 @@ class TimeseriesMetricOfType(str, Enum): session_count = "sessionCount" -class CustomMetricChartPayloadSchema(CustomMetricRawPayloadSchema): +class CustomMetricSessionsPayloadSchema(BaseModel): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) + + class Config: + alias_generator = attribute_to_camel_case + + +class CustomMetricChartPayloadSchema(CustomMetricSessionsPayloadSchema): density: int = Field(7) - viewType: MetricViewType = Field(MetricViewType.line_chart) - metricType: MetricType = Field(MetricType.timeseries) - metricOf: Union[TableMetricOfType, TimeseriesMetricOfType] = Field(TableMetricOfType.user_id) + + class Config: + alias_generator = attribute_to_camel_case + + +class CreateCustomMetricsSchema(CustomMetricChartPayloadSchema): + name: str = Field(...) + series: List[CustomMetricCreateSeriesSchema] = Field(..., min_items=1) + is_public: bool = Field(default=True, const=True) + view_type: Union[MetricTimeseriesViewType, MetricTableViewType] = Field(MetricTimeseriesViewType.line_chart) + metric_type: MetricType = Field(MetricType.timeseries) + metric_of: Union[TableMetricOfType, TimeseriesMetricOfType] = Field(TableMetricOfType.user_id) + metric_value: List[IssueType] = Field([]) # metricFraction: float = Field(None, gt=0, lt=1) @root_validator def validator(cls, values): - if isinstance(values.get("metricOf"), TimeseriesMetricOfType): - assert values.get("metricType") == MetricType.timeseries, \ - f"Only metricType:{MetricType.timeseries.value} is allowed for metricOf: {values.get('metricOf')}" + if values.get("metric_type") == MetricType.table: + assert isinstance(values.get("view_type"), MetricTableViewType), \ + f"viewType must be of type {MetricTableViewType} for metricType:{MetricType.table.value}" + assert isinstance(values.get("metric_of"), TableMetricOfType), \ + f"metricOf must be of type {TableMetricOfType} for metricType:{MetricType.table.value}" + if values.get("metric_of") != TableMetricOfType.issues: + assert values.get("metric_value") is None or len(values.get("metric_value")) == 0, \ + f"metricValue is only available for metricOf:{TableMetricOfType.issues.value}" + elif values.get("metric_type") == MetricType.timeseries: + assert isinstance(values.get("view_type"), MetricTimeseriesViewType), \ + f"viewType must be of type {MetricTimeseriesViewType} for metricType:{MetricType.timeseries.value}" + assert isinstance(values.get("metric_of"), TimeseriesMetricOfType), \ + f"metricOf must be of type {TimeseriesMetricOfType} for metricType:{MetricType.timeseries.value}" return values - -class CustomMetricChartPayloadSchema2(CustomMetricChartPayloadSchema): - metric_id: int = Field(...) - - -class TryCustomMetricsSchema(CreateCustomMetricsSchema, CustomMetricChartPayloadSchema): - name: Optional[str] = Field(None) + class Config: + alias_generator = attribute_to_camel_case class CustomMetricUpdateSeriesSchema(CustomMetricCreateSeriesSchema): diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index bb24fae51..e89a97f47 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -5,6 +5,10 @@ $$ SELECT 'v1.5.X-ee' $$ LANGUAGE sql IMMUTABLE; +UPDATE metrics +SET is_public= TRUE; + + DO $$ BEGIN @@ -20,7 +24,27 @@ $$ $$ LANGUAGE plpgsql; +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE nsp.nspname = current_schema() + AND typ.typname = 'metric_view_type') THEN + CREATE TYPE metric_view_type AS ENUM ('lineChart','progress','table','pieChart'); + END IF; + END; +$$ +LANGUAGE plpgsql; + ALTER TABLE metrics ADD COLUMN IF NOT EXISTS - metric_type metric_type NOT NULL DEFAULT 'timeseries'; + metric_type metric_type NOT NULL DEFAULT 'timeseries', + ADD COLUMN IF NOT EXISTS + view_type metric_view_type NOT NULL DEFAULT 'lineChart', + ADD COLUMN IF NOT EXISTS + metric_of text NOT NULL DEFAULT 'sessionCount'; + COMMIT; \ No newline at end of file diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 00b533f16..2cca09903 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -771,17 +771,20 @@ $$ CREATE INDEX IF NOT EXISTS traces_tenant_id_idx ON traces (tenant_id); CREATE TYPE metric_type AS ENUM ('timeseries','table'); + CREATE TYPE metric_view_type AS ENUM ('lineChart','progress','table','pieChart'); CREATE TABLE IF NOT EXISTS metrics ( metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, - project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, - user_id integer REFERENCES users (user_id) ON DELETE SET NULL, - name text NOT NULL, - is_public boolean NOT NULL DEFAULT FALSE, - active boolean NOT NULL DEFAULT TRUE, - created_at timestamp default timezone('utc'::text, now()) not null, + project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, + user_id integer REFERENCES users (user_id) ON DELETE SET NULL, + name text NOT NULL, + is_public boolean NOT NULL DEFAULT FALSE, + active boolean NOT NULL DEFAULT TRUE, + created_at timestamp DEFAULT timezone('utc'::text, now()) not null, deleted_at timestamp, - metric_type metric_type NOT NULL DEFAULT 'timeseries' + metric_type metric_type NOT NULL DEFAULT 'timeseries', + view_type metric_view_type NOT NULL DEFAULT 'lineChart', + metric_of text NOT NULL DEFAULT 'sessionCount' ); CREATE INDEX IF NOT EXISTS metrics_user_id_is_public_idx ON public.metrics (user_id, is_public); CREATE TABLE IF NOT EXISTS metric_series diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index 9c5878fd4..704e08ab5 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -5,6 +5,9 @@ $$ SELECT 'v1.5.X' $$ LANGUAGE sql IMMUTABLE; +UPDATE metrics +SET is_public= TRUE; + DO $$ BEGIN @@ -20,7 +23,27 @@ $$ $$ LANGUAGE plpgsql; +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE nsp.nspname = current_schema() + AND typ.typname = 'metric_view_type') THEN + CREATE TYPE metric_view_type AS ENUM ('lineChart','progress','table','pieChart'); + END IF; + END; +$$ +LANGUAGE plpgsql; + ALTER TABLE metrics ADD COLUMN IF NOT EXISTS - metric_type metric_type NOT NULL DEFAULT 'timeseries'; + metric_type metric_type NOT NULL DEFAULT 'timeseries', + ADD COLUMN IF NOT EXISTS + view_type metric_view_type NOT NULL DEFAULT 'lineChart', + ADD COLUMN IF NOT EXISTS + metric_of text NOT NULL DEFAULT 'sessionCount'; + COMMIT; \ No newline at end of file diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 14a495ada..51fa20242 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -901,17 +901,20 @@ $$ CREATE INDEX jobs_project_id_idx ON jobs (project_id); CREATE TYPE metric_type AS ENUM ('timeseries','table'); + CREATE TYPE metric_view_type AS ENUM ('lineChart','progress','table','pieChart'); CREATE TABLE metrics ( metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, - project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, - user_id integer REFERENCES users (user_id) ON DELETE SET NULL, - name text NOT NULL, - is_public boolean NOT NULL DEFAULT FALSE, - active boolean NOT NULL DEFAULT TRUE, - created_at timestamp default timezone('utc'::text, now()) not null, + project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, + user_id integer REFERENCES users (user_id) ON DELETE SET NULL, + name text NOT NULL, + is_public boolean NOT NULL DEFAULT FALSE, + active boolean NOT NULL DEFAULT TRUE, + created_at timestamp default timezone('utc'::text, now()) not null, deleted_at timestamp, - metric_type metric_type NOT NULL DEFAULT 'timeseries' + metric_type metric_type NOT NULL DEFAULT 'timeseries', + view_type metric_view_type NOT NULL DEFAULT 'lineChart', + metric_of text NOT NULL DEFAULT 'sessionCount' ); CREATE INDEX metrics_user_id_is_public_idx ON public.metrics (user_id, is_public); CREATE TABLE metric_series From 8c151e5bea5307949ac9b499d6176fb07481fe3f Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 2 Mar 2022 20:01:59 +0100 Subject: [PATCH 029/101] feat(api): custom_metrics support metric_format --- api/chalicelib/core/custom_metrics.py | 11 +++++++---- api/schemas.py | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index a48723ec5..ecb61732f 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -85,9 +85,10 @@ def create(project_id, user_id, data: schemas.CreateCustomMetricsSchema): data.series = None params = {"user_id": user_id, "project_id": project_id, **data.dict(), **_data} query = cur.mogrify(f"""\ - WITH m AS (INSERT INTO metrics (project_id, user_id, name, is_public, view_type, metric_type, metric_of, metric_value) + WITH m AS (INSERT INTO metrics (project_id, user_id, name, is_public, + view_type, metric_type, metric_of, metric_value, metric_format) VALUES (%(project_id)s, %(user_id)s, %(name)s, %(is_public)s, - %(view_type)s, %(metric_type)s, %(metric_of)s, %(metric_value)s) + %(view_type)s, %(metric_type)s, %(metric_of)s, %(metric_value)s, %(metric_format)s) RETURNING *) INSERT INTO metric_series(metric_id, index, name, filter) @@ -113,7 +114,8 @@ def update(metric_id, user_id, project_id, data: schemas.UpdateCustomMetricsSche u_series_ids = [] params = {"metric_id": metric_id, "is_public": data.is_public, "name": data.name, "user_id": user_id, "project_id": project_id, "view_type": data.view_type, - "metric_type": data.metric_type, "metric_of": data.metric_of, "metric_value": data.metric_value} + "metric_type": data.metric_type, "metric_of": data.metric_of, + "metric_value": data.metric_value, "metric_format": data.metric_format} for i, s in enumerate(data.series): prefix = "u_" if s.series_id is None or s.series_id not in series_ids: @@ -160,7 +162,8 @@ def update(metric_id, user_id, project_id, data: schemas.UpdateCustomMetricsSche UPDATE metrics SET name = %(name)s, is_public= %(is_public)s, view_type= %(view_type)s, metric_type= %(metric_type)s, - metric_of= %(metric_of)s, metric_value= %(metric_value)s + metric_of= %(metric_of)s, metric_value= %(metric_value)s, + metric_format= %(metric_format)s WHERE metric_id = %(metric_id)s AND project_id = %(project_id)s AND (user_id = %(user_id)s OR is_public) diff --git a/api/schemas.py b/api/schemas.py index 40cc8e24d..7245dd82a 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -775,6 +775,7 @@ class CreateCustomMetricsSchema(CustomMetricChartPayloadSchema): metric_type: MetricType = Field(MetricType.timeseries) metric_of: Union[TableMetricOfType, TimeseriesMetricOfType] = Field(TableMetricOfType.user_id) metric_value: List[IssueType] = Field([]) + metric_format: Optional[str] = Field(None) # metricFraction: float = Field(None, gt=0, lt=1) @root_validator From fb72c2894b922a0504601f0ed4325e83c5cf8324 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 2 Mar 2022 20:13:18 +0100 Subject: [PATCH 030/101] feat(api): custom_metrics support metric_format feat(api): custom_metrics metric_value accept wrong values --- api/schemas.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/schemas.py b/api/schemas.py index 7245dd82a..6c94e2efa 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -778,6 +778,15 @@ class CreateCustomMetricsSchema(CustomMetricChartPayloadSchema): metric_format: Optional[str] = Field(None) # metricFraction: float = Field(None, gt=0, lt=1) + # This is used to handle wrong values sent by the UI + @root_validator(pre=True) + def remove_metric_value(cls, values): + if values.get("metric_type") == MetricType.timeseries \ + or values.get("metric_type") == MetricType.table \ + and values.get("metric_of") != TableMetricOfType.issues: + values["metric_of"] = [] + return values + @root_validator def validator(cls, values): if values.get("metric_type") == MetricType.table: From 27bb11e009294e34b7f86e6e172fea1fd2bcc808 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 2 Mar 2022 20:15:40 +0100 Subject: [PATCH 031/101] feat(DB): add metric_value and metric_format to custom_metrics --- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 10 +++++--- .../db/init_dbs/postgresql/init_schema.sql | 24 ++++++++++--------- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 10 +++++--- .../db/init_dbs/postgresql/init_schema.sql | 24 ++++++++++--------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index e89a97f47..88e1aab74 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -41,10 +41,14 @@ LANGUAGE plpgsql; ALTER TABLE metrics ADD COLUMN IF NOT EXISTS - metric_type metric_type NOT NULL DEFAULT 'timeseries', + metric_type metric_type NOT NULL DEFAULT 'timeseries', ADD COLUMN IF NOT EXISTS - view_type metric_view_type NOT NULL DEFAULT 'lineChart', + view_type metric_view_type NOT NULL DEFAULT 'lineChart', ADD COLUMN IF NOT EXISTS - metric_of text NOT NULL DEFAULT 'sessionCount'; + metric_of text NOT NULL DEFAULT 'sessionCount', + ADD COLUMN IF NOT EXISTS + metric_value text[] NOT NULL DEFAULT '{}'::text[], + ADD COLUMN IF NOT EXISTS + metric_format text; COMMIT; \ No newline at end of file diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 2cca09903..1f0f4d6f1 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -774,17 +774,19 @@ $$ CREATE TYPE metric_view_type AS ENUM ('lineChart','progress','table','pieChart'); CREATE TABLE IF NOT EXISTS metrics ( - metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, - project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, - user_id integer REFERENCES users (user_id) ON DELETE SET NULL, - name text NOT NULL, - is_public boolean NOT NULL DEFAULT FALSE, - active boolean NOT NULL DEFAULT TRUE, - created_at timestamp DEFAULT timezone('utc'::text, now()) not null, - deleted_at timestamp, - metric_type metric_type NOT NULL DEFAULT 'timeseries', - view_type metric_view_type NOT NULL DEFAULT 'lineChart', - metric_of text NOT NULL DEFAULT 'sessionCount' + metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, + project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, + user_id integer REFERENCES users (user_id) ON DELETE SET NULL, + name text NOT NULL, + is_public boolean NOT NULL DEFAULT FALSE, + active boolean NOT NULL DEFAULT TRUE, + created_at timestamp DEFAULT timezone('utc'::text, now()) not null, + deleted_at timestamp, + metric_type metric_type NOT NULL DEFAULT 'timeseries', + view_type metric_view_type NOT NULL DEFAULT 'lineChart', + metric_of text NOT NULL DEFAULT 'sessionCount', + metric_value text[] NOT NULL DEFAULT '{}'::text[], + metric_format text ); CREATE INDEX IF NOT EXISTS metrics_user_id_is_public_idx ON public.metrics (user_id, is_public); CREATE TABLE IF NOT EXISTS metric_series diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index 704e08ab5..b471511f4 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -40,10 +40,14 @@ LANGUAGE plpgsql; ALTER TABLE metrics ADD COLUMN IF NOT EXISTS - metric_type metric_type NOT NULL DEFAULT 'timeseries', + metric_type metric_type NOT NULL DEFAULT 'timeseries', ADD COLUMN IF NOT EXISTS - view_type metric_view_type NOT NULL DEFAULT 'lineChart', + view_type metric_view_type NOT NULL DEFAULT 'lineChart', ADD COLUMN IF NOT EXISTS - metric_of text NOT NULL DEFAULT 'sessionCount'; + metric_of text NOT NULL DEFAULT 'sessionCount', + ADD COLUMN IF NOT EXISTS + metric_value text[] NOT NULL DEFAULT '{}'::text[], + ADD COLUMN IF NOT EXISTS + metric_format text; COMMIT; \ No newline at end of file diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 51fa20242..232596696 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -904,17 +904,19 @@ $$ CREATE TYPE metric_view_type AS ENUM ('lineChart','progress','table','pieChart'); CREATE TABLE metrics ( - metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, - project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, - user_id integer REFERENCES users (user_id) ON DELETE SET NULL, - name text NOT NULL, - is_public boolean NOT NULL DEFAULT FALSE, - active boolean NOT NULL DEFAULT TRUE, - created_at timestamp default timezone('utc'::text, now()) not null, - deleted_at timestamp, - metric_type metric_type NOT NULL DEFAULT 'timeseries', - view_type metric_view_type NOT NULL DEFAULT 'lineChart', - metric_of text NOT NULL DEFAULT 'sessionCount' + metric_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY, + project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE, + user_id integer REFERENCES users (user_id) ON DELETE SET NULL, + name text NOT NULL, + is_public boolean NOT NULL DEFAULT FALSE, + active boolean NOT NULL DEFAULT TRUE, + created_at timestamp default timezone('utc'::text, now()) not null, + deleted_at timestamp, + metric_type metric_type NOT NULL DEFAULT 'timeseries', + view_type metric_view_type NOT NULL DEFAULT 'lineChart', + metric_of text NOT NULL DEFAULT 'sessionCount', + metric_value text[] NOT NULL DEFAULT '{}'::text[], + metric_format text ); CREATE INDEX metrics_user_id_is_public_idx ON public.metrics (user_id, is_public); CREATE TABLE metric_series From 68cdb08395781d50d42a99838bd32dfbd20694b5 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 2 Mar 2022 20:42:44 +0100 Subject: [PATCH 032/101] feat(DB): graphql_details support feat(api): graphql_details support --- api/chalicelib/core/sessions.py | 37 +++++++++++++++++-- api/schemas.py | 21 +++++++++-- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 25 ++++++++----- 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index 0bf3c9366..dc6bf85c7 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -592,14 +592,15 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr is_any = _isAny_opreator(event.operator) if not isinstance(event.value, list): event.value = [event.value] - if not is_any and len(event.value) == 0 and event_type not in [schemas.EventType.request_details] \ + if not is_any and len(event.value) == 0 and event_type not in [schemas.EventType.request_details, + schemas.EventType.graphql_details] \ or event_type in [schemas.PerformanceEventType.location_dom_complete, schemas.PerformanceEventType.location_largest_contentful_paint_time, schemas.PerformanceEventType.location_ttfb, schemas.PerformanceEventType.location_avg_cpu_load, schemas.PerformanceEventType.location_avg_memory_usage ] and (event.source is None or len(event.source) == 0) \ - or event_type in [schemas.EventType.request_details] and ( + or event_type in [schemas.EventType.request_details, schemas.EventType.graphql_details] and ( event.filters is None or len(event.filters) == 0): continue op = __get_sql_operator(event.operator) @@ -848,7 +849,37 @@ def search_query_parts(data, error_status, errors_only, favorite_only, issue, pr event_where.append( _multiple_conditions(f"main.response_body {op} %({e_k_f})s", f.value, value_key=e_k_f)) else: - print(f"undefined fetch filter: {f.type}") + print(f"undefined FETCH filter: {f.type}") + elif event_type == schemas.EventType.graphql_details: + event_from = event_from % f"{events.event_type.GRAPHQL.table} AS main " + for j, f in enumerate(event.filters): + is_any = _isAny_opreator(f.operator) + if is_any or len(f.value) == 0: + continue + op = __get_sql_operator(f.operator) + e_k_f = e_k + f"_graphql{j}" + full_args = {**full_args, **_multiple_values(f.value, value_key=e_k_f)} + if f.type == schemas.GraphqlFilterType._name: + event_where.append( + _multiple_conditions(f"main.{events.event_type.GRAPHQL.column} {op} %({e_k_f})s", f.value, + value_key=e_k_f)) + elif f.type == schemas.GraphqlFilterType._status_code: + event_where.append( + _multiple_conditions(f"main.status_code {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.GraphqlFilterType._method: + event_where.append( + _multiple_conditions(f"main.method {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.GraphqlFilterType._duration: + event_where.append( + _multiple_conditions(f"main.duration {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.GraphqlFilterType._request_body: + event_where.append( + _multiple_conditions(f"main.request_body {op} %({e_k_f})s", f.value, value_key=e_k_f)) + elif f.type == schemas.GraphqlFilterType._response_body: + event_where.append( + _multiple_conditions(f"main.response_body {op} %({e_k_f})s", f.value, value_key=e_k_f)) + else: + print(f"undefined GRAPHQL filter: {f.type}") else: continue if event_index == 0 or or_events: diff --git a/api/schemas.py b/api/schemas.py index 6c94e2efa..2acdab45f 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -386,6 +386,7 @@ class EventType(str, Enum): request = "REQUEST" request_details = "FETCH" graphql = "GRAPHQL" + graphql_details = "GRAPHQL_DETAILS" state_action = "STATEACTION" error = "ERROR" click_ios = "CLICK_IOS" @@ -512,8 +513,17 @@ class FetchFilterType(str, Enum): _response_body = "FETCH_RESPONSE_BODY" -class RequestFilterSchema(BaseModel): - type: FetchFilterType = Field(...) +class GraphqlFilterType(str, Enum): + _name = "GRAPHQL_NAME" + _status_code = "GRAPHQL_STATUS_CODE" + _method = "GRAPHQL_METHOD" + _duration = "GRAPHQL_DURATION" + _request_body = "GRAPHQL_REQUEST_BODY" + _response_body = "GRAPHQL_RESPONSE_BODY" + + +class RequestGraphqlFilterSchema(BaseModel): + type: Union[FetchFilterType, GraphqlFilterType] = Field(...) value: List[Union[int, str]] = Field(...) operator: Union[SearchEventOperator, MathOperator] = Field(...) @@ -525,7 +535,7 @@ class _SessionSearchEventRaw(__MixedSearchFilter): operator: SearchEventOperator = Field(...) source: Optional[List[Union[ErrorSource, int, str]]] = Field(None) sourceOperator: Optional[MathOperator] = Field(None) - filters: Optional[List[RequestFilterSchema]] = Field(None) + filters: Optional[List[RequestGraphqlFilterSchema]] = Field(None) @root_validator def event_validator(cls, values): @@ -552,7 +562,10 @@ class _SessionSearchEventRaw(__MixedSearchFilter): values["source"] = [ErrorSource.js_exception] elif values.get("type") == EventType.request_details: assert isinstance(values.get("filters"), List) and len(values.get("filters", [])) > 0, \ - f"filters should be defined for {EventType.request_details}" + f"filters should be defined for {EventType.request_details.value}" + elif values.get("type") == EventType.graphql_details: + assert isinstance(values.get("filters"), List) and len(values.get("filters", [])) > 0, \ + f"filters should be defined for {EventType.graphql_details.value}" return values diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql index b774c4bea..ce3eafd2a 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -7,17 +7,17 @@ $$ SELECT 'v1.5.X' $$ LANGUAGE sql IMMUTABLE; -CREATE TYPE events_common.http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); +CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); ALTER TABLE events_common.requests - ADD COLUMN IF NOT EXISTS schema text NULL, - ADD COLUMN IF NOT EXISTS host text NULL, - ADD COLUMN IF NOT EXISTS base_path text NULL, - ADD COLUMN IF NOT EXISTS query_string text NULL, - ADD COLUMN IF NOT EXISTS request_body text NULL, - ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code text NULL, - ADD COLUMN IF NOT EXISTS method events_common.http_method NULL; + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL, + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL; -- Split requests-URL: Takes too long to use -- UPDATE events_common.requests @@ -50,4 +50,11 @@ ALTER TABLE events_common.requests -- END; +ALTER TABLE events.graphql + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL, + ADD COLUMN IF NOT EXISTS duration integer NULL; + COMMIT; \ No newline at end of file From b3da76a1bb10cc3b4db6b6fe20d400799f59197a Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 12:56:46 +0100 Subject: [PATCH 033/101] feat(api): custom_metrics fixed ignore metricValue for timeseries --- api/schemas.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/schemas.py b/api/schemas.py index 2acdab45f..1b0ab9ac5 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -794,10 +794,10 @@ class CreateCustomMetricsSchema(CustomMetricChartPayloadSchema): # This is used to handle wrong values sent by the UI @root_validator(pre=True) def remove_metric_value(cls, values): - if values.get("metric_type") == MetricType.timeseries \ - or values.get("metric_type") == MetricType.table \ - and values.get("metric_of") != TableMetricOfType.issues: - values["metric_of"] = [] + if values.get("metricType") == MetricType.timeseries \ + or values.get("metricType") == MetricType.table \ + and values.get("metricOf") != TableMetricOfType.issues: + values["metricValue"] = [] return values @root_validator From ed56d206be8e0e3b8b92845dd2a593f11f723485 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Thu, 3 Mar 2022 13:24:39 +0100 Subject: [PATCH 034/101] feat(ui) - custom metrics - wip --- .../app/components/Dashboard/Dashboard.js | 1 - .../CustomMetriLineChart.tsx | 4 +- .../CustomMetriPercentage/index.ts | 1 - .../CustomMetricPercentage.tsx} | 7 +- .../CustomMetricPercentage/index.ts | 1 + .../CustomMetricPieChart.tsx | 43 ++++++-- .../CustomMetricWidget/CustomMetricWidget.tsx | 102 +++++++++--------- .../CustomMetricWidgetPreview.tsx | 72 +++++++++---- .../CustomMetricsWidgets.tsx | 12 ++- .../CustomMetricForm/CustomMetricForm.tsx | 61 ++++++----- .../FilterSeries/FilterSeries.tsx | 2 +- .../SessionListModal/SessionListModal.tsx | 3 +- .../shared/DropdownPlain/DropdownPlain.tsx | 4 +- .../shared/FilterDropdown/FilterDropdown.js | 26 ++--- .../shared/Filters/FilterList/FilterList.tsx | 2 +- .../ui/SegmentSelection/SegmentSelection.js | 5 +- .../ui/SegmentSelection/segmentSelection.css | 13 ++- frontend/app/constants/filterOptions.js | 16 +++ frontend/app/svg/icons/table.svg | 3 + frontend/app/types/app/period.js | 6 ++ frontend/app/types/customMetric.js | 4 +- frontend/app/types/filter/newFilter.js | 17 +-- 22 files changed, 254 insertions(+), 151 deletions(-) delete mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriPercentage/index.ts rename frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/{CustomMetriPercentage/CustomMetriPercentage.tsx => CustomMetricPercentage/CustomMetricPercentage.tsx} (55%) create mode 100644 frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/index.ts create mode 100644 frontend/app/svg/icons/table.svg diff --git a/frontend/app/components/Dashboard/Dashboard.js b/frontend/app/components/Dashboard/Dashboard.js index aacda8b07..8ad8ecdf8 100644 --- a/frontend/app/components/Dashboard/Dashboard.js +++ b/frontend/app/components/Dashboard/Dashboard.js @@ -240,7 +240,6 @@ export default class Dashboard extends React.PureComponent { Custom Metrics are not supported for comparison.
)} - {/* */}
} > diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx index 9f68abf3a..c9287c4ed 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx @@ -8,15 +8,17 @@ interface Props { params: any; seriesMap: any; colors: any; + onClick?: (event, index) => void; } function CustomMetriLineChart(props: Props) { - const { data, params, seriesMap, colors } = props; + const { data, params, seriesMap, colors, onClick = () => null } = props; return ( void; } function CustomMetriPercentage(props: Props) { const { data } = props; return (
-
0%
-
0 ( 0.0% ) from previous hour
+
{data.count}
+
{`${data.previousCount} ( ${data.countProgress}% ) from previous hour`}
) } diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/index.ts b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/index.ts new file mode 100644 index 000000000..0e1f80170 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/index.ts @@ -0,0 +1 @@ +export { default } from './CustomMetricPercentage'; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx index a771a0f45..b0f7dc36f 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -1,15 +1,46 @@ import React from 'react' - +import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; +import { LineChart, Line, Legend, PieChart, Pie } from 'recharts'; +import { Styles } from '../../common'; interface Props { data: any; + params: any; + // seriesMap: any; + colors: any; + onClick?: (event, index) => void; } function CustomMetricPieChart(props: Props) { - const { data } = props; + const { data, params, colors, onClick = () => null } = props; + const data01 = [ + { "name": "Group A", "value": 400 }, + { "name": "Group B", "value": 300 }, + { "name": "Group C", "value": 300 }, + { "name": "Group D", "value": 200 }, + { "name": "Group E", "value": 278 }, + { "name": "Group F", "value": 189 } + ]; return ( -
-
0%
-
0 ( 0.0% ) from previous hour
-
+ //
+ //
0%
+ //
0 ( 0.0% ) from previous hour
+ //
+ + + + + + ) } diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index bbf37408a..7898b980d 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -2,22 +2,24 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { Loader, NoContent, Icon, Popup } from 'UI'; import { Styles } from '../../common'; -import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; -import { LineChart, Line, Legend } from 'recharts'; +import { ResponsiveContainer } from 'recharts'; import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; import stl from './CustomMetricWidget.css'; import { getChartFormatter, getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper'; import { init, edit, remove, setAlertMetricId, setActiveWidget, updateActiveState } from 'Duck/customMetrics'; import APIClient from 'App/api_client'; import { setShowAlerts } from 'Duck/dashboard'; +import CustomMetriLineChart from '../CustomMetriLineChart'; +import CustomMetricPieChart from '../CustomMetricPieChart'; +import CustomMetricPercentage from '../CustomMetricPercentage'; const customParams = rangeName => { const params = { density: 70 } - if (rangeName === LAST_24_HOURS) params.density = 70 - if (rangeName === LAST_30_MINUTES) params.density = 70 - if (rangeName === YESTERDAY) params.density = 70 - if (rangeName === LAST_7_DAYS) params.density = 70 + // if (rangeName === LAST_24_HOURS) params.density = 70 + // if (rangeName === LAST_30_MINUTES) params.density = 70 + // if (rangeName === YESTERDAY) params.density = 70 + // if (rangeName === LAST_7_DAYS) params.density = 70 return params } @@ -47,11 +49,10 @@ function CustomMetricWidget(props: Props) { const colors = Styles.customMetricColors; const params = customParams(period.rangeName) - const gradientDef = Styles.gradientDef(); const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart', startDate: period.start, endDate: period.end } useEffect(() => { - new APIClient()['post']('/custom_metrics/chart', { ...metricParams, q: metric.name }) + new APIClient()['post'](`/custom_metrics/${metricParams.metricId}/chart`, { ...metricParams, q: metric.name }) .then(response => response.json()) .then(({ errors, data }) => { if (errors) { @@ -78,8 +79,19 @@ function CustomMetricWidget(props: Props) { if (event) { const payload = event.activePayload[0].payload; const timestamp = payload.timestamp; - const { startTimestamp, endTimestamp } = getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density); - props.setActiveWidget({ widget: metric, startTimestamp, endTimestamp, timestamp: payload.timestamp, index }) + const periodTimestamps = metric.metricType === 'timeseries' ? + getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density) : + period.toTimestamps(); + + const activeWidget = { + widget: metric, + period: period, + ...periodTimestamps, + timestamp: payload.timestamp, + index, + } + + props.setActiveWidget(activeWidget); } } @@ -104,49 +116,35 @@ function CustomMetricWidget(props: Props) { show={ data.length === 0 } > - - - - - - - - - - - - - { seriesMap.map((key, index) => ( - + {metric.viewType === 'lineChart' && ( + - ))} - + )} + + {metric.viewType === 'pieChart' && ( + + )} + + {metric.viewType === 'progress' && ( + + )} + diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index f0ca8aa80..7aa43f94b 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react'; import { connect } from 'react-redux'; import { Loader, NoContent, SegmentSelection, Icon } from 'UI'; import { Styles } from '../../common'; -import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, LineChart, Line, Legend } from 'recharts'; +// import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, LineChart, Line, Legend } from 'recharts'; import Period, { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; import stl from './CustomMetricWidgetPreview.css'; import { getChartFormatter } from 'Types/dashboard/helper'; @@ -10,10 +10,11 @@ import { remove } from 'Duck/customMetrics'; import DateRange from 'Shared/DateRange'; import { edit } from 'Duck/customMetrics'; import CustomMetriLineChart from '../CustomMetriLineChart'; -import CustomMetriPercentage from '../CustomMetriPercentage'; +import CustomMetricPercentage from '../CustomMetricPercentage'; import CustomMetricTable from '../CustomMetricTable'; import APIClient from 'App/api_client'; +import CustomMetricPieChart from '../CustomMetricPieChart'; const customParams = rangeName => { const params = { density: 70 } @@ -46,8 +47,9 @@ function CustomMetricWidget(props: Props) { const params = customParams(period.rangeName) const gradientDef = Styles.gradientDef(); const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart' } - const prevMetricRef = useRef(); + const isTimeSeries = metric.metricType === 'timeseries'; + const isTable = metric.metricType === 'table'; useEffect(() => { // Check for title change @@ -95,17 +97,35 @@ function CustomMetricWidget(props: Props) {
Preview
- + {isTimeSeries && ( + + )} + + {isTable && ( + + )}
Time Range - { metric.metricType === 'timeseries' && ( + { isTimeSeries && ( <> - { metric.viewType === 'percent' && ( - + { metric.viewType === 'progress' && ( + )} - { metric.viewType === 'chart' && ( + { metric.viewType === 'lineChart' && ( )} - { metric.metricType === 'table' && ( + { isTable && (
- + { metric.viewType === 'table' ? ( + + ) : ( + + )}
)} diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx index 6cf633518..57c181904 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx @@ -5,6 +5,7 @@ import CustomMetricWidget from './CustomMetricWidget'; import AlertFormModal from 'App/components/Alerts/AlertFormModal'; import { init as initAlert } from 'Duck/alerts'; import LazyLoad from 'react-lazyload'; +import CustomMetrics from 'App/components/shared/CustomMetrics'; interface Props { fetchList: Function; @@ -22,7 +23,7 @@ function CustomMetricsWidgets(props: Props) { return ( <> - {list.filter(item => item.active).map((item: any) => ( + {list.map((item: any) => ( ))} + {list.size === 0 && ( +
+
Be proactive by monitoring the metrics you care about the most.
+ +
+ )} + ({ - list: state.getIn(['customMetrics', 'list']), + list: state.getIn(['customMetrics', 'list']).filter(item => item.active), }), { fetchList, initAlert })(CustomMetricsWidgets); \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index 754af89e2..b10b1dfe4 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Form, SegmentSelection, Button, IconButton } from 'UI'; +import { Form, Button, IconButton } from 'UI'; import FilterSeries from '../FilterSeries'; import { connect } from 'react-redux'; import { edit as editMetric, save, addSeries, removeSeries, remove } from 'Duck/customMetrics'; @@ -8,8 +8,7 @@ import { confirm } from 'UI/Confirmation'; import { toast } from 'react-toastify'; import cn from 'classnames'; import DropdownPlain from '../../DropdownPlain'; -import { metricTypes, metricOf } from 'App/constants/filterOptions'; - +import { metricTypes, metricOf, issueOptions } from 'App/constants/filterOptions'; interface Props { metric: any; editMetric: (metric, shouldFetch?) => void; @@ -23,7 +22,7 @@ interface Props { function CustomMetricForm(props: Props) { const { metric, loading } = props; - const metricOfOptions = metricOf.filter(i => i.key === metric.metricType); + // const metricOfOptions = metricOf.filter(i => i.key === metric.metricType); const timeseriesOptions = metricOf.filter(i => i.key === 'timeseries'); const tableOptions = metricOf.filter(i => i.key === 'table'); @@ -39,18 +38,28 @@ function CustomMetricForm(props: Props) { const writeOption = (e, { value, name }) => { props.editMetric({ [ name ]: value }, false); + if (name === 'metricValue') { + props.editMetric({ metricValue: [value] }, false); + } + + if (name === 'metricOf') { + if (value === 'ISSUES') { + props.editMetric({ metricValue: [issueOptions[0].value] }, false); + } + } + if (name === 'metricType') { if (value === 'timeseries') { - props.editMetric({ metricOf: timeseriesOptions[0].value }, false); + props.editMetric({ metricOf: timeseriesOptions[0].value, viewType: 'lineChart' }, false); } else if (value === 'table') { - props.editMetric({ metricOf: tableOptions[0].value }, false); + props.editMetric({ metricOf: tableOptions[0].value, viewType: 'table' }, false); } } }; - const changeConditionTab = (e, { name, value }) => { - props.editMetric({[ 'viewType' ]: value }); - }; + // const changeConditionTab = (e, { name, value }) => { + // props.editMetric({[ 'viewType' ]: value }); + // }; const save = () => { props.save(metric).then(() => { @@ -126,38 +135,32 @@ function CustomMetricForm(props: Props) { )} + {metric.metricOf === 'ISSUES' && ( + <> + issue type + + + )} + {metric.metricType === 'table' && ( <> showing )}
- {/*
- Timeseries - of -
- -
-
*/}
diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx index 0f5df220b..7054e4516 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx @@ -81,7 +81,7 @@ function FilterSeries(props: Props) {
Add user event or filter to define the series by clicking Add Step.
)}
-
+
setActiveSeries(value); const filteredSessions = getListSessionsBySeries(activeSeries); - const startTime = DateTime.fromMillis(activeWidget.startTimestamp).toFormat('LLL dd, yyyy HH:mm a'); const endTime = DateTime.fromMillis(activeWidget.endTimestamp).toFormat('LLL dd, yyyy HH:mm a'); + return ( : null } diff --git a/frontend/app/components/shared/FilterDropdown/FilterDropdown.js b/frontend/app/components/shared/FilterDropdown/FilterDropdown.js index 66da1f586..5b8a4ac76 100644 --- a/frontend/app/components/shared/FilterDropdown/FilterDropdown.js +++ b/frontend/app/components/shared/FilterDropdown/FilterDropdown.js @@ -100,18 +100,20 @@ const FilterDropdown = props => {
)} {showDropdown && ( -
-
SELECT FILTER
- {filterKeys.filter(f => !filterKeyMaps.includes(f.key)).map(f => ( -
onFilterKeySelect(f.key)} - className={cn(stl.filterItem, 'py-3 -mx-3 px-3 flex items-center cursor-pointer')} - > - - {f.name} -
- ))} +
+
SELECT FILTER
+
+ {filterKeys.filter(f => !filterKeyMaps.includes(f.key)).map(f => ( +
onFilterKeySelect(f.key)} + className={cn(stl.filterItem, 'py-3 -mx-3 px-3 flex items-center cursor-pointer')} + > + + {f.name} +
+ ))} +
)} {filterKey && ( diff --git a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx index 0e62d20e1..8eba891bb 100644 --- a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx +++ b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx @@ -32,7 +32,7 @@ function FilterList(props: Props) {
Events Order
} - content={ `Events Order` } + content={ `Select the operator to be applied between events in your search.` } size="tiny" inverted position="top center" diff --git a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js index f564131cb..e18faf096 100644 --- a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js +++ b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js @@ -9,13 +9,14 @@ class SegmentSelection extends React.Component { } render() { - const { className, list, small = false, extraSmall = false, primary = false, size = "normal" } = this.props; + const { className, list, small = false, extraSmall = false, primary = false, size = "normal", icons = false } = this.props; return (
{ list.map(item => ( @@ -27,7 +28,7 @@ class SegmentSelection extends React.Component { data-active={ this.props.value && this.props.value.value === item.value } onClick={ () => !item.disabled && this.setActiveItem(item) } > - { item.icon && } + { item.icon && }
{ item.name }
} diff --git a/frontend/app/components/ui/SegmentSelection/segmentSelection.css b/frontend/app/components/ui/SegmentSelection/segmentSelection.css index 197627c9f..f63559c0c 100644 --- a/frontend/app/components/ui/SegmentSelection/segmentSelection.css +++ b/frontend/app/components/ui/SegmentSelection/segmentSelection.css @@ -54,9 +54,15 @@ color: $teal; background-color: white; border-right: solid thin $teal; + & svg { + fill: $teal !important; + } &[data-active=true] { background-color: $teal; color: white; + & svg { + fill: white !important; + } } } } @@ -66,6 +72,11 @@ } .extraSmall .item { - padding: 6px !important; + padding: 0 4px !important; + font-size: 12px; +} + +.icons .item { + padding: 4px !important; font-size: 12px; } \ No newline at end of file diff --git a/frontend/app/constants/filterOptions.js b/frontend/app/constants/filterOptions.js index 3a497e8cf..6b9b5b70d 100644 --- a/frontend/app/constants/filterOptions.js +++ b/frontend/app/constants/filterOptions.js @@ -69,6 +69,21 @@ export const metricOf = [ { text: 'URL', value: 'VISITED_URL', key: 'table' }, ] +export const issueOptions = [ + { text: 'Click Rage', value: 'click_rage' }, + { text: 'Dead Click', value: 'dead_click' }, + { text: 'Excessive Scrolling', value: 'excessive_scrolling' }, + { text: 'Bad Request', value: 'bad_request' }, + { text: 'Missing Resource', value: 'missing_resource' }, + { text: 'Memory', value: 'memory' }, + { text: 'CPU', value: 'cpu' }, + { text: 'Slow Resource', value: 'slow_resource' }, + { text: 'Slow Page Load', value: 'slow_page_load' }, + { text: 'Crash', value: 'crash' }, + { text: 'Custom', value: 'custom' }, + { text: 'JS Exception', value: 'js_exception' }, +] + export default { options, baseOperators, @@ -79,4 +94,5 @@ export default { getOperatorsByKeys, metricTypes, metricOf, + issueOptions, } \ No newline at end of file diff --git a/frontend/app/svg/icons/table.svg b/frontend/app/svg/icons/table.svg new file mode 100644 index 000000000..5e70d22c4 --- /dev/null +++ b/frontend/app/svg/icons/table.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/types/app/period.js b/frontend/app/types/app/period.js index 5e5e9aba8..deebf9cad 100644 --- a/frontend/app/types/app/period.js +++ b/frontend/app/types/app/period.js @@ -103,5 +103,11 @@ export default Record({ endTimestamp: this.end, }; }, + toTimestampstwo() { + return { + startTimestamp: this.start / 1000, + endTimestamp: this.end / 1000, + }; + }, } }); \ No newline at end of file diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index 9b3585be1..9ce5841f0 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -29,7 +29,9 @@ export default Record({ name: 'Series', metricType: 'table', metricOf: 'USERID', - viewType: 'lineChart', + metricValue: ['sessionCount'], + metricFormat: 'sessionCount', + viewType: 'table', series: List(), isPublic: true, startDate: '', diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 99726b4a6..db0248458 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -6,21 +6,6 @@ import { capitalize } from 'App/utils'; const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i })); const containsFilters = [{ key: 'contains', text: 'contains', value: 'contains' }] -const ISSUE_OPTIONS = [ - { text: 'Click Rage', value: 'click_rage' }, - { text: 'Dead Click', value: 'dead_click' }, - { text: 'Excessive Scrolling', value: 'excessive_scrolling' }, - { text: 'Bad Request', value: 'bad_request' }, - { text: 'Missing Resource', value: 'missing_resource' }, - { text: 'Memory', value: 'memory' }, - { text: 'CPU', value: 'cpu' }, - { text: 'Slow Resource', value: 'slow_resource' }, - { text: 'Slow Page Load', value: 'slow_page_load' }, - { text: 'Crash', value: 'crash' }, - { text: 'Custom', value: 'custom' }, - { text: 'JS Exception', value: 'js_exception' }, -] - export const filtersMap = { // EVENTS [FilterKey.CLICK]: { key: FilterKey.CLICK, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Click', operator: 'on', operatorOptions: filterOptions.targetOperators, icon: 'filters/click', isEvent: true }, @@ -59,7 +44,7 @@ export const filtersMap = { [FilterKey.AVG_CPU_LOAD]: { key: FilterKey.AVG_CPU_LOAD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg CPU Load', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/cpu-load', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, [FilterKey.AVG_MEMORY_USAGE]: { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg Memory Usage', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/memory-load', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, [FilterKey.FETCH_FAILED]: { key: FilterKey.FETCH_FAILED, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Failed Request', operator: 'isAny', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch-failed', isEvent: true }, - [FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/click', options: ISSUE_OPTIONS }, + [FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/click', options: filterOptions.issueOptions }, } export const liveFiltersMap = { From bebe6169f0a05ce32960dd1fb6d63984f15385ee Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 13:28:19 +0100 Subject: [PATCH 035/101] feat(api): custom_metrics changed countProgress formula --- api/chalicelib/core/custom_metrics.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index ecb61732f..d4e0b6b45 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -22,7 +22,9 @@ def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): r["previousCount"] = sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, view_type=data.view_type, metric_type=data.metric_type, metric_of=data.metric_of, metric_value=data.metric_value) - r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) + # r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) + r["countProgress"] = ((r["count"] - r["previousCount"]) / r["previousCount"]) * 100 \ + if r["previousCount"] > 0 else 0 r["seriesName"] = s.name if s.name else i + 1 r["seriesId"] = s.series_id if s.series_id else None results[-1] = r From 50a7283daeb1542f79a3aaaa3969cdf64c983284 Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Thu, 3 Mar 2022 14:40:23 +0100 Subject: [PATCH 036/101] chore(helm): force upgrade frontend Signed-off-by: rjshrjndrn --- scripts/helmcharts/openreplay-cli | 6 +++++- scripts/helmcharts/openreplay/files/dbops.sh | 5 +++++ scripts/helmcharts/openreplay/templates/job.yaml | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/helmcharts/openreplay-cli b/scripts/helmcharts/openreplay-cli index 1b52e2bd5..d4b36a663 100755 --- a/scripts/helmcharts/openreplay-cli +++ b/scripts/helmcharts/openreplay-cli @@ -96,7 +96,11 @@ restart() { helmInstall() { - helm upgrade --install openreplay -n app openreplay -f vars.yaml + [[ FORCE_UPGRADE_FRONTENT -eq 1 ]] && { + helm upgrade --install openreplay -n app openreplay -f vars.yaml --set forceUpgradeFrontend=true + } || { + helm upgrade --install openreplay -n app openreplay -f vars.yaml + } } upgrade() { diff --git a/scripts/helmcharts/openreplay/files/dbops.sh b/scripts/helmcharts/openreplay/files/dbops.sh index b77fd61ff..fd238471e 100644 --- a/scripts/helmcharts/openreplay/files/dbops.sh +++ b/scripts/helmcharts/openreplay/files/dbops.sh @@ -21,6 +21,11 @@ function migration() { if [[ $FORCE_MIGRATION == "true" ]]; then echo "Forcing db migration from $PREVIOUS_APP_VERSION to $CHART_APP_VERSION" + # This is a special case where we force upgrade frontend + elif [[ $UPGRADE_FRONTENT == "true" ]]; then + echo "[WARN] Skipping regular upgrdades. Forcing frontend upgrade." + /bin/bash minio.sh migrate + exit 0 elif [[ $PREVIOUS_APP_VERSION == $CHART_APP_VERSION ]]; then echo "No application version change. Not upgrading." exit 0 diff --git a/scripts/helmcharts/openreplay/templates/job.yaml b/scripts/helmcharts/openreplay/templates/job.yaml index a5a6e6241..8eedf6f62 100644 --- a/scripts/helmcharts/openreplay/templates/job.yaml +++ b/scripts/helmcharts/openreplay/templates/job.yaml @@ -80,6 +80,8 @@ spec: env: - name: FORCE_MIGRATION value: "{{ .Values.forceMigration }}" + - name: UPGRADE_FRONTENT + value: "{{ .Values.forceUpgradeFrontend }}" - name: PREVIOUS_APP_VERSION value: "{{ .Values.fromVersion }}" - name: CHART_APP_VERSION From b09292a580846cae42f96e02baa128c0b6bf70f2 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 15:15:12 +0100 Subject: [PATCH 037/101] feat(api): requests indexes feat(api): graphql indexes --- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql index ce3eafd2a..2b71f3ac4 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -16,7 +16,7 @@ ALTER TABLE events_common.requests ADD COLUMN IF NOT EXISTS query_string text NULL, ADD COLUMN IF NOT EXISTS request_body text NULL, ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, ADD COLUMN IF NOT EXISTS method http_method NULL; -- Split requests-URL: Takes too long to use @@ -53,8 +53,26 @@ ALTER TABLE events_common.requests ALTER TABLE events.graphql ADD COLUMN IF NOT EXISTS request_body text NULL, ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, ADD COLUMN IF NOT EXISTS method http_method NULL, ADD COLUMN IF NOT EXISTS duration integer NULL; -COMMIT; \ No newline at end of file +COMMIT; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; \ No newline at end of file From ce8459815297afdbd3e1a34ea2f27ee2da15f5dd Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Thu, 3 Mar 2022 16:27:51 +0100 Subject: [PATCH 038/101] chore(helm): upgrading version --- scripts/helmcharts/openreplay/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/alerts/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/assets/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/chalice/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/db/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/ender/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/http/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/integrations/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/sink/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/storage/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/utilities/Chart.yaml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/helmcharts/openreplay/Chart.yaml b/scripts/helmcharts/openreplay/Chart.yaml index 8057ec335..e621e543d 100644 --- a/scripts/helmcharts/openreplay/Chart.yaml +++ b/scripts/helmcharts/openreplay/Chart.yaml @@ -22,4 +22,4 @@ version: 0.1.0 # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. # Ref: https://github.com/helm/helm/issues/7858#issuecomment-608114589 -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml b/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml index 885ad5503..0bfe8b4bc 100644 --- a/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/assets/Chart.yaml b/scripts/helmcharts/openreplay/charts/assets/Chart.yaml index 75657b1df..9b8c32623 100644 --- a/scripts/helmcharts/openreplay/charts/assets/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/assets/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml b/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml index 8de5927eb..1d0441f7e 100644 --- a/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/db/Chart.yaml b/scripts/helmcharts/openreplay/charts/db/Chart.yaml index b0cdbebd4..0aa5f39e3 100644 --- a/scripts/helmcharts/openreplay/charts/db/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/db/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/ender/Chart.yaml b/scripts/helmcharts/openreplay/charts/ender/Chart.yaml index ec411fad1..8a7ce610e 100644 --- a/scripts/helmcharts/openreplay/charts/ender/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/ender/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/http/Chart.yaml b/scripts/helmcharts/openreplay/charts/http/Chart.yaml index 5b65ded45..5422d1f3d 100644 --- a/scripts/helmcharts/openreplay/charts/http/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/http/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml b/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml index f98a99254..e8fc92887 100644 --- a/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml b/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml index 75cf9a946..2c473b4b4 100644 --- a/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/sink/Chart.yaml b/scripts/helmcharts/openreplay/charts/sink/Chart.yaml index 51c85b6f3..7ece0a5bf 100644 --- a/scripts/helmcharts/openreplay/charts/sink/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/sink/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/storage/Chart.yaml b/scripts/helmcharts/openreplay/charts/storage/Chart.yaml index 5b535bc5a..9e1c06d8c 100644 --- a/scripts/helmcharts/openreplay/charts/storage/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/storage/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" diff --git a/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml b/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml index 895405214..acc73d941 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.1" +AppVersion: "v1.5.2" From 61d6e017089e8eb0e9bd398a9d8a011e3865b0b0 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 16:30:00 +0100 Subject: [PATCH 039/101] feat(api): reverted countProgress formula --- api/chalicelib/core/custom_metrics.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index d4e0b6b45..785324591 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -22,9 +22,9 @@ def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): r["previousCount"] = sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, view_type=data.view_type, metric_type=data.metric_type, metric_of=data.metric_of, metric_value=data.metric_value) - # r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) - r["countProgress"] = ((r["count"] - r["previousCount"]) / r["previousCount"]) * 100 \ - if r["previousCount"] > 0 else 0 + r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) + # r["countProgress"] = ((r["count"] - r["previousCount"]) / r["previousCount"]) * 100 \ + # if r["previousCount"] > 0 else 0 r["seriesName"] = s.name if s.name else i + 1 r["seriesId"] = s.series_id if s.series_id else None results[-1] = r @@ -63,8 +63,7 @@ def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricSessi metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) if metric is None: return None - metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj( - {**data.dict(), **metric}) + metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) results = [] for s in metric.series: s.filter.startDate = data.startDate From 2fef9044e10176f87d57b2ebaa75ebad06a2b605 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 17:06:47 +0100 Subject: [PATCH 040/101] feat(api): drill down custom_metrics by merged filters --- api/chalicelib/core/custom_metrics.py | 24 +++++++++++++++++++++--- api/schemas.py | 10 +++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index 785324591..05d729dbe 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -1,4 +1,5 @@ import json +from typing import Union import schemas from chalicelib.core import sessions @@ -43,11 +44,28 @@ def merged_live(project_id, data: schemas.CreateCustomMetricsSchema): return results -def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema): +def __get_merged_metric(project_id, user_id, metric_id, + data: Union[schemas.CustomMetricChartPayloadSchema, + schemas.CustomMetricSessionsPayloadSchema]) \ + -> Union[schemas.CreateCustomMetricsSchema, None]: metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) if metric is None: return None metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) + if len(data.filters) > 0 or len(data.events) > 0: + for s in metric.series: + if len(data.filters) > 0: + s.filter.filters += data.filters + if len(data.events) > 0: + s.filter.events += data.events + return metric + + +def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema): + metric: schemas.CreateCustomMetricsSchema = __get_merged_metric(project_id=project_id, user_id=user_id, + metric_id=metric_id, data=data) + if metric is None: + return None series_charts = __try_live(project_id=project_id, data=metric) if metric.view_type == schemas.MetricTimeseriesViewType.progress: return series_charts @@ -60,10 +78,10 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricSessionsPayloadSchema): - metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) + metric: schemas.CreateCustomMetricsSchema = __get_merged_metric(project_id=project_id, user_id=user_id, + metric_id=metric_id, data=data) if metric is None: return None - metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) results = [] for s in metric.series: s.filter.startDate = data.startDate diff --git a/api/schemas.py b/api/schemas.py index 1b0ab9ac5..e4dc7f1e7 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -428,7 +428,7 @@ class FilterType(str, Enum): duration = "DURATION" platform = "PLATFORM" metadata = "METADATA" - issue = "ISSUE" + issue = "ISSUES" events_count = "EVENTS_COUNT" utm_source = "UTM_SOURCE" utm_medium = "UTM_MEDIUM" @@ -619,7 +619,7 @@ class SessionsSearchPayloadSchema(BaseModel): alias_generator = attribute_to_camel_case -class FlatSessionsSearchPayloadSchema(SessionsSearchPayloadSchema): +class FlatSessionsSearch(BaseModel): events: Optional[List[_SessionSearchEventSchema]] = Field([]) filters: List[Union[SessionSearchFilterSchema, _SessionSearchEventSchema]] = Field([]) @@ -645,6 +645,10 @@ class FlatSessionsSearchPayloadSchema(SessionsSearchPayloadSchema): return values +class FlatSessionsSearchPayloadSchema(FlatSessionsSearch, SessionsSearchPayloadSchema): + pass + + class SessionsSearchCountSchema(FlatSessionsSearchPayloadSchema): # class SessionsSearchCountSchema(SessionsSearchPayloadSchema): sort: Optional[str] = Field(default=None) @@ -765,7 +769,7 @@ class TimeseriesMetricOfType(str, Enum): session_count = "sessionCount" -class CustomMetricSessionsPayloadSchema(BaseModel): +class CustomMetricSessionsPayloadSchema(FlatSessionsSearch): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) From 62af49af315767dcf1b884a11d6a27ea669167f0 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 17:41:29 +0100 Subject: [PATCH 041/101] feat(api): changes --- api/chalicelib/core/sessions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index dc6bf85c7..bb5e9b974 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -225,9 +225,9 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f # ORDER BY favorite DESC, issue_score DESC, {sort} {order};""", # full_args) - print("--------------------") - print(main_query) - print("--------------------") + # print("--------------------") + # print(main_query) + # print("--------------------") cur.execute(main_query) if count_only: From f2bcef3b7d7b4fd2dc44ad061595e8df91f813fb Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 15:15:12 +0100 Subject: [PATCH 042/101] feat(api): requests indexes feat(api): graphql indexes --- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql index ce3eafd2a..2b71f3ac4 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql @@ -16,7 +16,7 @@ ALTER TABLE events_common.requests ADD COLUMN IF NOT EXISTS query_string text NULL, ADD COLUMN IF NOT EXISTS request_body text NULL, ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, ADD COLUMN IF NOT EXISTS method http_method NULL; -- Split requests-URL: Takes too long to use @@ -53,8 +53,26 @@ ALTER TABLE events_common.requests ALTER TABLE events.graphql ADD COLUMN IF NOT EXISTS request_body text NULL, ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, ADD COLUMN IF NOT EXISTS method http_method NULL, ADD COLUMN IF NOT EXISTS duration integer NULL; -COMMIT; \ No newline at end of file +COMMIT; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; \ No newline at end of file From a60a300227c28449b53eabca961493ae8cb72c51 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 16:30:00 +0100 Subject: [PATCH 043/101] feat(api): reverted countProgress formula --- api/chalicelib/core/custom_metrics.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index d4e0b6b45..785324591 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -22,9 +22,9 @@ def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): r["previousCount"] = sessions.search2_series(data=s.filter, project_id=project_id, density=data.density, view_type=data.view_type, metric_type=data.metric_type, metric_of=data.metric_of, metric_value=data.metric_value) - # r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) - r["countProgress"] = ((r["count"] - r["previousCount"]) / r["previousCount"]) * 100 \ - if r["previousCount"] > 0 else 0 + r["countProgress"] = helper.__progress(old_val=r["previousCount"], new_val=r["count"]) + # r["countProgress"] = ((r["count"] - r["previousCount"]) / r["previousCount"]) * 100 \ + # if r["previousCount"] > 0 else 0 r["seriesName"] = s.name if s.name else i + 1 r["seriesId"] = s.series_id if s.series_id else None results[-1] = r @@ -63,8 +63,7 @@ def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricSessi metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) if metric is None: return None - metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj( - {**data.dict(), **metric}) + metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) results = [] for s in metric.series: s.filter.startDate = data.startDate From 27b4642d87317dbd71714a0a487f105d0cd55b32 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 17:06:47 +0100 Subject: [PATCH 044/101] feat(api): drill down custom_metrics by merged filters --- api/chalicelib/core/custom_metrics.py | 24 +++++++++++++++++++++--- api/schemas.py | 10 +++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index 785324591..05d729dbe 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -1,4 +1,5 @@ import json +from typing import Union import schemas from chalicelib.core import sessions @@ -43,11 +44,28 @@ def merged_live(project_id, data: schemas.CreateCustomMetricsSchema): return results -def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema): +def __get_merged_metric(project_id, user_id, metric_id, + data: Union[schemas.CustomMetricChartPayloadSchema, + schemas.CustomMetricSessionsPayloadSchema]) \ + -> Union[schemas.CreateCustomMetricsSchema, None]: metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) if metric is None: return None metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) + if len(data.filters) > 0 or len(data.events) > 0: + for s in metric.series: + if len(data.filters) > 0: + s.filter.filters += data.filters + if len(data.events) > 0: + s.filter.events += data.events + return metric + + +def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPayloadSchema): + metric: schemas.CreateCustomMetricsSchema = __get_merged_metric(project_id=project_id, user_id=user_id, + metric_id=metric_id, data=data) + if metric is None: + return None series_charts = __try_live(project_id=project_id, data=metric) if metric.view_type == schemas.MetricTimeseriesViewType.progress: return series_charts @@ -60,10 +78,10 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa def get_sessions(project_id, user_id, metric_id, data: schemas.CustomMetricSessionsPayloadSchema): - metric = get(metric_id=metric_id, project_id=project_id, user_id=user_id, flatten=False) + metric: schemas.CreateCustomMetricsSchema = __get_merged_metric(project_id=project_id, user_id=user_id, + metric_id=metric_id, data=data) if metric is None: return None - metric: schemas.CreateCustomMetricsSchema = schemas.CreateCustomMetricsSchema.parse_obj({**data.dict(), **metric}) results = [] for s in metric.series: s.filter.startDate = data.startDate diff --git a/api/schemas.py b/api/schemas.py index 1b0ab9ac5..e4dc7f1e7 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -428,7 +428,7 @@ class FilterType(str, Enum): duration = "DURATION" platform = "PLATFORM" metadata = "METADATA" - issue = "ISSUE" + issue = "ISSUES" events_count = "EVENTS_COUNT" utm_source = "UTM_SOURCE" utm_medium = "UTM_MEDIUM" @@ -619,7 +619,7 @@ class SessionsSearchPayloadSchema(BaseModel): alias_generator = attribute_to_camel_case -class FlatSessionsSearchPayloadSchema(SessionsSearchPayloadSchema): +class FlatSessionsSearch(BaseModel): events: Optional[List[_SessionSearchEventSchema]] = Field([]) filters: List[Union[SessionSearchFilterSchema, _SessionSearchEventSchema]] = Field([]) @@ -645,6 +645,10 @@ class FlatSessionsSearchPayloadSchema(SessionsSearchPayloadSchema): return values +class FlatSessionsSearchPayloadSchema(FlatSessionsSearch, SessionsSearchPayloadSchema): + pass + + class SessionsSearchCountSchema(FlatSessionsSearchPayloadSchema): # class SessionsSearchCountSchema(SessionsSearchPayloadSchema): sort: Optional[str] = Field(default=None) @@ -765,7 +769,7 @@ class TimeseriesMetricOfType(str, Enum): session_count = "sessionCount" -class CustomMetricSessionsPayloadSchema(BaseModel): +class CustomMetricSessionsPayloadSchema(FlatSessionsSearch): startDate: int = Field(TimeUTC.now(-7)) endDate: int = Field(TimeUTC.now()) From 8cd9256fae04e0bc4d51c94c094df9da8d1e43b8 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 17:41:29 +0100 Subject: [PATCH 045/101] feat(api): changes --- api/chalicelib/core/sessions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/chalicelib/core/sessions.py b/api/chalicelib/core/sessions.py index dc6bf85c7..bb5e9b974 100644 --- a/api/chalicelib/core/sessions.py +++ b/api/chalicelib/core/sessions.py @@ -225,9 +225,9 @@ def search2_pg(data: schemas.SessionsSearchPayloadSchema, project_id, user_id, f # ORDER BY favorite DESC, issue_score DESC, {sort} {order};""", # full_args) - print("--------------------") - print(main_query) - print("--------------------") + # print("--------------------") + # print(main_query) + # print("--------------------") cur.execute(main_query) if count_only: From 08e6fc5324f6fbbee26281ea36096954bc6e6bf7 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 18:38:05 +0100 Subject: [PATCH 046/101] feat(utilities): WS update query-event --- utilities/package-lock.json | 11 +---------- utilities/package.json | 3 +-- utilities/servers/websocket.js | 11 +++++++++++ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/utilities/package-lock.json b/utilities/package-lock.json index 8fe161f1a..5ff7612c2 100644 --- a/utilities/package-lock.json +++ b/utilities/package-lock.json @@ -15,8 +15,7 @@ "peer": "^0.6.1", "socket.io": "^4.4.1", "source-map": "^0.7.3", - "ua-parser-js": "^1.0.2", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.6.0" + "ua-parser-js": "^1.0.2" } }, "node_modules/@maxmind/geoip2-node": { @@ -1288,10 +1287,6 @@ "uuid": "bin/uuid" } }, - "node_modules/uWebSockets.js": { - "version": "20.6.0", - "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#a58e810e47a23696410f6073c8c905dc38f75da5" - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2355,10 +2350,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, - "uWebSockets.js": { - "version": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#a58e810e47a23696410f6073c8c905dc38f75da5", - "from": "uWebSockets.js@github:uNetworking/uWebSockets.js#v20.6.0" - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/utilities/package.json b/utilities/package.json index 79c8513a4..452c3fe00 100644 --- a/utilities/package.json +++ b/utilities/package.json @@ -24,7 +24,6 @@ "peer": "^0.6.1", "socket.io": "^4.4.1", "source-map": "^0.7.3", - "ua-parser-js": "^1.0.2", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.6.0" + "ua-parser-js": "^1.0.2" } } diff --git a/utilities/servers/websocket.js b/utilities/servers/websocket.js index ab6a2c4d5..9334dd800 100644 --- a/utilities/servers/websocket.js +++ b/utilities/servers/websocket.js @@ -4,6 +4,7 @@ const uaParser = require('ua-parser-js'); const geoip2Reader = require('@maxmind/geoip2-node').Reader; var {extractPeerId} = require('./peerjs-server'); var wsRouter = express.Router(); +const UPDATE_EVENT = "UPDATE_SESSION"; const IDENTITIES = {agent: 'agent', session: 'session'}; const NEW_AGENT = "NEW_AGENT"; const NO_AGENTS = "NO_AGENT"; @@ -226,6 +227,16 @@ module.exports = { } }); + socket.on(UPDATE_EVENT, async (...args) => { + debug && console.log(`${socket.id} sent update event.`); + if (socket.identity !== IDENTITIES.session) { + debug && console.log('Ignoring update event.'); + return + } + socket.handshake.query.sessionInfo = {...socket.handshake.query.sessionInfo, ...args[0]}; + socket.to(socket.peerId).emit(UPDATE_EVENT, args[0]); + }); + socket.onAny(async (eventName, ...args) => { socket.lastMessageReceivedAt = Date.now(); if (socket.identity === IDENTITIES.session) { From bd9403c47a5cbeed899744d6a8b453587d8f07fe Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 19:00:52 +0100 Subject: [PATCH 047/101] feat(api): fixed metricType:table for chart --- api/chalicelib/core/custom_metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index 05d729dbe..7d46cc316 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -67,7 +67,7 @@ def make_chart(project_id, user_id, metric_id, data: schemas.CustomMetricChartPa if metric is None: return None series_charts = __try_live(project_id=project_id, data=metric) - if metric.view_type == schemas.MetricTimeseriesViewType.progress: + if metric.view_type == schemas.MetricTimeseriesViewType.progress or metric.metric_type == schemas.MetricType.table: return series_charts results = [{}] * len(series_charts[0]) for i in range(len(results)): From 57874c06101509c78ded4973f18a9b96f394a89c Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 19:01:13 +0100 Subject: [PATCH 048/101] feat(api): format core --- api/routers/core.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/api/routers/core.py b/api/routers/core.py index 9cf9dfd0c..076ca81f4 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -1091,8 +1091,7 @@ def change_client_password(data: schemas.EditUserPasswordSchema = Body(...), @app.put('/{projectId}/custom_metrics/try', tags=["customMetrics"]) def try_custom_metric(projectId: int, data: schemas.CreateCustomMetricsSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - return {"data": custom_metrics.merged_live - (project_id=projectId, data=data)} + return {"data": custom_metrics.merged_live(project_id=projectId, data=data)} @app.post('/{projectId}/custom_metrics', tags=["customMetrics"]) From a37f11e261d5059778a8a7c27db281ff8c1f7747 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 19:23:56 +0100 Subject: [PATCH 049/101] feat(api): custom_metrics group elements for pieChart --- api/chalicelib/core/custom_metrics.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index 7d46cc316..53864c624 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -29,6 +29,12 @@ def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): r["seriesName"] = s.name if s.name else i + 1 r["seriesId"] = s.series_id if s.series_id else None results[-1] = r + elif data.view_type == schemas.MetricTableViewType.pie_chart: + if len(results[i].get("values", [])) > 8: + results[i]["values"] = results[i]["values"][:8] \ + + [{"name": "Others", "group": True, + "sessionCount": sum(r["sessionCount"] for r in results[i][8:])}] + return results From e47f5d1f4d8ea6c68f1c64ebdf600e14ae0e89ee Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 19:28:40 +0100 Subject: [PATCH 050/101] feat(api): custom_metrics changed group elements limit --- api/chalicelib/core/custom_metrics.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index 53864c624..e045dbbb6 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -6,6 +6,8 @@ from chalicelib.core import sessions from chalicelib.utils import helper, pg_client from chalicelib.utils.TimeUTC import TimeUTC +PIE_CHART_GROUP = 5 + def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): results = [] @@ -30,10 +32,12 @@ def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): r["seriesId"] = s.series_id if s.series_id else None results[-1] = r elif data.view_type == schemas.MetricTableViewType.pie_chart: - if len(results[i].get("values", [])) > 8: - results[i]["values"] = results[i]["values"][:8] \ - + [{"name": "Others", "group": True, - "sessionCount": sum(r["sessionCount"] for r in results[i][8:])}] + if len(results[i].get("values", [])) > PIE_CHART_GROUP: + results[i]["values"] = results[i]["values"][:PIE_CHART_GROUP] \ + + [{ + "name": "Others", "group": True, + "sessionCount": sum(r["sessionCount"] for r in results[i][PIE_CHART_GROUP:]) + }] return results From 0f7f21380eabcf5e1e4197a9ff0ac2083c36519e Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 3 Mar 2022 19:33:15 +0100 Subject: [PATCH 051/101] feat(api): custom_metrics fixed group elements --- api/chalicelib/core/custom_metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index e045dbbb6..06a2c328b 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -36,7 +36,7 @@ def __try_live(project_id, data: schemas.CreateCustomMetricsSchema): results[i]["values"] = results[i]["values"][:PIE_CHART_GROUP] \ + [{ "name": "Others", "group": True, - "sessionCount": sum(r["sessionCount"] for r in results[i][PIE_CHART_GROUP:]) + "sessionCount": sum(r["sessionCount"] for r in results[i]["values"][PIE_CHART_GROUP:]) }] return results From 984b29f451bf994ab1b1895e1bd329598295a108 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 11:32:09 +0100 Subject: [PATCH 052/101] feat(ui) - custom metrics - wip --- .../CustomMetriLineChart.tsx | 1 + .../CustomMetricPercentage.tsx | 4 +- .../CustomMetricPieChart.tsx | 150 +++++++++++++++--- .../CustomMetricTable/CustomMetricTable.tsx | 17 +- .../CustomMetricWidget/CustomMetricWidget.tsx | 18 ++- .../CustomMetricWidgetPreview.css | 11 +- .../CustomMetricWidgetPreview.tsx | 73 +++++---- .../Dashboard/Widgets/common/Styles.js | 2 + .../Dashboard/Widgets/common/Table.js | 4 +- .../CustomMetricForm/CustomMetricForm.tsx | 19 ++- .../FilterSeries/FilterSeries.tsx | 8 +- .../ui/SegmentSelection/SegmentSelection.js | 4 +- .../ui/SegmentSelection/segmentSelection.css | 2 +- frontend/app/types/customMetric.js | 2 +- frontend/app/types/filter/newFilter.js | 2 +- 15 files changed, 227 insertions(+), 90 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx index c9287c4ed..ffbbc6b88 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetriLineChart/CustomMetriLineChart.tsx @@ -19,6 +19,7 @@ function CustomMetriLineChart(props: Props) { margin={Styles.chartMargins} // syncId={ showSync ? "domainsErrors_4xx" : undefined } onClick={onClick} + isAnimationActive={ false } > void; } function CustomMetriPercentage(props: Props) { - const { data } = props; + const { data = {} } = props; return (
{data.count}
-
{`${data.previousCount} ( ${data.countProgress}% ) from previous hour`}
+
{`${data.previousCount} ( ${data.countProgress}% ) from previous period.`}
) } diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx index b0f7dc36f..99c054fae 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -1,7 +1,36 @@ import React from 'react' import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; -import { LineChart, Line, Legend, PieChart, Pie } from 'recharts'; +import { LineChart, Line, Legend, PieChart, Pie, Cell } from 'recharts'; import { Styles } from '../../common'; + + +function renderCustomizedLabel({ + cx, cy, midAngle, innerRadius, outerRadius, value, color, startAngle, endAngle}) { + const RADIAN = Math.PI / 180; + const diffAngle = endAngle - startAngle; + const delta = ((360-diffAngle)/15)-1; + const radius = innerRadius + (outerRadius - innerRadius); + const x = cx + (radius+delta) * Math.cos(-midAngle * RADIAN); + const y = cy + (radius+(delta*delta)) * Math.sin(-midAngle * RADIAN); + return ( + cx ? 'start' : 'end'} dominantBaseline="central" fontSize={12} fontWeight="normal"> + {value} + + ); +}; +function renderCustomizedLabelLine(props){ + let { cx, cy, midAngle, innerRadius, outerRadius, color, startAngle, endAngle } = props; + const RADIAN = Math.PI / 180; + const diffAngle = endAngle - startAngle; + const radius = 10 + innerRadius + (outerRadius - innerRadius); + let path=''; + for(let i=0;i<((360-diffAngle)/15);i++){ + path += `${(cx + (radius+i) * Math.cos(-midAngle * RADIAN))},${(cy + (radius+i*i) * Math.sin(-midAngle * RADIAN))} ` + } + return ( + + ); +} interface Props { data: any; params: any; @@ -9,35 +38,114 @@ interface Props { colors: any; onClick?: (event, index) => void; } + function CustomMetricPieChart(props: Props) { - const { data, params, colors, onClick = () => null } = props; - const data01 = [ - { "name": "Group A", "value": 400 }, - { "name": "Group B", "value": 300 }, - { "name": "Group C", "value": 300 }, - { "name": "Group D", "value": 200 }, - { "name": "Group E", "value": 278 }, - { "name": "Group F", "value": 189 } - ]; + const { data = { values: [] }, params, colors, onClick = () => null } = props; return ( - //
- //
0%
- //
0 ( 0.0% ) from previous hour
- //
- + + labelLine={({ + cx, + cy, + midAngle, + innerRadius, + outerRadius, + value, + index + }) => { + const RADIAN = Math.PI / 180; + let radius1 = 15 + innerRadius + (outerRadius - innerRadius); + let radius2 = innerRadius + (outerRadius - innerRadius); + let x2 = cx + radius1 * Math.cos(-midAngle * RADIAN); + let y2 = cy + radius1 * Math.sin(-midAngle * RADIAN); + let x1 = cx + radius2 * Math.cos(-midAngle * RADIAN); + let y1 = cy + radius2 * Math.sin(-midAngle * RADIAN); + + const percentage = value * 100 / data.values.reduce((a, b) => a + b.sessionCount, 0); + + if (percentage<3){ + return null; + } + + return( + + ) + }} + label={({ + cx, + cy, + midAngle, + innerRadius, + outerRadius, + value, + index + }) => { + const RADIAN = Math.PI / 180; + let radius = 20 + innerRadius + (outerRadius - innerRadius); + let x = cx + radius * Math.cos(-midAngle * RADIAN); + let y = cy + radius * Math.sin(-midAngle * RADIAN); + const percentage = (value / data.values.reduce((a, b) => a + b.sessionCount, 0)) * 100; + if (percentage<3){ + return null; + } + return ( + cx ? "start" : "end"} + dominantBaseline="central" + fill='#3EAAAF' + > + {data.values[index].name} - ({value}) + + ); + }} + // label={({ + // cx, + // cy, + // midAngle, + // innerRadius, + // outerRadius, + // value, + // index + // }) => { + // const RADIAN = Math.PI / 180; + // const radius = 30 + innerRadius + (outerRadius - innerRadius); + // const x = cx + radius * Math.cos(-midAngle * RADIAN); + // const y = cy + radius * Math.sin(-midAngle * RADIAN); + + // return ( + // cx ? "start" : "end"} + // dominantBaseline="top" + // fontSize={10} + // > + // {data.values[index].name} ({value}) + // + // ); + // }} + > + {data.values.map((entry, index) => ( + + ))} + diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx index 9ab0d72eb..be94acc57 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx @@ -6,11 +6,11 @@ const cols = [ { key: 'name', title: 'Resource', - toText: name => name, + toText: name => name || 'Unidentified', width: '70%', }, { - key: 'sessions', + key: 'sessionCount', title: 'Sessions', toText: sessions => sessions, width: '30%', @@ -19,18 +19,13 @@ const cols = [ interface Props { data: any; + onClick?: (event, index) => void; } function CustomMetriTable(props: Props) { - const { data } = props; - const rows = List([ - { name: 'one', sessions: 2 }, - { name: 'two', sessions: 3 }, - { name: 'three', sessions: 4 }, - { name: 'four', sessions: 1 }, - { name: 'five', sessions: 6 }, - ]) + const { data = { values: [] }, onClick = () => null } = props; + const rows = List(data.values); return ( -
+
{ const params = { density: 70 } @@ -101,7 +102,7 @@ function CustomMetricWidget(props: Props) { return (
-
+
{metric.name}
@@ -109,7 +110,7 @@ function CustomMetricWidget(props: Props) { updateActiveState(metric.metricId, false)} />
-
+
)} + + {metric.viewType === 'table' && ( + + )} diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css index 1d1ef3ee4..42444d934 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css @@ -1,6 +1,13 @@ .wrapper { - background-color: white; + background-color: $gray-light; /* border: solid thin $gray-medium; */ border-radius: 3px; - padding: 10px; + padding: 20px; +} + +.innerWapper { + border-radius: 3px; + width: 70%; + margin: 0 auto; + background-color: white; } \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index 7aa43f94b..eb37268fc 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -106,8 +106,8 @@ function CustomMetricWidget(props: Props) { onSelect={ chagneViewType } value={{ value: metric.viewType }} list={ [ - { value: 'lineChart', icon: 'graph-up-arrow' }, - { value: 'progress', icon: 'hash' }, + { value: 'lineChart', name: 'Chart', icon: 'graph-up-arrow' }, + { value: 'progress', name: 'Progress', icon: 'hash' }, ]} /> )} @@ -121,8 +121,8 @@ function CustomMetricWidget(props: Props) { onSelect={ chagneViewType } value={{ value: metric.viewType }} list={[ - { value: 'table', icon: 'table' }, - { value: 'pieChart', icon: 'graph-up-arrow' }, + { value: 'table', name: 'Table', icon: 'table' }, + { value: 'pieChart', name: 'Chart', icon: 'graph-up-arrow' }, ]} /> )} @@ -139,45 +139,50 @@ function CustomMetricWidget(props: Props) {
-
+
+
+ {metric.name} +
+
{ isTimeSeries && ( - <> - { metric.viewType === 'progress' && ( - - )} - { metric.viewType === 'lineChart' && ( - - )} - - )} - - { isTable && ( -
- { metric.viewType === 'table' ? ( - - ) : ( - + { metric.viewType === 'progress' && ( + - )} -
- )} + )} + { metric.viewType === 'lineChart' && ( + + )} + + )} + + { isTable && ( + <> + { metric.viewType === 'table' ? ( + + ) : ( + + )} + + )} +
diff --git a/frontend/app/components/Dashboard/Widgets/common/Styles.js b/frontend/app/components/Dashboard/Widgets/common/Styles.js index 7b763f698..f071127dd 100644 --- a/frontend/app/components/Dashboard/Widgets/common/Styles.js +++ b/frontend/app/components/Dashboard/Widgets/common/Styles.js @@ -5,6 +5,7 @@ const colorsx = ['#256669', '#38999e', '#3eaaaf', '#51b3b7', '#78c4c7', '#9fd5d7 const compareColors = ['#394EFF', '#4D5FFF', '#808DFF', '#B3BBFF', '#E5E8FF']; const compareColorsx = ["#222F99", "#2E3ECC", "#394EFF", "#6171FF", "#8895FF", "#B0B8FF", "#D7DCFF"].reverse(); const customMetricColors = ['#3EAAAF', '#394EFF', '#666666']; +const colorsPie = colors.concat(["#DDDDDD"]); const countView = count => { const isMoreThanK = count >= 1000; @@ -14,6 +15,7 @@ const countView = count => { export default { customMetricColors, colors, + colorsPie, colorsx, compareColors, compareColorsx, diff --git a/frontend/app/components/Dashboard/Widgets/common/Table.js b/frontend/app/components/Dashboard/Widgets/common/Table.js index 73192a501..8fcef4315 100644 --- a/frontend/app/components/Dashboard/Widgets/common/Table.js +++ b/frontend/app/components/Dashboard/Widgets/common/Table.js @@ -45,14 +45,14 @@ export default class Table extends React.PureComponent { )) }
{ rows.size > (small ? 3 : 5) && !showAll && -
+
} diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index b10b1dfe4..ea923a6e1 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -25,6 +25,10 @@ function CustomMetricForm(props: Props) { // const metricOfOptions = metricOf.filter(i => i.key === metric.metricType); const timeseriesOptions = metricOf.filter(i => i.key === 'timeseries'); const tableOptions = metricOf.filter(i => i.key === 'table'); + const isTable = metric.metricType === 'table'; + const isTimeSeries = metric.metricType === 'timeseries'; + const _issueOptions = [{ text: 'All', value: '' }].concat(issueOptions); + const addSeries = () => { props.addSeries(); @@ -44,7 +48,7 @@ function CustomMetricForm(props: Props) { if (name === 'metricOf') { if (value === 'ISSUES') { - props.editMetric({ metricValue: [issueOptions[0].value] }, false); + props.editMetric({ metricValue: [''] }, false); } } @@ -140,7 +144,7 @@ function CustomMetricForm(props: Props) { issue type @@ -165,9 +169,10 @@ function CustomMetricForm(props: Props) {
- {metric.series && metric.series.size > 0 && metric.series.map((series: any, index: number) => ( + {metric.series && metric.series.size > 0 && metric.series.take(isTable ? 1 : metric.series.size).map((series: any, index: number) => (
removeSeries(index)} @@ -177,9 +182,11 @@ function CustomMetricForm(props: Props) { ))}
-
2})}> - -
+ { isTimeSeries && ( +
2})}> + +
+ )}
diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx index 7054e4516..aea20aea1 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx @@ -25,10 +25,12 @@ interface Props { editSeriesFilterFilter: typeof editSeriesFilterFilter; editSeriesFilter: typeof editSeriesFilter; removeSeriesFilterFilter: typeof removeSeriesFilterFilter; + hideHeader?: boolean; + emptyMessage?: any; } function FilterSeries(props: Props) { - const { canDelete } = props; + const { canDelete, hideHeader = false, emptyMessage = 'Add user event or filter to define the series by clicking Add Step.' } = props; const [expanded, setExpanded] = useState(true) const { series, seriesIndex } = props; @@ -51,7 +53,7 @@ function FilterSeries(props: Props) { return (
-
+
props.updateSeries(seriesIndex, { name }) } />
@@ -78,7 +80,7 @@ function FilterSeries(props: Props) { onChangeEventsOrder={onChangeEventsOrder} /> ): ( -
Add user event or filter to define the series by clicking Add Step.
+
{emptyMessage}
)}
diff --git a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js index e18faf096..74335fddd 100644 --- a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js +++ b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js @@ -28,8 +28,8 @@ class SegmentSelection extends React.Component { data-active={ this.props.value && this.props.value.value === item.value } onClick={ () => !item.disabled && this.setActiveItem(item) } > - { item.icon && } -
{ item.name }
+ { item.icon && } +
{ item.name }
} disabled={!item.disabled} diff --git a/frontend/app/components/ui/SegmentSelection/segmentSelection.css b/frontend/app/components/ui/SegmentSelection/segmentSelection.css index f63559c0c..907f81e37 100644 --- a/frontend/app/components/ui/SegmentSelection/segmentSelection.css +++ b/frontend/app/components/ui/SegmentSelection/segmentSelection.css @@ -72,7 +72,7 @@ } .extraSmall .item { - padding: 0 4px !important; + padding: 2px 4px !important; font-size: 12px; } diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index 9ce5841f0..0686af87d 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -31,7 +31,7 @@ export default Record({ metricOf: 'USERID', metricValue: ['sessionCount'], metricFormat: 'sessionCount', - viewType: 'table', + viewType: 'pieChart', series: List(), isPublic: true, startDate: '', diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index db0248458..154db3f23 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -44,7 +44,7 @@ export const filtersMap = { [FilterKey.AVG_CPU_LOAD]: { key: FilterKey.AVG_CPU_LOAD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg CPU Load', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/cpu-load', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, [FilterKey.AVG_MEMORY_USAGE]: { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg Memory Usage', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/memory-load', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, [FilterKey.FETCH_FAILED]: { key: FilterKey.FETCH_FAILED, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Failed Request', operator: 'isAny', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch-failed', isEvent: true }, - [FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/click', options: filterOptions.issueOptions }, + [FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.getOperatorsByKeys(['is', 'isAny', 'isNot']), icon: 'filters/click', options: filterOptions.issueOptions }, } export const liveFiltersMap = { From 6c00eb94719c575c2123d048e6d652a7e72a84af Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 12:50:31 +0100 Subject: [PATCH 053/101] feat(ui) - custom metrics - wip --- .../app/components/Dashboard/Dashboard.js | 2 +- .../CustomMetricPercentage.tsx | 3 +- .../CustomMetricWidgetPreview.tsx | 58 ++++++++++--------- .../CustomMetricsWidgets.tsx | 39 ++++++++----- .../CustomMetricForm/CustomMetricForm.tsx | 4 +- frontend/app/svg/icons/pie-chart-fill.svg | 3 + 6 files changed, 65 insertions(+), 44 deletions(-) create mode 100644 frontend/app/svg/icons/pie-chart-fill.svg diff --git a/frontend/app/components/Dashboard/Dashboard.js b/frontend/app/components/Dashboard/Dashboard.js index 8ad8ecdf8..2b71ef253 100644 --- a/frontend/app/components/Dashboard/Dashboard.js +++ b/frontend/app/components/Dashboard/Dashboard.js @@ -243,7 +243,7 @@ export default class Dashboard extends React.PureComponent {
} > -
+
null}/>
diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/CustomMetricPercentage.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/CustomMetricPercentage.tsx index cfd0d5295..ed4f3cc85 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/CustomMetricPercentage.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPercentage/CustomMetricPercentage.tsx @@ -11,7 +11,8 @@ function CustomMetriPercentage(props: Props) { return (
{data.count}
-
{`${data.previousCount} ( ${data.countProgress}% ) from previous period.`}
+
{`${data.previousCount} ( ${data.countProgress}% )`}
+
from previous period.
) } diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index eb37268fc..55d07da1f 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -94,39 +94,45 @@ function CustomMetricWidget(props: Props) { return (
-
+
Preview
{isTimeSeries && ( - + <> + Visualization + + )} {isTable && ( - + <> + Visualization + + )} -
+
Time Range item.active); useEffect(() => { props.fetchList() @@ -23,27 +24,35 @@ function CustomMetricsWidgets(props: Props) { return ( <> - {list.map((item: any) => ( - - { - setActiveMetricId(item.metricId) - props.initAlert({ query: { left: item.series.first().seriesId }}) - }} - /> - - ))} +
+ {activeList.map((item: any) => ( + + { + setActiveMetricId(item.metricId) + props.initAlert({ query: { left: item.series.first().seriesId }}) + }} + /> + + ))} +
{list.size === 0 && (
-
Be proactive by monitoring the metrics you care about the most.
+
Be proactive by monitoring the metrics you care about the most.
)} + {list.size > 0 && activeList && activeList.size === 0 && ( +
+
It's blank here, add a metric to this section.
+
+ )} + ({ - list: state.getIn(['customMetrics', 'list']).filter(item => item.active), + list: state.getIn(['customMetrics', 'list']), }), { fetchList, initAlert })(CustomMetricsWidgets); \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index ea923a6e1..4ff533029 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -168,7 +168,9 @@ function CustomMetricForm(props: Props) {
- + {metric.series && metric.series.size > 0 && metric.series.take(isTable ? 1 : metric.series.size).map((series: any, index: number) => (
+ + \ No newline at end of file From df52a9dfe33210a1b5d4ce2c235e61e4f94e6d25 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 14:45:21 +0100 Subject: [PATCH 054/101] feat(api): Accelerated login/status for long projects --- api/chalicelib/core/projects.py | 31 +++++++++++++++++------------- ee/api/chalicelib/core/projects.py | 31 +++++++++++++++++------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/api/chalicelib/core/projects.py b/api/chalicelib/core/projects.py index 2536ee956..c5ae912aa 100644 --- a/api/chalicelib/core/projects.py +++ b/api/chalicelib/core/projects.py @@ -69,20 +69,25 @@ def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, st ) rows = cur.fetchall() if recording_state: + project_ids = [f'({r["project_id"]})' for r in rows] + query = f"""SELECT projects.project_id, COALESCE(MAX(start_ts), 0) AS last + FROM (VALUES {",".join(project_ids)}) AS projects(project_id) + LEFT JOIN sessions USING (project_id) + GROUP BY project_id;""" + cur.execute( + query=query + ) + status = cur.fetchall() for r in rows: - query = cur.mogrify( - "select COALESCE(MAX(start_ts),0) AS last from public.sessions where project_id=%(project_id)s;", - {"project_id": r["project_id"]}) - cur.execute( - query=query - ) - status = cur.fetchone() - if status["last"] < TimeUTC.now(-2): - r["status"] = "red" - elif status["last"] < TimeUTC.now(-1): - r["status"] = "yellow" - else: - r["status"] = "green" + for s in status: + if s["project_id"] == r["project_id"]: + if s["last"] < TimeUTC.now(-2): + r["status"] = "red" + elif s["last"] < TimeUTC.now(-1): + r["status"] = "yellow" + else: + r["status"] = "green" + break return helper.list_to_camel_case(rows) diff --git a/ee/api/chalicelib/core/projects.py b/ee/api/chalicelib/core/projects.py index 2728e5077..75a3a31d0 100644 --- a/ee/api/chalicelib/core/projects.py +++ b/ee/api/chalicelib/core/projects.py @@ -81,20 +81,25 @@ def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, st ) rows = cur.fetchall() if recording_state: + project_ids = [f'({r["project_id"]})' for r in rows] + query = f"""SELECT projects.project_id, COALESCE(MAX(start_ts), 0) AS last + FROM (VALUES {",".join(project_ids)}) AS projects(project_id) + LEFT JOIN sessions USING (project_id) + GROUP BY project_id;""" + cur.execute( + query=query + ) + status = cur.fetchall() for r in rows: - query = cur.mogrify( - "select COALESCE(MAX(start_ts),0) AS last from public.sessions where project_id=%(project_id)s;", - {"project_id": r["project_id"]}) - cur.execute( - query=query - ) - status = cur.fetchone() - if status["last"] < TimeUTC.now(-2): - r["status"] = "red" - elif status["last"] < TimeUTC.now(-1): - r["status"] = "yellow" - else: - r["status"] = "green" + for s in status: + if s["project_id"] == r["project_id"]: + if s["last"] < TimeUTC.now(-2): + r["status"] = "red" + elif s["last"] < TimeUTC.now(-1): + r["status"] = "yellow" + else: + r["status"] = "green" + break return helper.list_to_camel_case(rows) From 5e2d9734e23241e276ba9e1c493f51ea6e5ef124 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 15:13:24 +0100 Subject: [PATCH 055/101] feat(api): changed python version for Dockerfile.bundle --- api/Dockerfile.bundle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/Dockerfile.bundle b/api/Dockerfile.bundle index 54709db89..a1577d8c3 100644 --- a/api/Dockerfile.bundle +++ b/api/Dockerfile.bundle @@ -1,4 +1,4 @@ -FROM python:3.6-slim +FROM python:3.9.7-slim LABEL Maintainer="Rajesh Rajendran" WORKDIR /work COPY . . From 04326494e6dc5bab4f1e3307711c32fac781b291 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 15:54:23 +0100 Subject: [PATCH 056/101] feat(api): changed issue type --- api/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/schemas.py b/api/schemas.py index e4dc7f1e7..ac50aad71 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -428,7 +428,7 @@ class FilterType(str, Enum): duration = "DURATION" platform = "PLATFORM" metadata = "METADATA" - issue = "ISSUES" + issue = "ISSUE" events_count = "EVENTS_COUNT" utm_source = "UTM_SOURCE" utm_medium = "UTM_MEDIUM" From a030b2b95594a04e4c95580d319cae4b819d274d Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 13:05:51 +0100 Subject: [PATCH 057/101] feat(ui) - custom metrics - wip --- .../CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx | 4 ++-- frontend/app/duck/customMetrics.js | 2 +- frontend/tailwind.config.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx index cba21a33b..75054fc6b 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx @@ -36,7 +36,7 @@ function SeriesName(props: Props) { setEditing(true)} /> ) : ( -
{name}
+
{name}
)}
setEditing(true)}>
diff --git a/frontend/app/duck/customMetrics.js b/frontend/app/duck/customMetrics.js index f27429130..e6713acb4 100644 --- a/frontend/app/duck/customMetrics.js +++ b/frontend/app/duck/customMetrics.js @@ -187,7 +187,7 @@ export const init = (instance = null, forceNull = false) => (dispatch, getState) export const fetchSessionList = (params) => (dispatch, getState) => { dispatch({ types: array(FETCH_SESSION_LIST), - call: client => client.post(`/custom_metrics/sessions`, { ...params }), + call: client => client.post(`/custom_metrics/${params.metricId}/sessions`, { ...params }), }); } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index e15ec72e9..0da29c3d5 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -19,7 +19,7 @@ module.exports = { // 'backgroundSize', // 'borderCollapse', 'borderColor', - // 'borderOpacity', + 'borderOpacity', 'borderRadius', // 'borderStyle', 'borderWidth', From 1d957f90b518b640e3a3692c80b4e12b759bec10 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 16:25:35 +0100 Subject: [PATCH 058/101] feat(ui) - custom metrics - wip --- .../CustomMetricPieChart.tsx | 234 ++++++++---------- .../CustomMetricTable/CustomMetricTable.tsx | 39 ++- .../CustomMetricWidget/CustomMetricWidget.tsx | 16 +- .../CustomMetricWidgetPreview.css | 1 + .../Dashboard/Widgets/common/Table.js | 7 +- .../CustomMetricForm/CustomMetricForm.tsx | 17 +- .../SessionListModal/SessionListModal.tsx | 3 +- .../DateRangeDropdown/dateRangeDropdown.css | 8 +- .../shared/DropdownPlain/DropdownPlain.css | 4 +- frontend/app/constants/filterOptions.js | 16 +- frontend/app/types/customMetric.js | 9 +- 11 files changed, 194 insertions(+), 160 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx index 99c054fae..21f2d6d23 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -1,36 +1,8 @@ import React from 'react' -import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; -import { LineChart, Line, Legend, PieChart, Pie, Cell } from 'recharts'; +import { ResponsiveContainer, Tooltip } from 'recharts'; +import { PieChart, Pie, Cell } from 'recharts'; import { Styles } from '../../common'; - - -function renderCustomizedLabel({ - cx, cy, midAngle, innerRadius, outerRadius, value, color, startAngle, endAngle}) { - const RADIAN = Math.PI / 180; - const diffAngle = endAngle - startAngle; - const delta = ((360-diffAngle)/15)-1; - const radius = innerRadius + (outerRadius - innerRadius); - const x = cx + (radius+delta) * Math.cos(-midAngle * RADIAN); - const y = cy + (radius+(delta*delta)) * Math.sin(-midAngle * RADIAN); - return ( - cx ? 'start' : 'end'} dominantBaseline="central" fontSize={12} fontWeight="normal"> - {value} - - ); -}; -function renderCustomizedLabelLine(props){ - let { cx, cy, midAngle, innerRadius, outerRadius, color, startAngle, endAngle } = props; - const RADIAN = Math.PI / 180; - const diffAngle = endAngle - startAngle; - const radius = 10 + innerRadius + (outerRadius - innerRadius); - let path=''; - for(let i=0;i<((360-diffAngle)/15);i++){ - path += `${(cx + (radius+i) * Math.cos(-midAngle * RADIAN))},${(cy + (radius+i*i) * Math.sin(-midAngle * RADIAN))} ` - } - return ( - - ); -} +import { NoContent } from 'UI'; interface Props { data: any; params: any; @@ -42,47 +14,22 @@ interface Props { function CustomMetricPieChart(props: Props) { const { data = { values: [] }, params, colors, onClick = () => null } = props; return ( - - - { - const RADIAN = Math.PI / 180; - let radius1 = 15 + innerRadius + (outerRadius - innerRadius); - let radius2 = innerRadius + (outerRadius - innerRadius); - let x2 = cx + radius1 * Math.cos(-midAngle * RADIAN); - let y2 = cy + radius1 * Math.sin(-midAngle * RADIAN); - let x1 = cx + radius2 * Math.cos(-midAngle * RADIAN); - let y1 = cy + radius2 * Math.sin(-midAngle * RADIAN); - - const percentage = value * 100 / data.values.reduce((a, b) => a + b.sessionCount, 0); - - if (percentage<3){ - return null; - } - - return( - - ) - }} - label={({ +
+ + + + { const RADIAN = Math.PI / 180; - let radius = 20 + innerRadius + (outerRadius - innerRadius); - let x = cx + radius * Math.cos(-midAngle * RADIAN); - let y = cy + radius * Math.sin(-midAngle * RADIAN); - const percentage = (value / data.values.reduce((a, b) => a + b.sessionCount, 0)) * 100; - if (percentage<3){ - return null; - } - return ( - cx ? "start" : "end"} - dominantBaseline="central" - fill='#3EAAAF' - > - {data.values[index].name} - ({value}) - - ); - }} - // label={({ - // cx, - // cy, - // midAngle, - // innerRadius, - // outerRadius, - // value, - // index - // }) => { - // const RADIAN = Math.PI / 180; - // const radius = 30 + innerRadius + (outerRadius - innerRadius); - // const x = cx + radius * Math.cos(-midAngle * RADIAN); - // const y = cy + radius * Math.sin(-midAngle * RADIAN); + let radius1 = 15 + innerRadius + (outerRadius - innerRadius); + let radius2 = innerRadius + (outerRadius - innerRadius); + let x2 = cx + radius1 * Math.cos(-midAngle * RADIAN); + let y2 = cy + radius1 * Math.sin(-midAngle * RADIAN); + let x1 = cx + radius2 * Math.cos(-midAngle * RADIAN); + let y1 = cy + radius2 * Math.sin(-midAngle * RADIAN); + + const percentage = value * 100 / data.values.reduce((a, b) => a + b.sessionCount, 0); + + if (percentage<3){ + return null; + } + + return( + + ) + }} + label={({ + cx, + cy, + midAngle, + innerRadius, + outerRadius, + value, + index + }) => { + const RADIAN = Math.PI / 180; + let radius = 20 + innerRadius + (outerRadius - innerRadius); + let x = cx + radius * Math.cos(-midAngle * RADIAN); + let y = cy + radius * Math.sin(-midAngle * RADIAN); + const percentage = (value / data.values.reduce((a, b) => a + b.sessionCount, 0)) * 100; + if (percentage<3){ + return null; + } + return ( + cx ? "start" : "end"} + dominantBaseline="central" + fill='#666' + > + {data.values[index].name} - ({value}) + + ); + }} + // label={({ + // cx, + // cy, + // midAngle, + // innerRadius, + // outerRadius, + // value, + // index + // }) => { + // const RADIAN = Math.PI / 180; + // const radius = 30 + innerRadius + (outerRadius - innerRadius); + // const x = cx + radius * Math.cos(-midAngle * RADIAN); + // const y = cy + radius * Math.sin(-midAngle * RADIAN); + + // return ( + // cx ? "start" : "end"} + // dominantBaseline="top" + // fontSize={10} + // > + // {data.values[index].name} ({value}) + // + // ); + // }} + > + {data.values.map((entry, index) => ( + + ))} + + + - // return ( - // cx ? "start" : "end"} - // dominantBaseline="top" - // fontSize={10} - // > - // {data.values[index].name} ({value}) - // - // ); - // }} - > - {data.values.map((entry, index) => ( - - ))} - - - - + +
Top 5
+
+
) } diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx index be94acc57..d067b6666 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx @@ -1,6 +1,9 @@ import React from 'react' import { Table } from '../../common'; import { List } from 'immutable'; +import { FilterKey } from 'Types/filter/filterType'; +import { filtersMap } from 'Types/filter/newFilter'; +import { NoContent } from 'UI'; const cols = [ { @@ -18,20 +21,40 @@ const cols = [ ]; interface Props { + metric?: any, data: any; - onClick?: (event, index) => void; + onClick?: (filters) => void; } function CustomMetriTable(props: Props) { - const { data = { values: [] }, onClick = () => null } = props; + const { metric = {}, data = { values: [] }, onClick = () => null } = props; const rows = List(data.values); + + const onClickHandler = (event, data) => { + const filters = Array(); + let filter = { ...filtersMap[metric.metricOf] } + filter.value = [data.name] + filter.type = filter.key + delete filter.key + delete filter.operatorOptions + delete filter.category + delete filter.icon + delete filter.label + delete filter.options + + filters.push(filter); + onClick(filters); + } return (
-
+ +
+ ) } diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index f473ed270..89e3416fa 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -76,6 +76,19 @@ function CustomMetricWidget(props: Props) { }).finally(() => setLoading(false)); }, [period]) + const clickHandlerTable = (filters) => { + const activeWidget = { + widget: metric, + period: period, + ...period.toTimestamps(), + filters, + // timestamp: payload.timestamp, + // index, + } + props.setActiveWidget(activeWidget); + // props.updateActiveState(metric.metricId, data); + } + const clickHandler = (event, index) => { if (event) { const payload = event.activePayload[0].payload; @@ -148,10 +161,11 @@ function CustomMetricWidget(props: Props) { {metric.viewType === 'table' && ( )} diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css index 42444d934..2088330ba 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.css @@ -10,4 +10,5 @@ width: 70%; margin: 0 auto; background-color: white; + min-height: 220px; } \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/common/Table.js b/frontend/app/components/Dashboard/Widgets/common/Table.js index 8fcef4315..5e3c2fe0e 100644 --- a/frontend/app/components/Dashboard/Widgets/common/Table.js +++ b/frontend/app/components/Dashboard/Widgets/common/Table.js @@ -18,6 +18,7 @@ export default class Table extends React.PureComponent { small = false, compare = false, maxHeight = 200, + onRowClick = () => {}, } = this.props; const { showAll } = this.state; @@ -33,7 +34,11 @@ export default class Table extends React.PureComponent {
{ rows.take(showAll ? 10 : (small ? 3 : 5)).map(row => ( -
+
onRowClick(e, row)} + > { cols.map(({ cellClass = '', className = '', Component, key, toText = t => t, width }) => (
{ Component ? diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index 4ff533029..db6585654 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -9,6 +9,7 @@ import { toast } from 'react-toastify'; import cn from 'classnames'; import DropdownPlain from '../../DropdownPlain'; import { metricTypes, metricOf, issueOptions } from 'App/constants/filterOptions'; +import { FilterKey } from 'Types/filter/filterType'; interface Props { metric: any; editMetric: (metric, shouldFetch?) => void; @@ -23,11 +24,11 @@ interface Props { function CustomMetricForm(props: Props) { const { metric, loading } = props; // const metricOfOptions = metricOf.filter(i => i.key === metric.metricType); - const timeseriesOptions = metricOf.filter(i => i.key === 'timeseries'); - const tableOptions = metricOf.filter(i => i.key === 'table'); + const timeseriesOptions = metricOf.filter(i => i.type === 'timeseries'); + const tableOptions = metricOf.filter(i => i.type === 'table'); const isTable = metric.metricType === 'table'; const isTimeSeries = metric.metricType === 'timeseries'; - const _issueOptions = [{ text: 'All', value: '' }].concat(issueOptions); + const _issueOptions = [{ text: 'All', value: 'all' }].concat(issueOptions); const addSeries = () => { @@ -47,8 +48,8 @@ function CustomMetricForm(props: Props) { } if (name === 'metricOf') { - if (value === 'ISSUES') { - props.editMetric({ metricValue: [''] }, false); + if (value === FilterKey.ISSUE) { + props.editMetric({ metricValue: ['all'] }, false); } } @@ -139,7 +140,7 @@ function CustomMetricForm(props: Props) { )} - {metric.metricOf === 'ISSUES' && ( + {metric.metricOf === FilterKey.ISSUE && ( <> issue type removeSeries(index)} canDelete={metric.series.size > 1} + emptyMessage={isTable ? + 'Filter table data by user environment and metadata attributes. Use add step button below to filter.' : + 'Add user event or filter to define the series by clicking Add Step.' + } />
))} diff --git a/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx b/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx index bafa68fd1..d6434fadb 100644 --- a/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx +++ b/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx @@ -23,7 +23,8 @@ function SessionListModal(props: Props) { props.fetchSessionList({ metricId: activeWidget.widget.metricId, startDate: activeWidget.startTimestamp, - endDate: activeWidget.endTimestamp + endDate: activeWidget.endTimestamp, + filters: activeWidget.filters || [], }); }, [activeWidget]); diff --git a/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css b/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css index 27ae5b3bc..1cf17bf82 100644 --- a/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css +++ b/frontend/app/components/shared/DateRangeDropdown/dateRangeDropdown.css @@ -1,5 +1,5 @@ .button { - padding: 0 8px; + padding: 0 4px; border-radius: 3px; color: $teal; cursor: pointer; @@ -12,7 +12,7 @@ } .dropdownTrigger { - padding: 4px 6px; + padding: 4px; &:hover { background-color: $gray-light; } @@ -42,7 +42,7 @@ .dropdown { display: flex !important; - padding: 4px 6px; + padding: 4px 4px; border-radius: 3px; color: $gray-darkest; font-weight: 500; @@ -52,7 +52,7 @@ } .dropdownTrigger { - padding: 4px 8px; + padding: 4px 4px; border-radius: 3px; &:hover { background-color: $gray-light; diff --git a/frontend/app/components/shared/DropdownPlain/DropdownPlain.css b/frontend/app/components/shared/DropdownPlain/DropdownPlain.css index 1bf3e305c..dd7b9a2a5 100644 --- a/frontend/app/components/shared/DropdownPlain/DropdownPlain.css +++ b/frontend/app/components/shared/DropdownPlain/DropdownPlain.css @@ -1,6 +1,6 @@ .dropdown { display: flex !important; - padding: 4px 6px; + padding: 4px; border-radius: 3px; color: $gray-darkest; font-weight: 500; @@ -12,7 +12,7 @@ } .dropdownTrigger { - padding: 4px 8px; + padding: 4px; border-radius: 3px; &:hover { background-color: $gray-light; diff --git a/frontend/app/constants/filterOptions.js b/frontend/app/constants/filterOptions.js index 6b9b5b70d..6fa6d0cbf 100644 --- a/frontend/app/constants/filterOptions.js +++ b/frontend/app/constants/filterOptions.js @@ -1,3 +1,5 @@ +import { FilterKey } from 'Types/filter/filterType'; + export const options = [ { key: 'on', text: 'on', value: 'on' }, { key: 'notOn', text: 'not on', value: 'notOn' }, @@ -60,13 +62,13 @@ export const metricTypes = [ ]; export const metricOf = [ - { text: 'Session Count', value: 'sessionCount', key: 'timeseries' }, - { text: 'Users', value: 'USERID', key: 'table' }, - { text: 'Issues', value: 'ISSUES', key: 'table' }, - { text: 'Browser', value: 'USERBROWSER', key: 'table' }, - { text: 'Device', value: 'USERDEVICE', key: 'table' }, - { text: 'Country', value: 'USERCOUNTRY', key: 'table' }, - { text: 'URL', value: 'VISITED_URL', key: 'table' }, + { text: 'Session Count', value: 'sessionCount', type: 'timeseries' }, + { text: 'Users', value: FilterKey.USERID, type: 'table' }, + { text: 'Issues', value: FilterKey.ISSUE, type: 'table' }, + { text: 'Browser', value: FilterKey.USER_BROWSER, type: 'table' }, + { text: 'Device', value: FilterKey.USER_DEVICE, type: 'table' }, + { text: 'Country', value: FilterKey.USER_COUNTRY, type: 'table' }, + { text: 'URL', value: FilterKey.LOCATION, type: 'table' }, ] export const issueOptions = [ diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index 0686af87d..0140faec4 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -3,6 +3,7 @@ import { List } from 'immutable'; import Filter from 'Types/filter'; import { validateName } from 'App/validate'; import { LAST_7_DAYS } from 'Types/app/period'; +import { FilterKey } from 'Types/filter/filterType'; import { filterMap } from 'Duck/search'; export const FilterSeries = Record({ @@ -47,11 +48,13 @@ export default Record({ toSaveData() { const js = this.toJS(); + + js.metricValue = js.metricValue.map(value => value === 'all' ? '' : value); js.series = js.series.map(series => { series.filter.filters = series.filter.filters.map(filterMap); // delete series._key - // delete series.key + delete series.key return series; }); @@ -65,8 +68,10 @@ export default Record({ return js; }, }, - fromJS: ({ series, ...rest }) => ({ + fromJS: ({ metricOf, metricValue, series, ...rest }) => ({ ...rest, series: List(series).map(FilterSeries), + metricOf, + metricValue: metricOf === FilterKey.ISSUE && metricValue.length === 0 ? ['all'] : metricValue, }), }); From 35cc75c9d6e00fe20250040052aded82d7f8ece0 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 16:46:38 +0100 Subject: [PATCH 059/101] feat(ui) - custom metrics - wip --- .../CustomMetricPieChart.tsx | 25 +++++++++++++++++-- .../CustomMetricWidget/CustomMetricWidget.tsx | 6 ++--- .../Dashboard/Widgets/common/Table.js | 6 ++--- .../shared/CustomMetrics/CustomMetrics.tsx | 3 --- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx index 21f2d6d23..cdb561dd7 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -3,16 +3,36 @@ import { ResponsiveContainer, Tooltip } from 'recharts'; import { PieChart, Pie, Cell } from 'recharts'; import { Styles } from '../../common'; import { NoContent } from 'UI'; +import { filtersMap } from 'Types/filter/newFilter'; interface Props { + metric: any, data: any; params: any; // seriesMap: any; colors: any; - onClick?: (event, index) => void; + onClick?: (filters) => void; } function CustomMetricPieChart(props: Props) { - const { data = { values: [] }, params, colors, onClick = () => null } = props; + const { metric, data = { values: [] }, onClick = () => null } = props; + + const onClickHandler = (event) => { + if (event) { + const filters = Array(); + let filter = { ...filtersMap[metric.metricOf] } + filter.value = [event.payload.name] + filter.type = filter.key + delete filter.key + delete filter.operatorOptions + delete filter.category + delete filter.icon + delete filter.label + delete filter.options + + filters.push(filter); + onClick(filters); + } + } return (
@@ -29,6 +49,7 @@ function CustomMetricPieChart(props: Props) { outerRadius={70} // fill={colors[0]} activeIndex={1} + onClick={onClickHandler} labelLine={({ cx, cy, diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index 89e3416fa..50471b5f9 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -82,11 +82,8 @@ function CustomMetricWidget(props: Props) { period: period, ...period.toTimestamps(), filters, - // timestamp: payload.timestamp, - // index, } props.setActiveWidget(activeWidget); - // props.updateActiveState(metric.metricId, data); } const clickHandler = (event, index) => { @@ -143,10 +140,11 @@ function CustomMetricWidget(props: Props) { {metric.viewType === 'pieChart' && ( )} diff --git a/frontend/app/components/Dashboard/Widgets/common/Table.js b/frontend/app/components/Dashboard/Widgets/common/Table.js index 5e3c2fe0e..e1b6a503c 100644 --- a/frontend/app/components/Dashboard/Widgets/common/Table.js +++ b/frontend/app/components/Dashboard/Widgets/common/Table.js @@ -18,7 +18,7 @@ export default class Table extends React.PureComponent { small = false, compare = false, maxHeight = 200, - onRowClick = () => {}, + onRowClick = null, } = this.props; const { showAll } = this.state; @@ -35,9 +35,9 @@ export default class Table extends React.PureComponent {
{ rows.take(showAll ? 10 : (small ? 3 : 5)).map(row => (
onRowClick(e, row)} + onClick={onRowClick ? (e) => onRowClick(e, row) : () => null} > { cols.map(({ cellClass = '', className = '', Component, key, toText = t => t, width }) => (
{ Component diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx index ae0718aea..77a49a7e1 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx @@ -7,9 +7,6 @@ interface Props { init: (instance?, setDefault?) => void; } function CustomMetrics(props: Props) { - useEffect(() => { // TODO remove this block - props.init() - }, []) return (
props.init()} /> From 35e7df94e07b5a3abb78d64a38a58768955dcaf4 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 17:08:22 +0100 Subject: [PATCH 060/101] feat(ui) - custom metrics - wip --- .../CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index 55d07da1f..e0b286562 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -181,6 +181,7 @@ function CustomMetricWidget(props: Props) { ) : ( Date: Fri, 4 Mar 2022 17:12:07 +0100 Subject: [PATCH 061/101] feat(DB): DB structure changes --- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 90 ++++++++++++++++++- .../db/init_dbs/postgresql/init_schema.sql | 52 +++++++++-- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 89 +++++++++++++++++- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 78 ---------------- .../db/init_dbs/postgresql/init_schema.sql | 33 +++++-- 5 files changed, 248 insertions(+), 94 deletions(-) delete mode 100644 scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index 88e1aab74..936e56968 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -51,4 +51,92 @@ ALTER TABLE metrics ADD COLUMN IF NOT EXISTS metric_format text; -COMMIT; \ No newline at end of file + +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; + END; +$$ +LANGUAGE plpgsql; + + +ALTER TABLE events.graphql + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL, + ADD COLUMN IF NOT EXISTS duration integer NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL; + +COMMIT; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + + + +-- Split requests-URL: Takes too long to use +-- UPDATE events_common.requests +-- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, +-- host=CASE +-- WHEN POSITION('://' IN url) = 0 THEN NULL +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( +-- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, +-- base_path=CASE +-- WHEN POSITION('://' IN url) = 0 THEN +-- CASE +-- WHEN POSITION('?' IN url) > 0 THEN +-- SUBSTRING(url, 1, POSITION('?' IN url) - 1) +-- ELSE url END +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- CASE +-- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, +-- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + +-- 1) END +-- END, +-- query_string=CASE +-- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) +-- END; + diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 1f0f4d6f1..92e25c9e1 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -994,7 +994,11 @@ $$ CREATE INDEX IF NOT EXISTS errors_error_id_timestamp_session_id_idx ON events.errors (error_id, timestamp, session_id); CREATE INDEX IF NOT EXISTS errors_error_id_idx ON events.errors (error_id); - + IF NOT EXISTS(SELECT * + FROM pg_type typ + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; CREATE TABLE IF NOT EXISTS events.graphql ( session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, @@ -1006,6 +1010,12 @@ $$ CREATE INDEX IF NOT EXISTS graphql_name_idx ON events.graphql (name); CREATE INDEX IF NOT EXISTS graphql_name_gin_idx ON events.graphql USING GIN (name gin_trgm_ops); CREATE INDEX IF NOT EXISTS graphql_timestamp_idx ON events.graphql (timestamp); + CREATE INDEX IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; CREATE TABLE IF NOT EXISTS events.state_actions ( @@ -1147,15 +1157,27 @@ $$ CREATE INDEX IF NOT EXISTS issues_issue_id_timestamp_idx ON events_common.issues (issue_id, timestamp); CREATE INDEX IF NOT EXISTS issues_timestamp_idx ON events_common.issues (timestamp); - + IF NOT EXISTS(SELECT * + FROM pg_type typ + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; CREATE TABLE IF NOT EXISTS events_common.requests ( - session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, - timestamp bigint NOT NULL, - seq_index integer NOT NULL, - url text NOT NULL, - duration integer NOT NULL, - success boolean NOT NULL, + session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, + timestamp bigint NOT NULL, + seq_index integer NOT NULL, + url text NOT NULL, + duration integer NOT NULL, + success boolean NOT NULL, + request_body text NULL, + response_body text NULL, + status_code smallint NULL, + method http_method NULL, + schema text NULL, + host text NULL, + base_path text NULL, + query_string text NULL, PRIMARY KEY (session_id, timestamp, seq_index) ); CREATE INDEX IF NOT EXISTS requests_url_idx ON events_common.requests (url); @@ -1172,6 +1194,20 @@ $$ ELSE 0 END)) gin_trgm_ops); CREATE INDEX IF NOT EXISTS requests_timestamp_session_id_failed_idx ON events_common.requests (timestamp, session_id) WHERE success = FALSE; + CREATE INDEX IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + + CREATE INDEX IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + + END IF; END; $$ diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index b471511f4..e661e526a 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -50,4 +50,91 @@ ALTER TABLE metrics ADD COLUMN IF NOT EXISTS metric_format text; -COMMIT; \ No newline at end of file +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; + END; +$$ +LANGUAGE plpgsql; + + +ALTER TABLE events.graphql + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL, + ADD COLUMN IF NOT EXISTS duration integer NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL; + +COMMIT; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + + + +-- Split requests-URL: Takes too long to use +-- UPDATE events_common.requests +-- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, +-- host=CASE +-- WHEN POSITION('://' IN url) = 0 THEN NULL +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( +-- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, +-- base_path=CASE +-- WHEN POSITION('://' IN url) = 0 THEN +-- CASE +-- WHEN POSITION('?' IN url) > 0 THEN +-- SUBSTRING(url, 1, POSITION('?' IN url) - 1) +-- ELSE url END +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- CASE +-- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, +-- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + +-- 1) END +-- END, +-- query_string=CASE +-- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) +-- END; + diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql deleted file mode 100644 index 2b71f3ac4..000000000 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ /dev/null @@ -1,78 +0,0 @@ --- !!!!NOT IN CREATE DB YET - -BEGIN; -CREATE OR REPLACE FUNCTION openreplay_version() - RETURNS text AS -$$ -SELECT 'v1.5.X' -$$ LANGUAGE sql IMMUTABLE; - -CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); - -ALTER TABLE events_common.requests - ADD COLUMN IF NOT EXISTS schema text NULL, - ADD COLUMN IF NOT EXISTS host text NULL, - ADD COLUMN IF NOT EXISTS base_path text NULL, - ADD COLUMN IF NOT EXISTS query_string text NULL, - ADD COLUMN IF NOT EXISTS request_body text NULL, - ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code smallint NULL, - ADD COLUMN IF NOT EXISTS method http_method NULL; - --- Split requests-URL: Takes too long to use --- UPDATE events_common.requests --- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, --- host=CASE --- WHEN POSITION('://' IN url) = 0 THEN NULL --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( --- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, --- base_path=CASE --- WHEN POSITION('://' IN url) = 0 THEN --- CASE --- WHEN POSITION('?' IN url) > 0 THEN --- SUBSTRING(url, 1, POSITION('?' IN url) - 1) --- ELSE url END --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- CASE --- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, --- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + --- 1) END --- END, --- query_string=CASE --- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) --- END; - - -ALTER TABLE events.graphql - ADD COLUMN IF NOT EXISTS request_body text NULL, - ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code smallint NULL, - ADD COLUMN IF NOT EXISTS method http_method NULL, - ADD COLUMN IF NOT EXISTS duration integer NULL; - -COMMIT; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; \ No newline at end of file diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 232596696..57fae7794 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -631,14 +631,23 @@ $$ CREATE INDEX issues_timestamp_idx ON events_common.issues (timestamp); CREATE INDEX issues_project_id_issue_id_idx ON public.issues (project_id, issue_id); + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); CREATE TABLE events_common.requests ( - session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, - timestamp bigint NOT NULL, - seq_index integer NOT NULL, - url text NOT NULL, - duration integer NOT NULL, - success boolean NOT NULL, + session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, + timestamp bigint NOT NULL, + seq_index integer NOT NULL, + url text NOT NULL, + duration integer NOT NULL, + success boolean NOT NULL, + request_body text NULL, + response_body text NULL, + status_code smallint NULL, + method http_method NULL, + schema text NULL, + host text NULL, + base_path text NULL, + query_string text NULL, PRIMARY KEY (session_id, timestamp, seq_index) ); CREATE INDEX requests_url_idx ON events_common.requests (url); @@ -653,6 +662,18 @@ $$ ELSE 0 END)) gin_trgm_ops); CREATE INDEX requests_timestamp_session_id_failed_idx ON events_common.requests (timestamp, session_id) WHERE success = FALSE; + CREATE INDEX requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; + CREATE INDEX requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; + CREATE INDEX requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; + CREATE INDEX requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; + CREATE INDEX requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + CREATE INDEX requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; + CREATE INDEX requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; + CREATE INDEX requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; + CREATE INDEX requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; + CREATE INDEX requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; + CREATE INDEX requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + -- --- events.sql --- CREATE SCHEMA IF NOT EXISTS events; From 9028e67dfa430e3b96f18aedc9d9bdb4cd240fc4 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 17:20:05 +0100 Subject: [PATCH 062/101] feat(DB): DB changed version number --- .../init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} | 2 +- ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql | 2 +- .../init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} | 2 +- scripts/helm/db/init_dbs/postgresql/init_schema.sql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename ee/scripts/helm/db/init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} (99%) rename scripts/helm/db/init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} (99%) diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql similarity index 99% rename from ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql rename to ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql index 936e56968..399a2199f 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql @@ -2,7 +2,7 @@ BEGIN; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.X-ee' +SELECT 'v1.5.3-ee' $$ LANGUAGE sql IMMUTABLE; UPDATE metrics diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 92e25c9e1..6a81a107d 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -7,7 +7,7 @@ CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.2-ee' +SELECT 'v1.5.3-ee' $$ LANGUAGE sql IMMUTABLE; diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql similarity index 99% rename from scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql rename to scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql index e661e526a..0e25a7396 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql @@ -2,7 +2,7 @@ BEGIN; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.X' +SELECT 'v1.5.3' $$ LANGUAGE sql IMMUTABLE; UPDATE metrics diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 57fae7794..fb2e7bb63 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -6,7 +6,7 @@ CREATE SCHEMA IF NOT EXISTS events; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.2' +SELECT 'v1.5.3' $$ LANGUAGE sql IMMUTABLE; -- --- accounts.sql --- From 82ceecbef997321c2fc379d672972cfed4d16b2e Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 17:55:24 +0100 Subject: [PATCH 063/101] feat(ui) - code snippet changes as per the latest tracker --- .../ProjectCodeSnippet/ProjectCodeSnippet.js | 9 ++++--- .../ProjectCodeSnippet/ProjectCodeSnippet.js | 25 +++++++------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js index fb52d0e5f..bf0e83791 100644 --- a/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js +++ b/frontend/app/components/Onboarding/components/OnboardingTabs/ProjectCodeSnippet/ProjectCodeSnippet.js @@ -17,9 +17,11 @@ const inputModeOptions = [ const codeSnippet = ` `; diff --git a/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js index 1fc8eea7b..e269c2cc7 100644 --- a/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js +++ b/frontend/app/components/shared/TrackingCodeModal/ProjectCodeSnippet/ProjectCodeSnippet.js @@ -1,12 +1,12 @@ import React, { useState } from 'react' import { connect } from 'react-redux'; import { editGDPR, saveGDPR } from 'Duck/site'; -import { Controlled as CodeMirror } from 'react-codemirror2'; import copy from 'copy-to-clipboard'; import { Select, Checkbox } from 'UI'; import GDPR from 'Types/site/gdpr'; import cn from 'classnames' import styles from './projectCodeSnippet.css' +import Highlight from 'react-highlight' const inputModeOptions = [ { text: 'Record all inputs', value: 'plain' }, @@ -16,9 +16,11 @@ const inputModeOptions = [ const codeSnippet = ` `; @@ -132,17 +133,9 @@ const ProjectCodeSnippet = props => {
- + + {_snippet} +
You can also setup OpenReplay using Google Tag Manager (GTM).
From cf87b226ab88e7326da5b8413798411b212e02d2 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 18:56:55 +0100 Subject: [PATCH 064/101] feat(ui) - custom metrics - wip --- .../CustomMetricPieChart/CustomMetricPieChart.tsx | 2 +- .../CustomMetricTable/CustomMetricTable.tsx | 2 +- .../components/shared/Filters/FilterValue/FilterValue.tsx | 1 + frontend/app/types/customMetric.js | 6 +++--- frontend/app/types/filter/filterType.ts | 6 +++++- frontend/app/types/filter/newFilter.js | 5 ++++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx index cdb561dd7..b33a13f62 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -35,7 +35,7 @@ function CustomMetricPieChart(props: Props) { } return (
- + - +
) case FilterType.NUMBER: + case FilterType.NUMBER_MULTIPLE: return ( Date: Fri, 4 Mar 2022 17:12:07 +0100 Subject: [PATCH 066/101] feat(DB): DB structure changes --- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 90 ++++++++++++++++++- .../db/init_dbs/postgresql/init_schema.sql | 52 +++++++++-- .../db/init_dbs/postgresql/1.5.99/1.5.99.sql | 89 +++++++++++++++++- .../db/init_dbs/postgresql/1.5.X/1.5.X.sql | 78 ---------------- .../db/init_dbs/postgresql/init_schema.sql | 33 +++++-- 5 files changed, 248 insertions(+), 94 deletions(-) delete mode 100644 scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index 88e1aab74..936e56968 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -51,4 +51,92 @@ ALTER TABLE metrics ADD COLUMN IF NOT EXISTS metric_format text; -COMMIT; \ No newline at end of file + +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; + END; +$$ +LANGUAGE plpgsql; + + +ALTER TABLE events.graphql + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL, + ADD COLUMN IF NOT EXISTS duration integer NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL; + +COMMIT; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + + + +-- Split requests-URL: Takes too long to use +-- UPDATE events_common.requests +-- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, +-- host=CASE +-- WHEN POSITION('://' IN url) = 0 THEN NULL +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( +-- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, +-- base_path=CASE +-- WHEN POSITION('://' IN url) = 0 THEN +-- CASE +-- WHEN POSITION('?' IN url) > 0 THEN +-- SUBSTRING(url, 1, POSITION('?' IN url) - 1) +-- ELSE url END +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- CASE +-- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, +-- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + +-- 1) END +-- END, +-- query_string=CASE +-- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) +-- END; + diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 1f0f4d6f1..92e25c9e1 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -994,7 +994,11 @@ $$ CREATE INDEX IF NOT EXISTS errors_error_id_timestamp_session_id_idx ON events.errors (error_id, timestamp, session_id); CREATE INDEX IF NOT EXISTS errors_error_id_idx ON events.errors (error_id); - + IF NOT EXISTS(SELECT * + FROM pg_type typ + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; CREATE TABLE IF NOT EXISTS events.graphql ( session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, @@ -1006,6 +1010,12 @@ $$ CREATE INDEX IF NOT EXISTS graphql_name_idx ON events.graphql (name); CREATE INDEX IF NOT EXISTS graphql_name_gin_idx ON events.graphql USING GIN (name gin_trgm_ops); CREATE INDEX IF NOT EXISTS graphql_timestamp_idx ON events.graphql (timestamp); + CREATE INDEX IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; + CREATE INDEX IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; CREATE TABLE IF NOT EXISTS events.state_actions ( @@ -1147,15 +1157,27 @@ $$ CREATE INDEX IF NOT EXISTS issues_issue_id_timestamp_idx ON events_common.issues (issue_id, timestamp); CREATE INDEX IF NOT EXISTS issues_timestamp_idx ON events_common.issues (timestamp); - + IF NOT EXISTS(SELECT * + FROM pg_type typ + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; CREATE TABLE IF NOT EXISTS events_common.requests ( - session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, - timestamp bigint NOT NULL, - seq_index integer NOT NULL, - url text NOT NULL, - duration integer NOT NULL, - success boolean NOT NULL, + session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, + timestamp bigint NOT NULL, + seq_index integer NOT NULL, + url text NOT NULL, + duration integer NOT NULL, + success boolean NOT NULL, + request_body text NULL, + response_body text NULL, + status_code smallint NULL, + method http_method NULL, + schema text NULL, + host text NULL, + base_path text NULL, + query_string text NULL, PRIMARY KEY (session_id, timestamp, seq_index) ); CREATE INDEX IF NOT EXISTS requests_url_idx ON events_common.requests (url); @@ -1172,6 +1194,20 @@ $$ ELSE 0 END)) gin_trgm_ops); CREATE INDEX IF NOT EXISTS requests_timestamp_session_id_failed_idx ON events_common.requests (timestamp, session_id) WHERE success = FALSE; + CREATE INDEX IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + + CREATE INDEX IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; + CREATE INDEX IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + + END IF; END; $$ diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql index b471511f4..e661e526a 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql @@ -50,4 +50,91 @@ ALTER TABLE metrics ADD COLUMN IF NOT EXISTS metric_format text; -COMMIT; \ No newline at end of file +DO +$$ + BEGIN + IF NOT EXISTS(SELECT * + FROM pg_type typ + INNER JOIN pg_namespace nsp + ON nsp.oid = typ.typnamespace + WHERE typ.typname = 'http_method') THEN + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); + END IF; + END; +$$ +LANGUAGE plpgsql; + + +ALTER TABLE events.graphql + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL, + ADD COLUMN IF NOT EXISTS duration integer NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS request_body text NULL, + ADD COLUMN IF NOT EXISTS response_body text NULL, + ADD COLUMN IF NOT EXISTS status_code smallint NULL, + ADD COLUMN IF NOT EXISTS method http_method NULL; + +ALTER TABLE events_common.requests + ADD COLUMN IF NOT EXISTS schema text NULL, + ADD COLUMN IF NOT EXISTS host text NULL, + ADD COLUMN IF NOT EXISTS base_path text NULL, + ADD COLUMN IF NOT EXISTS query_string text NULL; + +COMMIT; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; + +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; +CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + + + +-- Split requests-URL: Takes too long to use +-- UPDATE events_common.requests +-- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, +-- host=CASE +-- WHEN POSITION('://' IN url) = 0 THEN NULL +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( +-- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, +-- base_path=CASE +-- WHEN POSITION('://' IN url) = 0 THEN +-- CASE +-- WHEN POSITION('?' IN url) > 0 THEN +-- SUBSTRING(url, 1, POSITION('?' IN url) - 1) +-- ELSE url END +-- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- CASE +-- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN +-- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, +-- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) +-- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), +-- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + +-- 1) END +-- END, +-- query_string=CASE +-- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) +-- END; + diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql b/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql deleted file mode 100644 index 2b71f3ac4..000000000 --- a/scripts/helm/db/init_dbs/postgresql/1.5.X/1.5.X.sql +++ /dev/null @@ -1,78 +0,0 @@ --- !!!!NOT IN CREATE DB YET - -BEGIN; -CREATE OR REPLACE FUNCTION openreplay_version() - RETURNS text AS -$$ -SELECT 'v1.5.X' -$$ LANGUAGE sql IMMUTABLE; - -CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); - -ALTER TABLE events_common.requests - ADD COLUMN IF NOT EXISTS schema text NULL, - ADD COLUMN IF NOT EXISTS host text NULL, - ADD COLUMN IF NOT EXISTS base_path text NULL, - ADD COLUMN IF NOT EXISTS query_string text NULL, - ADD COLUMN IF NOT EXISTS request_body text NULL, - ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code smallint NULL, - ADD COLUMN IF NOT EXISTS method http_method NULL; - --- Split requests-URL: Takes too long to use --- UPDATE events_common.requests --- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, --- host=CASE --- WHEN POSITION('://' IN url) = 0 THEN NULL --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( --- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, --- base_path=CASE --- WHEN POSITION('://' IN url) = 0 THEN --- CASE --- WHEN POSITION('?' IN url) > 0 THEN --- SUBSTRING(url, 1, POSITION('?' IN url) - 1) --- ELSE url END --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- CASE --- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, --- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + --- 1) END --- END, --- query_string=CASE --- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) --- END; - - -ALTER TABLE events.graphql - ADD COLUMN IF NOT EXISTS request_body text NULL, - ADD COLUMN IF NOT EXISTS response_body text NULL, - ADD COLUMN IF NOT EXISTS status_code smallint NULL, - ADD COLUMN IF NOT EXISTS method http_method NULL, - ADD COLUMN IF NOT EXISTS duration integer NULL; - -COMMIT; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_idx ON events.graphql (request_body) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_request_body_nn_gin_idx ON events.graphql USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.graphql (response_body) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; \ No newline at end of file diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 232596696..57fae7794 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -631,14 +631,23 @@ $$ CREATE INDEX issues_timestamp_idx ON events_common.issues (timestamp); CREATE INDEX issues_project_id_issue_id_idx ON public.issues (project_id, issue_id); + CREATE TYPE http_method AS ENUM ('GET','HEAD','POST','PUT','DELETE','CONNECT','OPTIONS','TRACE','PATCH'); CREATE TABLE events_common.requests ( - session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, - timestamp bigint NOT NULL, - seq_index integer NOT NULL, - url text NOT NULL, - duration integer NOT NULL, - success boolean NOT NULL, + session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE, + timestamp bigint NOT NULL, + seq_index integer NOT NULL, + url text NOT NULL, + duration integer NOT NULL, + success boolean NOT NULL, + request_body text NULL, + response_body text NULL, + status_code smallint NULL, + method http_method NULL, + schema text NULL, + host text NULL, + base_path text NULL, + query_string text NULL, PRIMARY KEY (session_id, timestamp, seq_index) ); CREATE INDEX requests_url_idx ON events_common.requests (url); @@ -653,6 +662,18 @@ $$ ELSE 0 END)) gin_trgm_ops); CREATE INDEX requests_timestamp_session_id_failed_idx ON events_common.requests (timestamp, session_id) WHERE success = FALSE; + CREATE INDEX requests_request_body_nn_idx ON events_common.requests (request_body) WHERE request_body IS NOT NULL; + CREATE INDEX requests_request_body_nn_gin_idx ON events_common.requests USING GIN (request_body gin_trgm_ops) WHERE request_body IS NOT NULL; + CREATE INDEX requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; + CREATE INDEX requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; + CREATE INDEX requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; + CREATE INDEX requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; + CREATE INDEX requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; + CREATE INDEX requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; + CREATE INDEX requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; + CREATE INDEX requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; + CREATE INDEX requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; + -- --- events.sql --- CREATE SCHEMA IF NOT EXISTS events; From 94b777f21a16e9d8cb97b0a929057c6ef4c9fec4 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 17:20:05 +0100 Subject: [PATCH 067/101] feat(DB): DB changed version number --- .../init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} | 2 +- ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql | 2 +- .../init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} | 2 +- scripts/helm/db/init_dbs/postgresql/init_schema.sql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename ee/scripts/helm/db/init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} (99%) rename scripts/helm/db/init_dbs/postgresql/{1.5.99/1.5.99.sql => 1.5.3/1.5.3.sql} (99%) diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql similarity index 99% rename from ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql rename to ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql index 936e56968..399a2199f 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql @@ -2,7 +2,7 @@ BEGIN; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.X-ee' +SELECT 'v1.5.3-ee' $$ LANGUAGE sql IMMUTABLE; UPDATE metrics diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 92e25c9e1..6a81a107d 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -7,7 +7,7 @@ CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.2-ee' +SELECT 'v1.5.3-ee' $$ LANGUAGE sql IMMUTABLE; diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql b/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql similarity index 99% rename from scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql rename to scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql index e661e526a..0e25a7396 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.99/1.5.99.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql @@ -2,7 +2,7 @@ BEGIN; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.X' +SELECT 'v1.5.3' $$ LANGUAGE sql IMMUTABLE; UPDATE metrics diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 57fae7794..fb2e7bb63 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -6,7 +6,7 @@ CREATE SCHEMA IF NOT EXISTS events; CREATE OR REPLACE FUNCTION openreplay_version() RETURNS text AS $$ -SELECT 'v1.5.2' +SELECT 'v1.5.3' $$ LANGUAGE sql IMMUTABLE; -- --- accounts.sql --- From 48041a3680aae69bba1efc471d78229e80d983f2 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 19:04:18 +0100 Subject: [PATCH 068/101] feat(api): autocomplete for FETCH_URL feat(api): no alerts for table-custom-metrics --- api/chalicelib/core/alerts_processor.py | 26 ------------------------- api/chalicelib/core/custom_metrics.py | 1 + api/routers/core.py | 5 +++-- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/api/chalicelib/core/alerts_processor.py b/api/chalicelib/core/alerts_processor.py index 80973fadd..21249773c 100644 --- a/api/chalicelib/core/alerts_processor.py +++ b/api/chalicelib/core/alerts_processor.py @@ -119,12 +119,6 @@ def Build(a): q = f"""SELECT coalesce(value,0) AS value, coalesce(value,0) {a["query"]["operator"]} {a["query"]["right"]} AS valid""" - # if len(colDef.group) > 0 { - # subQ = subQ.Column(colDef.group + " AS group_value") - # subQ = subQ.GroupBy(colDef.group) - # q = q.Column("group_value") - # } - if a["detectionMethod"] == schemas.AlertDetectionMethod.threshold: if a["seriesId"] is not None: q += f""" FROM ({subQ}) AS stat""" @@ -134,16 +128,6 @@ def Build(a): params = {**params, **full_args, "startDate": TimeUTC.now() - a["options"]["currentPeriod"] * 60 * 1000} else: if a["options"]["change"] == schemas.AlertDetectionChangeType.change: - # if len(colDef.group) > 0: - # subq1 := subQ.Where(sq.Expr("timestamp>=$2 ", time.Now().Unix()-a.Options.CurrentPeriod * 60)) - # sub2, args2, _ := subQ.Where( - # sq.And{ - # sq.Expr("timestamp<$3 ", time.Now().Unix()-a.Options.CurrentPeriod * 60), - # sq.Expr("timestamp>=$4 ", time.Now().Unix()-2 * a.Options.CurrentPeriod * 60), - # }).ToSql() - # sub1 := sq.Select("group_value", "(stat1.value-stat2.value) AS value").FromSelect(subq1, "stat1").JoinClause("INNER JOIN ("+sub2+") AS stat2 USING(group_value)", args2...) - # q = q.FromSelect(sub1, "stat") - # else: if a["seriesId"] is not None: sub2 = subQ.replace("%(startDate)s", "%(timestamp_sub2)s").replace("%(endDate)s", "%(startDate)s") sub1 = f"SELECT (({subQ})-({sub2})) AS value" @@ -163,16 +147,6 @@ def Build(a): q += f" FROM ( {sub1} ) AS stat" else: - # if len(colDef.group) >0 { - # subq1 := subQ.Where(sq.Expr("timestamp>=$2 ", time.Now().Unix()-a.Options.CurrentPeriod * 60)) - # sub2, args2, _ := subQ.Where( - # sq.And{ - # sq.Expr("timestamp<$3 ", time.Now().Unix()-a.Options.CurrentPeriod * 60), - # sq.Expr("timestamp>=$4 ", time.Now().Unix()-a.Options.PreviousPeriod * 60-a.Options.CurrentPeriod * 60), - # }).ToSql() - # sub1 := sq.Select("group_value", "(stat1.value/stat2.value-1)*100 AS value").FromSelect(subq1, "stat1").JoinClause("INNER JOIN ("+sub2+") AS stat2 USING(group_value)", args2...) - # q = q.FromSelect(sub1, "stat") - # } else { if a["seriesId"] is not None: sub2 = subQ.replace("%(startDate)s", "%(timestamp_sub2)s").replace("%(endDate)s", "%(startDate)s") sub1 = f"SELECT (({subQ})/NULLIF(({sub2}),0)-1)*100 AS value" diff --git a/api/chalicelib/core/custom_metrics.py b/api/chalicelib/core/custom_metrics.py index 06a2c328b..6c8e7ddc3 100644 --- a/api/chalicelib/core/custom_metrics.py +++ b/api/chalicelib/core/custom_metrics.py @@ -288,6 +288,7 @@ def get_series_for_alert(project_id, user_id): INNER JOIN metrics USING (metric_id) WHERE metrics.deleted_at ISNULL AND metrics.project_id = %(project_id)s + AND metrics.metric_type = 'timeseries' AND (user_id = %(user_id)s OR is_public) ORDER BY name;""", {"project_id": project_id, "user_id": user_id} diff --git a/api/routers/core.py b/api/routers/core.py index 8aacdb99b..d523176e1 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -101,7 +101,8 @@ def comment_assignment(projectId: int, sessionId: int, issueId: str, data: schem @app.get('/{projectId}/events/search', tags=["events"]) def events_search(projectId: int, q: str, - type: Union[schemas.FilterType, schemas.EventType, schemas.PerformanceEventType] = None, + type: Union[schemas.FilterType, schemas.EventType, + schemas.PerformanceEventType, schemas.FetchFilterType._url] = None, key: str = None, source: str = None, context: schemas.CurrentContext = Depends(OR_context)): if len(q) == 0: @@ -114,7 +115,7 @@ def events_search(projectId: int, q: str, schemas.PerformanceEventType.location_avg_memory_usage ]: type = schemas.EventType.location - elif type in [schemas.PerformanceEventType.fetch_failed]: + elif type in [schemas.PerformanceEventType.fetch_failed, schemas.FetchFilterType._url]: type = schemas.EventType.request else: return {"data": []} From 1d04f7f372b6e573053da3903051673b6aebcf93 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 19:11:55 +0100 Subject: [PATCH 069/101] feat(api): custom_metrics changed VISITED_URL to LOCATION --- api/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/schemas.py b/api/schemas.py index ac50aad71..062900fc2 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -762,7 +762,7 @@ class TableMetricOfType(str, Enum): user_country = FilterType.user_country.value user_id = FilterType.user_id.value issues = FilterType.issue.value - visited_url = "VISITED_URL" + visited_url = EventType.location.value class TimeseriesMetricOfType(str, Enum): From b771a74a8d8b7980f4d7d45733b575f01ed7365e Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 19:25:49 +0100 Subject: [PATCH 070/101] feat(api): fixed autocomplete for Request --- api/routers/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/routers/core.py b/api/routers/core.py index d523176e1..504b94418 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -102,7 +102,7 @@ def comment_assignment(projectId: int, sessionId: int, issueId: str, data: schem @app.get('/{projectId}/events/search', tags=["events"]) def events_search(projectId: int, q: str, type: Union[schemas.FilterType, schemas.EventType, - schemas.PerformanceEventType, schemas.FetchFilterType._url] = None, + schemas.PerformanceEventType, schemas.FetchFilterType] = None, key: str = None, source: str = None, context: schemas.CurrentContext = Depends(OR_context)): if len(q) == 0: From 9e924c458e7a9a98e9777fd624bd11807848b639 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 19:40:02 +0100 Subject: [PATCH 071/101] feat(api): fixed autocomplete for Request --- api/routers/core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/routers/core.py b/api/routers/core.py index 504b94418..d01b8ee94 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -107,7 +107,9 @@ def events_search(projectId: int, q: str, source: str = None, context: schemas.CurrentContext = Depends(OR_context)): if len(q) == 0: return {"data": []} - if isinstance(type, schemas.PerformanceEventType): + if type in [schemas.FetchFilterType._url]: + type = schemas.EventType.request + elif isinstance(type, schemas.PerformanceEventType): if type in [schemas.PerformanceEventType.location_dom_complete, schemas.PerformanceEventType.location_largest_contentful_paint_time, schemas.PerformanceEventType.location_ttfb, @@ -115,7 +117,7 @@ def events_search(projectId: int, q: str, schemas.PerformanceEventType.location_avg_memory_usage ]: type = schemas.EventType.location - elif type in [schemas.PerformanceEventType.fetch_failed, schemas.FetchFilterType._url]: + elif type in [schemas.PerformanceEventType.fetch_failed]: type = schemas.EventType.request else: return {"data": []} From 0232f20e8ba6e21792f062a8a2791ed0388a8422 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 20:13:56 +0100 Subject: [PATCH 072/101] feat(api): changed signup for version_number feat(DB): version_number update feat(DB): removed unused columns --- api/chalicelib/core/signup.py | 5 +- ee/api/chalicelib/core/signup.py | 5 +- .../db/init_dbs/postgresql/1.5.3/1.5.3.sql | 46 +----------------- .../db/init_dbs/postgresql/init_schema.sql | 11 ----- .../db/init_dbs/postgresql/1.5.3/1.5.3.sql | 47 +------------------ .../db/init_dbs/postgresql/init_schema.sql | 10 ---- 6 files changed, 7 insertions(+), 117 deletions(-) diff --git a/api/chalicelib/core/signup.py b/api/chalicelib/core/signup.py index b4f02f0b8..ab23eef68 100644 --- a/api/chalicelib/core/signup.py +++ b/api/chalicelib/core/signup.py @@ -63,13 +63,12 @@ def create_step1(data: schemas.UserSignupSchema): "fullname": fullname, "projectName": project_name, "data": json.dumps({"lastAnnouncementView": TimeUTC.now()}), - "organizationName": company_name, - "versionNumber": config("version_number") + "organizationName": company_name } query = f"""\ WITH t AS ( INSERT INTO public.tenants (name, version_number, edition) - VALUES (%(organizationName)s, %(versionNumber)s, 'fos') + VALUES (%(organizationName)s, (SELECT openreplay_version()), 'fos') RETURNING api_key ), u AS ( diff --git a/ee/api/chalicelib/core/signup.py b/ee/api/chalicelib/core/signup.py index aa4ba2af9..4014f5e92 100644 --- a/ee/api/chalicelib/core/signup.py +++ b/ee/api/chalicelib/core/signup.py @@ -1,7 +1,5 @@ import json -from decouple import config - import schemas from chalicelib.core import users, telemetry, tenants from chalicelib.utils import captcha @@ -63,12 +61,11 @@ def create_step1(data: schemas.UserSignupSchema): params = {"email": email, "password": password, "fullname": fullname, "companyName": company_name, "projectName": project_name, - "versionNumber": config("version_number"), "data": json.dumps({"lastAnnouncementView": TimeUTC.now()})} query = """\ WITH t AS ( INSERT INTO public.tenants (name, version_number, edition) - VALUES (%(companyName)s, %(versionNumber)s, 'ee') + VALUES (%(companyName)s, (SELECT openreplay_version()), 'ee') RETURNING tenant_id, api_key ), r AS ( diff --git a/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql b/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql index 399a2199f..1e08dfeae 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql @@ -80,11 +80,8 @@ ALTER TABLE events_common.requests ADD COLUMN IF NOT EXISTS status_code smallint NULL, ADD COLUMN IF NOT EXISTS method http_method NULL; -ALTER TABLE events_common.requests - ADD COLUMN IF NOT EXISTS schema text NULL, - ADD COLUMN IF NOT EXISTS host text NULL, - ADD COLUMN IF NOT EXISTS base_path text NULL, - ADD COLUMN IF NOT EXISTS query_string text NULL; +UPDATE tenants +SET version_number= openreplay_version(); COMMIT; @@ -101,42 +98,3 @@ CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON even CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; - - - --- Split requests-URL: Takes too long to use --- UPDATE events_common.requests --- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, --- host=CASE --- WHEN POSITION('://' IN url) = 0 THEN NULL --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( --- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, --- base_path=CASE --- WHEN POSITION('://' IN url) = 0 THEN --- CASE --- WHEN POSITION('?' IN url) > 0 THEN --- SUBSTRING(url, 1, POSITION('?' IN url) - 1) --- ELSE url END --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- CASE --- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, --- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + --- 1) END --- END, --- query_string=CASE --- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) --- END; - diff --git a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql index 6a81a107d..ae724f60b 100644 --- a/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/ee/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -1174,10 +1174,6 @@ $$ response_body text NULL, status_code smallint NULL, method http_method NULL, - schema text NULL, - host text NULL, - base_path text NULL, - query_string text NULL, PRIMARY KEY (session_id, timestamp, seq_index) ); CREATE INDEX IF NOT EXISTS requests_url_idx ON events_common.requests (url); @@ -1200,13 +1196,6 @@ $$ CREATE INDEX IF NOT EXISTS requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; CREATE INDEX IF NOT EXISTS requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; - CREATE INDEX IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; - CREATE INDEX IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; - CREATE INDEX IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; - CREATE INDEX IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; - CREATE INDEX IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; - CREATE INDEX IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; - END IF; END; diff --git a/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql b/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql index 0e25a7396..1030ba55d 100644 --- a/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql +++ b/scripts/helm/db/init_dbs/postgresql/1.5.3/1.5.3.sql @@ -78,11 +78,8 @@ ALTER TABLE events_common.requests ADD COLUMN IF NOT EXISTS status_code smallint NULL, ADD COLUMN IF NOT EXISTS method http_method NULL; -ALTER TABLE events_common.requests - ADD COLUMN IF NOT EXISTS schema text NULL, - ADD COLUMN IF NOT EXISTS host text NULL, - ADD COLUMN IF NOT EXISTS base_path text NULL, - ADD COLUMN IF NOT EXISTS query_string text NULL; +UPDATE tenants +SET version_number= openreplay_version(); COMMIT; @@ -98,43 +95,3 @@ CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_idx ON events.g CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_response_body_nn_gin_idx ON events.graphql USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_status_code_nn_idx ON events.graphql (status_code) WHERE status_code IS NOT NULL; CREATE INDEX CONCURRENTLY IF NOT EXISTS graphql_duration_nn_gt0_idx ON events.graphql (duration) WHERE duration IS NOT NULL AND duration > 0; - -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; -CREATE INDEX CONCURRENTLY IF NOT EXISTS requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; - - - --- Split requests-URL: Takes too long to use --- UPDATE events_common.requests --- SET schema=CASE WHEN POSITION('://' IN url) > 0 THEN SUBSTRING(url, 1, POSITION('://' IN url) - 1) END, --- host=CASE --- WHEN POSITION('://' IN url) = 0 THEN NULL --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN SUBSTRING( --- SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), 1, --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1) END, --- base_path=CASE --- WHEN POSITION('://' IN url) = 0 THEN --- CASE --- WHEN POSITION('?' IN url) > 0 THEN --- SUBSTRING(url, 1, POSITION('?' IN url) - 1) --- ELSE url END --- WHEN POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- CASE --- WHEN POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) > 0 THEN --- SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + 1, --- POSITION('?' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) - 1) --- ELSE SUBSTRING(SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1), --- POSITION('/' IN SUBSTRING(SUBSTRING(url, POSITION('://' IN url) + 3), 1)) + --- 1) END --- END, --- query_string=CASE --- WHEN POSITION('?' IN url) > 0 THEN SUBSTRING(url, POSITION('?' IN url) + 1) --- END; - diff --git a/scripts/helm/db/init_dbs/postgresql/init_schema.sql b/scripts/helm/db/init_dbs/postgresql/init_schema.sql index fb2e7bb63..c7d1f2110 100644 --- a/scripts/helm/db/init_dbs/postgresql/init_schema.sql +++ b/scripts/helm/db/init_dbs/postgresql/init_schema.sql @@ -644,10 +644,6 @@ $$ response_body text NULL, status_code smallint NULL, method http_method NULL, - schema text NULL, - host text NULL, - base_path text NULL, - query_string text NULL, PRIMARY KEY (session_id, timestamp, seq_index) ); CREATE INDEX requests_url_idx ON events_common.requests (url); @@ -667,12 +663,6 @@ $$ CREATE INDEX requests_response_body_nn_idx ON events_common.requests (response_body) WHERE response_body IS NOT NULL; CREATE INDEX requests_response_body_nn_gin_idx ON events_common.requests USING GIN (response_body gin_trgm_ops) WHERE response_body IS NOT NULL; CREATE INDEX requests_status_code_nn_idx ON events_common.requests (status_code) WHERE status_code IS NOT NULL; - CREATE INDEX requests_host_nn_idx ON events_common.requests (host) WHERE host IS NOT NULL; - CREATE INDEX requests_host_nn_gin_idx ON events_common.requests USING GIN (host gin_trgm_ops) WHERE host IS NOT NULL; - CREATE INDEX requests_base_path_nn_idx ON events_common.requests (base_path) WHERE base_path IS NOT NULL; - CREATE INDEX requests_base_path_nn_gin_idx ON events_common.requests USING GIN (base_path gin_trgm_ops) WHERE base_path IS NOT NULL; - CREATE INDEX requests_query_string_nn_idx ON events_common.requests (query_string) WHERE query_string IS NOT NULL; - CREATE INDEX requests_query_string_nn_gin_idx ON events_common.requests USING GIN (query_string gin_trgm_ops) WHERE query_string IS NOT NULL; -- --- events.sql --- CREATE SCHEMA IF NOT EXISTS events; From 755d947775089988b6d195de72b5b71ac6198c96 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Mar 2022 20:22:22 +0100 Subject: [PATCH 073/101] feat(ui) - network request --- .../Dashboard/SideMenu/SideMenuSection.js | 3 -- .../CustomMetricPieChart.tsx | 6 ++- .../CustomMetricTable/CustomMetricTable.tsx | 34 ++++++++------- .../CustomMetricWidgetPreview.tsx | 2 +- .../CustomMetricForm/CustomMetricForm.tsx | 2 +- .../FilterAutoCompleteLocal.tsx | 8 +++- .../Filters/FilterValue/FilterValue.tsx | 38 +++++++++++++--- .../FilterValueDropdown.css | 1 + .../FilterValueDropdown.tsx | 43 +++++++++++-------- frontend/app/constants/filterOptions.js | 22 ++++++++++ frontend/app/duck/search.js | 5 ++- frontend/app/types/filter/newFilter.js | 4 +- 12 files changed, 113 insertions(+), 55 deletions(-) diff --git a/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js b/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js index 77d72f013..e26e24da2 100644 --- a/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js +++ b/frontend/app/components/Dashboard/SideMenu/SideMenuSection.js @@ -33,9 +33,6 @@ function SideMenuSection({ title, items, onItemClick, setShowAlerts, siteId }) {
-
- Be proactive by monitoring the metrics you care about the most. -
); diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx index b33a13f62..219f4cc98 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart/CustomMetricPieChart.tsx @@ -17,7 +17,7 @@ function CustomMetricPieChart(props: Props) { const { metric, data = { values: [] }, onClick = () => null } = props; const onClickHandler = (event) => { - if (event) { + if (event && !event.payload.group) { const filters = Array(); let filter = { ...filtersMap[metric.metricOf] } filter.value = [event.payload.name] @@ -91,6 +91,8 @@ function CustomMetricPieChart(props: Props) { let x = cx + radius * Math.cos(-midAngle * RADIAN); let y = cy + radius * Math.sin(-midAngle * RADIAN); const percentage = (value / data.values.reduce((a, b) => a + b.sessionCount, 0)) * 100; + let name = data.values[index].name || 'Unidentified'; + name = name.length > 20 ? name.substring(0, 20) + '...' : name; if (percentage<3){ return null; } @@ -105,7 +107,7 @@ function CustomMetricPieChart(props: Props) { dominantBaseline="central" fill='#666' > - {data.values[index].name} - ({value}) + {name || 'Unidentified'} {value} ); }} diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx index 2b85e8839..6a9481077 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable/CustomMetricTable.tsx @@ -1,24 +1,26 @@ import React from 'react' import { Table } from '../../common'; import { List } from 'immutable'; -import { FilterKey } from 'Types/filter/filterType'; import { filtersMap } from 'Types/filter/newFilter'; import { NoContent } from 'UI'; +import { tableColumnName } from 'App/constants/filterOptions'; -const cols = [ - { - key: 'name', - title: 'Resource', - toText: name => name || 'Unidentified', - width: '70%', - }, - { - key: 'sessionCount', - title: 'Sessions', - toText: sessions => sessions, - width: '30%', - }, -]; +const getColumns = (metric) => { + return [ + { + key: 'name', + title: tableColumnName[metric.metricOf], + toText: name => name || 'Unidentified', + width: '70%', + }, + { + key: 'sessionCount', + title: 'Sessions', + toText: sessions => sessions, + width: '30%', + }, + ] +} interface Props { metric?: any, @@ -49,7 +51,7 @@ function CustomMetriTable(props: Props) {
{isTimeSeries && ( <> - Visualization + Visualization removeSeries(index)} canDelete={metric.series.size > 1} emptyMessage={isTable ? - 'Filter table data by user environment and metadata attributes. Use add step button below to filter.' : + 'Filter data using any event or attribute. Use Add Step button below to do so.' : 'Add user event or filter to define the series by clicking Add Step.' } /> diff --git a/frontend/app/components/shared/Filters/FilterAutoCompleteLocal/FilterAutoCompleteLocal.tsx b/frontend/app/components/shared/Filters/FilterAutoCompleteLocal/FilterAutoCompleteLocal.tsx index 96156e6db..542dfce1c 100644 --- a/frontend/app/components/shared/Filters/FilterAutoCompleteLocal/FilterAutoCompleteLocal.tsx +++ b/frontend/app/components/shared/Filters/FilterAutoCompleteLocal/FilterAutoCompleteLocal.tsx @@ -13,6 +13,8 @@ interface Props { onSelect: (e, item) => void; value: any; icon?: string; + type?: string; + isMultilple?: boolean; } function FilterAutoCompleteLocal(props: Props) { @@ -24,6 +26,8 @@ function FilterAutoCompleteLocal(props: Props) { onAddValue = () => null, value = '', icon = null, + type = "text", + isMultilple = true, } = props; const [showModal, setShowModal] = useState(true) const [query, setQuery] = useState(value); @@ -59,7 +63,7 @@ function FilterAutoCompleteLocal(props: Props) { onFocus={ () => setShowModal(true)} value={ query } autoFocus={ true } - type="text" + type={ type } placeholder={ placeholder } onKeyDown={handleKeyDown} /> @@ -71,7 +75,7 @@ function FilterAutoCompleteLocal(props: Props) { - { !showOrButton &&
or
} + { !showOrButton && isMultilple &&
or
} ); } diff --git a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx index b3bc02305..ba7b8650e 100644 --- a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx +++ b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx @@ -63,7 +63,7 @@ function FilterValue(props: Props) { } const renderValueFiled = (value, valueIndex) => { - const showOrButton = valueIndex === lastIndex; + const showOrButton = valueIndex === lastIndex && filter.type !== FilterType.NUMBER; switch(filter.type) { case FilterType.STRING: return ( @@ -113,17 +113,41 @@ function FilterValue(props: Props) { maxDuration={ durationValues.maxDuration } /> ) - case FilterType.NUMBER: case FilterType.NUMBER_MULTIPLE: return ( - onChange(e, { value: e.target.value }, valueIndex)} + showCloseButton={showCloseButton} + showOrButton={showOrButton} + onAddValue={onAddValue} + onRemoveValue={() => onRemoveValue(valueIndex)} + onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)} + icon={filter.icon} + type="number" /> ) + case FilterType.NUMBER: + return ( + onRemoveValue(valueIndex)} + onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)} + icon={filter.icon} + type="number" + isMultilple={false} + /> + // onChange(e, { value: e.target.value }, valueIndex)} + // /> + ) case FilterType.MULTIPLE: return ( void; onAddValue?: () => void; + isMultilple?: boolean; } function FilterValueDropdown(props: Props) { - const { filter, multiple = false, search = false, options, onChange, value, className = '', showCloseButton = true, showOrButton = true } = props; + const { filter, multiple = false, isMultilple = true, search = false, options, onChange, value, className = '', showCloseButton = true, showOrButton = true } = props; // const options = [] return ( -
- } - /> -
- { showCloseButton &&
} - { showOrButton &&
or
} +
+
+ } + /> +
+ { showCloseButton &&
} + { showOrButton &&
or
} +
+ + { !showOrButton && isMultilple &&
or
}
); } diff --git a/frontend/app/constants/filterOptions.js b/frontend/app/constants/filterOptions.js index 6fa6d0cbf..560ad7912 100644 --- a/frontend/app/constants/filterOptions.js +++ b/frontend/app/constants/filterOptions.js @@ -61,6 +61,15 @@ export const metricTypes = [ { text: 'Table', value: 'table' }, ]; +export const tableColumnName = { + [FilterKey.USERID]: 'User', + [FilterKey.ISSUE]: 'Issue', + [FilterKey.USER_BROWSER]: 'Browser', + [FilterKey.USER_DEVICE]: 'Device', + [FilterKey.USER_COUNTRY]: 'Country', + [FilterKey.LOCATION]: 'URL', +} + export const metricOf = [ { text: 'Session Count', value: 'sessionCount', type: 'timeseries' }, { text: 'Users', value: FilterKey.USERID, type: 'table' }, @@ -71,6 +80,18 @@ export const metricOf = [ { text: 'URL', value: FilterKey.LOCATION, type: 'table' }, ] +export const methodOptions = [ + { text: 'GET', value: 'GET' }, + { text: 'POST', value: 'POST' }, + { text: 'PUT', value: 'PUT' }, + { text: 'DELETE', value: 'DELETE' }, + { text: 'PATCH', value: 'PATCH' }, + { text: 'HEAD', value: 'HEAD' }, + { text: 'OPTIONS', value: 'OPTIONS' }, + { text: 'TRACE', value: 'TRACE' }, + { text: 'CONNECT', value: 'CONNECT' }, +] + export const issueOptions = [ { text: 'Click Rage', value: 'click_rage' }, { text: 'Dead Click', value: 'dead_click' }, @@ -97,4 +118,5 @@ export default { metricTypes, metricOf, issueOptions, + methodOptions, } \ No newline at end of file diff --git a/frontend/app/duck/search.js b/frontend/app/duck/search.js index 00799e5d7..4bd05ad2f 100644 --- a/frontend/app/duck/search.js +++ b/frontend/app/duck/search.js @@ -107,14 +107,15 @@ export const checkFilterValue = (value) => { return Array.isArray(value) ? (value.length === 0 ? [""] : value) : [value]; } -export const filterMap = ({category, value, key, operator, sourceOperator, source, custom, isEvent }) => ({ +export const filterMap = ({category, value, key, operator, sourceOperator, source, custom, isEvent, subFilters }) => ({ value: checkValues(key, value), custom, type: category === FilterCategory.METADATA ? FilterKey.METADATA : key, operator, source: category === FilterCategory.METADATA ? key : source, sourceOperator, - isEvent + isEvent, + filters: subFilters ? subFilters.map(filterMap) : [], }); const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => { diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 6ad2c4c22..7ce792b78 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -33,10 +33,10 @@ export const filtersMap = { [FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'User AnonymousId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' }, // PERFORMANCE - [FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.SUB_FILTERS, category: FilterCategory.PERFORMANCE, label: 'Fetch Request', subFilters: [ + [FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.SUB_FILTERS, category: FilterCategory.PERFORMANCE, operator: 'is', label: 'Network Request', subFilters: [ { key: FilterKey.FETCH_URL, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with URL', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, { key: FilterKey.FETCH_STATUS_CODE, type: FilterType.NUMBER_MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with status code', operator: '=', operatorOptions: filterOptions.customOperators, icon: 'filters/fetch' }, - { key: FilterKey.FETCH_METHOD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'with method', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, + { key: FilterKey.FETCH_METHOD, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.PERFORMANCE, label: 'with method', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch', options: filterOptions.methodOptions }, { key: FilterKey.FETCH_DURATION, type: FilterType.NUMBER, category: FilterCategory.PERFORMANCE, label: 'with duration', operator: '=', operatorOptions: filterOptions.customOperators, icon: 'filters/fetch' }, { key: FilterKey.FETCH_REQUEST_BODY, type: FilterType.STRING, category: FilterCategory.PERFORMANCE, label: 'with request body', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, { key: FilterKey.FETCH_RESPONSE_BODY, type: FilterType.STRING, category: FilterCategory.PERFORMANCE, label: 'with response body', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch' }, From ffdd053c7b94c14d8b9732e3a81a0b91c690e921 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 4 Mar 2022 19:45:02 +0000 Subject: [PATCH 074/101] update version number --- frontend/env.js | 2 +- scripts/helmcharts/init.sh | 2 +- scripts/helmcharts/openreplay/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/alerts/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/assets/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/chalice/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/db/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/ender/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/http/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/integrations/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/sink/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/storage/Chart.yaml | 2 +- scripts/helmcharts/openreplay/charts/utilities/Chart.yaml | 2 +- scripts/helmcharts/vars.yaml | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontend/env.js b/frontend/env.js index 7d3ab7e6e..591332eca 100644 --- a/frontend/env.js +++ b/frontend/env.js @@ -13,7 +13,7 @@ const oss = { ORIGIN: () => 'window.location.origin', API_EDP: () => 'window.location.origin + "/api"', ASSETS_HOST: () => 'window.location.origin + "/assets"', - VERSION: '1.5.2', + VERSION: '1.5.3', SOURCEMAP: true, MINIO_ENDPOINT: process.env.MINIO_ENDPOINT, MINIO_PORT: process.env.MINIO_PORT, diff --git a/scripts/helmcharts/init.sh b/scripts/helmcharts/init.sh index 2df3b8450..6e4f70613 100644 --- a/scripts/helmcharts/init.sh +++ b/scripts/helmcharts/init.sh @@ -15,7 +15,7 @@ fatal() exit 1 } -version="v1.5.2" +version="v1.5.3" usr=`whoami` # Installing k3s diff --git a/scripts/helmcharts/openreplay/Chart.yaml b/scripts/helmcharts/openreplay/Chart.yaml index e621e543d..f0b5ef469 100644 --- a/scripts/helmcharts/openreplay/Chart.yaml +++ b/scripts/helmcharts/openreplay/Chart.yaml @@ -22,4 +22,4 @@ version: 0.1.0 # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. # Ref: https://github.com/helm/helm/issues/7858#issuecomment-608114589 -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml b/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml index 0bfe8b4bc..b39fb2e99 100644 --- a/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/alerts/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/assets/Chart.yaml b/scripts/helmcharts/openreplay/charts/assets/Chart.yaml index 9b8c32623..b1be7b726 100644 --- a/scripts/helmcharts/openreplay/charts/assets/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/assets/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml b/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml index 1d0441f7e..755fb8648 100644 --- a/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/chalice/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/db/Chart.yaml b/scripts/helmcharts/openreplay/charts/db/Chart.yaml index 0aa5f39e3..796e1ef76 100644 --- a/scripts/helmcharts/openreplay/charts/db/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/db/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/ender/Chart.yaml b/scripts/helmcharts/openreplay/charts/ender/Chart.yaml index 8a7ce610e..571ef34c0 100644 --- a/scripts/helmcharts/openreplay/charts/ender/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/ender/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/http/Chart.yaml b/scripts/helmcharts/openreplay/charts/http/Chart.yaml index 5422d1f3d..166b3e22d 100644 --- a/scripts/helmcharts/openreplay/charts/http/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/http/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml b/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml index e8fc92887..710f7ffe5 100644 --- a/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/integrations/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml b/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml index 2c473b4b4..b0baf2637 100644 --- a/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/nginx-ingress/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/sink/Chart.yaml b/scripts/helmcharts/openreplay/charts/sink/Chart.yaml index 7ece0a5bf..fea7646a4 100644 --- a/scripts/helmcharts/openreplay/charts/sink/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/sink/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/storage/Chart.yaml b/scripts/helmcharts/openreplay/charts/storage/Chart.yaml index 9e1c06d8c..879a077c6 100644 --- a/scripts/helmcharts/openreplay/charts/storage/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/storage/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml b/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml index acc73d941..e432835d0 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/Chart.yaml @@ -21,4 +21,4 @@ version: 0.1.0 # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -AppVersion: "v1.5.2" +AppVersion: "v1.5.3" diff --git a/scripts/helmcharts/vars.yaml b/scripts/helmcharts/vars.yaml index ed0ab4c05..f4b49dd5c 100644 --- a/scripts/helmcharts/vars.yaml +++ b/scripts/helmcharts/vars.yaml @@ -1,4 +1,4 @@ -fromVersion: "v1.5.2" +fromVersion: "v1.5.3" # Databases specific variables postgresql: &postgres # For generating passwords From 2e287cfd77f46083d72ff1e90a3f1ff82f1aa586 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 21:36:36 +0100 Subject: [PATCH 075/101] feat(utilities): EE WS with redis & uWS --- ee/utilities/.gitignore | 2 +- ee/utilities/package-lock.json | 829 +++++++++++----------- ee/utilities/package.json | 3 +- ee/utilities/server.js | 68 +- ee/utilities/servers/websocket-cluster.js | 70 +- ee/utilities/servers/websocket.js | 309 ++++++++ utilities/package-lock.json | 468 ++++++------ utilities/servers/websocket.js | 29 +- 8 files changed, 1091 insertions(+), 687 deletions(-) create mode 100644 ee/utilities/servers/websocket.js diff --git a/ee/utilities/.gitignore b/ee/utilities/.gitignore index 84f619088..fc05191e0 100644 --- a/ee/utilities/.gitignore +++ b/ee/utilities/.gitignore @@ -10,4 +10,4 @@ build.sh servers/peerjs-server.js servers/sourcemaps-handler.js servers/sourcemaps-server.js -servers/websocket.js \ No newline at end of file +#servers/websocket.js \ No newline at end of file diff --git a/ee/utilities/package-lock.json b/ee/utilities/package-lock.json index 0255b7ce1..e7974f3f2 100644 --- a/ee/utilities/package-lock.json +++ b/ee/utilities/package-lock.json @@ -17,7 +17,8 @@ "redis": "^4.0.3", "socket.io": "^4.4.1", "source-map": "^0.7.3", - "ua-parser-js": "^1.0.2" + "ua-parser-js": "^1.0.2", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.6.0" } }, "node_modules/@maxmind/geoip2-node": { @@ -40,9 +41,9 @@ } }, "node_modules/@node-redis/client": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", - "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.4.tgz", + "integrity": "sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g==", "dependencies": { "cluster-key-slot": "1.1.0", "generic-pool": "3.8.2", @@ -70,17 +71,17 @@ } }, "node_modules/@node-redis/search": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", - "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.3.tgz", + "integrity": "sha512-rsrzkGWI84di/uYtEctS/4qLusWt0DESx/psjfB0TFpORDhe7JfC0h8ary+eHulTksumor244bXLRSqQXbFJmw==", "peerDependencies": { "@node-redis/client": "^1.0.0" } }, "node_modules/@node-redis/time-series": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", - "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.2.tgz", + "integrity": "sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA==", "peerDependencies": { "@node-redis/client": "^1.0.0" } @@ -107,27 +108,6 @@ "node": ">=10.0.0" } }, - "node_modules/@socket.io/redis-adapter/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@socket.io/redis-adapter/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -172,9 +152,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.26", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", - "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -187,9 +167,9 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "16.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz", - "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==" + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -219,12 +199,12 @@ } }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -266,14 +246,14 @@ } }, "node_modules/aws-sdk": { - "version": "2.1043.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1043.0.tgz", - "integrity": "sha512-WysMTSLfi8ZCj6QAAitJkxObxOzGLhcu6FxoKHiEnrefvfQtSvwqUq7BbT/pIfijnF9dE/7e9XwjW8Dz/hqF4Q==", + "version": "2.1087.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1087.0.tgz", + "integrity": "sha512-m5EERT29Fwh2cv3SaSdygeAjJBXnjSaXRRERy70bf6PQ7KgmASJouBxY11g5G7LTEPK/yfB0TGshujKh3hEtPA==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", - "jmespath": "0.15.0", + "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", @@ -312,25 +292,38 @@ } }, "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" }, "engines": { "node": ">= 0.8" } }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/buffer": { "version": "4.9.2", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", @@ -342,19 +335,22 @@ } }, "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/camelcase-keys": { @@ -374,17 +370,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -425,11 +410,11 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" @@ -444,9 +429,9 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } @@ -474,11 +459,19 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dependencies": { - "ms": "2.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -521,9 +514,9 @@ } }, "node_modules/engine.io": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", - "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -533,7 +526,7 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", + "engine.io-parser": "~5.0.3", "ws": "~8.2.3" }, "engines": { @@ -551,35 +544,6 @@ "node": ">=10.0.0" } }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/engine.io/node_modules/ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", @@ -622,16 +586,16 @@ } }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -645,13 +609,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -661,6 +625,19 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -686,6 +663,19 @@ "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -731,15 +721,15 @@ } }, "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -762,9 +752,9 @@ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ip6addr": { "version": "0.2.5", @@ -797,9 +787,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", "engines": { "node": ">= 0.6.0" } @@ -924,14 +914,14 @@ } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -1063,11 +1053,14 @@ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" }, "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/querystring": { @@ -1099,12 +1092,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -1113,16 +1106,16 @@ } }, "node_modules/redis": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", - "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.4.tgz", + "integrity": "sha512-KaM1OAj/nGrSeybmmOWSMY0LXTGT6FVWgUZZrd2MYzXKJ+VGtqVaciGQeNMfZiQX+kDM8Ke4uttb54m2rm6V0A==", "dependencies": { "@node-redis/bloom": "1.0.1", - "@node-redis/client": "1.0.3", + "@node-redis/client": "1.0.4", "@node-redis/graph": "1.0.0", "@node-redis/json": "1.0.2", - "@node-redis/search": "1.0.2", - "@node-redis/time-series": "1.0.1" + "@node-redis/search": "1.0.3", + "@node-redis/time-series": "1.0.2" } }, "node_modules/redis-errors": { @@ -1158,9 +1151,23 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -1173,9 +1180,9 @@ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dependencies": { "debug": "2.6.9", "depd": "~1.1.2", @@ -1184,9 +1191,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -1195,20 +1202,33 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" }, "engines": { "node": ">= 0.8.0" @@ -1220,9 +1240,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/socket.io": { "version": "4.4.1", @@ -1258,48 +1278,6 @@ "node": ">=10.0.0" } }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", @@ -1349,9 +1327,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -1436,6 +1414,10 @@ "uuid": "bin/uuid" } }, + "node_modules/uWebSockets.js": { + "version": "20.6.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#a58e810e47a23696410f6073c8c905dc38f75da5" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1476,9 +1458,9 @@ } }, "node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "engines": { "node": ">=8.3.0" }, @@ -1554,6 +1536,14 @@ "engines": { "node": ">=6" } + }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } } }, "dependencies": { @@ -1575,9 +1565,9 @@ "requires": {} }, "@node-redis/client": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.3.tgz", - "integrity": "sha512-IXNgOG99PHGL3NxN3/e8J8MuX+H08I+OMNmheGmZBXngE0IntaCQwwrd7NzmiHA+zH3SKHiJ+6k3P7t7XYknMw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@node-redis/client/-/client-1.0.4.tgz", + "integrity": "sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g==", "requires": { "cluster-key-slot": "1.1.0", "generic-pool": "3.8.2", @@ -1598,15 +1588,15 @@ "requires": {} }, "@node-redis/search": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.2.tgz", - "integrity": "sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@node-redis/search/-/search-1.0.3.tgz", + "integrity": "sha512-rsrzkGWI84di/uYtEctS/4qLusWt0DESx/psjfB0TFpORDhe7JfC0h8ary+eHulTksumor244bXLRSqQXbFJmw==", "requires": {} }, "@node-redis/time-series": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.1.tgz", - "integrity": "sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@node-redis/time-series/-/time-series-1.0.2.tgz", + "integrity": "sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA==", "requires": {} }, "@socket.io/base64-arraybuffer": { @@ -1623,21 +1613,6 @@ "notepack.io": "~2.2.0", "socket.io-adapter": "~2.3.0", "uid2": "0.0.3" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } } }, "@types/body-parser": { @@ -1684,9 +1659,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.26", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", - "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -1699,9 +1674,9 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "@types/node": { - "version": "16.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz", - "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==" + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" }, "@types/qs": { "version": "6.9.7", @@ -1731,12 +1706,12 @@ } }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "ansi-regex": { @@ -1763,14 +1738,14 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "aws-sdk": { - "version": "2.1043.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1043.0.tgz", - "integrity": "sha512-WysMTSLfi8ZCj6QAAitJkxObxOzGLhcu6FxoKHiEnrefvfQtSvwqUq7BbT/pIfijnF9dE/7e9XwjW8Dz/hqF4Q==", + "version": "2.1087.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1087.0.tgz", + "integrity": "sha512-m5EERT29Fwh2cv3SaSdygeAjJBXnjSaXRRERy70bf6PQ7KgmASJouBxY11g5G7LTEPK/yfB0TGshujKh3hEtPA==", "requires": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", - "jmespath": "0.15.0", + "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", @@ -1789,20 +1764,35 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } } }, "buffer": { @@ -1816,14 +1806,14 @@ } }, "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" }, "camelcase-keys": { "version": "7.0.2", @@ -1834,13 +1824,6 @@ "map-obj": "^4.1.0", "quick-lru": "^5.1.1", "type-fest": "^1.2.1" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" - } } }, "cliui": { @@ -1877,11 +1860,11 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" } }, "content-type": { @@ -1890,9 +1873,9 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" }, "cookie-signature": { "version": "1.0.6", @@ -1914,11 +1897,11 @@ } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { - "ms": "2.0.0" + "ms": "2.1.2" } }, "decamelize": { @@ -1952,9 +1935,9 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "engine.io": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", - "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", "requires": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -1964,28 +1947,10 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", + "engine.io-parser": "~5.0.3", "ws": "~8.2.3" }, "dependencies": { - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", @@ -2018,16 +1983,16 @@ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -2041,17 +2006,32 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } } }, "extsprintf": { @@ -2071,6 +2051,21 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } } }, "find-up": { @@ -2103,15 +2098,15 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, "iconv-lite": { @@ -2128,9 +2123,9 @@ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip6addr": { "version": "0.2.5", @@ -2157,9 +2152,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" }, "json-schema": { "version": "0.4.0", @@ -2243,14 +2238,14 @@ "integrity": "sha512-shi1I+fCPQonhTi7qyb6hr7hi87R7YS69FlfJiMFuJ12+grx0JyL56gLNzGTYXPU7EhAPkMLliGeyHer0K+AVA==" }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "notepack.io": { "version": "2.2.0", @@ -2344,9 +2339,9 @@ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" }, "querystring": { "version": "0.2.0", @@ -2364,27 +2359,27 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "redis": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.3.tgz", - "integrity": "sha512-SJMRXvgiQUYN0HaWwWv002J5ZgkhYXOlbLomzcrL3kP42yRNZ8Jx5nvLYhVpgmf10xcDpanFOxxJkphu2eyIFQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.0.4.tgz", + "integrity": "sha512-KaM1OAj/nGrSeybmmOWSMY0LXTGT6FVWgUZZrd2MYzXKJ+VGtqVaciGQeNMfZiQX+kDM8Ke4uttb54m2rm6V0A==", "requires": { "@node-redis/bloom": "1.0.1", - "@node-redis/client": "1.0.3", + "@node-redis/client": "1.0.4", "@node-redis/graph": "1.0.0", "@node-redis/json": "1.0.2", - "@node-redis/search": "1.0.2", - "@node-redis/time-series": "1.0.1" + "@node-redis/search": "1.0.3", + "@node-redis/time-series": "1.0.2" } }, "redis-errors": { @@ -2411,9 +2406,9 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", @@ -2426,9 +2421,9 @@ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -2437,30 +2432,45 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" } }, "set-blocking": { @@ -2469,9 +2479,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "socket.io": { "version": "4.4.1", @@ -2484,21 +2494,6 @@ "engine.io": "~6.1.0", "socket.io-adapter": "~2.3.3", "socket.io-parser": "~4.0.4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } } }, "socket.io-adapter": { @@ -2514,21 +2509,6 @@ "@types/component-emitter": "^1.2.10", "component-emitter": "~1.3.0", "debug": "~4.3.1" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } } }, "source-map": { @@ -2565,9 +2545,9 @@ "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==" }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "type-fest": { "version": "1.4.0", @@ -2617,6 +2597,10 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "uWebSockets.js": { + "version": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#a58e810e47a23696410f6073c8c905dc38f75da5", + "from": "uWebSockets.js@github:uNetworking/uWebSockets.js#v20.6.0" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2648,9 +2632,9 @@ } }, "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "requires": {} }, "xml2js": { @@ -2702,6 +2686,13 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } } } } diff --git a/ee/utilities/package.json b/ee/utilities/package.json index 76b7d2013..87e1d1596 100644 --- a/ee/utilities/package.json +++ b/ee/utilities/package.json @@ -26,6 +26,7 @@ "redis": "^4.0.3", "socket.io": "^4.4.1", "source-map": "^0.7.3", - "ua-parser-js": "^1.0.2" + "ua-parser-js": "^1.0.2", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.6.0" } } diff --git a/ee/utilities/server.js b/ee/utilities/server.js index 1d9a680b8..b6a4cb42d 100644 --- a/ee/utilities/server.js +++ b/ee/utilities/server.js @@ -4,6 +4,7 @@ var express = require('express'); const {ExpressPeerServer} = require('peer'); var socket; if (process.env.cluster === "true") { + console.log("Using Redis"); socket = require("./servers/websocket-cluster"); } else { socket = require("./servers/websocket"); @@ -13,7 +14,7 @@ const HOST = '0.0.0.0'; const PORT = 9000; var app = express(); -var wsapp = express(); + let debug = process.env.debug === "1" || false; const request_logger = (identity) => { return (req, res, next) => { @@ -28,20 +29,16 @@ const request_logger = (identity) => { } }; app.use(request_logger("[app]")); -wsapp.use(request_logger("[wsapp]")); + app.use('/sourcemaps', sourcemapsReaderServer); app.use('/assist', peerRouter); -wsapp.use('/assist', socket.wsRouter); const server = app.listen(PORT, HOST, () => { console.log(`App listening on http://${HOST}:${PORT}`); console.log('Press Ctrl+C to quit.'); }); -const wsserver = wsapp.listen(PORT + 1, HOST, () => { - console.log(`WS App listening on http://${HOST}:${PORT + 1}`); - console.log('Press Ctrl+C to quit.'); -}); + const peerServer = ExpressPeerServer(server, { debug: true, path: '/', @@ -53,6 +50,57 @@ peerServer.on('disconnect', peerDisconnect); peerServer.on('error', peerError); app.use('/', peerServer); app.enable('trust proxy'); -wsapp.enable('trust proxy'); -socket.start(wsserver); -module.exports = {wsserver, server}; + +if (process.env.uws !== "true") { + var wsapp = express(); + wsapp.use(request_logger("[wsapp]")); + wsapp.use('/assist', socket.wsRouter); + + const wsserver = wsapp.listen(PORT + 1, HOST, () => { + console.log(`WS App listening on http://${HOST}:${PORT + 1}`); + console.log('Press Ctrl+C to quit.'); + }); + wsapp.enable('trust proxy'); + socket.start(wsserver); + module.exports = {wsserver, server}; +} else { + console.log("Using uWebSocket"); + const {App} = require("uWebSockets.js"); + const PREFIX = process.env.prefix || '/assist' + + const uapp = new App(); + + const healthFn = (res, req) => { + res.writeStatus('200 OK').end('ok!'); + } + uapp.get(PREFIX, healthFn); + uapp.get(`${PREFIX}/`, healthFn); + + const uWrapper = function (fn) { + return (res, req) => fn(req, res); + } + uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-list`, uWrapper(socket.handlers.socketsList)); + uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-list/:projectKey`, uWrapper(socket.handlers.socketsListByProject)); + + uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-live`, uWrapper(socket.handlers.socketsLive)); + uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-live/:projectKey`, uWrapper(socket.handlers.socketsLiveByProject)); + + + socket.start(uapp); + + uapp.listen(HOST, PORT + 1, (token) => { + if (!token) { + console.warn("port already in use"); + } + console.log(`WS App listening on http://${HOST}:${PORT + 1}`); + console.log('Press Ctrl+C to quit.'); + }); + + + process.on('uncaughtException', err => { + console.log(`Uncaught Exception: ${err.message}`); + debug && console.log(err.stack); + // process.exit(1); + }); + module.exports = {uapp, server}; +} \ No newline at end of file diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index 175c0bab1..f9255905f 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -7,6 +7,7 @@ const {createAdapter} = require("@socket.io/redis-adapter"); const {createClient} = require("redis"); var wsRouter = express.Router(); +const UPDATE_EVENT = "UPDATE_SESSION"; const IDENTITIES = {agent: 'agent', session: 'session'}; const NEW_AGENT = "NEW_AGENT"; const NO_AGENTS = "NO_AGENT"; @@ -34,7 +35,8 @@ const uniqueSessions = function (data) { } return resArr; } -wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, async function (req, res) { + +const socketsList = async function (req, res) { debug && console.log("[WS]looking for all available sessions"); let liveSessions = {}; let rooms = await io.of('/').adapter.allRooms(); @@ -48,8 +50,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, async function (req, res) { res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions})); -}); -wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, async function (req, res) { +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); + +const socketsListByProject = async function (req, res) { debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); let liveSessions = {}; let rooms = await io.of('/').adapter.allRooms(); @@ -63,9 +67,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, async function ( res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); -}); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, socketsListByProject); -wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { +const socketsLive = async function (req, res) { debug && console.log("[WS]looking for all available LIVE sessions"); let liveSessions = {}; let rooms = await io.of('/').adapter.allRooms(); @@ -86,8 +91,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions})); -}); -wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function (req, res) { +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); + +const socketsLiveByProject = async function (req, res) { debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); let liveSessions = {}; let rooms = await io.of('/').adapter.allRooms(); @@ -107,7 +114,8 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function ( res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); -}); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, socketsLiveByProject); const findSessionSocketId = async (io, peerId) => { const connected_sockets = await io.in(peerId).fetchSockets(); @@ -187,14 +195,28 @@ function extractSessionInfo(socket) { module.exports = { wsRouter, start: (server) => { - io = _io(server, { - maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, - cors: { - origin: "*", - methods: ["GET", "POST", "PUT"] - }, - path: '/socket' - }); + if (process.env.uws !== "true") { + io = _io(server, { + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, + cors: { + origin: "*", + methods: ["GET", "POST", "PUT"] + }, + path: '/socket' + }); + } else { + io = new _io.Server({ + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, + cors: { + origin: "*", + methods: ["GET", "POST", "PUT"] + }, + path: '/socket', + // transports: ['websocket'], + // upgrade: false + }); + io.attachApp(server); + } io.on('connection', async (socket) => { debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`); @@ -255,6 +277,16 @@ module.exports = { } }); + socket.on(UPDATE_EVENT, async (...args) => { + debug && console.log(`${socket.id} sent update event.`); + if (socket.identity !== IDENTITIES.session) { + debug && console.log('Ignoring update event.'); + return + } + socket.handshake.query.sessionInfo = {...socket.handshake.query.sessionInfo, ...args[0]}; + socket.to(socket.peerId).emit(UPDATE_EVENT, args[0]); + }); + socket.onAny(async (eventName, ...args) => { socket.lastMessageReceivedAt = Date.now(); if (socket.identity === IDENTITIES.session) { @@ -304,5 +336,11 @@ module.exports = { console.log("> redis connected."); // io.listen(3000); }); + }, + handlers: { + socketsList, + socketsListByProject, + socketsLive, + socketsLiveByProject } }; \ No newline at end of file diff --git a/ee/utilities/servers/websocket.js b/ee/utilities/servers/websocket.js new file mode 100644 index 000000000..2fb5c3499 --- /dev/null +++ b/ee/utilities/servers/websocket.js @@ -0,0 +1,309 @@ +const _io = require('socket.io'); +const express = require('express'); +const uaParser = require('ua-parser-js'); +const geoip2Reader = require('@maxmind/geoip2-node').Reader; +var {extractPeerId} = require('./peerjs-server'); +var wsRouter = express.Router(); +const UPDATE_EVENT = "UPDATE_SESSION"; +const IDENTITIES = {agent: 'agent', session: 'session'}; +const NEW_AGENT = "NEW_AGENT"; +const NO_AGENTS = "NO_AGENT"; +const AGENT_DISCONNECT = "AGENT_DISCONNECTED"; +const AGENTS_CONNECTED = "AGENTS_CONNECTED"; +const NO_SESSIONS = "SESSION_DISCONNECTED"; +const SESSION_ALREADY_CONNECTED = "SESSION_ALREADY_CONNECTED"; +// const wsReconnectionTimeout = process.env.wsReconnectionTimeout | 10 * 1000; + +let io; +let debug = process.env.debug === "1" || false; + +const socketsList = function (req, res) { + debug && console.log("[WS]looking for all available sessions"); + let liveSessions = {}; + for (let peerId of io.sockets.adapter.rooms.keys()) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey !== undefined) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(sessionId); + } + } + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions})); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); + +const socketsListByProject = function (req, res) { + debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); + let liveSessions = {}; + for (let peerId of io.sockets.adapter.rooms.keys()) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey === req.params.projectKey) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(sessionId); + } + } + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, socketsListByProject); + +const socketsLive = async function (req, res) { + debug && console.log("[WS]looking for all available LIVE sessions"); + let liveSessions = {}; + for (let peerId of io.sockets.adapter.rooms.keys()) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey !== undefined) { + let connected_sockets = await io.in(peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(item.handshake.query.sessionInfo); + } + } + } + } + + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions})); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); + +const socketsLiveByProject = async function (req, res) { + debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); + let liveSessions = {}; + for (let peerId of io.sockets.adapter.rooms.keys()) { + let {projectKey, sessionId} = extractPeerId(peerId); + if (projectKey === req.params.projectKey) { + let connected_sockets = await io.in(peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + liveSessions[projectKey] = liveSessions[projectKey] || []; + liveSessions[projectKey].push(item.handshake.query.sessionInfo); + } + } + } + } + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, socketsLiveByProject); + +const findSessionSocketId = async (io, peerId) => { + const connected_sockets = await io.in(peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + return item.id; + } + } + return null; +}; + +async function sessions_agents_count(io, socket) { + let c_sessions = 0, c_agents = 0; + if (io.sockets.adapter.rooms.get(socket.peerId)) { + const connected_sockets = await io.in(socket.peerId).fetchSockets(); + + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.session) { + c_sessions++; + } else { + c_agents++; + } + } + } else { + c_agents = -1; + c_sessions = -1; + } + return {c_sessions, c_agents}; +} + +async function get_all_agents_ids(io, socket) { + let agents = []; + if (io.sockets.adapter.rooms.get(socket.peerId)) { + const connected_sockets = await io.in(socket.peerId).fetchSockets(); + for (let item of connected_sockets) { + if (item.handshake.query.identity === IDENTITIES.agent) { + agents.push(item.id); + } + } + } + return agents; +} + +function extractSessionInfo(socket) { + if (socket.handshake.query.sessionInfo !== undefined) { + debug && console.log("received headers"); + debug && console.log(socket.handshake.headers); + socket.handshake.query.sessionInfo = JSON.parse(socket.handshake.query.sessionInfo); + + let ua = uaParser(socket.handshake.headers['user-agent']); + socket.handshake.query.sessionInfo.userOs = ua.os.name || null; + socket.handshake.query.sessionInfo.userBrowser = ua.browser.name || null; + socket.handshake.query.sessionInfo.userBrowserVersion = ua.browser.version || null; + socket.handshake.query.sessionInfo.userDevice = ua.device.model || null; + socket.handshake.query.sessionInfo.userDeviceType = ua.device.type || 'desktop'; + socket.handshake.query.sessionInfo.userCountry = null; + + const options = { + // you can use options like `cache` or `watchForUpdates` + }; + // console.log("Looking for MMDB file in " + process.env.MAXMINDDB_FILE); + geoip2Reader.open(process.env.MAXMINDDB_FILE, options) + .then(reader => { + debug && console.log("looking for location of "); + debug && console.log(socket.handshake.headers['x-forwarded-for'] || socket.handshake.address); + let country = reader.country(socket.handshake.headers['x-forwarded-for'] || socket.handshake.address); + socket.handshake.query.sessionInfo.userCountry = country.country.isoCode; + }) + .catch(error => { + console.error(error); + }); + } +} + +module.exports = { + wsRouter, + start: (server) => { + if (process.env.uws !== "true") { + io = _io(server, { + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, + cors: { + origin: "*", + methods: ["GET", "POST", "PUT"] + }, + path: '/socket' + }); + } else { + io = new _io.Server({ + maxHttpBufferSize: (parseInt(process.env.maxHttpBufferSize) || 5) * 1e6, + cors: { + origin: "*", + methods: ["GET", "POST", "PUT"] + }, + path: '/socket', + // transports: ['websocket'], + // upgrade: false + }); + io.attachApp(server); + } + io.on('connection', async (socket) => { + debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`); + socket.peerId = socket.handshake.query.peerId; + socket.identity = socket.handshake.query.identity; + const {projectKey, sessionId} = extractPeerId(socket.peerId); + socket.sessionId = sessionId; + socket.projectKey = projectKey; + socket.lastMessageReceivedAt = Date.now(); + let {c_sessions, c_agents} = await sessions_agents_count(io, socket); + if (socket.identity === IDENTITIES.session) { + if (c_sessions > 0) { + debug && console.log(`session already connected, refusing new connexion`); + io.to(socket.id).emit(SESSION_ALREADY_CONNECTED); + return socket.disconnect(); + } + extractSessionInfo(socket); + if (c_agents > 0) { + debug && console.log(`notifying new session about agent-existence`); + let agents_ids = await get_all_agents_ids(io, socket); + io.to(socket.id).emit(AGENTS_CONNECTED, agents_ids); + } + + } else if (c_sessions <= 0) { + debug && console.log(`notifying new agent about no SESSIONS`); + io.to(socket.id).emit(NO_SESSIONS); + } + socket.join(socket.peerId); + if (io.sockets.adapter.rooms.get(socket.peerId)) { + debug && console.log(`${socket.id} joined room:${socket.peerId}, as:${socket.identity}, members:${io.sockets.adapter.rooms.get(socket.peerId).size}`); + } + if (socket.identity === IDENTITIES.agent) { + if (socket.handshake.query.agentInfo !== undefined) { + socket.handshake.query.agentInfo = JSON.parse(socket.handshake.query.agentInfo); + } + socket.to(socket.peerId).emit(NEW_AGENT, socket.id, socket.handshake.query.agentInfo); + } + + socket.on('disconnect', async () => { + debug && console.log(`${socket.id} disconnected from ${socket.peerId}`); + if (socket.identity === IDENTITIES.agent) { + socket.to(socket.peerId).emit(AGENT_DISCONNECT, socket.id); + } + debug && console.log("checking for number of connected agents and sessions"); + let {c_sessions, c_agents} = await sessions_agents_count(io, socket); + if (c_sessions === -1 && c_agents === -1) { + debug && console.log(`room not found: ${socket.peerId}`); + } + if (c_sessions === 0) { + debug && console.log(`notifying everyone in ${socket.peerId} about no SESSIONS`); + socket.to(socket.peerId).emit(NO_SESSIONS); + } + if (c_agents === 0) { + debug && console.log(`notifying everyone in ${socket.peerId} about no AGENTS`); + socket.to(socket.peerId).emit(NO_AGENTS); + } + }); + + socket.on(UPDATE_EVENT, async (...args) => { + debug && console.log(`${socket.id} sent update event.`); + if (socket.identity !== IDENTITIES.session) { + debug && console.log('Ignoring update event.'); + return + } + socket.handshake.query.sessionInfo = {...socket.handshake.query.sessionInfo, ...args[0]}; + socket.to(socket.peerId).emit(UPDATE_EVENT, args[0]); + }); + + socket.onAny(async (eventName, ...args) => { + socket.lastMessageReceivedAt = Date.now(); + if (socket.identity === IDENTITIES.session) { + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to room:${socket.peerId}, members: ${io.sockets.adapter.rooms.get(socket.peerId).size}`); + socket.to(socket.peerId).emit(eventName, args[0]); + } else { + debug && console.log(`received event:${eventName}, from:${socket.identity}, sending message to session of room:${socket.peerId}, members:${io.sockets.adapter.rooms.get(socket.peerId).size}`); + let socketId = await findSessionSocketId(io, socket.peerId); + if (socketId === null) { + debug && console.log(`session not found for:${socket.peerId}`); + io.to(socket.id).emit(NO_SESSIONS); + } else { + debug && console.log("message sent"); + io.to(socketId).emit(eventName, socket.id, args[0]); + } + } + }); + + }); + console.log("WS server started") + setInterval((io) => { + try { + let count = 0; + console.log(` ====== Rooms: ${io.sockets.adapter.rooms.size} ====== `); + const arr = Array.from(io.sockets.adapter.rooms) + const filtered = arr.filter(room => !room[1].has(room[0])) + for (let i of filtered) { + let {projectKey, sessionId} = extractPeerId(i[0]); + if (projectKey !== null && sessionId !== null) { + count++; + } + } + console.log(` ====== Valid Rooms: ${count} ====== `); + if (debug) { + for (let item of filtered) { + console.log(`Room: ${item[0]} connected: ${item[1].size}`) + } + } + } catch (e) { + console.error(e); + } + }, 20000, io); + }, + handlers: { + socketsList, + socketsListByProject, + socketsLive, + socketsLiveByProject + } +}; \ No newline at end of file diff --git a/utilities/package-lock.json b/utilities/package-lock.json index 5ff7612c2..724f7341a 100644 --- a/utilities/package-lock.json +++ b/utilities/package-lock.json @@ -81,9 +81,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.26", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", - "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -96,9 +96,9 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "16.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz", - "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==" + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -128,12 +128,12 @@ } }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -175,14 +175,14 @@ } }, "node_modules/aws-sdk": { - "version": "2.1043.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1043.0.tgz", - "integrity": "sha512-WysMTSLfi8ZCj6QAAitJkxObxOzGLhcu6FxoKHiEnrefvfQtSvwqUq7BbT/pIfijnF9dE/7e9XwjW8Dz/hqF4Q==", + "version": "2.1087.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1087.0.tgz", + "integrity": "sha512-m5EERT29Fwh2cv3SaSdygeAjJBXnjSaXRRERy70bf6PQ7KgmASJouBxY11g5G7LTEPK/yfB0TGshujKh3hEtPA==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", - "jmespath": "0.15.0", + "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", @@ -221,20 +221,20 @@ } }, "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" }, "engines": { "node": ">= 0.8" @@ -251,19 +251,22 @@ } }, "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/camelcase-keys": { @@ -283,17 +286,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -326,11 +318,11 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" @@ -345,9 +337,9 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } @@ -422,9 +414,9 @@ } }, "node_modules/engine.io": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", - "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -434,7 +426,7 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", + "engine.io-parser": "~5.0.3", "ws": "~8.2.3" }, "engines": { @@ -452,14 +444,6 @@ "node": ">=10.0.0" } }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/engine.io/node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -523,16 +507,16 @@ } }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -546,13 +530,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -624,15 +608,15 @@ } }, "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -655,9 +639,9 @@ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ip6addr": { "version": "0.2.5", @@ -690,9 +674,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", "engines": { "node": ">= 0.6.0" } @@ -822,9 +806,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -951,11 +935,14 @@ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" }, "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/querystring": { @@ -987,12 +974,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -1014,9 +1001,23 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -1029,9 +1030,9 @@ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dependencies": { "debug": "2.6.9", "depd": "~1.1.2", @@ -1040,9 +1041,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -1052,19 +1053,19 @@ } }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" }, "engines": { "node": ">= 0.8.0" @@ -1076,9 +1077,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/socket.io": { "version": "4.4.1", @@ -1205,9 +1206,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -1327,9 +1328,9 @@ } }, "node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "engines": { "node": ">=8.3.0" }, @@ -1400,6 +1401,14 @@ "engines": { "node": ">=6" } + }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } } }, "dependencies": { @@ -1463,9 +1472,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.26", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", - "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -1478,9 +1487,9 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "@types/node": { - "version": "16.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz", - "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==" + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" }, "@types/qs": { "version": "6.9.7", @@ -1510,12 +1519,12 @@ } }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "ansi-regex": { @@ -1542,14 +1551,14 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "aws-sdk": { - "version": "2.1043.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1043.0.tgz", - "integrity": "sha512-WysMTSLfi8ZCj6QAAitJkxObxOzGLhcu6FxoKHiEnrefvfQtSvwqUq7BbT/pIfijnF9dE/7e9XwjW8Dz/hqF4Q==", + "version": "2.1087.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1087.0.tgz", + "integrity": "sha512-m5EERT29Fwh2cv3SaSdygeAjJBXnjSaXRRERy70bf6PQ7KgmASJouBxY11g5G7LTEPK/yfB0TGshujKh3hEtPA==", "requires": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", - "jmespath": "0.15.0", + "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", @@ -1568,20 +1577,20 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" } }, "buffer": { @@ -1595,14 +1604,14 @@ } }, "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" }, "camelcase-keys": { "version": "7.0.2", @@ -1613,13 +1622,6 @@ "map-obj": "^4.1.0", "quick-lru": "^5.1.1", "type-fest": "^1.2.1" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" - } } }, "cliui": { @@ -1651,11 +1653,11 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" } }, "content-type": { @@ -1664,9 +1666,9 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" }, "cookie-signature": { "version": "1.0.6", @@ -1726,9 +1728,9 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "engine.io": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", - "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", + "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", "requires": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -1738,15 +1740,10 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", + "engine.io-parser": "~5.0.3", "ws": "~8.2.3" }, "dependencies": { - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -1792,16 +1789,16 @@ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -1815,13 +1812,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -1872,15 +1869,15 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" } }, "iconv-lite": { @@ -1897,9 +1894,9 @@ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip6addr": { "version": "0.2.5", @@ -1926,9 +1923,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" }, "json-schema": { "version": "0.4.0", @@ -2017,9 +2014,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "object-assign": { "version": "4.1.1", @@ -2108,9 +2105,9 @@ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" }, "querystring": { "version": "0.2.0", @@ -2128,12 +2125,12 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -2149,9 +2146,9 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", @@ -2164,9 +2161,9 @@ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -2175,30 +2172,30 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" }, "dependencies": { "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" } }, "set-blocking": { @@ -2207,9 +2204,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "socket.io": { "version": "4.4.1", @@ -2303,9 +2300,9 @@ "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==" }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "type-fest": { "version": "1.4.0", @@ -2381,9 +2378,9 @@ } }, "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "requires": {} }, "xml2js": { @@ -2430,6 +2427,13 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } } } } diff --git a/utilities/servers/websocket.js b/utilities/servers/websocket.js index 0bc48fec6..b772228be 100644 --- a/utilities/servers/websocket.js +++ b/utilities/servers/websocket.js @@ -16,7 +16,8 @@ const SESSION_ALREADY_CONNECTED = "SESSION_ALREADY_CONNECTED"; let io; let debug = process.env.debug === "1" || false; -wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, function (req, res) { + +const socketsList = function (req, res) { debug && console.log("[WS]looking for all available sessions"); let liveSessions = {}; for (let peerId of io.sockets.adapter.rooms.keys()) { @@ -29,8 +30,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, function (req, res) { res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions})); -}); -wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, function (req, res) { +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); + +const socketsListByProject = function (req, res) { debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); let liveSessions = {}; for (let peerId of io.sockets.adapter.rooms.keys()) { @@ -43,9 +46,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, function (req, r res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); -}); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, socketsListByProject); -wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { +const socketsLive = async function (req, res) { debug && console.log("[WS]looking for all available LIVE sessions"); let liveSessions = {}; for (let peerId of io.sockets.adapter.rooms.keys()) { @@ -64,8 +68,10 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, async function (req, res) { res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions})); -}); -wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function (req, res) { +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); + +const socketsLiveByProject = async function (req, res) { debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); let liveSessions = {}; for (let peerId of io.sockets.adapter.rooms.keys()) { @@ -83,7 +89,8 @@ wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, async function ( res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); -}); +} +wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, socketsLiveByProject); const findSessionSocketId = async (io, peerId) => { const connected_sockets = await io.in(peerId).fetchSockets(); @@ -279,5 +286,11 @@ module.exports = { console.error(e); } }, 20000, io); + }, + handlers: { + socketsList, + socketsListByProject, + socketsLive, + socketsLiveByProject } }; \ No newline at end of file From d955cc4bac6695ed053840431475ac056871bd81 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 21:49:08 +0100 Subject: [PATCH 076/101] feat(utilities): EE support different responses --- ee/utilities/servers/websocket-cluster.js | 45 ++++++++++++++++------- ee/utilities/servers/websocket.js | 45 ++++++++++++++++------- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index f9255905f..605879922 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -47,9 +47,14 @@ const socketsList = async function (req, res) { liveSessions[projectKey].push(sessionId); } } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions})); + let result = {"data": liveSessions}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); @@ -64,9 +69,14 @@ const socketsListByProject = async function (req, res) { liveSessions[projectKey].push(sessionId); } } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); + let result = {"data": liveSessions[req.params.projectKey] || []}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, socketsListByProject); @@ -87,10 +97,14 @@ const socketsLive = async function (req, res) { liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); } } - - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions})); + let result = {"data": liveSessions}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); @@ -111,9 +125,14 @@ const socketsLiveByProject = async function (req, res) { liveSessions[projectKey] = uniqueSessions(liveSessions[projectKey]); } } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); + let result = {"data": liveSessions[req.params.projectKey] || []}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, socketsLiveByProject); diff --git a/ee/utilities/servers/websocket.js b/ee/utilities/servers/websocket.js index 2fb5c3499..37331e7a5 100644 --- a/ee/utilities/servers/websocket.js +++ b/ee/utilities/servers/websocket.js @@ -27,9 +27,14 @@ const socketsList = function (req, res) { liveSessions[projectKey].push(sessionId); } } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions})); + let result = {"data": liveSessions}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); @@ -43,9 +48,14 @@ const socketsListByProject = function (req, res) { liveSessions[projectKey].push(sessionId); } } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); + let result = {"data": liveSessions[req.params.projectKey] || []}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify()); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-list/:projectKey`, socketsListByProject); @@ -64,10 +74,14 @@ const socketsLive = async function (req, res) { } } } - - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions})); + let result = {"data": liveSessions}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); @@ -86,9 +100,14 @@ const socketsLiveByProject = async function (req, res) { } } } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({"data": liveSessions[req.params.projectKey] || []})); + let result = {"data": liveSessions[req.params.projectKey] || []}; + if (process.env.uws !== "true") { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(result)); + } else { + res.writeStatus('200 OK').writeHeader('Content-Type', 'application/json').end(JSON.stringify(result)); + } } wsRouter.get(`/${process.env.S3_KEY}/sockets-live/:projectKey`, socketsLiveByProject); From 3863f3e4ee3d94136e35b623f455d683972c69c2 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 22:11:42 +0100 Subject: [PATCH 077/101] feat(utilities): EE support different requests --- ee/utilities/servers/websocket-cluster.js | 6 ++++++ ee/utilities/servers/websocket.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index 605879922..fc26cc2d3 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -59,6 +59,9 @@ const socketsList = async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); const socketsListByProject = async function (req, res) { + if (process.env.uws !== "true") { + req.params = {projectKey: req.getParameter(0)}; + } debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); let liveSessions = {}; let rooms = await io.of('/').adapter.allRooms(); @@ -109,6 +112,9 @@ const socketsLive = async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); const socketsLiveByProject = async function (req, res) { + if (process.env.uws !== "true") { + req.params = {projectKey: req.getParameter(0)}; + } debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); let liveSessions = {}; let rooms = await io.of('/').adapter.allRooms(); diff --git a/ee/utilities/servers/websocket.js b/ee/utilities/servers/websocket.js index 37331e7a5..974a1cf64 100644 --- a/ee/utilities/servers/websocket.js +++ b/ee/utilities/servers/websocket.js @@ -39,6 +39,9 @@ const socketsList = function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); const socketsListByProject = function (req, res) { + if (process.env.uws !== "true") { + req.params = {projectKey: req.getParameter(0)}; + } debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); let liveSessions = {}; for (let peerId of io.sockets.adapter.rooms.keys()) { @@ -86,6 +89,9 @@ const socketsLive = async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); const socketsLiveByProject = async function (req, res) { + if (process.env.uws !== "true") { + req.params = {projectKey: req.getParameter(0)}; + } debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); let liveSessions = {}; for (let peerId of io.sockets.adapter.rooms.keys()) { From 899920c29ddd18c3381a67e99031ed7bf685b85d Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 22:17:22 +0100 Subject: [PATCH 078/101] feat(utilities): EE support different requests --- ee/utilities/servers/websocket.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ee/utilities/servers/websocket.js b/ee/utilities/servers/websocket.js index 974a1cf64..34f045a51 100644 --- a/ee/utilities/servers/websocket.js +++ b/ee/utilities/servers/websocket.js @@ -39,7 +39,7 @@ const socketsList = function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); const socketsListByProject = function (req, res) { - if (process.env.uws !== "true") { + if (process.env.uws === "true") { req.params = {projectKey: req.getParameter(0)}; } debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); @@ -89,7 +89,7 @@ const socketsLive = async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); const socketsLiveByProject = async function (req, res) { - if (process.env.uws !== "true") { + if (process.env.uws === "true") { req.params = {projectKey: req.getParameter(0)}; } debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); From 493e87a61b624df4d71d183dde1b85c319a7fb01 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 4 Mar 2022 22:36:34 +0100 Subject: [PATCH 079/101] feat(utilities): EE support different requests feat(utilities): EE redis-uws --- ee/utilities/servers/websocket-cluster.js | 4 ++-- scripts/helmcharts/openreplay/charts/utilities/values.yaml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ee/utilities/servers/websocket-cluster.js b/ee/utilities/servers/websocket-cluster.js index fc26cc2d3..940f83879 100644 --- a/ee/utilities/servers/websocket-cluster.js +++ b/ee/utilities/servers/websocket-cluster.js @@ -59,7 +59,7 @@ const socketsList = async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-list`, socketsList); const socketsListByProject = async function (req, res) { - if (process.env.uws !== "true") { + if (process.env.uws === "true") { req.params = {projectKey: req.getParameter(0)}; } debug && console.log(`[WS]looking for available sessions for ${req.params.projectKey}`); @@ -112,7 +112,7 @@ const socketsLive = async function (req, res) { wsRouter.get(`/${process.env.S3_KEY}/sockets-live`, socketsLive); const socketsLiveByProject = async function (req, res) { - if (process.env.uws !== "true") { + if (process.env.uws === "true") { req.params = {projectKey: req.getParameter(0)}; } debug && console.log(`[WS]looking for available LIVE sessions for ${req.params.projectKey}`); diff --git a/scripts/helmcharts/openreplay/charts/utilities/values.yaml b/scripts/helmcharts/openreplay/charts/utilities/values.yaml index 8d58b5227..87b3d771d 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/values.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/values.yaml @@ -81,7 +81,8 @@ autoscaling: targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 -env: {} +env: + REDIS_URL: "redis://redis-master.db.svc.cluster.local:6379" nodeSelector: {} From 135a8d0e7baf3e18c389aceb1d61f5ee3fb0e734 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 14:56:43 +0100 Subject: [PATCH 080/101] feat(tracker):3.5.3:internal API - session change callbacks & log-levels fix --- tracker/tracker/package.json | 4 +- tracker/tracker/src/main/app/index.ts | 43 +++++-------- tracker/tracker/src/main/app/logger.ts | 32 +++++----- tracker/tracker/src/main/app/session.ts | 84 +++++++++++++++++++++++++ tracker/tracker/src/main/index.ts | 6 +- 5 files changed, 118 insertions(+), 51 deletions(-) create mode 100644 tracker/tracker/src/main/app/session.ts diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index 744a2a375..e485faf11 100644 --- a/tracker/tracker/package.json +++ b/tracker/tracker/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker", "description": "The OpenReplay tracker main package", - "version": "3.5.1", + "version": "3.5.3", "keywords": [ "logging", "replay" @@ -41,6 +41,6 @@ "error-stack-parser": "^2.0.6" }, "engines": { - "node": ">=14" + "node": ">=12" } } diff --git a/tracker/tracker/src/main/app/index.ts b/tracker/tracker/src/main/app/index.ts index ca747411c..59129cbec 100644 --- a/tracker/tracker/src/main/app/index.ts +++ b/tracker/tracker/src/main/app/index.ts @@ -6,6 +6,7 @@ import Observer from "./observer/top_observer.js"; import Sanitizer from "./sanitizer.js"; import Ticker from "./ticker.js"; import Logger, { LogLevel } from "./logger.js"; +import Session from "./session.js"; import { deviceMemory, jsHeapSizeLimit } from "../modules/performance.js"; @@ -69,6 +70,7 @@ export default class App { readonly sanitizer: Sanitizer; readonly debug: Logger; readonly notify: Logger; + readonly session: Session; private readonly messages: Array = []; private readonly observer: Observer; private readonly startCallbacks: Array = []; @@ -76,9 +78,6 @@ export default class App { private readonly commitCallbacks: Array = []; private readonly options: AppOptions; private readonly revID: string; - private _sessionID: string | null = null; - private _userID: string | null = null; - private _metadata: Record = {}; private activityState: ActivityState = ActivityState.NotActive; private version = 'TRACKER_VERSION'; // TODO: version compatability check inside each plugin. private readonly worker?: Worker; @@ -120,6 +119,7 @@ export default class App { this.ticker.attach(() => this.commit()); this.debug = new Logger(this.options.__debug__); this.notify = new Logger(this.options.verbose ? LogLevel.Warnings : LogLevel.Silent); + this.session = new Session(this); try { this.worker = new Worker( URL.createObjectURL( @@ -129,18 +129,12 @@ export default class App { this.worker.onerror = e => { this._debug("webworker_error", e) } - let lastTs = timestamp(); - let fileno = 0; this.worker.onmessage = ({ data }: MessageEvent) => { if (data === null) { this.stop(); } else if (data === "restart") { this.stop(); - this.start({ - forceNew: true, - userID: this._userID || undefined, - metadata: this._metadata || undefined, - }); + this.start({ forceNew: true }); } }; const alertWorker = () => { @@ -197,10 +191,6 @@ export default class App { } } - attachCommitCallback(cb: CommitCallback): void { - this.commitCallbacks.push(cb) - } - safe void>(fn: T): T { const app = this; return function (this: any, ...args: any) { @@ -216,6 +206,10 @@ export default class App { } as any // TODO: correct typing } + attachCommitCallback(cb: CommitCallback): void { + this.commitCallbacks.push(cb) + } + attachStartCallback(cb: Callback): void { this.startCallbacks.push(cb); } @@ -258,15 +252,12 @@ export default class App { revID: this.revID, timestamp: timestamp(), trackerVersion: this.version, - userID: this._userID, isSnippet: this.options.__is_snippet, } - } getSessionInfo() { return { - sessionID: this._sessionID, - metadata: this._metadata, + ...this.session.getInfo(), ...this.getStartInfo() } } @@ -277,7 +268,7 @@ export default class App { } } getSessionID(): string | undefined { - return this._sessionID || undefined; + return this.session.getInfo().sessionID || undefined; } getHost(): string { return new URL(this.options.ingestPoint).hostname @@ -338,10 +329,7 @@ export default class App { } sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString()); - this._userID = startOpts.userID || null - this._metadata = startOpts.metadata || {} // TODO: update both dynamically on corresponding messages const startInfo = this.getStartInfo() - const messageData: WorkerMessageData = { ingestPoint: this.options.ingestPoint, pageNo, @@ -361,6 +349,7 @@ export default class App { }, body: JSON.stringify({ ...startInfo, + userID: startOpts.userID || this.session.getInfo().userID, token: sessionStorage.getItem(this.options.session_token_key), deviceMemory, jsHeapSizeLimit, @@ -389,9 +378,10 @@ export default class App { } sessionStorage.setItem(this.options.session_token_key, token); localStorage.setItem(this.options.local_uuid_key, userUUID); - if (typeof sessionID === 'string') { - this._sessionID = sessionID; - } + this.session.update({ + sessionID, // any. TODO check + ...startOpts + }); this.activityState = ActivityState.Active this.worker.postMessage({ token, beaconSizeLimit }); @@ -399,9 +389,6 @@ export default class App { this.observer.observe(); this.ticker.start(); - Object.entries(this._metadata).forEach(([key, value]) => - this.send(new Metadata(key, value))) - this.notify.log("OpenReplay tracking started."); // TODO: get rid of onStart const onStartInfo = { sessionToken: token, userUUID, sessionID }; diff --git a/tracker/tracker/src/main/app/logger.ts b/tracker/tracker/src/main/app/logger.ts index 42dfa5347..34d8c12c6 100644 --- a/tracker/tracker/src/main/app/logger.ts +++ b/tracker/tracker/src/main/app/logger.ts @@ -1,11 +1,9 @@ - - export const LogLevel = { - Verbose: 4, - Errors: 4, + Verbose: 5, + Log: 4, Warnings: 3, - Log: 2, + Errors: 2, Silent: 0, } as const; type LogLevel = typeof LogLevel[keyof typeof LogLevel] @@ -31,30 +29,30 @@ interface _Options { export type Options = true | _Options | LogLevel export default class Logger { - private readonly opts: _Options; - constructor(private readonly options: Options = LogLevel.Silent) { - this.opts = options === true + private readonly options: _Options; + constructor(options: Options = LogLevel.Silent) { + this.options = options === true ? { level: LogLevel.Verbose } : typeof options === "number" ? { level: options } : options; } log(...args: any) { - if (IsCustomLevel(this.opts.level) - ? this.opts.level.log - : this.opts.level >= LogLevel.Log) { + if (IsCustomLevel(this.options.level) + ? this.options.level.log + : this.options.level >= LogLevel.Log) { console.log(...args) } } warn(...args: any) { - if (IsCustomLevel(this.opts.level) - ? this.opts.level.warn - : this.opts.level >= LogLevel.Warnings) { + if (IsCustomLevel(this.options.level) + ? this.options.level.warn + : this.options.level >= LogLevel.Warnings) { console.warn(...args) } } error(...args: any) { - if (IsCustomLevel(this.opts.level) - ? this.opts.level.error - : this.opts.level >= LogLevel.Errors) { + if (IsCustomLevel(this.options.level) + ? this.options.level.error + : this.options.level >= LogLevel.Errors) { console.error(...args) } } diff --git a/tracker/tracker/src/main/app/session.ts b/tracker/tracker/src/main/app/session.ts new file mode 100644 index 000000000..ec5dadf51 --- /dev/null +++ b/tracker/tracker/src/main/app/session.ts @@ -0,0 +1,84 @@ +import App, { StartOptions } from "./index.js"; +import { UserID, UserAnonymousID, Metadata } from "../../messages/index.js"; + + +enum ActivityState { + NotActive, + Starting, + Active, +} + +interface SessionInfo { + sessionID: string | null, + metadata: Record, + userID: string | null, +} +type OnUpdateCallback = (i: Partial) => void + + +export default class Session { + private metadata: Record = {} + private userID: string | null = null + private sessionID: string | null = null + private activityState: ActivityState = ActivityState.NotActive + private callbacks: OnUpdateCallback[] = [] + + constructor(private app: App) {} + + + attachUpdateCallback(cb: OnUpdateCallback) { + this.callbacks.push(cb) + } + private handleUpdate() { + const sessInfo: Partial = this.getInfo() + if (sessInfo.userID == null) { + delete sessInfo.userID + } + if (sessInfo.sessionID == null) { + delete sessInfo.sessionID + } + this.callbacks.forEach(cb => cb(sessInfo)) + } + + update({ userID, metadata, sessionID }: Partial) { + if (userID != null) { // TODO clear nullable/undefinable types + this._setUserID(userID) + } + if (metadata !== undefined) { + Object.entries(metadata).forEach(kv => this._setMetadata(...kv)) + } + if (sessionID !== undefined) { + this.sessionID = sessionID + } + this.handleUpdate() + } + + private _setMetadata(key: string, value: string) { + this.app.send(new Metadata(key, value)) + this.metadata[key] = value + } + private _setUserID(userID: string) { + this.app.send(new UserID(userID)) + this.userID = userID + } + + + + setMetadata(key: string, value: string) { + this._setMetadata(key, value) + this.handleUpdate() + } + setUserID(userID: string) { + this._setUserID(userID) + this.handleUpdate() + } + + getInfo(): SessionInfo { + return { + sessionID: this.sessionID, + metadata: this.metadata, + userID: this.userID, + + } + } +} \ No newline at end of file diff --git a/tracker/tracker/src/main/index.ts b/tracker/tracker/src/main/index.ts index 3ef4d8c98..8961d6e54 100644 --- a/tracker/tracker/src/main/index.ts +++ b/tracker/tracker/src/main/index.ts @@ -15,7 +15,6 @@ import Timing from "./modules/timing.js"; import Performance from "./modules/performance.js"; import Scroll from "./modules/scroll.js"; import Viewport from "./modules/viewport.js"; -import Longtasks from "./modules/longtasks.js"; import CSSRules from "./modules/cssrules.js"; import { IN_BROWSER, deprecationWarn, DOCS_HOST } from "./utils.js"; @@ -109,7 +108,6 @@ export default class API { Timing(app, options); Performance(app, options); Scroll(app); - Longtasks(app); (window as any).__OPENREPLAY__ = this; if (options.autoResetOnWindowOpen) { @@ -190,7 +188,7 @@ export default class API { setUserID(id: string): void { if (typeof id === 'string' && this.app !== null) { - this.app.send(new UserID(id)); + this.app.session.setUserID(id); } } userID(id: string): void { @@ -214,7 +212,7 @@ export default class API { typeof value === 'string' && this.app !== null ) { - this.app.send(new Metadata(key, value)); + this.app.session.setMetadata(key, value); } } metadata(key: string, value: string): void { From ce2cd38db16298c62e632a6bf28ee74c4e06c3ce Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 14:59:28 +0100 Subject: [PATCH 081/101] feat(tracker-assist):3.5.5: SESSION_UPDATE for title, hiddenstate, userID and metadata --- tracker/tracker-assist/package.json | 4 +-- tracker/tracker-assist/src/Assist.ts | 47 +++++++++++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/tracker/tracker-assist/package.json b/tracker/tracker-assist/package.json index c90a674d3..30f85875b 100644 --- a/tracker/tracker-assist/package.json +++ b/tracker/tracker-assist/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker-assist", "description": "Tracker plugin for screen assistance through the WebRTC", - "version": "3.5.4", + "version": "3.5.5", "keywords": [ "WebRTC", "assistance", @@ -20,7 +20,7 @@ "replace-paths": "replace-in-files cjs/* --string='@openreplay/tracker' --replacement='@openreplay/tracker/cjs' && replace-in-files cjs/* --string='/lib/' --replacement='/'", "replace-versions": "npm run replace-pkg-version && npm run replace-req-version", "replace-pkg-version": "replace-in-files lib/* cjs/* --string='PACKAGE_VERSION' --replacement=$npm_package_version", - "replace-req-version": "replace-in-files lib/* cjs/* --string='REQUIRED_TRACKER_VERSION' --replacement='3.5.0'", + "replace-req-version": "replace-in-files lib/* cjs/* --string='REQUIRED_TRACKER_VERSION' --replacement='3.5.3'", "prepublishOnly": "npm run build" }, "dependencies": { diff --git a/tracker/tracker-assist/src/Assist.ts b/tracker/tracker-assist/src/Assist.ts index 55ace11a4..b5272510b 100644 --- a/tracker/tracker-assist/src/Assist.ts +++ b/tracker/tracker-assist/src/Assist.ts @@ -72,21 +72,43 @@ export default class Assist { }, options, ); - app.attachStartCallback(() => { - if (this.assistDemandedRestart) { return; } - this.onStart() + + if (document.hidden !== undefined) { + const sendActivityState = () => this.emit("UPDATE_SESSION", { active: !document.hidden }) + app.attachEventListener( + document, + 'visibilitychange', + sendActivityState, + false, + false, + ) + } + const titleNode = document.querySelector('title') + const observer = titleNode && new MutationObserver(() => { + this.emit("UPDATE_SESSION", { pageTitle: document.title }) }) - app.attachCommitCallback((messages) => { - if (this.socket && this.agentsConnected) { - // @ts-ignore No need in statistics messages. TODO proper filter - if (messages.length === 2 && messages[0]._id === 0 && messages[1]._id === 49) { return } - this.socket.emit("messages", messages) - } + app.attachStartCallback(() => { + if (this.assistDemandedRestart) { return; } + this.onStart() + observer && observer.observe(titleNode, { subtree: true, characterData: true, childList: true }) }) app.attachStopCallback(() => { if (this.assistDemandedRestart) { return; } this.clean() + observer && observer.disconnect() }) + app.attachCommitCallback((messages) => { + if (this.agentsConnected) { + // @ts-ignore No need in statistics messages. TODO proper filter + if (messages.length === 2 && messages[0]._id === 0 && messages[1]._id === 49) { return } + this.emit("messages", messages) + } + }) + app.session.attachUpdateCallback(sessInfo => this.emit("UPDATE_SESSION", sessInfo)) + } + + private emit(ev: string, ...args) { + this.socket && this.socket.emit(ev, ...args) } private get agentsConnected(): boolean { @@ -94,7 +116,7 @@ export default class Assist { } private notifyCallEnd() { - this.socket && this.socket.emit("call_end"); + this.emit("call_end"); } private onRemoteCallEnd = () => {} @@ -108,7 +130,10 @@ export default class Assist { query: { "peerId": peerID, "identity": "session", - "sessionInfo": JSON.stringify(this.app.getSessionInfo()), + "sessionInfo": JSON.stringify({ + pageTitle: document.title, + ...this.app.getSessionInfo() + }), }, transports: ["websocket"], }) From 777648dedd558d0cbaa63f408ace7184f36d8762 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 17:30:27 +0100 Subject: [PATCH 082/101] format(backend): format some go files --- backend/pkg/db/cache/messages_ios.go | 36 +++++---- backend/pkg/db/cache/pg_cache.go | 19 ++--- backend/pkg/db/cache/project.go | 15 ++-- backend/pkg/db/cache/session.go | 8 +- backend/pkg/db/postgres/errors.go | 4 +- backend/pkg/db/postgres/helpers.go | 4 +- backend/pkg/db/postgres/listener.go | 2 - backend/pkg/db/postgres/messages_ios.go | 14 ++-- backend/pkg/db/postgres/messages_web.go | 12 ++- backend/pkg/db/postgres/notification.go | 2 +- backend/pkg/db/postgres/project.go | 12 +-- backend/pkg/db/postgres/unstarted_session.go | 26 +++---- backend/pkg/db/types/project.go | 21 +++--- backend/pkg/db/types/session.go | 8 +- backend/services/db/messages.go | 12 +-- backend/services/ender/builder/builder.go | 77 ++++++++++---------- 16 files changed, 127 insertions(+), 145 deletions(-) diff --git a/backend/pkg/db/cache/messages_ios.go b/backend/pkg/db/cache/messages_ios.go index 0cced5472..4bbc8c1f5 100644 --- a/backend/pkg/db/cache/messages_ios.go +++ b/backend/pkg/db/cache/messages_ios.go @@ -1,41 +1,40 @@ package cache -import ( +import ( "errors" - . "openreplay/backend/pkg/messages" . "openreplay/backend/pkg/db/types" + . "openreplay/backend/pkg/messages" ) func (c *PGCache) InsertIOSSessionStart(sessionID uint64, s *IOSSessionStart) error { - if c.sessions[ sessionID ] != nil { + if c.sessions[sessionID] != nil { return errors.New("This session already in cache!") } - c.sessions[ sessionID ] = &Session{ - SessionID: sessionID, - Platform: "ios", - Timestamp: s.Timestamp, - ProjectID: uint32(s.ProjectID), + c.sessions[sessionID] = &Session{ + SessionID: sessionID, + Platform: "ios", + Timestamp: s.Timestamp, + ProjectID: uint32(s.ProjectID), TrackerVersion: s.TrackerVersion, - RevID: s.RevID, - UserUUID: s.UserUUID, - UserOS: s.UserOS, - UserOSVersion: s.UserOSVersion, - UserDevice: s.UserDevice, - UserCountry: s.UserCountry, + RevID: s.RevID, + UserUUID: s.UserUUID, + UserOS: s.UserOS, + UserOSVersion: s.UserOSVersion, + UserDevice: s.UserDevice, + UserCountry: s.UserCountry, UserDeviceType: s.UserDeviceType, } - if err := c.Conn.InsertSessionStart(sessionID, c.sessions[ sessionID ]); err != nil { - c.sessions[ sessionID ] = nil + if err := c.Conn.InsertSessionStart(sessionID, c.sessions[sessionID]); err != nil { + c.sessions[sessionID] = nil return err } - return nil; + return nil } func (c *PGCache) InsertIOSSessionEnd(sessionID uint64, e *IOSSessionEnd) error { return c.insertSessionEnd(sessionID, e.Timestamp) } - func (c *PGCache) InsertIOSScreenEnter(sessionID uint64, screenEnter *IOSScreenEnter) error { if err := c.Conn.InsertIOSScreenEnter(sessionID, screenEnter); err != nil { return err @@ -95,4 +94,3 @@ func (c *PGCache) InsertIOSIssueEvent(sessionID uint64, issueEvent *IOSIssueEven // } return nil } - diff --git a/backend/pkg/db/cache/pg_cache.go b/backend/pkg/db/cache/pg_cache.go index 9a62354f1..6422209d4 100644 --- a/backend/pkg/db/cache/pg_cache.go +++ b/backend/pkg/db/cache/pg_cache.go @@ -1,8 +1,8 @@ package cache -import ( - "time" +import ( "sync" + "time" "openreplay/backend/pkg/db/postgres" . "openreplay/backend/pkg/db/types" @@ -10,32 +10,29 @@ import ( type ProjectMeta struct { *Project - expirationTime time.Time + expirationTime time.Time } // !TODO: remove old sessions by timeout to avoid memleaks -/* +/* * Cache layer around the stateless PG adapter **/ type PGCache struct { *postgres.Conn - sessions map[uint64]*Session - projects map[uint32]*ProjectMeta - projectsByKeys sync.Map // map[string]*ProjectMeta + sessions map[uint64]*Session + projects map[uint32]*ProjectMeta + projectsByKeys sync.Map // map[string]*ProjectMeta projectExpirationTimeout time.Duration } // TODO: create conn automatically func NewPGCache(pgConn *postgres.Conn, projectExpirationTimeoutMs int64) *PGCache { return &PGCache{ - Conn: pgConn, + Conn: pgConn, sessions: make(map[uint64]*Session), projects: make(map[uint32]*ProjectMeta), //projectsByKeys: make(map[string]*ProjectMeta), projectExpirationTimeout: time.Duration(1000 * projectExpirationTimeoutMs), } } - - - diff --git a/backend/pkg/db/cache/project.go b/backend/pkg/db/cache/project.go index daf498d32..35d952302 100644 --- a/backend/pkg/db/cache/project.go +++ b/backend/pkg/db/cache/project.go @@ -1,8 +1,8 @@ package cache -import ( - "time" +import ( . "openreplay/backend/pkg/db/types" + "time" ) func (c *PGCache) GetProjectByKey(projectKey string) (*Project, error) { @@ -24,19 +24,16 @@ func (c *PGCache) GetProjectByKey(projectKey string) (*Project, error) { return p, nil } - - func (c *PGCache) GetProject(projectID uint32) (*Project, error) { - if c.projects[ projectID ] != nil && - time.Now().Before(c.projects[ projectID ].expirationTime) { - return c.projects[ projectID ].Project, nil + if c.projects[projectID] != nil && + time.Now().Before(c.projects[projectID].expirationTime) { + return c.projects[projectID].Project, nil } p, err := c.Conn.GetProject(projectID) if err != nil { return nil, err } - c.projects[ projectID ] = &ProjectMeta{ p, time.Now().Add(c.projectExpirationTimeout) } + c.projects[projectID] = &ProjectMeta{p, time.Now().Add(c.projectExpirationTimeout)} //c.projectsByKeys.Store(p.ProjectKey, c.projects[ projectID ]) return p, nil } - diff --git a/backend/pkg/db/cache/session.go b/backend/pkg/db/cache/session.go index 2038fd1bd..a79462022 100644 --- a/backend/pkg/db/cache/session.go +++ b/backend/pkg/db/cache/session.go @@ -1,13 +1,13 @@ package cache -import ( +import ( "github.com/jackc/pgx/v4" . "openreplay/backend/pkg/db/types" ) func (c *PGCache) GetSession(sessionID uint64) (*Session, error) { - if s, inCache := c.sessions[ sessionID ]; inCache { + if s, inCache := c.sessions[sessionID]; inCache { // TODO: review. Might cause bugs in case of multiple instances if s == nil { return nil, pgx.ErrNoRows @@ -16,12 +16,12 @@ func (c *PGCache) GetSession(sessionID uint64) (*Session, error) { } s, err := c.Conn.GetSession(sessionID) if err == pgx.ErrNoRows { - c.sessions[ sessionID ] = nil + c.sessions[sessionID] = nil } if err != nil { return nil, err } - c.sessions[ sessionID ] = s + c.sessions[sessionID] = s return s, nil } diff --git a/backend/pkg/db/postgres/errors.go b/backend/pkg/db/postgres/errors.go index a83c8f03a..de105f7ce 100644 --- a/backend/pkg/db/postgres/errors.go +++ b/backend/pkg/db/postgres/errors.go @@ -3,14 +3,14 @@ package postgres import ( "errors" - "github.com/jackc/pgx/v4" "github.com/jackc/pgconn" "github.com/jackc/pgerrcode" + "github.com/jackc/pgx/v4" ) func IsPkeyViolation(err error) bool { var pgErr *pgconn.PgError - return errors.As(err, &pgErr) && pgErr.Code == pgerrcode.UniqueViolation + return errors.As(err, &pgErr) && pgErr.Code == pgerrcode.UniqueViolation } func IsNoRowsErr(err error) bool { diff --git a/backend/pkg/db/postgres/helpers.go b/backend/pkg/db/postgres/helpers.go index e6e9747e8..2d4c96e28 100644 --- a/backend/pkg/db/postgres/helpers.go +++ b/backend/pkg/db/postgres/helpers.go @@ -8,7 +8,7 @@ func getIssueScore(issueEvent *messages.IssueEvent) int { switch issueEvent.Type { case "crash", "dead_click", "memory", "cpu": return 1000 - case "bad_request", "excessive_scrolling", "click_rage", "missing_resource" : + case "bad_request", "excessive_scrolling", "click_rage", "missing_resource": return 500 case "slow_resource", "slow_page_load": return 100 @@ -32,4 +32,4 @@ func calcResponseTime(pe *messages.PageEvent) uint64 { return pe.ResponseEnd - pe.ResponseStart } return 0 -} \ No newline at end of file +} diff --git a/backend/pkg/db/postgres/listener.go b/backend/pkg/db/postgres/listener.go index 0f6d73ef7..f90d83485 100644 --- a/backend/pkg/db/postgres/listener.go +++ b/backend/pkg/db/postgres/listener.go @@ -6,8 +6,6 @@ import ( "fmt" "github.com/jackc/pgx/v4" - - ) type Listener struct { diff --git a/backend/pkg/db/postgres/messages_ios.go b/backend/pkg/db/postgres/messages_ios.go index b54a88af7..e75ff2acd 100644 --- a/backend/pkg/db/postgres/messages_ios.go +++ b/backend/pkg/db/postgres/messages_ios.go @@ -1,8 +1,8 @@ package postgres import ( - "openreplay/backend/pkg/messages" "openreplay/backend/pkg/hashid" + "openreplay/backend/pkg/messages" "openreplay/backend/pkg/url" ) @@ -33,7 +33,7 @@ func (conn *Conn) InsertIOSUserAnonymousID(sessionID uint64, userAnonymousID *me func (conn *Conn) InsertIOSNetworkCall(sessionID uint64, e *messages.IOSNetworkCall) error { err := conn.InsertRequest(sessionID, e.Timestamp, e.Index, e.URL, e.Duration, e.Success) if err == nil { - conn.insertAutocompleteValue(sessionID, "REQUEST_IOS", url.DiscardURLQuery(e.URL)) + conn.insertAutocompleteValue(sessionID, "REQUEST_IOS", url.DiscardURLQuery(e.URL)) } return err } @@ -65,7 +65,7 @@ func (conn *Conn) InsertIOSScreenEnter(sessionID uint64, screenEnter *messages.I if err = tx.commit(); err != nil { return err } - conn.insertAutocompleteValue(sessionID, "VIEW_IOS", screenEnter.ViewName) + conn.insertAutocompleteValue(sessionID, "VIEW_IOS", screenEnter.ViewName) return nil } @@ -81,7 +81,7 @@ func (conn *Conn) InsertIOSClickEvent(sessionID uint64, clickEvent *messages.IOS session_id, timestamp, seq_index, label ) VALUES ( $1, $2, $3, $4 - )`, + )`, sessionID, clickEvent.Timestamp, clickEvent.Index, clickEvent.Label, ); err != nil { return err @@ -153,7 +153,7 @@ func (conn *Conn) InsertIOSCrash(sessionID uint64, projectID uint32, crash *mess project_id, $2, $3, $4, $5 FROM sessions WHERE session_id = $1 - )ON CONFLICT DO NOTHING`, + )ON CONFLICT DO NOTHING`, sessionID, crashID, crash.Name, crash.Reason, crash.Stacktrace, ); err != nil { return err @@ -163,7 +163,7 @@ func (conn *Conn) InsertIOSCrash(sessionID uint64, projectID uint32, crash *mess session_id, timestamp, seq_index, crash_id ) VALUES ( $1, $2, $3, $4 - )`, + )`, sessionID, crash.Timestamp, crash.Index, crashID, ); err != nil { return err @@ -177,5 +177,3 @@ func (conn *Conn) InsertIOSCrash(sessionID uint64, projectID uint32, crash *mess } return tx.commit() } - - diff --git a/backend/pkg/db/postgres/messages_web.go b/backend/pkg/db/postgres/messages_web.go index 64d7ba561..3903714ee 100644 --- a/backend/pkg/db/postgres/messages_web.go +++ b/backend/pkg/db/postgres/messages_web.go @@ -13,9 +13,8 @@ func getSqIdx(messageID uint64) uint { return uint(messageID % math.MaxInt32) } - func (conn *Conn) InsertWebCustomEvent(sessionID uint64, e *CustomEvent) error { - err := conn.InsertCustomEvent(sessionID, e.Timestamp, + err := conn.InsertCustomEvent(sessionID, e.Timestamp, e.MessageID, e.Name, e.Payload) if err == nil { @@ -44,12 +43,12 @@ func (conn *Conn) InsertWebResourceEvent(sessionID uint64, e *ResourceEvent) err if e.Type != "fetch" { return nil } - err := conn.InsertRequest(sessionID, e.Timestamp, + err := conn.InsertRequest(sessionID, e.Timestamp, e.MessageID, e.URL, e.Duration, e.Success, ) if err == nil { - conn.insertAutocompleteValue(sessionID, "REQUEST", url.DiscardURLQuery(e.URL)) + conn.insertAutocompleteValue(sessionID, "REQUEST", url.DiscardURLQuery(e.URL)) } return err } @@ -62,7 +61,7 @@ func (conn *Conn) InsertWebPageEvent(sessionID uint64, e *PageEvent) error { } tx, err := conn.begin() if err != nil { - return err + return err } defer tx.rollback() if err := tx.exec(` @@ -79,7 +78,7 @@ func (conn *Conn) InsertWebPageEvent(sessionID uint64, e *PageEvent) error { ) `, sessionID, e.MessageID, e.Timestamp, e.Referrer, url.DiscardURLQuery(e.Referrer), host, path, url.DiscardURLQuery(path), - e.DomContentLoadedEventEnd, e.LoadEventEnd, e.ResponseEnd, e.FirstPaint, e.FirstContentfulPaint, + e.DomContentLoadedEventEnd, e.LoadEventEnd, e.ResponseEnd, e.FirstPaint, e.FirstContentfulPaint, e.SpeedIndex, e.VisuallyComplete, e.TimeToInteractive, calcResponseTime(e), calcDomBuildingTime(e), ); err != nil { @@ -133,7 +132,6 @@ func (conn *Conn) InsertWebClickEvent(sessionID uint64, e *ClickEvent) error { return nil } - func (conn *Conn) InsertWebInputEvent(sessionID uint64, e *InputEvent) error { tx, err := conn.begin() if err != nil { diff --git a/backend/pkg/db/postgres/notification.go b/backend/pkg/db/postgres/notification.go index 063e92f7b..c9670b8bd 100644 --- a/backend/pkg/db/postgres/notification.go +++ b/backend/pkg/db/postgres/notification.go @@ -14,7 +14,7 @@ type TenantNotification struct { Title string `db:"title" json:"title"` Description string `db:"description" json:"description"` ButtonText string `db:"button_text" json:"buttonText"` - ButtonUrl string `db:"button_url" json:"buttonUrl"` + ButtonUrl string `db:"button_url" json:"buttonUrl"` ImageUrl *string `db:"image_url" json:"imageUrl"` Options map[string]interface{} `db:"options" json:"options"` } diff --git a/backend/pkg/db/postgres/project.go b/backend/pkg/db/postgres/project.go index 2eea30662..730980176 100644 --- a/backend/pkg/db/postgres/project.go +++ b/backend/pkg/db/postgres/project.go @@ -5,7 +5,7 @@ import ( ) func (conn *Conn) GetProjectByKey(projectKey string) (*Project, error) { - p := &Project{ ProjectKey: projectKey } + p := &Project{ProjectKey: projectKey} if err := conn.queryRow(` SELECT max_session_duration, sample_rate, project_id FROM projects @@ -20,7 +20,7 @@ func (conn *Conn) GetProjectByKey(projectKey string) (*Project, error) { // TODO: logical separation of metadata func (conn *Conn) GetProject(projectID uint32) (*Project, error) { - p := &Project{ ProjectID: projectID } + p := &Project{ProjectID: projectID} if err := conn.queryRow(` SELECT project_key, max_session_duration, metadata_1, metadata_2, metadata_3, metadata_4, metadata_5, @@ -29,10 +29,10 @@ func (conn *Conn) GetProject(projectID uint32) (*Project, error) { WHERE project_id=$1 AND active = true `, projectID, - ).Scan(&p.ProjectKey,&p.MaxSessionDuration, - &p.Metadata1, &p.Metadata2, &p.Metadata3, &p.Metadata4, &p.Metadata5, - &p.Metadata6, &p.Metadata7, &p.Metadata8, &p.Metadata9, &p.Metadata10); err != nil { + ).Scan(&p.ProjectKey, &p.MaxSessionDuration, + &p.Metadata1, &p.Metadata2, &p.Metadata3, &p.Metadata4, &p.Metadata5, + &p.Metadata6, &p.Metadata7, &p.Metadata8, &p.Metadata9, &p.Metadata10); err != nil { return nil, err } return p, nil -} \ No newline at end of file +} diff --git a/backend/pkg/db/postgres/unstarted_session.go b/backend/pkg/db/postgres/unstarted_session.go index 162946e97..2a9a71037 100644 --- a/backend/pkg/db/postgres/unstarted_session.go +++ b/backend/pkg/db/postgres/unstarted_session.go @@ -1,18 +1,18 @@ package postgres type UnstartedSession struct { - ProjectKey string - TrackerVersion string - DoNotTrack bool - Platform string - UserAgent string - UserOS string - UserOSVersion string - UserBrowser string + ProjectKey string + TrackerVersion string + DoNotTrack bool + Platform string + UserAgent string + UserOS string + UserOSVersion string + UserBrowser string UserBrowserVersion string - UserDevice string - UserDeviceType string - UserCountry string + UserDevice string + UserDeviceType string + UserCountry string } func (conn *Conn) InsertUnstartedSession(s UnstartedSession) error { @@ -34,12 +34,12 @@ func (conn *Conn) InsertUnstartedSession(s UnstartedSession) error { $10, $11, $12 )`, - s.ProjectKey, + s.ProjectKey, s.TrackerVersion, s.DoNotTrack, s.Platform, s.UserAgent, s.UserOS, s.UserOSVersion, s.UserBrowser, s.UserBrowserVersion, - s.UserDevice, s.UserDeviceType, + s.UserDevice, s.UserDeviceType, s.UserCountry, ) } diff --git a/backend/pkg/db/types/project.go b/backend/pkg/db/types/project.go index 74ec90c47..7a8172061 100644 --- a/backend/pkg/db/types/project.go +++ b/backend/pkg/db/types/project.go @@ -6,20 +6,19 @@ type Project struct { ProjectID uint32 ProjectKey string MaxSessionDuration int64 - SampleRate byte - Metadata1 *string - Metadata2 *string - Metadata3 *string - Metadata4 *string - Metadata5 *string - Metadata6 *string - Metadata7 *string - Metadata8 *string - Metadata9 *string + SampleRate byte + Metadata1 *string + Metadata2 *string + Metadata3 *string + Metadata4 *string + Metadata5 *string + Metadata6 *string + Metadata7 *string + Metadata8 *string + Metadata9 *string Metadata10 *string } - func (p *Project) GetMetadataNo(key string) uint { if p == nil { log.Printf("GetMetadataNo: Project is nil") diff --git a/backend/pkg/db/types/session.go b/backend/pkg/db/types/session.go index 92607514d..4cf8dd1ea 100644 --- a/backend/pkg/db/types/session.go +++ b/backend/pkg/db/types/session.go @@ -12,10 +12,10 @@ type Session struct { UserDevice string UserCountry string - Duration *uint64 - PagesCount int - EventsCount int - ErrorsCount int + Duration *uint64 + PagesCount int + EventsCount int + ErrorsCount int UserID *string // pointer?? UserAnonymousID *string diff --git a/backend/services/db/messages.go b/backend/services/db/messages.go index 6aa4ac076..38edd7c45 100644 --- a/backend/services/db/messages.go +++ b/backend/services/db/messages.go @@ -11,7 +11,7 @@ func insertMessage(sessionID uint64, msg Message) error { return pg.InsertMetadata(sessionID, m) case *IssueEvent: return pg.InsertIssueEvent(sessionID, m) - //TODO: message adapter (transformer) (at the level of pkg/message) for types: + //TODO: message adapter (transformer) (at the level of pkg/message) for types: // case *IOSMetadata, *IOSIssueEvent and others // Web @@ -34,10 +34,10 @@ func insertMessage(sessionID uint64, msg Message) error { return pg.InsertWebResourceEvent(sessionID, m) case *PageEvent: return pg.InsertWebPageEvent(sessionID, m) - case *ErrorEvent: + case *ErrorEvent: return pg.InsertWebErrorEvent(sessionID, m) - // IOS + // IOS case *IOSSessionStart: return pg.InsertIOSSessionStart(sessionID, m) case *IOSSessionEnd: @@ -57,8 +57,8 @@ func insertMessage(sessionID uint64, msg Message) error { return pg.InsertIOSNetworkCall(sessionID, m) case *IOSScreenEnter: return pg.InsertIOSScreenEnter(sessionID, m) - case *IOSCrash: + case *IOSCrash: return pg.InsertIOSCrash(sessionID, m) } - return nil // "Not implemented" -} \ No newline at end of file + return nil // "Not implemented" +} diff --git a/backend/services/ender/builder/builder.go b/backend/services/ender/builder/builder.go index c0690a3ad..5bca49a53 100644 --- a/backend/services/ender/builder/builder.go +++ b/backend/services/ender/builder/builder.go @@ -41,33 +41,32 @@ func getResourceType(initiator string, URL string) string { } type builder struct { - readyMsgs []Message - timestamp uint64 - lastProcessedTimestamp int64 - peBuilder *pageEventBuilder - ptaBuilder *performanceTrackAggrBuilder - ieBuilder *inputEventBuilder - ciFinder *cpuIssueFinder - miFinder *memoryIssueFinder - ddDetector *domDropDetector - crDetector *clickRageDetector - dcDetector *deadClickDetector - integrationsWaiting bool - + readyMsgs []Message + timestamp uint64 + lastProcessedTimestamp int64 + peBuilder *pageEventBuilder + ptaBuilder *performanceTrackAggrBuilder + ieBuilder *inputEventBuilder + ciFinder *cpuIssueFinder + miFinder *memoryIssueFinder + ddDetector *domDropDetector + crDetector *clickRageDetector + dcDetector *deadClickDetector + integrationsWaiting bool sid uint64 } func NewBuilder() *builder { return &builder{ - peBuilder: &pageEventBuilder{}, - ptaBuilder: &performanceTrackAggrBuilder{}, - ieBuilder: NewInputEventBuilder(), - ciFinder: &cpuIssueFinder{}, - miFinder: &memoryIssueFinder{}, - ddDetector: &domDropDetector{}, - crDetector: &clickRageDetector{}, - dcDetector: &deadClickDetector{}, + peBuilder: &pageEventBuilder{}, + ptaBuilder: &performanceTrackAggrBuilder{}, + ieBuilder: NewInputEventBuilder(), + ciFinder: &cpuIssueFinder{}, + miFinder: &memoryIssueFinder{}, + ddDetector: &domDropDetector{}, + crDetector: &clickRageDetector{}, + dcDetector: &deadClickDetector{}, integrationsWaiting: true, } } @@ -115,15 +114,14 @@ func (b *builder) handleMessage(message Message, messageID uint64) { b.timestamp = timestamp } - b.lastProcessedTimestamp = time.Now().UnixNano()/1e6 - + b.lastProcessedTimestamp = time.Now().UnixNano() / 1e6 // Might happen before the first timestamp. switch msg := message.(type) { case *SessionStart, - *Metadata, - *UserID, - *UserAnonymousID: + *Metadata, + *UserID, + *UserAnonymousID: b.appendReadyMessage(msg) case *RawErrorEvent: b.appendReadyMessage(&ErrorEvent{ @@ -220,14 +218,14 @@ func (b *builder) handleMessage(message Message, messageID uint64) { Type: tp, Success: success, }) - if !success && tp == "fetch" { - b.appendReadyMessage(&IssueEvent{ - Type: "bad_request", - MessageID: messageID, - Timestamp: msg.Timestamp, + if !success && tp == "fetch" { + b.appendReadyMessage(&IssueEvent{ + Type: "bad_request", + MessageID: messageID, + Timestamp: msg.Timestamp, ContextString: msg.URL, - Context: "", - Payload: "", + Context: "", + Payload: "", }) } case *RawCustomEvent: @@ -239,11 +237,11 @@ func (b *builder) handleMessage(message Message, messageID uint64) { }) case *CustomIssue: b.appendReadyMessage(&IssueEvent{ - Type: "custom", - Timestamp: b.timestamp, - MessageID: messageID, + Type: "custom", + Timestamp: b.timestamp, + MessageID: messageID, ContextString: msg.Name, - Payload: msg.Payload, + Payload: msg.Payload, }) case *Fetch: b.appendReadyMessage(&ResourceEvent{ @@ -283,11 +281,10 @@ func (b *builder) handleMessage(message Message, messageID uint64) { } } - func (b *builder) checkTimeouts(ts int64) bool { - if b.timestamp == 0 { + if b.timestamp == 0 { return false // There was no timestamp events yet - } + } if b.peBuilder.HasInstance() && int64(b.peBuilder.GetTimestamp())+intervals.EVENTS_PAGE_EVENT_TIMEOUT < ts { b.buildPageEvent() From 15f67c85959118cda6ab717ef6794e1b8ce2e6d9 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 19:09:02 +0100 Subject: [PATCH 083/101] feat(backend): save payloads --- backend/pkg/db/cache/messages_web.go | 24 + backend/pkg/db/postgres/messages_web.go | 73 +- backend/pkg/db/postgres/project.go | 4 +- backend/pkg/db/types/project.go | 29 +- backend/pkg/messages/messages.go | 1606 ++++++++-------- backend/pkg/messages/read_message.go | 2109 ++++++++++++++------- backend/services/db/messages.go | 8 +- backend/services/ender/builder/builder.go | 25 +- 8 files changed, 2397 insertions(+), 1481 deletions(-) diff --git a/backend/pkg/db/cache/messages_web.go b/backend/pkg/db/cache/messages_web.go index 4aa4dfa7b..71f2c38d0 100644 --- a/backend/pkg/db/cache/messages_web.go +++ b/backend/pkg/db/cache/messages_web.go @@ -53,3 +53,27 @@ func (c *PGCache) InsertWebErrorEvent(sessionID uint64, e *ErrorEvent) error { session.ErrorsCount += 1 return nil } + +func (c *PGCache) InsertWebFetchEvent(sessionID uint64, e *FetchEvent) error { + session, err := c.GetSession(sessionID) + if err != nil { + return err + } + project, err := c.GetProject(session.ProjectID) + if err != nil { + return err + } + return c.Conn.InsertWebFetchEvent(sessionID, project.SaveRequestPayloads, e) +} + +func (c *PGCache) InsertWebGraphQLEvent(sessionID uint64, e *GraphQLEvent) error { + session, err := c.GetSession(sessionID) + if err != nil { + return err + } + project, err := c.GetProject(session.ProjectID) + if err != nil { + return err + } + return c.Conn.InsertWebGraphQLEvent(sessionID, project.SaveRequestPayloads, e) +} diff --git a/backend/pkg/db/postgres/messages_web.go b/backend/pkg/db/postgres/messages_web.go index 3903714ee..d3fdec446 100644 --- a/backend/pkg/db/postgres/messages_web.go +++ b/backend/pkg/db/postgres/messages_web.go @@ -39,19 +39,19 @@ func (conn *Conn) InsertWebUserAnonymousID(sessionID uint64, userAnonymousID *Us return err } -func (conn *Conn) InsertWebResourceEvent(sessionID uint64, e *ResourceEvent) error { - if e.Type != "fetch" { - return nil - } - err := conn.InsertRequest(sessionID, e.Timestamp, - e.MessageID, - e.URL, e.Duration, e.Success, - ) - if err == nil { - conn.insertAutocompleteValue(sessionID, "REQUEST", url.DiscardURLQuery(e.URL)) - } - return err -} +// func (conn *Conn) InsertWebResourceEvent(sessionID uint64, e *ResourceEvent) error { +// if e.Type != "fetch" { +// return nil +// } +// err := conn.InsertRequest(sessionID, e.Timestamp, +// e.MessageID, +// e.URL, e.Duration, e.Success, +// ) +// if err == nil { +// conn.insertAutocompleteValue(sessionID, "REQUEST", url.DiscardURLQuery(e.URL)) +// } +// return err +// } // TODO: fix column "dom_content_loaded_event_end" of relation "pages" func (conn *Conn) InsertWebPageEvent(sessionID uint64, e *PageEvent) error { @@ -203,3 +203,50 @@ func (conn *Conn) InsertWebErrorEvent(sessionID uint64, projectID uint32, e *Err } return tx.commit() } + +func (conn *Conn) InsertWebFetchEvent(sessionID uint64, savePayload bool, e *FetchEvent) error { + var request, response *string + if savePayload { + request = &e.Request + response = &e.Response + } + conn.insertAutocompleteValue(sessionID, "REQUEST", url.DiscardURLQuery(e.URL)) + return conn.batchQueue(sessionID, ` + INSERT INTO events_common.requests ( + session_id, timestamp, + seq_index, url, duration, success, + request_body, response_body, status_code, method + ) VALUES ( + $1, $2, + $3, $4, $5, $6, + $7, $8, $9, NULLIF($10, '') + )`, + sessionID, e.Timestamp, + getSqIdx(e.MessageID), e.URL, e.Duration, e.Status < 400, + request, response, e.Status, url.EnsureMethod(e.Method), + ) + +} + +func (conn *Conn) InsertWebGraphQLEvent(sessionID uint64, savePayload bool, e *GraphQLEvent) error { + var request, response *string + if savePayload { + request = &e.Variables + response = &e.Response + } + conn.insertAutocompleteValue(sessionID, "GRAPHQL", e.OperationName) + return conn.batchQueue(sessionID, ` + INSERT INTO events_common.requests ( + session_id, timestamp, message_id, + name, + request_body, response_body + ) VALUES ( + $1, $2, $3, + $4, + $5, $6 + )`, + sessionID, e.Timestamp, e.MessageID, + e.OperationName, + request, response, + ) +} diff --git a/backend/pkg/db/postgres/project.go b/backend/pkg/db/postgres/project.go index 730980176..60f21531a 100644 --- a/backend/pkg/db/postgres/project.go +++ b/backend/pkg/db/postgres/project.go @@ -7,12 +7,12 @@ import ( func (conn *Conn) GetProjectByKey(projectKey string) (*Project, error) { p := &Project{ProjectKey: projectKey} if err := conn.queryRow(` - SELECT max_session_duration, sample_rate, project_id + SELECT max_session_duration, sample_rate, project_id, save_request_payloads FROM projects WHERE project_key=$1 AND active = true `, projectKey, - ).Scan(&p.MaxSessionDuration, &p.SampleRate, &p.ProjectID); err != nil { + ).Scan(&p.MaxSessionDuration, &p.SampleRate, &p.ProjectID, &p.SaveRequestPayloads); err != nil { return nil, err } return p, nil diff --git a/backend/pkg/db/types/project.go b/backend/pkg/db/types/project.go index 7a8172061..a5bc2e82c 100644 --- a/backend/pkg/db/types/project.go +++ b/backend/pkg/db/types/project.go @@ -3,20 +3,21 @@ package types import "log" type Project struct { - ProjectID uint32 - ProjectKey string - MaxSessionDuration int64 - SampleRate byte - Metadata1 *string - Metadata2 *string - Metadata3 *string - Metadata4 *string - Metadata5 *string - Metadata6 *string - Metadata7 *string - Metadata8 *string - Metadata9 *string - Metadata10 *string + ProjectID uint32 + ProjectKey string + MaxSessionDuration int64 + SampleRate byte + SaveRequestPayloads bool + Metadata1 *string + Metadata2 *string + Metadata3 *string + Metadata4 *string + Metadata5 *string + Metadata6 *string + Metadata7 *string + Metadata8 *string + Metadata9 *string + Metadata10 *string } func (p *Project) GetMetadataNo(key string) uint { diff --git a/backend/pkg/messages/messages.go b/backend/pkg/messages/messages.go index cdff71e1d..38a1f61ba 100644 --- a/backend/pkg/messages/messages.go +++ b/backend/pkg/messages/messages.go @@ -8,8 +8,8 @@ type Message interface { type meta struct { Timestamp int64 - Index uint64 - TypeID uint64 + Index uint64 + TypeID uint64 } // Might also implement Encode() here (?) @@ -17,20 +17,20 @@ func (m *meta) Meta() *meta { return m } - type BatchMeta struct { *meta - PageNo uint64 -FirstIndex uint64 -Timestamp int64 + PageNo uint64 + FirstIndex uint64 + Timestamp int64 } -func (msg *BatchMeta) Encode() []byte{ - buf := make([]byte, 31 ) + +func (msg *BatchMeta) Encode() []byte { + buf := make([]byte, 31) buf[0] = 80 p := 1 p = WriteUint(msg.PageNo, buf, p) -p = WriteUint(msg.FirstIndex, buf, p) -p = WriteInt(msg.Timestamp, buf, p) + p = WriteUint(msg.FirstIndex, buf, p) + p = WriteInt(msg.Timestamp, buf, p) return buf[:p] } @@ -38,8 +38,9 @@ type Timestamp struct { *meta Timestamp uint64 } -func (msg *Timestamp) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *Timestamp) Encode() []byte { + buf := make([]byte, 11) buf[0] = 0 p := 1 p = WriteUint(msg.Timestamp, buf, p) @@ -48,43 +49,44 @@ func (msg *Timestamp) Encode() []byte{ type SessionStart struct { *meta - Timestamp uint64 -ProjectID uint64 -TrackerVersion string -RevID string -UserUUID string -UserAgent string -UserOS string -UserOSVersion string -UserBrowser string -UserBrowserVersion string -UserDevice string -UserDeviceType string -UserDeviceMemorySize uint64 -UserDeviceHeapSize uint64 -UserCountry string -UserID string + Timestamp uint64 + ProjectID uint64 + TrackerVersion string + RevID string + UserUUID string + UserAgent string + UserOS string + UserOSVersion string + UserBrowser string + UserBrowserVersion string + UserDevice string + UserDeviceType string + UserDeviceMemorySize uint64 + UserDeviceHeapSize uint64 + UserCountry string + UserID string } -func (msg *SessionStart) Encode() []byte{ - buf := make([]byte, 161 + len(msg.TrackerVersion)+ len(msg.RevID)+ len(msg.UserUUID)+ len(msg.UserAgent)+ len(msg.UserOS)+ len(msg.UserOSVersion)+ len(msg.UserBrowser)+ len(msg.UserBrowserVersion)+ len(msg.UserDevice)+ len(msg.UserDeviceType)+ len(msg.UserCountry)+ len(msg.UserID)) + +func (msg *SessionStart) Encode() []byte { + buf := make([]byte, 161+len(msg.TrackerVersion)+len(msg.RevID)+len(msg.UserUUID)+len(msg.UserAgent)+len(msg.UserOS)+len(msg.UserOSVersion)+len(msg.UserBrowser)+len(msg.UserBrowserVersion)+len(msg.UserDevice)+len(msg.UserDeviceType)+len(msg.UserCountry)+len(msg.UserID)) buf[0] = 1 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.ProjectID, buf, p) -p = WriteString(msg.TrackerVersion, buf, p) -p = WriteString(msg.RevID, buf, p) -p = WriteString(msg.UserUUID, buf, p) -p = WriteString(msg.UserAgent, buf, p) -p = WriteString(msg.UserOS, buf, p) -p = WriteString(msg.UserOSVersion, buf, p) -p = WriteString(msg.UserBrowser, buf, p) -p = WriteString(msg.UserBrowserVersion, buf, p) -p = WriteString(msg.UserDevice, buf, p) -p = WriteString(msg.UserDeviceType, buf, p) -p = WriteUint(msg.UserDeviceMemorySize, buf, p) -p = WriteUint(msg.UserDeviceHeapSize, buf, p) -p = WriteString(msg.UserCountry, buf, p) -p = WriteString(msg.UserID, buf, p) + p = WriteUint(msg.ProjectID, buf, p) + p = WriteString(msg.TrackerVersion, buf, p) + p = WriteString(msg.RevID, buf, p) + p = WriteString(msg.UserUUID, buf, p) + p = WriteString(msg.UserAgent, buf, p) + p = WriteString(msg.UserOS, buf, p) + p = WriteString(msg.UserOSVersion, buf, p) + p = WriteString(msg.UserBrowser, buf, p) + p = WriteString(msg.UserBrowserVersion, buf, p) + p = WriteString(msg.UserDevice, buf, p) + p = WriteString(msg.UserDeviceType, buf, p) + p = WriteUint(msg.UserDeviceMemorySize, buf, p) + p = WriteUint(msg.UserDeviceHeapSize, buf, p) + p = WriteString(msg.UserCountry, buf, p) + p = WriteString(msg.UserID, buf, p) return buf[:p] } @@ -92,8 +94,9 @@ type SessionDisconnect struct { *meta Timestamp uint64 } -func (msg *SessionDisconnect) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *SessionDisconnect) Encode() []byte { + buf := make([]byte, 11) buf[0] = 2 p := 1 p = WriteUint(msg.Timestamp, buf, p) @@ -104,8 +107,9 @@ type SessionEnd struct { *meta Timestamp uint64 } -func (msg *SessionEnd) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *SessionEnd) Encode() []byte { + buf := make([]byte, 11) buf[0] = 3 p := 1 p = WriteUint(msg.Timestamp, buf, p) @@ -114,109 +118,115 @@ func (msg *SessionEnd) Encode() []byte{ type SetPageLocation struct { *meta - URL string -Referrer string -NavigationStart uint64 + URL string + Referrer string + NavigationStart uint64 } -func (msg *SetPageLocation) Encode() []byte{ - buf := make([]byte, 31 + len(msg.URL)+ len(msg.Referrer)) + +func (msg *SetPageLocation) Encode() []byte { + buf := make([]byte, 31+len(msg.URL)+len(msg.Referrer)) buf[0] = 4 p := 1 p = WriteString(msg.URL, buf, p) -p = WriteString(msg.Referrer, buf, p) -p = WriteUint(msg.NavigationStart, buf, p) + p = WriteString(msg.Referrer, buf, p) + p = WriteUint(msg.NavigationStart, buf, p) return buf[:p] } type SetViewportSize struct { *meta - Width uint64 -Height uint64 + Width uint64 + Height uint64 } -func (msg *SetViewportSize) Encode() []byte{ - buf := make([]byte, 21 ) + +func (msg *SetViewportSize) Encode() []byte { + buf := make([]byte, 21) buf[0] = 5 p := 1 p = WriteUint(msg.Width, buf, p) -p = WriteUint(msg.Height, buf, p) + p = WriteUint(msg.Height, buf, p) return buf[:p] } type SetViewportScroll struct { *meta X int64 -Y int64 + Y int64 } -func (msg *SetViewportScroll) Encode() []byte{ - buf := make([]byte, 21 ) + +func (msg *SetViewportScroll) Encode() []byte { + buf := make([]byte, 21) buf[0] = 6 p := 1 p = WriteInt(msg.X, buf, p) -p = WriteInt(msg.Y, buf, p) + p = WriteInt(msg.Y, buf, p) return buf[:p] } type CreateDocument struct { *meta - } -func (msg *CreateDocument) Encode() []byte{ - buf := make([]byte, 1 ) + +func (msg *CreateDocument) Encode() []byte { + buf := make([]byte, 1) buf[0] = 7 p := 1 - + return buf[:p] } type CreateElementNode struct { *meta - ID uint64 -ParentID uint64 -index uint64 -Tag string -SVG bool + ID uint64 + ParentID uint64 + index uint64 + Tag string + SVG bool } -func (msg *CreateElementNode) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Tag)) + +func (msg *CreateElementNode) Encode() []byte { + buf := make([]byte, 51+len(msg.Tag)) buf[0] = 8 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteUint(msg.ParentID, buf, p) -p = WriteUint(msg.index, buf, p) -p = WriteString(msg.Tag, buf, p) -p = WriteBoolean(msg.SVG, buf, p) + p = WriteUint(msg.ParentID, buf, p) + p = WriteUint(msg.index, buf, p) + p = WriteString(msg.Tag, buf, p) + p = WriteBoolean(msg.SVG, buf, p) return buf[:p] } type CreateTextNode struct { *meta - ID uint64 -ParentID uint64 -Index uint64 + ID uint64 + ParentID uint64 + Index uint64 } -func (msg *CreateTextNode) Encode() []byte{ - buf := make([]byte, 31 ) + +func (msg *CreateTextNode) Encode() []byte { + buf := make([]byte, 31) buf[0] = 9 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteUint(msg.ParentID, buf, p) -p = WriteUint(msg.Index, buf, p) + p = WriteUint(msg.ParentID, buf, p) + p = WriteUint(msg.Index, buf, p) return buf[:p] } type MoveNode struct { *meta - ID uint64 -ParentID uint64 -Index uint64 + ID uint64 + ParentID uint64 + Index uint64 } -func (msg *MoveNode) Encode() []byte{ - buf := make([]byte, 31 ) + +func (msg *MoveNode) Encode() []byte { + buf := make([]byte, 31) buf[0] = 10 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteUint(msg.ParentID, buf, p) -p = WriteUint(msg.Index, buf, p) + p = WriteUint(msg.ParentID, buf, p) + p = WriteUint(msg.Index, buf, p) return buf[:p] } @@ -224,8 +234,9 @@ type RemoveNode struct { *meta ID uint64 } -func (msg *RemoveNode) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *RemoveNode) Encode() []byte { + buf := make([]byte, 11) buf[0] = 11 p := 1 p = WriteUint(msg.ID, buf, p) @@ -234,257 +245,273 @@ func (msg *RemoveNode) Encode() []byte{ type SetNodeAttribute struct { *meta - ID uint64 -Name string -Value string + ID uint64 + Name string + Value string } -func (msg *SetNodeAttribute) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Name)+ len(msg.Value)) + +func (msg *SetNodeAttribute) Encode() []byte { + buf := make([]byte, 31+len(msg.Name)+len(msg.Value)) buf[0] = 12 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type RemoveNodeAttribute struct { *meta - ID uint64 -Name string + ID uint64 + Name string } -func (msg *RemoveNodeAttribute) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Name)) + +func (msg *RemoveNodeAttribute) Encode() []byte { + buf := make([]byte, 21+len(msg.Name)) buf[0] = 13 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Name, buf, p) return buf[:p] } type SetNodeData struct { *meta - ID uint64 -Data string + ID uint64 + Data string } -func (msg *SetNodeData) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Data)) + +func (msg *SetNodeData) Encode() []byte { + buf := make([]byte, 21+len(msg.Data)) buf[0] = 14 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Data, buf, p) + p = WriteString(msg.Data, buf, p) return buf[:p] } type SetCSSData struct { *meta - ID uint64 -Data string + ID uint64 + Data string } -func (msg *SetCSSData) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Data)) + +func (msg *SetCSSData) Encode() []byte { + buf := make([]byte, 21+len(msg.Data)) buf[0] = 15 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Data, buf, p) + p = WriteString(msg.Data, buf, p) return buf[:p] } type SetNodeScroll struct { *meta ID uint64 -X int64 -Y int64 + X int64 + Y int64 } -func (msg *SetNodeScroll) Encode() []byte{ - buf := make([]byte, 31 ) + +func (msg *SetNodeScroll) Encode() []byte { + buf := make([]byte, 31) buf[0] = 16 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteInt(msg.X, buf, p) -p = WriteInt(msg.Y, buf, p) + p = WriteInt(msg.X, buf, p) + p = WriteInt(msg.Y, buf, p) return buf[:p] } type SetInputTarget struct { *meta - ID uint64 -Label string + ID uint64 + Label string } -func (msg *SetInputTarget) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Label)) + +func (msg *SetInputTarget) Encode() []byte { + buf := make([]byte, 21+len(msg.Label)) buf[0] = 17 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Label, buf, p) + p = WriteString(msg.Label, buf, p) return buf[:p] } type SetInputValue struct { *meta - ID uint64 -Value string -Mask int64 + ID uint64 + Value string + Mask int64 } -func (msg *SetInputValue) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Value)) + +func (msg *SetInputValue) Encode() []byte { + buf := make([]byte, 31+len(msg.Value)) buf[0] = 18 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Value, buf, p) -p = WriteInt(msg.Mask, buf, p) + p = WriteString(msg.Value, buf, p) + p = WriteInt(msg.Mask, buf, p) return buf[:p] } type SetInputChecked struct { *meta - ID uint64 -Checked bool + ID uint64 + Checked bool } -func (msg *SetInputChecked) Encode() []byte{ - buf := make([]byte, 21 ) + +func (msg *SetInputChecked) Encode() []byte { + buf := make([]byte, 21) buf[0] = 19 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteBoolean(msg.Checked, buf, p) + p = WriteBoolean(msg.Checked, buf, p) return buf[:p] } type MouseMove struct { *meta X uint64 -Y uint64 + Y uint64 } -func (msg *MouseMove) Encode() []byte{ - buf := make([]byte, 21 ) + +func (msg *MouseMove) Encode() []byte { + buf := make([]byte, 21) buf[0] = 20 p := 1 p = WriteUint(msg.X, buf, p) -p = WriteUint(msg.Y, buf, p) + p = WriteUint(msg.Y, buf, p) return buf[:p] } type MouseClickDepricated struct { *meta - ID uint64 -HesitationTime uint64 -Label string + ID uint64 + HesitationTime uint64 + Label string } -func (msg *MouseClickDepricated) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Label)) + +func (msg *MouseClickDepricated) Encode() []byte { + buf := make([]byte, 31+len(msg.Label)) buf[0] = 21 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteUint(msg.HesitationTime, buf, p) -p = WriteString(msg.Label, buf, p) + p = WriteUint(msg.HesitationTime, buf, p) + p = WriteString(msg.Label, buf, p) return buf[:p] } type ConsoleLog struct { *meta Level string -Value string + Value string } -func (msg *ConsoleLog) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Level)+ len(msg.Value)) + +func (msg *ConsoleLog) Encode() []byte { + buf := make([]byte, 21+len(msg.Level)+len(msg.Value)) buf[0] = 22 p := 1 p = WriteString(msg.Level, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type PageLoadTiming struct { *meta - RequestStart uint64 -ResponseStart uint64 -ResponseEnd uint64 -DomContentLoadedEventStart uint64 -DomContentLoadedEventEnd uint64 -LoadEventStart uint64 -LoadEventEnd uint64 -FirstPaint uint64 -FirstContentfulPaint uint64 + RequestStart uint64 + ResponseStart uint64 + ResponseEnd uint64 + DomContentLoadedEventStart uint64 + DomContentLoadedEventEnd uint64 + LoadEventStart uint64 + LoadEventEnd uint64 + FirstPaint uint64 + FirstContentfulPaint uint64 } -func (msg *PageLoadTiming) Encode() []byte{ - buf := make([]byte, 91 ) + +func (msg *PageLoadTiming) Encode() []byte { + buf := make([]byte, 91) buf[0] = 23 p := 1 p = WriteUint(msg.RequestStart, buf, p) -p = WriteUint(msg.ResponseStart, buf, p) -p = WriteUint(msg.ResponseEnd, buf, p) -p = WriteUint(msg.DomContentLoadedEventStart, buf, p) -p = WriteUint(msg.DomContentLoadedEventEnd, buf, p) -p = WriteUint(msg.LoadEventStart, buf, p) -p = WriteUint(msg.LoadEventEnd, buf, p) -p = WriteUint(msg.FirstPaint, buf, p) -p = WriteUint(msg.FirstContentfulPaint, buf, p) + p = WriteUint(msg.ResponseStart, buf, p) + p = WriteUint(msg.ResponseEnd, buf, p) + p = WriteUint(msg.DomContentLoadedEventStart, buf, p) + p = WriteUint(msg.DomContentLoadedEventEnd, buf, p) + p = WriteUint(msg.LoadEventStart, buf, p) + p = WriteUint(msg.LoadEventEnd, buf, p) + p = WriteUint(msg.FirstPaint, buf, p) + p = WriteUint(msg.FirstContentfulPaint, buf, p) return buf[:p] } type PageRenderTiming struct { *meta - SpeedIndex uint64 -VisuallyComplete uint64 -TimeToInteractive uint64 + SpeedIndex uint64 + VisuallyComplete uint64 + TimeToInteractive uint64 } -func (msg *PageRenderTiming) Encode() []byte{ - buf := make([]byte, 31 ) + +func (msg *PageRenderTiming) Encode() []byte { + buf := make([]byte, 31) buf[0] = 24 p := 1 p = WriteUint(msg.SpeedIndex, buf, p) -p = WriteUint(msg.VisuallyComplete, buf, p) -p = WriteUint(msg.TimeToInteractive, buf, p) + p = WriteUint(msg.VisuallyComplete, buf, p) + p = WriteUint(msg.TimeToInteractive, buf, p) return buf[:p] } type JSException struct { *meta - Name string -Message string -Payload string + Name string + Message string + Payload string } -func (msg *JSException) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Name)+ len(msg.Message)+ len(msg.Payload)) + +func (msg *JSException) Encode() []byte { + buf := make([]byte, 31+len(msg.Name)+len(msg.Message)+len(msg.Payload)) buf[0] = 25 p := 1 p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Message, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteString(msg.Message, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type RawErrorEvent struct { *meta Timestamp uint64 -Source string -Name string -Message string -Payload string + Source string + Name string + Message string + Payload string } -func (msg *RawErrorEvent) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Source)+ len(msg.Name)+ len(msg.Message)+ len(msg.Payload)) + +func (msg *RawErrorEvent) Encode() []byte { + buf := make([]byte, 51+len(msg.Source)+len(msg.Name)+len(msg.Message)+len(msg.Payload)) buf[0] = 26 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Source, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Message, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteString(msg.Source, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Message, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type RawCustomEvent struct { *meta - Name string -Payload string + Name string + Payload string } -func (msg *RawCustomEvent) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Name)+ len(msg.Payload)) + +func (msg *RawCustomEvent) Encode() []byte { + buf := make([]byte, 21+len(msg.Name)+len(msg.Payload)) buf[0] = 27 p := 1 p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } @@ -492,8 +519,9 @@ type UserID struct { *meta ID string } -func (msg *UserID) Encode() []byte{ - buf := make([]byte, 11 + len(msg.ID)) + +func (msg *UserID) Encode() []byte { + buf := make([]byte, 11+len(msg.ID)) buf[0] = 28 p := 1 p = WriteString(msg.ID, buf, p) @@ -504,8 +532,9 @@ type UserAnonymousID struct { *meta ID string } -func (msg *UserAnonymousID) Encode() []byte{ - buf := make([]byte, 11 + len(msg.ID)) + +func (msg *UserAnonymousID) Encode() []byte { + buf := make([]byte, 11+len(msg.ID)) buf[0] = 29 p := 1 p = WriteString(msg.ID, buf, p) @@ -514,259 +543,271 @@ func (msg *UserAnonymousID) Encode() []byte{ type Metadata struct { *meta - Key string -Value string + Key string + Value string } -func (msg *Metadata) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Key)+ len(msg.Value)) + +func (msg *Metadata) Encode() []byte { + buf := make([]byte, 21+len(msg.Key)+len(msg.Value)) buf[0] = 30 p := 1 p = WriteString(msg.Key, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type PageEvent struct { *meta - MessageID uint64 -Timestamp uint64 -URL string -Referrer string -Loaded bool -RequestStart uint64 -ResponseStart uint64 -ResponseEnd uint64 -DomContentLoadedEventStart uint64 -DomContentLoadedEventEnd uint64 -LoadEventStart uint64 -LoadEventEnd uint64 -FirstPaint uint64 -FirstContentfulPaint uint64 -SpeedIndex uint64 -VisuallyComplete uint64 -TimeToInteractive uint64 + MessageID uint64 + Timestamp uint64 + URL string + Referrer string + Loaded bool + RequestStart uint64 + ResponseStart uint64 + ResponseEnd uint64 + DomContentLoadedEventStart uint64 + DomContentLoadedEventEnd uint64 + LoadEventStart uint64 + LoadEventEnd uint64 + FirstPaint uint64 + FirstContentfulPaint uint64 + SpeedIndex uint64 + VisuallyComplete uint64 + TimeToInteractive uint64 } -func (msg *PageEvent) Encode() []byte{ - buf := make([]byte, 171 + len(msg.URL)+ len(msg.Referrer)) + +func (msg *PageEvent) Encode() []byte { + buf := make([]byte, 171+len(msg.URL)+len(msg.Referrer)) buf[0] = 31 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.URL, buf, p) -p = WriteString(msg.Referrer, buf, p) -p = WriteBoolean(msg.Loaded, buf, p) -p = WriteUint(msg.RequestStart, buf, p) -p = WriteUint(msg.ResponseStart, buf, p) -p = WriteUint(msg.ResponseEnd, buf, p) -p = WriteUint(msg.DomContentLoadedEventStart, buf, p) -p = WriteUint(msg.DomContentLoadedEventEnd, buf, p) -p = WriteUint(msg.LoadEventStart, buf, p) -p = WriteUint(msg.LoadEventEnd, buf, p) -p = WriteUint(msg.FirstPaint, buf, p) -p = WriteUint(msg.FirstContentfulPaint, buf, p) -p = WriteUint(msg.SpeedIndex, buf, p) -p = WriteUint(msg.VisuallyComplete, buf, p) -p = WriteUint(msg.TimeToInteractive, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.URL, buf, p) + p = WriteString(msg.Referrer, buf, p) + p = WriteBoolean(msg.Loaded, buf, p) + p = WriteUint(msg.RequestStart, buf, p) + p = WriteUint(msg.ResponseStart, buf, p) + p = WriteUint(msg.ResponseEnd, buf, p) + p = WriteUint(msg.DomContentLoadedEventStart, buf, p) + p = WriteUint(msg.DomContentLoadedEventEnd, buf, p) + p = WriteUint(msg.LoadEventStart, buf, p) + p = WriteUint(msg.LoadEventEnd, buf, p) + p = WriteUint(msg.FirstPaint, buf, p) + p = WriteUint(msg.FirstContentfulPaint, buf, p) + p = WriteUint(msg.SpeedIndex, buf, p) + p = WriteUint(msg.VisuallyComplete, buf, p) + p = WriteUint(msg.TimeToInteractive, buf, p) return buf[:p] } type InputEvent struct { *meta - MessageID uint64 -Timestamp uint64 -Value string -ValueMasked bool -Label string + MessageID uint64 + Timestamp uint64 + Value string + ValueMasked bool + Label string } -func (msg *InputEvent) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Value)+ len(msg.Label)) + +func (msg *InputEvent) Encode() []byte { + buf := make([]byte, 51+len(msg.Value)+len(msg.Label)) buf[0] = 32 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Value, buf, p) -p = WriteBoolean(msg.ValueMasked, buf, p) -p = WriteString(msg.Label, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.Value, buf, p) + p = WriteBoolean(msg.ValueMasked, buf, p) + p = WriteString(msg.Label, buf, p) return buf[:p] } type ClickEvent struct { *meta - MessageID uint64 -Timestamp uint64 -HesitationTime uint64 -Label string -Selector string + MessageID uint64 + Timestamp uint64 + HesitationTime uint64 + Label string + Selector string } -func (msg *ClickEvent) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Label)+ len(msg.Selector)) + +func (msg *ClickEvent) Encode() []byte { + buf := make([]byte, 51+len(msg.Label)+len(msg.Selector)) buf[0] = 33 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.HesitationTime, buf, p) -p = WriteString(msg.Label, buf, p) -p = WriteString(msg.Selector, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteUint(msg.HesitationTime, buf, p) + p = WriteString(msg.Label, buf, p) + p = WriteString(msg.Selector, buf, p) return buf[:p] } type ErrorEvent struct { *meta MessageID uint64 -Timestamp uint64 -Source string -Name string -Message string -Payload string + Timestamp uint64 + Source string + Name string + Message string + Payload string } -func (msg *ErrorEvent) Encode() []byte{ - buf := make([]byte, 61 + len(msg.Source)+ len(msg.Name)+ len(msg.Message)+ len(msg.Payload)) + +func (msg *ErrorEvent) Encode() []byte { + buf := make([]byte, 61+len(msg.Source)+len(msg.Name)+len(msg.Message)+len(msg.Payload)) buf[0] = 34 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Source, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Message, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.Source, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Message, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type ResourceEvent struct { *meta - MessageID uint64 -Timestamp uint64 -Duration uint64 -TTFB uint64 -HeaderSize uint64 -EncodedBodySize uint64 -DecodedBodySize uint64 -URL string -Type string -Success bool -Method string -Status uint64 + MessageID uint64 + Timestamp uint64 + Duration uint64 + TTFB uint64 + HeaderSize uint64 + EncodedBodySize uint64 + DecodedBodySize uint64 + URL string + Type string + Success bool + Method string + Status uint64 } -func (msg *ResourceEvent) Encode() []byte{ - buf := make([]byte, 121 + len(msg.URL)+ len(msg.Type)+ len(msg.Method)) + +func (msg *ResourceEvent) Encode() []byte { + buf := make([]byte, 121+len(msg.URL)+len(msg.Type)+len(msg.Method)) buf[0] = 35 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Duration, buf, p) -p = WriteUint(msg.TTFB, buf, p) -p = WriteUint(msg.HeaderSize, buf, p) -p = WriteUint(msg.EncodedBodySize, buf, p) -p = WriteUint(msg.DecodedBodySize, buf, p) -p = WriteString(msg.URL, buf, p) -p = WriteString(msg.Type, buf, p) -p = WriteBoolean(msg.Success, buf, p) -p = WriteString(msg.Method, buf, p) -p = WriteUint(msg.Status, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteUint(msg.Duration, buf, p) + p = WriteUint(msg.TTFB, buf, p) + p = WriteUint(msg.HeaderSize, buf, p) + p = WriteUint(msg.EncodedBodySize, buf, p) + p = WriteUint(msg.DecodedBodySize, buf, p) + p = WriteString(msg.URL, buf, p) + p = WriteString(msg.Type, buf, p) + p = WriteBoolean(msg.Success, buf, p) + p = WriteString(msg.Method, buf, p) + p = WriteUint(msg.Status, buf, p) return buf[:p] } type CustomEvent struct { *meta MessageID uint64 -Timestamp uint64 -Name string -Payload string + Timestamp uint64 + Name string + Payload string } -func (msg *CustomEvent) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Name)+ len(msg.Payload)) + +func (msg *CustomEvent) Encode() []byte { + buf := make([]byte, 41+len(msg.Name)+len(msg.Payload)) buf[0] = 36 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type CSSInsertRule struct { *meta - ID uint64 -Rule string -Index uint64 + ID uint64 + Rule string + Index uint64 } -func (msg *CSSInsertRule) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Rule)) + +func (msg *CSSInsertRule) Encode() []byte { + buf := make([]byte, 31+len(msg.Rule)) buf[0] = 37 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Rule, buf, p) -p = WriteUint(msg.Index, buf, p) + p = WriteString(msg.Rule, buf, p) + p = WriteUint(msg.Index, buf, p) return buf[:p] } type CSSDeleteRule struct { *meta - ID uint64 -Index uint64 + ID uint64 + Index uint64 } -func (msg *CSSDeleteRule) Encode() []byte{ - buf := make([]byte, 21 ) + +func (msg *CSSDeleteRule) Encode() []byte { + buf := make([]byte, 21) buf[0] = 38 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteUint(msg.Index, buf, p) + p = WriteUint(msg.Index, buf, p) return buf[:p] } type Fetch struct { *meta - Method string -URL string -Request string -Response string -Status uint64 -Timestamp uint64 -Duration uint64 + Method string + URL string + Request string + Response string + Status uint64 + Timestamp uint64 + Duration uint64 } -func (msg *Fetch) Encode() []byte{ - buf := make([]byte, 71 + len(msg.Method)+ len(msg.URL)+ len(msg.Request)+ len(msg.Response)) + +func (msg *Fetch) Encode() []byte { + buf := make([]byte, 71+len(msg.Method)+len(msg.URL)+len(msg.Request)+len(msg.Response)) buf[0] = 39 p := 1 p = WriteString(msg.Method, buf, p) -p = WriteString(msg.URL, buf, p) -p = WriteString(msg.Request, buf, p) -p = WriteString(msg.Response, buf, p) -p = WriteUint(msg.Status, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Duration, buf, p) + p = WriteString(msg.URL, buf, p) + p = WriteString(msg.Request, buf, p) + p = WriteString(msg.Response, buf, p) + p = WriteUint(msg.Status, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteUint(msg.Duration, buf, p) return buf[:p] } type Profiler struct { *meta - Name string -Duration uint64 -Args string -Result string + Name string + Duration uint64 + Args string + Result string } -func (msg *Profiler) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Name)+ len(msg.Args)+ len(msg.Result)) + +func (msg *Profiler) Encode() []byte { + buf := make([]byte, 41+len(msg.Name)+len(msg.Args)+len(msg.Result)) buf[0] = 40 p := 1 p = WriteString(msg.Name, buf, p) -p = WriteUint(msg.Duration, buf, p) -p = WriteString(msg.Args, buf, p) -p = WriteString(msg.Result, buf, p) + p = WriteUint(msg.Duration, buf, p) + p = WriteString(msg.Args, buf, p) + p = WriteString(msg.Result, buf, p) return buf[:p] } type OTable struct { *meta - Key string -Value string + Key string + Value string } -func (msg *OTable) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Key)+ len(msg.Value)) + +func (msg *OTable) Encode() []byte { + buf := make([]byte, 21+len(msg.Key)+len(msg.Value)) buf[0] = 41 p := 1 p = WriteString(msg.Key, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } @@ -774,8 +815,9 @@ type StateAction struct { *meta Type string } -func (msg *StateAction) Encode() []byte{ - buf := make([]byte, 11 + len(msg.Type)) + +func (msg *StateAction) Encode() []byte { + buf := make([]byte, 11+len(msg.Type)) buf[0] = 42 p := 1 p = WriteString(msg.Type, buf, p) @@ -785,128 +827,169 @@ func (msg *StateAction) Encode() []byte{ type StateActionEvent struct { *meta MessageID uint64 -Timestamp uint64 -Type string + Timestamp uint64 + Type string } -func (msg *StateActionEvent) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Type)) + +func (msg *StateActionEvent) Encode() []byte { + buf := make([]byte, 31+len(msg.Type)) buf[0] = 43 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Type, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.Type, buf, p) return buf[:p] } type Redux struct { *meta - Action string -State string -Duration uint64 + Action string + State string + Duration uint64 } -func (msg *Redux) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Action)+ len(msg.State)) + +func (msg *Redux) Encode() []byte { + buf := make([]byte, 31+len(msg.Action)+len(msg.State)) buf[0] = 44 p := 1 p = WriteString(msg.Action, buf, p) -p = WriteString(msg.State, buf, p) -p = WriteUint(msg.Duration, buf, p) + p = WriteString(msg.State, buf, p) + p = WriteUint(msg.Duration, buf, p) return buf[:p] } type Vuex struct { *meta Mutation string -State string + State string } -func (msg *Vuex) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Mutation)+ len(msg.State)) + +func (msg *Vuex) Encode() []byte { + buf := make([]byte, 21+len(msg.Mutation)+len(msg.State)) buf[0] = 45 p := 1 p = WriteString(msg.Mutation, buf, p) -p = WriteString(msg.State, buf, p) + p = WriteString(msg.State, buf, p) return buf[:p] } type MobX struct { *meta - Type string -Payload string + Type string + Payload string } -func (msg *MobX) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Type)+ len(msg.Payload)) + +func (msg *MobX) Encode() []byte { + buf := make([]byte, 21+len(msg.Type)+len(msg.Payload)) buf[0] = 46 p := 1 p = WriteString(msg.Type, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type NgRx struct { *meta - Action string -State string -Duration uint64 + Action string + State string + Duration uint64 } -func (msg *NgRx) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Action)+ len(msg.State)) + +func (msg *NgRx) Encode() []byte { + buf := make([]byte, 31+len(msg.Action)+len(msg.State)) buf[0] = 47 p := 1 p = WriteString(msg.Action, buf, p) -p = WriteString(msg.State, buf, p) -p = WriteUint(msg.Duration, buf, p) + p = WriteString(msg.State, buf, p) + p = WriteUint(msg.Duration, buf, p) return buf[:p] } type GraphQL struct { *meta OperationKind string -OperationName string -Variables string -Response string + OperationName string + Variables string + Response string } -func (msg *GraphQL) Encode() []byte{ - buf := make([]byte, 41 + len(msg.OperationKind)+ len(msg.OperationName)+ len(msg.Variables)+ len(msg.Response)) + +func (msg *GraphQL) Encode() []byte { + buf := make([]byte, 41+len(msg.OperationKind)+len(msg.OperationName)+len(msg.Variables)+len(msg.Response)) buf[0] = 48 p := 1 p = WriteString(msg.OperationKind, buf, p) -p = WriteString(msg.OperationName, buf, p) -p = WriteString(msg.Variables, buf, p) -p = WriteString(msg.Response, buf, p) + p = WriteString(msg.OperationName, buf, p) + p = WriteString(msg.Variables, buf, p) + p = WriteString(msg.Response, buf, p) return buf[:p] } type PerformanceTrack struct { *meta - Frames int64 -Ticks int64 -TotalJSHeapSize uint64 -UsedJSHeapSize uint64 + Frames int64 + Ticks int64 + TotalJSHeapSize uint64 + UsedJSHeapSize uint64 } -func (msg *PerformanceTrack) Encode() []byte{ - buf := make([]byte, 41 ) + +func (msg *PerformanceTrack) Encode() []byte { + buf := make([]byte, 41) buf[0] = 49 p := 1 p = WriteInt(msg.Frames, buf, p) -p = WriteInt(msg.Ticks, buf, p) -p = WriteUint(msg.TotalJSHeapSize, buf, p) -p = WriteUint(msg.UsedJSHeapSize, buf, p) + p = WriteInt(msg.Ticks, buf, p) + p = WriteUint(msg.TotalJSHeapSize, buf, p) + p = WriteUint(msg.UsedJSHeapSize, buf, p) return buf[:p] } type GraphQLEvent struct { *meta - MessageID uint64 -Timestamp uint64 -Name string + MessageID uint64 + Timestamp uint64 + OperationKind string + OperationName string + Variables string + Response string } -func (msg *GraphQLEvent) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Name)) + +func (msg *GraphQLEvent) Encode() []byte { + buf := make([]byte, 61+len(msg.OperationKind)+len(msg.OperationName)+len(msg.Variables)+len(msg.Response)) buf[0] = 50 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Name, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.OperationKind, buf, p) + p = WriteString(msg.OperationName, buf, p) + p = WriteString(msg.Variables, buf, p) + p = WriteString(msg.Response, buf, p) + return buf[:p] +} + +type FetchEvent struct { + *meta + MessageID uint64 + Timestamp uint64 + Method string + URL string + Request string + Response string + Status uint64 + Duration uint64 +} + +func (msg *FetchEvent) Encode() []byte { + buf := make([]byte, 81+len(msg.Method)+len(msg.URL)+len(msg.Request)+len(msg.Response)) + buf[0] = 51 + p := 1 + p = WriteUint(msg.MessageID, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.Method, buf, p) + p = WriteString(msg.URL, buf, p) + p = WriteString(msg.Request, buf, p) + p = WriteString(msg.Response, buf, p) + p = WriteUint(msg.Status, buf, p) + p = WriteUint(msg.Duration, buf, p) return buf[:p] } @@ -914,8 +997,9 @@ type DOMDrop struct { *meta Timestamp uint64 } -func (msg *DOMDrop) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *DOMDrop) Encode() []byte { + buf := make([]byte, 11) buf[0] = 52 p := 1 p = WriteUint(msg.Timestamp, buf, p) @@ -924,41 +1008,43 @@ func (msg *DOMDrop) Encode() []byte{ type ResourceTiming struct { *meta - Timestamp uint64 -Duration uint64 -TTFB uint64 -HeaderSize uint64 -EncodedBodySize uint64 -DecodedBodySize uint64 -URL string -Initiator string + Timestamp uint64 + Duration uint64 + TTFB uint64 + HeaderSize uint64 + EncodedBodySize uint64 + DecodedBodySize uint64 + URL string + Initiator string } -func (msg *ResourceTiming) Encode() []byte{ - buf := make([]byte, 81 + len(msg.URL)+ len(msg.Initiator)) + +func (msg *ResourceTiming) Encode() []byte { + buf := make([]byte, 81+len(msg.URL)+len(msg.Initiator)) buf[0] = 53 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Duration, buf, p) -p = WriteUint(msg.TTFB, buf, p) -p = WriteUint(msg.HeaderSize, buf, p) -p = WriteUint(msg.EncodedBodySize, buf, p) -p = WriteUint(msg.DecodedBodySize, buf, p) -p = WriteString(msg.URL, buf, p) -p = WriteString(msg.Initiator, buf, p) + p = WriteUint(msg.Duration, buf, p) + p = WriteUint(msg.TTFB, buf, p) + p = WriteUint(msg.HeaderSize, buf, p) + p = WriteUint(msg.EncodedBodySize, buf, p) + p = WriteUint(msg.DecodedBodySize, buf, p) + p = WriteString(msg.URL, buf, p) + p = WriteString(msg.Initiator, buf, p) return buf[:p] } type ConnectionInformation struct { *meta Downlink uint64 -Type string + Type string } -func (msg *ConnectionInformation) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Type)) + +func (msg *ConnectionInformation) Encode() []byte { + buf := make([]byte, 21+len(msg.Type)) buf[0] = 54 p := 1 p = WriteUint(msg.Downlink, buf, p) -p = WriteString(msg.Type, buf, p) + p = WriteString(msg.Type, buf, p) return buf[:p] } @@ -966,8 +1052,9 @@ type SetPageVisibility struct { *meta hidden bool } -func (msg *SetPageVisibility) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *SetPageVisibility) Encode() []byte { + buf := make([]byte, 11) buf[0] = 55 p := 1 p = WriteBoolean(msg.hidden, buf, p) @@ -976,159 +1063,166 @@ func (msg *SetPageVisibility) Encode() []byte{ type PerformanceTrackAggr struct { *meta - TimestampStart uint64 -TimestampEnd uint64 -MinFPS uint64 -AvgFPS uint64 -MaxFPS uint64 -MinCPU uint64 -AvgCPU uint64 -MaxCPU uint64 -MinTotalJSHeapSize uint64 -AvgTotalJSHeapSize uint64 -MaxTotalJSHeapSize uint64 -MinUsedJSHeapSize uint64 -AvgUsedJSHeapSize uint64 -MaxUsedJSHeapSize uint64 + TimestampStart uint64 + TimestampEnd uint64 + MinFPS uint64 + AvgFPS uint64 + MaxFPS uint64 + MinCPU uint64 + AvgCPU uint64 + MaxCPU uint64 + MinTotalJSHeapSize uint64 + AvgTotalJSHeapSize uint64 + MaxTotalJSHeapSize uint64 + MinUsedJSHeapSize uint64 + AvgUsedJSHeapSize uint64 + MaxUsedJSHeapSize uint64 } -func (msg *PerformanceTrackAggr) Encode() []byte{ - buf := make([]byte, 141 ) + +func (msg *PerformanceTrackAggr) Encode() []byte { + buf := make([]byte, 141) buf[0] = 56 p := 1 p = WriteUint(msg.TimestampStart, buf, p) -p = WriteUint(msg.TimestampEnd, buf, p) -p = WriteUint(msg.MinFPS, buf, p) -p = WriteUint(msg.AvgFPS, buf, p) -p = WriteUint(msg.MaxFPS, buf, p) -p = WriteUint(msg.MinCPU, buf, p) -p = WriteUint(msg.AvgCPU, buf, p) -p = WriteUint(msg.MaxCPU, buf, p) -p = WriteUint(msg.MinTotalJSHeapSize, buf, p) -p = WriteUint(msg.AvgTotalJSHeapSize, buf, p) -p = WriteUint(msg.MaxTotalJSHeapSize, buf, p) -p = WriteUint(msg.MinUsedJSHeapSize, buf, p) -p = WriteUint(msg.AvgUsedJSHeapSize, buf, p) -p = WriteUint(msg.MaxUsedJSHeapSize, buf, p) + p = WriteUint(msg.TimestampEnd, buf, p) + p = WriteUint(msg.MinFPS, buf, p) + p = WriteUint(msg.AvgFPS, buf, p) + p = WriteUint(msg.MaxFPS, buf, p) + p = WriteUint(msg.MinCPU, buf, p) + p = WriteUint(msg.AvgCPU, buf, p) + p = WriteUint(msg.MaxCPU, buf, p) + p = WriteUint(msg.MinTotalJSHeapSize, buf, p) + p = WriteUint(msg.AvgTotalJSHeapSize, buf, p) + p = WriteUint(msg.MaxTotalJSHeapSize, buf, p) + p = WriteUint(msg.MinUsedJSHeapSize, buf, p) + p = WriteUint(msg.AvgUsedJSHeapSize, buf, p) + p = WriteUint(msg.MaxUsedJSHeapSize, buf, p) return buf[:p] } type LongTask struct { *meta - Timestamp uint64 -Duration uint64 -Context uint64 -ContainerType uint64 -ContainerSrc string -ContainerId string -ContainerName string + Timestamp uint64 + Duration uint64 + Context uint64 + ContainerType uint64 + ContainerSrc string + ContainerId string + ContainerName string } -func (msg *LongTask) Encode() []byte{ - buf := make([]byte, 71 + len(msg.ContainerSrc)+ len(msg.ContainerId)+ len(msg.ContainerName)) + +func (msg *LongTask) Encode() []byte { + buf := make([]byte, 71+len(msg.ContainerSrc)+len(msg.ContainerId)+len(msg.ContainerName)) buf[0] = 59 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Duration, buf, p) -p = WriteUint(msg.Context, buf, p) -p = WriteUint(msg.ContainerType, buf, p) -p = WriteString(msg.ContainerSrc, buf, p) -p = WriteString(msg.ContainerId, buf, p) -p = WriteString(msg.ContainerName, buf, p) + p = WriteUint(msg.Duration, buf, p) + p = WriteUint(msg.Context, buf, p) + p = WriteUint(msg.ContainerType, buf, p) + p = WriteString(msg.ContainerSrc, buf, p) + p = WriteString(msg.ContainerId, buf, p) + p = WriteString(msg.ContainerName, buf, p) return buf[:p] } type SetNodeAttributeURLBased struct { *meta - ID uint64 -Name string -Value string -BaseURL string + ID uint64 + Name string + Value string + BaseURL string } -func (msg *SetNodeAttributeURLBased) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Name)+ len(msg.Value)+ len(msg.BaseURL)) + +func (msg *SetNodeAttributeURLBased) Encode() []byte { + buf := make([]byte, 41+len(msg.Name)+len(msg.Value)+len(msg.BaseURL)) buf[0] = 60 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Value, buf, p) -p = WriteString(msg.BaseURL, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Value, buf, p) + p = WriteString(msg.BaseURL, buf, p) return buf[:p] } type SetCSSDataURLBased struct { *meta - ID uint64 -Data string -BaseURL string + ID uint64 + Data string + BaseURL string } -func (msg *SetCSSDataURLBased) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Data)+ len(msg.BaseURL)) + +func (msg *SetCSSDataURLBased) Encode() []byte { + buf := make([]byte, 31+len(msg.Data)+len(msg.BaseURL)) buf[0] = 61 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Data, buf, p) -p = WriteString(msg.BaseURL, buf, p) + p = WriteString(msg.Data, buf, p) + p = WriteString(msg.BaseURL, buf, p) return buf[:p] } type IssueEvent struct { *meta - MessageID uint64 -Timestamp uint64 -Type string -ContextString string -Context string -Payload string + MessageID uint64 + Timestamp uint64 + Type string + ContextString string + Context string + Payload string } -func (msg *IssueEvent) Encode() []byte{ - buf := make([]byte, 61 + len(msg.Type)+ len(msg.ContextString)+ len(msg.Context)+ len(msg.Payload)) + +func (msg *IssueEvent) Encode() []byte { + buf := make([]byte, 61+len(msg.Type)+len(msg.ContextString)+len(msg.Context)+len(msg.Payload)) buf[0] = 62 p := 1 p = WriteUint(msg.MessageID, buf, p) -p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Type, buf, p) -p = WriteString(msg.ContextString, buf, p) -p = WriteString(msg.Context, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteUint(msg.Timestamp, buf, p) + p = WriteString(msg.Type, buf, p) + p = WriteString(msg.ContextString, buf, p) + p = WriteString(msg.Context, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type TechnicalInfo struct { *meta - Type string -Value string + Type string + Value string } -func (msg *TechnicalInfo) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Type)+ len(msg.Value)) + +func (msg *TechnicalInfo) Encode() []byte { + buf := make([]byte, 21+len(msg.Type)+len(msg.Value)) buf[0] = 63 p := 1 p = WriteString(msg.Type, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type CustomIssue struct { *meta - Name string -Payload string + Name string + Payload string } -func (msg *CustomIssue) Encode() []byte{ - buf := make([]byte, 21 + len(msg.Name)+ len(msg.Payload)) + +func (msg *CustomIssue) Encode() []byte { + buf := make([]byte, 21+len(msg.Name)+len(msg.Payload)) buf[0] = 64 p := 1 p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type PageClose struct { *meta - } -func (msg *PageClose) Encode() []byte{ - buf := make([]byte, 1 ) + +func (msg *PageClose) Encode() []byte { + buf := make([]byte, 1) buf[0] = 65 p := 1 - + return buf[:p] } @@ -1136,8 +1230,9 @@ type AssetCache struct { *meta URL string } -func (msg *AssetCache) Encode() []byte{ - buf := make([]byte, 11 + len(msg.URL)) + +func (msg *AssetCache) Encode() []byte { + buf := make([]byte, 11+len(msg.URL)) buf[0] = 66 p := 1 p = WriteString(msg.URL, buf, p) @@ -1146,97 +1241,102 @@ func (msg *AssetCache) Encode() []byte{ type CSSInsertRuleURLBased struct { *meta - ID uint64 -Rule string -Index uint64 -BaseURL string + ID uint64 + Rule string + Index uint64 + BaseURL string } -func (msg *CSSInsertRuleURLBased) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Rule)+ len(msg.BaseURL)) + +func (msg *CSSInsertRuleURLBased) Encode() []byte { + buf := make([]byte, 41+len(msg.Rule)+len(msg.BaseURL)) buf[0] = 67 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteString(msg.Rule, buf, p) -p = WriteUint(msg.Index, buf, p) -p = WriteString(msg.BaseURL, buf, p) + p = WriteString(msg.Rule, buf, p) + p = WriteUint(msg.Index, buf, p) + p = WriteString(msg.BaseURL, buf, p) return buf[:p] } type MouseClick struct { *meta - ID uint64 -HesitationTime uint64 -Label string -Selector string + ID uint64 + HesitationTime uint64 + Label string + Selector string } -func (msg *MouseClick) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Label)+ len(msg.Selector)) + +func (msg *MouseClick) Encode() []byte { + buf := make([]byte, 41+len(msg.Label)+len(msg.Selector)) buf[0] = 69 p := 1 p = WriteUint(msg.ID, buf, p) -p = WriteUint(msg.HesitationTime, buf, p) -p = WriteString(msg.Label, buf, p) -p = WriteString(msg.Selector, buf, p) + p = WriteUint(msg.HesitationTime, buf, p) + p = WriteString(msg.Label, buf, p) + p = WriteString(msg.Selector, buf, p) return buf[:p] } type CreateIFrameDocument struct { *meta FrameID uint64 -ID uint64 + ID uint64 } -func (msg *CreateIFrameDocument) Encode() []byte{ - buf := make([]byte, 21 ) + +func (msg *CreateIFrameDocument) Encode() []byte { + buf := make([]byte, 21) buf[0] = 70 p := 1 p = WriteUint(msg.FrameID, buf, p) -p = WriteUint(msg.ID, buf, p) + p = WriteUint(msg.ID, buf, p) return buf[:p] } type IOSBatchMeta struct { *meta - Timestamp uint64 -Length uint64 -FirstIndex uint64 + Timestamp uint64 + Length uint64 + FirstIndex uint64 } -func (msg *IOSBatchMeta) Encode() []byte{ - buf := make([]byte, 31 ) + +func (msg *IOSBatchMeta) Encode() []byte { + buf := make([]byte, 31) buf[0] = 107 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteUint(msg.FirstIndex, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteUint(msg.FirstIndex, buf, p) return buf[:p] } type IOSSessionStart struct { *meta - Timestamp uint64 -ProjectID uint64 -TrackerVersion string -RevID string -UserUUID string -UserOS string -UserOSVersion string -UserDevice string -UserDeviceType string -UserCountry string + Timestamp uint64 + ProjectID uint64 + TrackerVersion string + RevID string + UserUUID string + UserOS string + UserOSVersion string + UserDevice string + UserDeviceType string + UserCountry string } -func (msg *IOSSessionStart) Encode() []byte{ - buf := make([]byte, 101 + len(msg.TrackerVersion)+ len(msg.RevID)+ len(msg.UserUUID)+ len(msg.UserOS)+ len(msg.UserOSVersion)+ len(msg.UserDevice)+ len(msg.UserDeviceType)+ len(msg.UserCountry)) + +func (msg *IOSSessionStart) Encode() []byte { + buf := make([]byte, 101+len(msg.TrackerVersion)+len(msg.RevID)+len(msg.UserUUID)+len(msg.UserOS)+len(msg.UserOSVersion)+len(msg.UserDevice)+len(msg.UserDeviceType)+len(msg.UserCountry)) buf[0] = 90 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.ProjectID, buf, p) -p = WriteString(msg.TrackerVersion, buf, p) -p = WriteString(msg.RevID, buf, p) -p = WriteString(msg.UserUUID, buf, p) -p = WriteString(msg.UserOS, buf, p) -p = WriteString(msg.UserOSVersion, buf, p) -p = WriteString(msg.UserDevice, buf, p) -p = WriteString(msg.UserDeviceType, buf, p) -p = WriteString(msg.UserCountry, buf, p) + p = WriteUint(msg.ProjectID, buf, p) + p = WriteString(msg.TrackerVersion, buf, p) + p = WriteString(msg.RevID, buf, p) + p = WriteString(msg.UserUUID, buf, p) + p = WriteString(msg.UserOS, buf, p) + p = WriteString(msg.UserOSVersion, buf, p) + p = WriteString(msg.UserDevice, buf, p) + p = WriteString(msg.UserDeviceType, buf, p) + p = WriteString(msg.UserCountry, buf, p) return buf[:p] } @@ -1244,8 +1344,9 @@ type IOSSessionEnd struct { *meta Timestamp uint64 } -func (msg *IOSSessionEnd) Encode() []byte{ - buf := make([]byte, 11 ) + +func (msg *IOSSessionEnd) Encode() []byte { + buf := make([]byte, 11) buf[0] = 91 p := 1 p = WriteUint(msg.Timestamp, buf, p) @@ -1255,324 +1356,339 @@ func (msg *IOSSessionEnd) Encode() []byte{ type IOSMetadata struct { *meta Timestamp uint64 -Length uint64 -Key string -Value string + Length uint64 + Key string + Value string } -func (msg *IOSMetadata) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Key)+ len(msg.Value)) + +func (msg *IOSMetadata) Encode() []byte { + buf := make([]byte, 41+len(msg.Key)+len(msg.Value)) buf[0] = 92 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Key, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Key, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type IOSCustomEvent struct { *meta Timestamp uint64 -Length uint64 -Name string -Payload string + Length uint64 + Name string + Payload string } -func (msg *IOSCustomEvent) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Name)+ len(msg.Payload)) + +func (msg *IOSCustomEvent) Encode() []byte { + buf := make([]byte, 41+len(msg.Name)+len(msg.Payload)) buf[0] = 93 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } type IOSUserID struct { *meta Timestamp uint64 -Length uint64 -Value string + Length uint64 + Value string } -func (msg *IOSUserID) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Value)) + +func (msg *IOSUserID) Encode() []byte { + buf := make([]byte, 31+len(msg.Value)) buf[0] = 94 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type IOSUserAnonymousID struct { *meta Timestamp uint64 -Length uint64 -Value string + Length uint64 + Value string } -func (msg *IOSUserAnonymousID) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Value)) + +func (msg *IOSUserAnonymousID) Encode() []byte { + buf := make([]byte, 31+len(msg.Value)) buf[0] = 95 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Value, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Value, buf, p) return buf[:p] } type IOSScreenChanges struct { *meta Timestamp uint64 -Length uint64 -X uint64 -Y uint64 -Width uint64 -Height uint64 + Length uint64 + X uint64 + Y uint64 + Width uint64 + Height uint64 } -func (msg *IOSScreenChanges) Encode() []byte{ - buf := make([]byte, 61 ) + +func (msg *IOSScreenChanges) Encode() []byte { + buf := make([]byte, 61) buf[0] = 96 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteUint(msg.X, buf, p) -p = WriteUint(msg.Y, buf, p) -p = WriteUint(msg.Width, buf, p) -p = WriteUint(msg.Height, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteUint(msg.X, buf, p) + p = WriteUint(msg.Y, buf, p) + p = WriteUint(msg.Width, buf, p) + p = WriteUint(msg.Height, buf, p) return buf[:p] } type IOSCrash struct { *meta - Timestamp uint64 -Length uint64 -Name string -Reason string -Stacktrace string + Timestamp uint64 + Length uint64 + Name string + Reason string + Stacktrace string } -func (msg *IOSCrash) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Name)+ len(msg.Reason)+ len(msg.Stacktrace)) + +func (msg *IOSCrash) Encode() []byte { + buf := make([]byte, 51+len(msg.Name)+len(msg.Reason)+len(msg.Stacktrace)) buf[0] = 97 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteString(msg.Reason, buf, p) -p = WriteString(msg.Stacktrace, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteString(msg.Reason, buf, p) + p = WriteString(msg.Stacktrace, buf, p) return buf[:p] } type IOSScreenEnter struct { *meta Timestamp uint64 -Length uint64 -Title string -ViewName string + Length uint64 + Title string + ViewName string } -func (msg *IOSScreenEnter) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Title)+ len(msg.ViewName)) + +func (msg *IOSScreenEnter) Encode() []byte { + buf := make([]byte, 41+len(msg.Title)+len(msg.ViewName)) buf[0] = 98 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Title, buf, p) -p = WriteString(msg.ViewName, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Title, buf, p) + p = WriteString(msg.ViewName, buf, p) return buf[:p] } type IOSScreenLeave struct { *meta Timestamp uint64 -Length uint64 -Title string -ViewName string + Length uint64 + Title string + ViewName string } -func (msg *IOSScreenLeave) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Title)+ len(msg.ViewName)) + +func (msg *IOSScreenLeave) Encode() []byte { + buf := make([]byte, 41+len(msg.Title)+len(msg.ViewName)) buf[0] = 99 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Title, buf, p) -p = WriteString(msg.ViewName, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Title, buf, p) + p = WriteString(msg.ViewName, buf, p) return buf[:p] } type IOSClickEvent struct { *meta Timestamp uint64 -Length uint64 -Label string -X uint64 -Y uint64 + Length uint64 + Label string + X uint64 + Y uint64 } -func (msg *IOSClickEvent) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Label)) + +func (msg *IOSClickEvent) Encode() []byte { + buf := make([]byte, 51+len(msg.Label)) buf[0] = 100 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Label, buf, p) -p = WriteUint(msg.X, buf, p) -p = WriteUint(msg.Y, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Label, buf, p) + p = WriteUint(msg.X, buf, p) + p = WriteUint(msg.Y, buf, p) return buf[:p] } type IOSInputEvent struct { *meta - Timestamp uint64 -Length uint64 -Value string -ValueMasked bool -Label string + Timestamp uint64 + Length uint64 + Value string + ValueMasked bool + Label string } -func (msg *IOSInputEvent) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Value)+ len(msg.Label)) + +func (msg *IOSInputEvent) Encode() []byte { + buf := make([]byte, 51+len(msg.Value)+len(msg.Label)) buf[0] = 101 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Value, buf, p) -p = WriteBoolean(msg.ValueMasked, buf, p) -p = WriteString(msg.Label, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Value, buf, p) + p = WriteBoolean(msg.ValueMasked, buf, p) + p = WriteString(msg.Label, buf, p) return buf[:p] } type IOSPerformanceEvent struct { *meta Timestamp uint64 -Length uint64 -Name string -Value uint64 + Length uint64 + Name string + Value uint64 } -func (msg *IOSPerformanceEvent) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Name)) + +func (msg *IOSPerformanceEvent) Encode() []byte { + buf := make([]byte, 41+len(msg.Name)) buf[0] = 102 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Name, buf, p) -p = WriteUint(msg.Value, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Name, buf, p) + p = WriteUint(msg.Value, buf, p) return buf[:p] } type IOSLog struct { *meta Timestamp uint64 -Length uint64 -Severity string -Content string + Length uint64 + Severity string + Content string } -func (msg *IOSLog) Encode() []byte{ - buf := make([]byte, 41 + len(msg.Severity)+ len(msg.Content)) + +func (msg *IOSLog) Encode() []byte { + buf := make([]byte, 41+len(msg.Severity)+len(msg.Content)) buf[0] = 103 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Severity, buf, p) -p = WriteString(msg.Content, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Severity, buf, p) + p = WriteString(msg.Content, buf, p) return buf[:p] } type IOSInternalError struct { *meta Timestamp uint64 -Length uint64 -Content string + Length uint64 + Content string } -func (msg *IOSInternalError) Encode() []byte{ - buf := make([]byte, 31 + len(msg.Content)) + +func (msg *IOSInternalError) Encode() []byte { + buf := make([]byte, 31+len(msg.Content)) buf[0] = 104 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteString(msg.Content, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteString(msg.Content, buf, p) return buf[:p] } type IOSNetworkCall struct { *meta Timestamp uint64 -Length uint64 -Duration uint64 -Headers string -Body string -URL string -Success bool -Method string -Status uint64 + Length uint64 + Duration uint64 + Headers string + Body string + URL string + Success bool + Method string + Status uint64 } -func (msg *IOSNetworkCall) Encode() []byte{ - buf := make([]byte, 91 + len(msg.Headers)+ len(msg.Body)+ len(msg.URL)+ len(msg.Method)) + +func (msg *IOSNetworkCall) Encode() []byte { + buf := make([]byte, 91+len(msg.Headers)+len(msg.Body)+len(msg.URL)+len(msg.Method)) buf[0] = 105 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteUint(msg.Length, buf, p) -p = WriteUint(msg.Duration, buf, p) -p = WriteString(msg.Headers, buf, p) -p = WriteString(msg.Body, buf, p) -p = WriteString(msg.URL, buf, p) -p = WriteBoolean(msg.Success, buf, p) -p = WriteString(msg.Method, buf, p) -p = WriteUint(msg.Status, buf, p) + p = WriteUint(msg.Length, buf, p) + p = WriteUint(msg.Duration, buf, p) + p = WriteString(msg.Headers, buf, p) + p = WriteString(msg.Body, buf, p) + p = WriteString(msg.URL, buf, p) + p = WriteBoolean(msg.Success, buf, p) + p = WriteString(msg.Method, buf, p) + p = WriteUint(msg.Status, buf, p) return buf[:p] } type IOSPerformanceAggregated struct { *meta TimestampStart uint64 -TimestampEnd uint64 -MinFPS uint64 -AvgFPS uint64 -MaxFPS uint64 -MinCPU uint64 -AvgCPU uint64 -MaxCPU uint64 -MinMemory uint64 -AvgMemory uint64 -MaxMemory uint64 -MinBattery uint64 -AvgBattery uint64 -MaxBattery uint64 + TimestampEnd uint64 + MinFPS uint64 + AvgFPS uint64 + MaxFPS uint64 + MinCPU uint64 + AvgCPU uint64 + MaxCPU uint64 + MinMemory uint64 + AvgMemory uint64 + MaxMemory uint64 + MinBattery uint64 + AvgBattery uint64 + MaxBattery uint64 } -func (msg *IOSPerformanceAggregated) Encode() []byte{ - buf := make([]byte, 141 ) + +func (msg *IOSPerformanceAggregated) Encode() []byte { + buf := make([]byte, 141) buf[0] = 110 p := 1 p = WriteUint(msg.TimestampStart, buf, p) -p = WriteUint(msg.TimestampEnd, buf, p) -p = WriteUint(msg.MinFPS, buf, p) -p = WriteUint(msg.AvgFPS, buf, p) -p = WriteUint(msg.MaxFPS, buf, p) -p = WriteUint(msg.MinCPU, buf, p) -p = WriteUint(msg.AvgCPU, buf, p) -p = WriteUint(msg.MaxCPU, buf, p) -p = WriteUint(msg.MinMemory, buf, p) -p = WriteUint(msg.AvgMemory, buf, p) -p = WriteUint(msg.MaxMemory, buf, p) -p = WriteUint(msg.MinBattery, buf, p) -p = WriteUint(msg.AvgBattery, buf, p) -p = WriteUint(msg.MaxBattery, buf, p) + p = WriteUint(msg.TimestampEnd, buf, p) + p = WriteUint(msg.MinFPS, buf, p) + p = WriteUint(msg.AvgFPS, buf, p) + p = WriteUint(msg.MaxFPS, buf, p) + p = WriteUint(msg.MinCPU, buf, p) + p = WriteUint(msg.AvgCPU, buf, p) + p = WriteUint(msg.MaxCPU, buf, p) + p = WriteUint(msg.MinMemory, buf, p) + p = WriteUint(msg.AvgMemory, buf, p) + p = WriteUint(msg.MaxMemory, buf, p) + p = WriteUint(msg.MinBattery, buf, p) + p = WriteUint(msg.AvgBattery, buf, p) + p = WriteUint(msg.MaxBattery, buf, p) return buf[:p] } type IOSIssueEvent struct { *meta - Timestamp uint64 -Type string -ContextString string -Context string -Payload string + Timestamp uint64 + Type string + ContextString string + Context string + Payload string } -func (msg *IOSIssueEvent) Encode() []byte{ - buf := make([]byte, 51 + len(msg.Type)+ len(msg.ContextString)+ len(msg.Context)+ len(msg.Payload)) + +func (msg *IOSIssueEvent) Encode() []byte { + buf := make([]byte, 51+len(msg.Type)+len(msg.ContextString)+len(msg.Context)+len(msg.Payload)) buf[0] = 111 p := 1 p = WriteUint(msg.Timestamp, buf, p) -p = WriteString(msg.Type, buf, p) -p = WriteString(msg.ContextString, buf, p) -p = WriteString(msg.Context, buf, p) -p = WriteString(msg.Payload, buf, p) + p = WriteString(msg.Type, buf, p) + p = WriteString(msg.ContextString, buf, p) + p = WriteString(msg.Context, buf, p) + p = WriteString(msg.Payload, buf, p) return buf[:p] } - diff --git a/backend/pkg/messages/read_message.go b/backend/pkg/messages/read_message.go index c226df728..31512c9c8 100644 --- a/backend/pkg/messages/read_message.go +++ b/backend/pkg/messages/read_message.go @@ -7,704 +7,1425 @@ import ( ) func ReadMessage(reader io.Reader) (Message, error) { - t, err := ReadUint(reader); + t, err := ReadUint(reader) if err != nil { return nil, err } switch t { - - case 80: - msg := &BatchMeta{ meta: &meta{ TypeID: 80} } - if msg.PageNo, err = ReadUint(reader); err != nil { return nil, err } -if msg.FirstIndex, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadInt(reader); err != nil { return nil, err } - return msg, nil - - case 0: - msg := &Timestamp{ meta: &meta{ TypeID: 0} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 1: - msg := &SessionStart{ meta: &meta{ TypeID: 1} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.ProjectID, err = ReadUint(reader); err != nil { return nil, err } -if msg.TrackerVersion, err = ReadString(reader); err != nil { return nil, err } -if msg.RevID, err = ReadString(reader); err != nil { return nil, err } -if msg.UserUUID, err = ReadString(reader); err != nil { return nil, err } -if msg.UserAgent, err = ReadString(reader); err != nil { return nil, err } -if msg.UserOS, err = ReadString(reader); err != nil { return nil, err } -if msg.UserOSVersion, err = ReadString(reader); err != nil { return nil, err } -if msg.UserBrowser, err = ReadString(reader); err != nil { return nil, err } -if msg.UserBrowserVersion, err = ReadString(reader); err != nil { return nil, err } -if msg.UserDevice, err = ReadString(reader); err != nil { return nil, err } -if msg.UserDeviceType, err = ReadString(reader); err != nil { return nil, err } -if msg.UserDeviceMemorySize, err = ReadUint(reader); err != nil { return nil, err } -if msg.UserDeviceHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.UserCountry, err = ReadString(reader); err != nil { return nil, err } -if msg.UserID, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 2: - msg := &SessionDisconnect{ meta: &meta{ TypeID: 2} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 3: - msg := &SessionEnd{ meta: &meta{ TypeID: 3} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 4: - msg := &SetPageLocation{ meta: &meta{ TypeID: 4} } - if msg.URL, err = ReadString(reader); err != nil { return nil, err } -if msg.Referrer, err = ReadString(reader); err != nil { return nil, err } -if msg.NavigationStart, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 5: - msg := &SetViewportSize{ meta: &meta{ TypeID: 5} } - if msg.Width, err = ReadUint(reader); err != nil { return nil, err } -if msg.Height, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 6: - msg := &SetViewportScroll{ meta: &meta{ TypeID: 6} } - if msg.X, err = ReadInt(reader); err != nil { return nil, err } -if msg.Y, err = ReadInt(reader); err != nil { return nil, err } - return msg, nil - - case 7: - msg := &CreateDocument{ meta: &meta{ TypeID: 7} } - - return msg, nil - - case 8: - msg := &CreateElementNode{ meta: &meta{ TypeID: 8} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.ParentID, err = ReadUint(reader); err != nil { return nil, err } -if msg.index, err = ReadUint(reader); err != nil { return nil, err } -if msg.Tag, err = ReadString(reader); err != nil { return nil, err } -if msg.SVG, err = ReadBoolean(reader); err != nil { return nil, err } - return msg, nil - - case 9: - msg := &CreateTextNode{ meta: &meta{ TypeID: 9} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.ParentID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Index, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 10: - msg := &MoveNode{ meta: &meta{ TypeID: 10} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.ParentID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Index, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 11: - msg := &RemoveNode{ meta: &meta{ TypeID: 11} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 12: - msg := &SetNodeAttribute{ meta: &meta{ TypeID: 12} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 13: - msg := &RemoveNodeAttribute{ meta: &meta{ TypeID: 13} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 14: - msg := &SetNodeData{ meta: &meta{ TypeID: 14} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Data, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 15: - msg := &SetCSSData{ meta: &meta{ TypeID: 15} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Data, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 16: - msg := &SetNodeScroll{ meta: &meta{ TypeID: 16} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.X, err = ReadInt(reader); err != nil { return nil, err } -if msg.Y, err = ReadInt(reader); err != nil { return nil, err } - return msg, nil - - case 17: - msg := &SetInputTarget{ meta: &meta{ TypeID: 17} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 18: - msg := &SetInputValue{ meta: &meta{ TypeID: 18} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } -if msg.Mask, err = ReadInt(reader); err != nil { return nil, err } - return msg, nil - - case 19: - msg := &SetInputChecked{ meta: &meta{ TypeID: 19} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Checked, err = ReadBoolean(reader); err != nil { return nil, err } - return msg, nil - - case 20: - msg := &MouseMove{ meta: &meta{ TypeID: 20} } - if msg.X, err = ReadUint(reader); err != nil { return nil, err } -if msg.Y, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 21: - msg := &MouseClickDepricated{ meta: &meta{ TypeID: 21} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.HesitationTime, err = ReadUint(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 22: - msg := &ConsoleLog{ meta: &meta{ TypeID: 22} } - if msg.Level, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 23: - msg := &PageLoadTiming{ meta: &meta{ TypeID: 23} } - if msg.RequestStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.ResponseStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.ResponseEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.DomContentLoadedEventStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.DomContentLoadedEventEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.LoadEventStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.LoadEventEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.FirstPaint, err = ReadUint(reader); err != nil { return nil, err } -if msg.FirstContentfulPaint, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 24: - msg := &PageRenderTiming{ meta: &meta{ TypeID: 24} } - if msg.SpeedIndex, err = ReadUint(reader); err != nil { return nil, err } -if msg.VisuallyComplete, err = ReadUint(reader); err != nil { return nil, err } -if msg.TimeToInteractive, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 25: - msg := &JSException{ meta: &meta{ TypeID: 25} } - if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Message, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 26: - msg := &RawErrorEvent{ meta: &meta{ TypeID: 26} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Source, err = ReadString(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Message, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 27: - msg := &RawCustomEvent{ meta: &meta{ TypeID: 27} } - if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 28: - msg := &UserID{ meta: &meta{ TypeID: 28} } - if msg.ID, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 29: - msg := &UserAnonymousID{ meta: &meta{ TypeID: 29} } - if msg.ID, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 30: - msg := &Metadata{ meta: &meta{ TypeID: 30} } - if msg.Key, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 31: - msg := &PageEvent{ meta: &meta{ TypeID: 31} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.URL, err = ReadString(reader); err != nil { return nil, err } -if msg.Referrer, err = ReadString(reader); err != nil { return nil, err } -if msg.Loaded, err = ReadBoolean(reader); err != nil { return nil, err } -if msg.RequestStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.ResponseStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.ResponseEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.DomContentLoadedEventStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.DomContentLoadedEventEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.LoadEventStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.LoadEventEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.FirstPaint, err = ReadUint(reader); err != nil { return nil, err } -if msg.FirstContentfulPaint, err = ReadUint(reader); err != nil { return nil, err } -if msg.SpeedIndex, err = ReadUint(reader); err != nil { return nil, err } -if msg.VisuallyComplete, err = ReadUint(reader); err != nil { return nil, err } -if msg.TimeToInteractive, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 32: - msg := &InputEvent{ meta: &meta{ TypeID: 32} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } -if msg.ValueMasked, err = ReadBoolean(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 33: - msg := &ClickEvent{ meta: &meta{ TypeID: 33} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.HesitationTime, err = ReadUint(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } -if msg.Selector, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 34: - msg := &ErrorEvent{ meta: &meta{ TypeID: 34} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Source, err = ReadString(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Message, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 35: - msg := &ResourceEvent{ meta: &meta{ TypeID: 35} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } -if msg.TTFB, err = ReadUint(reader); err != nil { return nil, err } -if msg.HeaderSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.EncodedBodySize, err = ReadUint(reader); err != nil { return nil, err } -if msg.DecodedBodySize, err = ReadUint(reader); err != nil { return nil, err } -if msg.URL, err = ReadString(reader); err != nil { return nil, err } -if msg.Type, err = ReadString(reader); err != nil { return nil, err } -if msg.Success, err = ReadBoolean(reader); err != nil { return nil, err } -if msg.Method, err = ReadString(reader); err != nil { return nil, err } -if msg.Status, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 36: - msg := &CustomEvent{ meta: &meta{ TypeID: 36} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 37: - msg := &CSSInsertRule{ meta: &meta{ TypeID: 37} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Rule, err = ReadString(reader); err != nil { return nil, err } -if msg.Index, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 38: - msg := &CSSDeleteRule{ meta: &meta{ TypeID: 38} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Index, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 39: - msg := &Fetch{ meta: &meta{ TypeID: 39} } - if msg.Method, err = ReadString(reader); err != nil { return nil, err } -if msg.URL, err = ReadString(reader); err != nil { return nil, err } -if msg.Request, err = ReadString(reader); err != nil { return nil, err } -if msg.Response, err = ReadString(reader); err != nil { return nil, err } -if msg.Status, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 40: - msg := &Profiler{ meta: &meta{ TypeID: 40} } - if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } -if msg.Args, err = ReadString(reader); err != nil { return nil, err } -if msg.Result, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 41: - msg := &OTable{ meta: &meta{ TypeID: 41} } - if msg.Key, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 42: - msg := &StateAction{ meta: &meta{ TypeID: 42} } - if msg.Type, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 43: - msg := &StateActionEvent{ meta: &meta{ TypeID: 43} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Type, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 44: - msg := &Redux{ meta: &meta{ TypeID: 44} } - if msg.Action, err = ReadString(reader); err != nil { return nil, err } -if msg.State, err = ReadString(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 45: - msg := &Vuex{ meta: &meta{ TypeID: 45} } - if msg.Mutation, err = ReadString(reader); err != nil { return nil, err } -if msg.State, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 46: - msg := &MobX{ meta: &meta{ TypeID: 46} } - if msg.Type, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 47: - msg := &NgRx{ meta: &meta{ TypeID: 47} } - if msg.Action, err = ReadString(reader); err != nil { return nil, err } -if msg.State, err = ReadString(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 48: - msg := &GraphQL{ meta: &meta{ TypeID: 48} } - if msg.OperationKind, err = ReadString(reader); err != nil { return nil, err } -if msg.OperationName, err = ReadString(reader); err != nil { return nil, err } -if msg.Variables, err = ReadString(reader); err != nil { return nil, err } -if msg.Response, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 49: - msg := &PerformanceTrack{ meta: &meta{ TypeID: 49} } - if msg.Frames, err = ReadInt(reader); err != nil { return nil, err } -if msg.Ticks, err = ReadInt(reader); err != nil { return nil, err } -if msg.TotalJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.UsedJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 50: - msg := &GraphQLEvent{ meta: &meta{ TypeID: 50} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 52: - msg := &DOMDrop{ meta: &meta{ TypeID: 52} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 53: - msg := &ResourceTiming{ meta: &meta{ TypeID: 53} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } -if msg.TTFB, err = ReadUint(reader); err != nil { return nil, err } -if msg.HeaderSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.EncodedBodySize, err = ReadUint(reader); err != nil { return nil, err } -if msg.DecodedBodySize, err = ReadUint(reader); err != nil { return nil, err } -if msg.URL, err = ReadString(reader); err != nil { return nil, err } -if msg.Initiator, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 54: - msg := &ConnectionInformation{ meta: &meta{ TypeID: 54} } - if msg.Downlink, err = ReadUint(reader); err != nil { return nil, err } -if msg.Type, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 55: - msg := &SetPageVisibility{ meta: &meta{ TypeID: 55} } - if msg.hidden, err = ReadBoolean(reader); err != nil { return nil, err } - return msg, nil - - case 56: - msg := &PerformanceTrackAggr{ meta: &meta{ TypeID: 56} } - if msg.TimestampStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.TimestampEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinFPS, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgFPS, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxFPS, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinCPU, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgCPU, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxCPU, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinTotalJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgTotalJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxTotalJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinUsedJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgUsedJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxUsedJSHeapSize, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 59: - msg := &LongTask{ meta: &meta{ TypeID: 59} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } -if msg.Context, err = ReadUint(reader); err != nil { return nil, err } -if msg.ContainerType, err = ReadUint(reader); err != nil { return nil, err } -if msg.ContainerSrc, err = ReadString(reader); err != nil { return nil, err } -if msg.ContainerId, err = ReadString(reader); err != nil { return nil, err } -if msg.ContainerName, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 60: - msg := &SetNodeAttributeURLBased{ meta: &meta{ TypeID: 60} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } -if msg.BaseURL, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 61: - msg := &SetCSSDataURLBased{ meta: &meta{ TypeID: 61} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Data, err = ReadString(reader); err != nil { return nil, err } -if msg.BaseURL, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 62: - msg := &IssueEvent{ meta: &meta{ TypeID: 62} } - if msg.MessageID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Type, err = ReadString(reader); err != nil { return nil, err } -if msg.ContextString, err = ReadString(reader); err != nil { return nil, err } -if msg.Context, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 63: - msg := &TechnicalInfo{ meta: &meta{ TypeID: 63} } - if msg.Type, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 64: - msg := &CustomIssue{ meta: &meta{ TypeID: 64} } - if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 65: - msg := &PageClose{ meta: &meta{ TypeID: 65} } - - return msg, nil - - case 66: - msg := &AssetCache{ meta: &meta{ TypeID: 66} } - if msg.URL, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 67: - msg := &CSSInsertRuleURLBased{ meta: &meta{ TypeID: 67} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.Rule, err = ReadString(reader); err != nil { return nil, err } -if msg.Index, err = ReadUint(reader); err != nil { return nil, err } -if msg.BaseURL, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 69: - msg := &MouseClick{ meta: &meta{ TypeID: 69} } - if msg.ID, err = ReadUint(reader); err != nil { return nil, err } -if msg.HesitationTime, err = ReadUint(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } -if msg.Selector, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 70: - msg := &CreateIFrameDocument{ meta: &meta{ TypeID: 70} } - if msg.FrameID, err = ReadUint(reader); err != nil { return nil, err } -if msg.ID, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 107: - msg := &IOSBatchMeta{ meta: &meta{ TypeID: 107} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.FirstIndex, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 90: - msg := &IOSSessionStart{ meta: &meta{ TypeID: 90} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.ProjectID, err = ReadUint(reader); err != nil { return nil, err } -if msg.TrackerVersion, err = ReadString(reader); err != nil { return nil, err } -if msg.RevID, err = ReadString(reader); err != nil { return nil, err } -if msg.UserUUID, err = ReadString(reader); err != nil { return nil, err } -if msg.UserOS, err = ReadString(reader); err != nil { return nil, err } -if msg.UserOSVersion, err = ReadString(reader); err != nil { return nil, err } -if msg.UserDevice, err = ReadString(reader); err != nil { return nil, err } -if msg.UserDeviceType, err = ReadString(reader); err != nil { return nil, err } -if msg.UserCountry, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 91: - msg := &IOSSessionEnd{ meta: &meta{ TypeID: 91} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 92: - msg := &IOSMetadata{ meta: &meta{ TypeID: 92} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Key, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 93: - msg := &IOSCustomEvent{ meta: &meta{ TypeID: 93} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 94: - msg := &IOSUserID{ meta: &meta{ TypeID: 94} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 95: - msg := &IOSUserAnonymousID{ meta: &meta{ TypeID: 95} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 96: - msg := &IOSScreenChanges{ meta: &meta{ TypeID: 96} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.X, err = ReadUint(reader); err != nil { return nil, err } -if msg.Y, err = ReadUint(reader); err != nil { return nil, err } -if msg.Width, err = ReadUint(reader); err != nil { return nil, err } -if msg.Height, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 97: - msg := &IOSCrash{ meta: &meta{ TypeID: 97} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Reason, err = ReadString(reader); err != nil { return nil, err } -if msg.Stacktrace, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 98: - msg := &IOSScreenEnter{ meta: &meta{ TypeID: 98} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Title, err = ReadString(reader); err != nil { return nil, err } -if msg.ViewName, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 99: - msg := &IOSScreenLeave{ meta: &meta{ TypeID: 99} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Title, err = ReadString(reader); err != nil { return nil, err } -if msg.ViewName, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 100: - msg := &IOSClickEvent{ meta: &meta{ TypeID: 100} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } -if msg.X, err = ReadUint(reader); err != nil { return nil, err } -if msg.Y, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 101: - msg := &IOSInputEvent{ meta: &meta{ TypeID: 101} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Value, err = ReadString(reader); err != nil { return nil, err } -if msg.ValueMasked, err = ReadBoolean(reader); err != nil { return nil, err } -if msg.Label, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 102: - msg := &IOSPerformanceEvent{ meta: &meta{ TypeID: 102} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Name, err = ReadString(reader); err != nil { return nil, err } -if msg.Value, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 103: - msg := &IOSLog{ meta: &meta{ TypeID: 103} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Severity, err = ReadString(reader); err != nil { return nil, err } -if msg.Content, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 104: - msg := &IOSInternalError{ meta: &meta{ TypeID: 104} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Content, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - - case 105: - msg := &IOSNetworkCall{ meta: &meta{ TypeID: 105} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Length, err = ReadUint(reader); err != nil { return nil, err } -if msg.Duration, err = ReadUint(reader); err != nil { return nil, err } -if msg.Headers, err = ReadString(reader); err != nil { return nil, err } -if msg.Body, err = ReadString(reader); err != nil { return nil, err } -if msg.URL, err = ReadString(reader); err != nil { return nil, err } -if msg.Success, err = ReadBoolean(reader); err != nil { return nil, err } -if msg.Method, err = ReadString(reader); err != nil { return nil, err } -if msg.Status, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 110: - msg := &IOSPerformanceAggregated{ meta: &meta{ TypeID: 110} } - if msg.TimestampStart, err = ReadUint(reader); err != nil { return nil, err } -if msg.TimestampEnd, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinFPS, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgFPS, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxFPS, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinCPU, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgCPU, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxCPU, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinMemory, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgMemory, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxMemory, err = ReadUint(reader); err != nil { return nil, err } -if msg.MinBattery, err = ReadUint(reader); err != nil { return nil, err } -if msg.AvgBattery, err = ReadUint(reader); err != nil { return nil, err } -if msg.MaxBattery, err = ReadUint(reader); err != nil { return nil, err } - return msg, nil - - case 111: - msg := &IOSIssueEvent{ meta: &meta{ TypeID: 111} } - if msg.Timestamp, err = ReadUint(reader); err != nil { return nil, err } -if msg.Type, err = ReadString(reader); err != nil { return nil, err } -if msg.ContextString, err = ReadString(reader); err != nil { return nil, err } -if msg.Context, err = ReadString(reader); err != nil { return nil, err } -if msg.Payload, err = ReadString(reader); err != nil { return nil, err } - return msg, nil - + + case 80: + msg := &BatchMeta{meta: &meta{TypeID: 80}} + if msg.PageNo, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.FirstIndex, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadInt(reader); err != nil { + return nil, err + } + return msg, nil + + case 0: + msg := &Timestamp{meta: &meta{TypeID: 0}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 1: + msg := &SessionStart{meta: &meta{TypeID: 1}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ProjectID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TrackerVersion, err = ReadString(reader); err != nil { + return nil, err + } + if msg.RevID, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserUUID, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserAgent, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserOS, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserOSVersion, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserBrowser, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserBrowserVersion, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserDevice, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserDeviceType, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserDeviceMemorySize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.UserDeviceHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.UserCountry, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserID, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 2: + msg := &SessionDisconnect{meta: &meta{TypeID: 2}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 3: + msg := &SessionEnd{meta: &meta{TypeID: 3}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 4: + msg := &SetPageLocation{meta: &meta{TypeID: 4}} + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Referrer, err = ReadString(reader); err != nil { + return nil, err + } + if msg.NavigationStart, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 5: + msg := &SetViewportSize{meta: &meta{TypeID: 5}} + if msg.Width, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Height, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 6: + msg := &SetViewportScroll{meta: &meta{TypeID: 6}} + if msg.X, err = ReadInt(reader); err != nil { + return nil, err + } + if msg.Y, err = ReadInt(reader); err != nil { + return nil, err + } + return msg, nil + + case 7: + msg := &CreateDocument{meta: &meta{TypeID: 7}} + + return msg, nil + + case 8: + msg := &CreateElementNode{meta: &meta{TypeID: 8}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ParentID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.index, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Tag, err = ReadString(reader); err != nil { + return nil, err + } + if msg.SVG, err = ReadBoolean(reader); err != nil { + return nil, err + } + return msg, nil + + case 9: + msg := &CreateTextNode{meta: &meta{TypeID: 9}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ParentID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Index, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 10: + msg := &MoveNode{meta: &meta{TypeID: 10}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ParentID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Index, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 11: + msg := &RemoveNode{meta: &meta{TypeID: 11}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 12: + msg := &SetNodeAttribute{meta: &meta{TypeID: 12}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 13: + msg := &RemoveNodeAttribute{meta: &meta{TypeID: 13}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 14: + msg := &SetNodeData{meta: &meta{TypeID: 14}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Data, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 15: + msg := &SetCSSData{meta: &meta{TypeID: 15}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Data, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 16: + msg := &SetNodeScroll{meta: &meta{TypeID: 16}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.X, err = ReadInt(reader); err != nil { + return nil, err + } + if msg.Y, err = ReadInt(reader); err != nil { + return nil, err + } + return msg, nil + + case 17: + msg := &SetInputTarget{meta: &meta{TypeID: 17}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 18: + msg := &SetInputValue{meta: &meta{TypeID: 18}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Mask, err = ReadInt(reader); err != nil { + return nil, err + } + return msg, nil + + case 19: + msg := &SetInputChecked{meta: &meta{TypeID: 19}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Checked, err = ReadBoolean(reader); err != nil { + return nil, err + } + return msg, nil + + case 20: + msg := &MouseMove{meta: &meta{TypeID: 20}} + if msg.X, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Y, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 21: + msg := &MouseClickDepricated{meta: &meta{TypeID: 21}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.HesitationTime, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 22: + msg := &ConsoleLog{meta: &meta{TypeID: 22}} + if msg.Level, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 23: + msg := &PageLoadTiming{meta: &meta{TypeID: 23}} + if msg.RequestStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ResponseStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ResponseEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.DomContentLoadedEventStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.DomContentLoadedEventEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.LoadEventStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.LoadEventEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.FirstPaint, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.FirstContentfulPaint, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 24: + msg := &PageRenderTiming{meta: &meta{TypeID: 24}} + if msg.SpeedIndex, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.VisuallyComplete, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TimeToInteractive, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 25: + msg := &JSException{meta: &meta{TypeID: 25}} + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Message, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 26: + msg := &RawErrorEvent{meta: &meta{TypeID: 26}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Source, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Message, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 27: + msg := &RawCustomEvent{meta: &meta{TypeID: 27}} + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 28: + msg := &UserID{meta: &meta{TypeID: 28}} + if msg.ID, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 29: + msg := &UserAnonymousID{meta: &meta{TypeID: 29}} + if msg.ID, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 30: + msg := &Metadata{meta: &meta{TypeID: 30}} + if msg.Key, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 31: + msg := &PageEvent{meta: &meta{TypeID: 31}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Referrer, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Loaded, err = ReadBoolean(reader); err != nil { + return nil, err + } + if msg.RequestStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ResponseStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ResponseEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.DomContentLoadedEventStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.DomContentLoadedEventEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.LoadEventStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.LoadEventEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.FirstPaint, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.FirstContentfulPaint, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.SpeedIndex, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.VisuallyComplete, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TimeToInteractive, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 32: + msg := &InputEvent{meta: &meta{TypeID: 32}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ValueMasked, err = ReadBoolean(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 33: + msg := &ClickEvent{meta: &meta{TypeID: 33}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.HesitationTime, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Selector, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 34: + msg := &ErrorEvent{meta: &meta{TypeID: 34}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Source, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Message, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 35: + msg := &ResourceEvent{meta: &meta{TypeID: 35}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TTFB, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.HeaderSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.EncodedBodySize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.DecodedBodySize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Success, err = ReadBoolean(reader); err != nil { + return nil, err + } + if msg.Method, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Status, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 36: + msg := &CustomEvent{meta: &meta{TypeID: 36}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 37: + msg := &CSSInsertRule{meta: &meta{TypeID: 37}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Rule, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Index, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 38: + msg := &CSSDeleteRule{meta: &meta{TypeID: 38}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Index, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 39: + msg := &Fetch{meta: &meta{TypeID: 39}} + if msg.Method, err = ReadString(reader); err != nil { + return nil, err + } + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Request, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Response, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Status, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 40: + msg := &Profiler{meta: &meta{TypeID: 40}} + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Args, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Result, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 41: + msg := &OTable{meta: &meta{TypeID: 41}} + if msg.Key, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 42: + msg := &StateAction{meta: &meta{TypeID: 42}} + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 43: + msg := &StateActionEvent{meta: &meta{TypeID: 43}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 44: + msg := &Redux{meta: &meta{TypeID: 44}} + if msg.Action, err = ReadString(reader); err != nil { + return nil, err + } + if msg.State, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 45: + msg := &Vuex{meta: &meta{TypeID: 45}} + if msg.Mutation, err = ReadString(reader); err != nil { + return nil, err + } + if msg.State, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 46: + msg := &MobX{meta: &meta{TypeID: 46}} + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 47: + msg := &NgRx{meta: &meta{TypeID: 47}} + if msg.Action, err = ReadString(reader); err != nil { + return nil, err + } + if msg.State, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 48: + msg := &GraphQL{meta: &meta{TypeID: 48}} + if msg.OperationKind, err = ReadString(reader); err != nil { + return nil, err + } + if msg.OperationName, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Variables, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Response, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 49: + msg := &PerformanceTrack{meta: &meta{TypeID: 49}} + if msg.Frames, err = ReadInt(reader); err != nil { + return nil, err + } + if msg.Ticks, err = ReadInt(reader); err != nil { + return nil, err + } + if msg.TotalJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.UsedJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 50: + msg := &GraphQLEvent{meta: &meta{TypeID: 50}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.OperationKind, err = ReadString(reader); err != nil { + return nil, err + } + if msg.OperationName, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Variables, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Response, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 51: + msg := &FetchEvent{meta: &meta{TypeID: 51}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Method, err = ReadString(reader); err != nil { + return nil, err + } + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Request, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Response, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Status, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 52: + msg := &DOMDrop{meta: &meta{TypeID: 52}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 53: + msg := &ResourceTiming{meta: &meta{TypeID: 53}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TTFB, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.HeaderSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.EncodedBodySize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.DecodedBodySize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Initiator, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 54: + msg := &ConnectionInformation{meta: &meta{TypeID: 54}} + if msg.Downlink, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 55: + msg := &SetPageVisibility{meta: &meta{TypeID: 55}} + if msg.hidden, err = ReadBoolean(reader); err != nil { + return nil, err + } + return msg, nil + + case 56: + msg := &PerformanceTrackAggr{meta: &meta{TypeID: 56}} + if msg.TimestampStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TimestampEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinFPS, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgFPS, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxFPS, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinCPU, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgCPU, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxCPU, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinTotalJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgTotalJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxTotalJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinUsedJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgUsedJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxUsedJSHeapSize, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 59: + msg := &LongTask{meta: &meta{TypeID: 59}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Context, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ContainerType, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ContainerSrc, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ContainerId, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ContainerName, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 60: + msg := &SetNodeAttributeURLBased{meta: &meta{TypeID: 60}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + if msg.BaseURL, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 61: + msg := &SetCSSDataURLBased{meta: &meta{TypeID: 61}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Data, err = ReadString(reader); err != nil { + return nil, err + } + if msg.BaseURL, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 62: + msg := &IssueEvent{meta: &meta{TypeID: 62}} + if msg.MessageID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ContextString, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Context, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 63: + msg := &TechnicalInfo{meta: &meta{TypeID: 63}} + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 64: + msg := &CustomIssue{meta: &meta{TypeID: 64}} + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 65: + msg := &PageClose{meta: &meta{TypeID: 65}} + + return msg, nil + + case 66: + msg := &AssetCache{meta: &meta{TypeID: 66}} + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 67: + msg := &CSSInsertRuleURLBased{meta: &meta{TypeID: 67}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Rule, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Index, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.BaseURL, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 69: + msg := &MouseClick{meta: &meta{TypeID: 69}} + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.HesitationTime, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Selector, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 70: + msg := &CreateIFrameDocument{meta: &meta{TypeID: 70}} + if msg.FrameID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ID, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 107: + msg := &IOSBatchMeta{meta: &meta{TypeID: 107}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.FirstIndex, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 90: + msg := &IOSSessionStart{meta: &meta{TypeID: 90}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.ProjectID, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TrackerVersion, err = ReadString(reader); err != nil { + return nil, err + } + if msg.RevID, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserUUID, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserOS, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserOSVersion, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserDevice, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserDeviceType, err = ReadString(reader); err != nil { + return nil, err + } + if msg.UserCountry, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 91: + msg := &IOSSessionEnd{meta: &meta{TypeID: 91}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 92: + msg := &IOSMetadata{meta: &meta{TypeID: 92}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Key, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 93: + msg := &IOSCustomEvent{meta: &meta{TypeID: 93}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 94: + msg := &IOSUserID{meta: &meta{TypeID: 94}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 95: + msg := &IOSUserAnonymousID{meta: &meta{TypeID: 95}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 96: + msg := &IOSScreenChanges{meta: &meta{TypeID: 96}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.X, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Y, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Width, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Height, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 97: + msg := &IOSCrash{meta: &meta{TypeID: 97}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Reason, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Stacktrace, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 98: + msg := &IOSScreenEnter{meta: &meta{TypeID: 98}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Title, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ViewName, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 99: + msg := &IOSScreenLeave{meta: &meta{TypeID: 99}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Title, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ViewName, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 100: + msg := &IOSClickEvent{meta: &meta{TypeID: 100}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + if msg.X, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Y, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 101: + msg := &IOSInputEvent{meta: &meta{TypeID: 101}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ValueMasked, err = ReadBoolean(reader); err != nil { + return nil, err + } + if msg.Label, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 102: + msg := &IOSPerformanceEvent{meta: &meta{TypeID: 102}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Name, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Value, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 103: + msg := &IOSLog{meta: &meta{TypeID: 103}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Severity, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Content, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 104: + msg := &IOSInternalError{meta: &meta{TypeID: 104}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Content, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + + case 105: + msg := &IOSNetworkCall{meta: &meta{TypeID: 105}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Length, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Duration, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Headers, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Body, err = ReadString(reader); err != nil { + return nil, err + } + if msg.URL, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Success, err = ReadBoolean(reader); err != nil { + return nil, err + } + if msg.Method, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Status, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 110: + msg := &IOSPerformanceAggregated{meta: &meta{TypeID: 110}} + if msg.TimestampStart, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.TimestampEnd, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinFPS, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgFPS, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxFPS, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinCPU, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgCPU, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxCPU, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinMemory, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgMemory, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxMemory, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MinBattery, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.AvgBattery, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.MaxBattery, err = ReadUint(reader); err != nil { + return nil, err + } + return msg, nil + + case 111: + msg := &IOSIssueEvent{meta: &meta{TypeID: 111}} + if msg.Timestamp, err = ReadUint(reader); err != nil { + return nil, err + } + if msg.Type, err = ReadString(reader); err != nil { + return nil, err + } + if msg.ContextString, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Context, err = ReadString(reader); err != nil { + return nil, err + } + if msg.Payload, err = ReadString(reader); err != nil { + return nil, err + } + return msg, nil + } return nil, fmt.Errorf("Unknown message code: %v", t) } diff --git a/backend/services/db/messages.go b/backend/services/db/messages.go index 38edd7c45..d3e4ae1ed 100644 --- a/backend/services/db/messages.go +++ b/backend/services/db/messages.go @@ -30,12 +30,16 @@ func insertMessage(sessionID uint64, msg Message) error { case *InputEvent: return pg.InsertWebInputEvent(sessionID, m) // Unique Web messages - case *ResourceEvent: - return pg.InsertWebResourceEvent(sessionID, m) + // case *ResourceEvent: + // return pg.InsertWebResourceEvent(sessionID, m) case *PageEvent: return pg.InsertWebPageEvent(sessionID, m) case *ErrorEvent: return pg.InsertWebErrorEvent(sessionID, m) + case *FetchEvent: + return pg.InsertWebFetchEvent(sessionID, m) + case *GraphQLEvent: + return pg.InsertWebGraphQLEvent(sessionID, m) // IOS case *IOSSessionStart: diff --git a/backend/services/ender/builder/builder.go b/backend/services/ender/builder/builder.go index 5bca49a53..e36bdcbe3 100644 --- a/backend/services/ender/builder/builder.go +++ b/backend/services/ender/builder/builder.go @@ -244,15 +244,24 @@ func (b *builder) handleMessage(message Message, messageID uint64) { Payload: msg.Payload, }) case *Fetch: - b.appendReadyMessage(&ResourceEvent{ + b.appendReadyMessage(&FetchEvent{ MessageID: messageID, Timestamp: msg.Timestamp, - Duration: msg.Duration, - URL: msg.URL, - Type: "fetch", - Success: msg.Status < 300, Method: msg.Method, + URL: msg.URL, + Request: msg.Request, + Response: msg.Response, Status: msg.Status, + Duration: msg.Duration, + }) + case *GraphQL: + b.appendReadyMessage(&GraphQLEvent{ + MessageID: messageID, + Timestamp: b.timestamp, + OperationKind: msg.OperationKind, + OperationName: msg.OperationName, + Variables: msg.Variables, + Response: msg.Response, }) case *StateAction: b.appendReadyMessage(&StateActionEvent{ @@ -260,12 +269,6 @@ func (b *builder) handleMessage(message Message, messageID uint64) { Timestamp: b.timestamp, Type: msg.Type, }) - case *GraphQL: - b.appendReadyMessage(&GraphQLEvent{ - MessageID: messageID, - Timestamp: b.timestamp, - Name: msg.OperationName, - }) case *CreateElementNode, *CreateTextNode: b.ddDetector.HandleNodeCreation() From 610dd854b29c5d95f5d52fe39a0c45a793383edc Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 19:36:41 +0100 Subject: [PATCH 084/101] fix(backend):SQLqueries --- backend/pkg/db/postgres/messages_web.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/pkg/db/postgres/messages_web.go b/backend/pkg/db/postgres/messages_web.go index d3fdec446..fcebb02e9 100644 --- a/backend/pkg/db/postgres/messages_web.go +++ b/backend/pkg/db/postgres/messages_web.go @@ -219,8 +219,8 @@ func (conn *Conn) InsertWebFetchEvent(sessionID uint64, savePayload bool, e *Fet ) VALUES ( $1, $2, $3, $4, $5, $6, - $7, $8, $9, NULLIF($10, '') - )`, + $7, $8, $9, NULLIF($10, '')::events_common.http_method + ) ON CONFLICT DO NOTHING`, sessionID, e.Timestamp, getSqIdx(e.MessageID), e.URL, e.Duration, e.Status < 400, request, response, e.Status, url.EnsureMethod(e.Method), @@ -236,7 +236,7 @@ func (conn *Conn) InsertWebGraphQLEvent(sessionID uint64, savePayload bool, e *G } conn.insertAutocompleteValue(sessionID, "GRAPHQL", e.OperationName) return conn.batchQueue(sessionID, ` - INSERT INTO events_common.requests ( + INSERT INTO events.graphql ( session_id, timestamp, message_id, name, request_body, response_body @@ -244,7 +244,7 @@ func (conn *Conn) InsertWebGraphQLEvent(sessionID uint64, savePayload bool, e *G $1, $2, $3, $4, $5, $6 - )`, + ) ON CONFLICT DO NOTHING`, sessionID, e.Timestamp, e.MessageID, e.OperationName, request, response, From ad35d6f5760c4aaf36daa6af07cc18d8e4f9233a Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 19:51:29 +0100 Subject: [PATCH 085/101] fix(backend):SQLqueries --- backend/pkg/db/postgres/messages_web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/pkg/db/postgres/messages_web.go b/backend/pkg/db/postgres/messages_web.go index fcebb02e9..4ff59cc63 100644 --- a/backend/pkg/db/postgres/messages_web.go +++ b/backend/pkg/db/postgres/messages_web.go @@ -219,7 +219,7 @@ func (conn *Conn) InsertWebFetchEvent(sessionID uint64, savePayload bool, e *Fet ) VALUES ( $1, $2, $3, $4, $5, $6, - $7, $8, $9, NULLIF($10, '')::events_common.http_method + $7, $8, $9::smallint, NULLIF($10, '')::events_common.http_method ) ON CONFLICT DO NOTHING`, sessionID, e.Timestamp, getSqIdx(e.MessageID), e.URL, e.Duration, e.Status < 400, From 8328739c2770e2baba0615a072f99e80c4e00419 Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Sun, 6 Mar 2022 20:06:04 +0100 Subject: [PATCH 086/101] fix(backend): project columns to select --- backend/pkg/db/postgres/project.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/pkg/db/postgres/project.go b/backend/pkg/db/postgres/project.go index 60f21531a..066339791 100644 --- a/backend/pkg/db/postgres/project.go +++ b/backend/pkg/db/postgres/project.go @@ -7,12 +7,12 @@ import ( func (conn *Conn) GetProjectByKey(projectKey string) (*Project, error) { p := &Project{ProjectKey: projectKey} if err := conn.queryRow(` - SELECT max_session_duration, sample_rate, project_id, save_request_payloads + SELECT max_session_duration, sample_rate, project_id FROM projects WHERE project_key=$1 AND active = true `, projectKey, - ).Scan(&p.MaxSessionDuration, &p.SampleRate, &p.ProjectID, &p.SaveRequestPayloads); err != nil { + ).Scan(&p.MaxSessionDuration, &p.SampleRate, &p.ProjectID); err != nil { return nil, err } return p, nil @@ -22,14 +22,14 @@ func (conn *Conn) GetProjectByKey(projectKey string) (*Project, error) { func (conn *Conn) GetProject(projectID uint32) (*Project, error) { p := &Project{ProjectID: projectID} if err := conn.queryRow(` - SELECT project_key, max_session_duration, + SELECT project_key, max_session_duration, save_request_payloads, metadata_1, metadata_2, metadata_3, metadata_4, metadata_5, metadata_6, metadata_7, metadata_8, metadata_9, metadata_10 FROM projects WHERE project_id=$1 AND active = true `, projectID, - ).Scan(&p.ProjectKey, &p.MaxSessionDuration, + ).Scan(&p.ProjectKey, &p.MaxSessionDuration, &p.SaveRequestPayloads, &p.Metadata1, &p.Metadata2, &p.Metadata3, &p.Metadata4, &p.Metadata5, &p.Metadata6, &p.Metadata7, &p.Metadata8, &p.Metadata9, &p.Metadata10); err != nil { return nil, err From 6f5d63b48d2ffbb460a84abe23af0c7a937969f0 Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Mon, 7 Mar 2022 11:11:22 +0100 Subject: [PATCH 087/101] chore(helm): enable nginx ingress annotations --- .../openreplay/charts/nginx-ingress/templates/service.yaml | 4 ++++ .../helmcharts/openreplay/charts/nginx-ingress/values.yaml | 1 + 2 files changed, 5 insertions(+) diff --git a/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/service.yaml b/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/service.yaml index c7bcb12be..6c978f7f6 100644 --- a/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/service.yaml +++ b/scripts/helmcharts/openreplay/charts/nginx-ingress/templates/service.yaml @@ -4,6 +4,10 @@ metadata: name: {{ include "nginx-ingress.fullname" . }} labels: {{- include "nginx-ingress.labels" . | nindent 4 }} + annotations: + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")}} diff --git a/scripts/helmcharts/openreplay/charts/nginx-ingress/values.yaml b/scripts/helmcharts/openreplay/charts/nginx-ingress/values.yaml index 43d6d3eae..6984c1938 100644 --- a/scripts/helmcharts/openreplay/charts/nginx-ingress/values.yaml +++ b/scripts/helmcharts/openreplay/charts/nginx-ingress/values.yaml @@ -37,6 +37,7 @@ securityContext: {} # runAsUser: 1000 service: + annotations: {} type: LoadBalancer ports: - port: 80 From e24ac1a6cc411777bbe7ee86dd618ca208004e24 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 12:39:58 +0100 Subject: [PATCH 088/101] change(ui) - uncomment --- frontend/app/duck/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/duck/search.js b/frontend/app/duck/search.js index 4bd05ad2f..70d74cf53 100644 --- a/frontend/app/duck/search.js +++ b/frontend/app/duck/search.js @@ -162,7 +162,7 @@ export const applySavedSearch = (filter) => (dispatch, getState) => { export const fetchSessions = (filter) => (dispatch, getState) => { const _filter = filter ? filter : getState().getIn([ 'search', 'instance']); - // return dispatch(applyFilter(_filter)); // TODO uncomment this line + return dispatch(applyFilter(_filter)); }; export const updateSeries = (index, series) => ({ From 261bb69295e08e7f8657b3da958246360a4d655e Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Mon, 7 Mar 2022 13:05:32 +0100 Subject: [PATCH 089/101] feat(utilities): EE changed uWrapper for redis-uws base --- ee/utilities/server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ee/utilities/server.js b/ee/utilities/server.js index b6a4cb42d..73aae5f70 100644 --- a/ee/utilities/server.js +++ b/ee/utilities/server.js @@ -77,7 +77,10 @@ if (process.env.uws !== "true") { uapp.get(`${PREFIX}/`, healthFn); const uWrapper = function (fn) { - return (res, req) => fn(req, res); + return async (res, req) => { + let response = await fn(req, res); + return response; + } } uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-list`, uWrapper(socket.handlers.socketsList)); uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-list/:projectKey`, uWrapper(socket.handlers.socketsListByProject)); From 0aa1a107c8a1be893e2368cb911caf3e452841a4 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Mon, 7 Mar 2022 13:14:39 +0100 Subject: [PATCH 090/101] feat(utilities): EE changed onAborted for redis-uws base --- ee/utilities/server.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/ee/utilities/server.js b/ee/utilities/server.js index 73aae5f70..672d27e54 100644 --- a/ee/utilities/server.js +++ b/ee/utilities/server.js @@ -76,10 +76,29 @@ if (process.env.uws !== "true") { uapp.get(PREFIX, healthFn); uapp.get(`${PREFIX}/`, healthFn); + + /* Either onAborted or simply finished request */ + function onAbortedOrFinishedResponse(res, readStream) { + + if (res.id === -1) { + console.log("ERROR! onAbortedOrFinishedResponse called twice for the same res!"); + } else { + console.log('Stream was closed, openStreams: ' + --openStreams); + console.timeEnd(res.id); + readStream.destroy(); + } + + /* Mark this response already accounted for */ + res.id = -1; + } + const uWrapper = function (fn) { - return async (res, req) => { - let response = await fn(req, res); - return response; + return (res, req) => { + res.id = 1; + res.onAborted(() => { + onAbortedOrFinishedResponse(res, readStream); + }); + return fn(req, res); } } uapp.get(`${PREFIX}/${process.env.S3_KEY}/sockets-list`, uWrapper(socket.handlers.socketsList)); From 1c940692d9184513d5d79fffe966fe745ba88f75 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 13:32:58 +0100 Subject: [PATCH 091/101] feat(ui) - show active session tab and tab title --- .../components/SessionList/SessionList.tsx | 12 +++++++++-- .../shared/SessionItem/SessionItem.js | 21 +++++++++++++------ frontend/app/types/session/session.js | 2 ++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/frontend/app/components/Assist/components/SessionList/SessionList.tsx b/frontend/app/components/Assist/components/SessionList/SessionList.tsx index f556a8f1d..956226385 100644 --- a/frontend/app/components/Assist/components/SessionList/SessionList.tsx +++ b/frontend/app/components/Assist/components/SessionList/SessionList.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import { connect } from 'react-redux'; import { fetchLiveList } from 'Duck/sessions'; -import { Loader, NoContent } from 'UI'; +import { Loader, NoContent, Label } from 'UI'; import SessionItem from 'Shared/SessionItem'; interface Props { @@ -22,7 +22,15 @@ function SessionList(props: Props) { title="No live sessions." >
- { props.list.map(session => ) } + { props.list.map(session => ( +
+
+ + {session.pageTitle} +
+ +
+ )) }
diff --git a/frontend/app/components/shared/SessionItem/SessionItem.js b/frontend/app/components/shared/SessionItem/SessionItem.js index 51599b3c7..0b7551760 100644 --- a/frontend/app/components/shared/SessionItem/SessionItem.js +++ b/frontend/app/components/shared/SessionItem/SessionItem.js @@ -7,7 +7,8 @@ import { BrowserIcon, CountryFlag, Avatar, - TextEllipsis + TextEllipsis, + Label, } from 'UI'; import { deviceTypeIcon } from 'App/iconNames'; import { toggleFavorite, setSessionPath } from 'Duck/sessions'; @@ -20,14 +21,15 @@ import Counter from './Counter' import { withRouter } from 'react-router-dom'; import SessionMetaList from './SessionMetaList'; import ErrorBars from './ErrorBars'; -import { assist as assistRoute, isRoute } from "App/routes"; +import { assist as assistRoute, liveSession, isRoute } from "App/routes"; import { capitalize } from 'App/utils'; const ASSIST_ROUTE = assistRoute(); +const ASSIST_LIVE_SESSION = liveSession() -const Label = ({ label = '', color = 'color-gray-medium'}) => ( -
{label}
-) +// const Label = ({ label = '', color = 'color-gray-medium'}) => ( +//
{label}
+// ) @connect(state => ({ timezone: state.getIn(['sessions', 'timezone']), siteId: state.getIn([ 'user', 'siteId' ]), @@ -59,16 +61,18 @@ export default class SessionItem extends React.PureComponent { metadata, userSessionsCount, issueTypes, + active, }, timezone, onUserClick = () => null, hasUserFilter = false, disableUser = false, metaList = [], + showActive = false, } = this.props; const formattedDuration = durationFormatted(duration); const hasUserId = userId || userAnonymousId; - const isAssist = isRoute(ASSIST_ROUTE, this.props.location.pathname); + const isAssist = isRoute(ASSIST_ROUTE, this.props.location.pathname) || isRoute(ASSIST_LIVE_SESSION, this.props.location.pathname); const _metaList = Object.keys(metadata).filter(i => metaList.includes(i)).map(key => { const value = metadata[key]; @@ -129,6 +133,11 @@ export default class SessionItem extends React.PureComponent {
+ { isAssist && showActive && ( + + )}
diff --git a/frontend/app/types/session/session.js b/frontend/app/types/session/session.js index 5eda0c987..5401e3008 100644 --- a/frontend/app/types/session/session.js +++ b/frontend/app/types/session/session.js @@ -25,6 +25,8 @@ function hashString(s: string): number { export default Record({ sessionId: '', + pageTitle: '', + active: true, siteId: '', projectKey: '', peerId: '', From ca1d3efd8beca838dfb099f66060f14213b316d4 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 13:34:35 +0100 Subject: [PATCH 092/101] change(ui) - tracker version --- frontend/env.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/env.js b/frontend/env.js index 591332eca..a76295cf1 100644 --- a/frontend/env.js +++ b/frontend/env.js @@ -21,7 +21,7 @@ const oss = { MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, ICE_SERVERS: process.env.ICE_SERVERS, - TRACKER_VERSION: '3.5.2' // trackerInfo.version, + TRACKER_VERSION: '3.5.3' // trackerInfo.version, } module.exports = { From e257ff8a7ff555c778de07bf18e4a13643c1fec5 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 13:39:22 +0100 Subject: [PATCH 093/101] fix(ui) - user title showing additional text, styles --- .../components/Assist/components/AssistTabs/AssistTabs.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx b/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx index 539c2d8d1..6bacc38fc 100644 --- a/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx +++ b/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx @@ -21,7 +21,7 @@ const AssistTabs = (props: Props) => {
- {props.userId}'s asdasd asdasdasdasd + {props.userId}'s
@@ -35,7 +35,7 @@ const AssistTabs = (props: Props) => { )}
Live Sessions by {props.userId}
} + title={
{props.userId}'s Live Sessions
} isDisplayed={ showMenu } content={ showMenu && } onClose={ () => setShowMenu(false) } From c0f53776c55be556bfe56af3577479b52dd4b395 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 13:54:31 +0100 Subject: [PATCH 094/101] change(ui) - remove alert for table metrics --- .../CustomMetricWidget/CustomMetricWidget.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index 50471b5f9..c5fd2ad3f 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -51,6 +51,10 @@ function CustomMetricWidget(props: Props) { const colors = Styles.customMetricColors; const params = customParams(period.rangeName) const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart', startDate: period.start, endDate: period.end } + const isLineChart = metric.viewType === 'lineChart'; + const isProgress = metric.viewType === 'progress'; + const isTable = metric.viewType === 'table'; + const isPieChart = metric.viewType === 'pieChart'; useEffect(() => { new APIClient()['post'](`/custom_metrics/${metricParams.metricId}/chart`, { ...metricParams, q: metric.name }) @@ -115,7 +119,7 @@ function CustomMetricWidget(props: Props) {
{metric.name}
- + {!isTable && !isPieChart && } props.init(metric)} /> updateActiveState(metric.metricId, false)} />
@@ -128,7 +132,7 @@ function CustomMetricWidget(props: Props) { > <> - {metric.viewType === 'lineChart' && ( + {isLineChart && ( )} - {metric.viewType === 'pieChart' && ( + {isPieChart && ( )} - {metric.viewType === 'progress' && ( + {isProgress && ( )} - {metric.viewType === 'table' && ( + {isTable && ( )} From ca99393de7b2c0dfbece6fd2978bdeed4ba91c56 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 14:10:45 +0100 Subject: [PATCH 095/101] change(ui) - filter series name --- .../shared/CustomMetrics/FilterSeries/FilterSeries.tsx | 2 +- .../CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx index aea20aea1..34388ba63 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx @@ -55,7 +55,7 @@ function FilterSeries(props: Props) {
- props.updateSeries(seriesIndex, { name }) } /> + props.updateSeries(seriesIndex, { name }) } />
diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx index 75054fc6b..5b5d5463c 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx @@ -4,8 +4,10 @@ import { Icon } from 'UI'; interface Props { name: string; onUpdate: (name) => void; + seriesIndex?: number; } function SeriesName(props: Props) { + const { seriesIndex } = props; const [editing, setEditing] = useState(false) const [name, setName] = useState(props.name) const ref = useRef(null) @@ -44,7 +46,7 @@ function SeriesName(props: Props) { onFocus={() => setEditing(true)} /> ) : ( -
{name}
+
{name.trim() === '' ? 'Seriess ' + (seriesIndex + 1) : name }
)}
setEditing(true)}>
From 46e6ad9fb6c3f0cf549c6c78865d5e27adaf4ba0 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Mar 2022 15:46:57 +0100 Subject: [PATCH 096/101] change(ui) - help text for chart series --- .../CustomMetricForm/CustomMetricForm.tsx | 5 +++-- .../FilterSeries/SeriesName/SeriesName.tsx | 2 +- .../app/components/ui/HelpText/HelpText.tsx | 22 +++++++++++++++++++ frontend/app/components/ui/HelpText/index.ts | 1 + frontend/app/components/ui/index.js | 1 + 5 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 frontend/app/components/ui/HelpText/HelpText.tsx create mode 100644 frontend/app/components/ui/HelpText/index.ts diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index 471bc9bbe..28a0cbc42 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Form, Button, IconButton } from 'UI'; +import { Form, Button, IconButton, HelpText } from 'UI'; import FilterSeries from '../FilterSeries'; import { connect } from 'react-redux'; import { edit as editMetric, save, addSeries, removeSeries, remove } from 'Duck/customMetrics'; @@ -169,8 +169,9 @@ function CustomMetricForm(props: Props) {
-