From 68b55db8723896a6906ad61c6f8e97e2cf6b1c49 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 26 Sep 2023 19:18:11 +0100 Subject: [PATCH 01/24] restore basic Angular Universal build --- frontend/angular.json | 50 + frontend/generate-config.js | 2 +- frontend/package-lock.json | 2659 ++++++++++++++++++++++++++++++++- frontend/package.json | 34 +- frontend/server.run.ts | 108 ++ frontend/server.ts | 146 ++ frontend/src/main.server.ts | 11 + frontend/tsconfig.server.json | 18 + 8 files changed, 2937 insertions(+), 91 deletions(-) create mode 100644 frontend/server.run.ts create mode 100644 frontend/server.ts create mode 100644 frontend/src/main.server.ts create mode 100644 frontend/tsconfig.server.json diff --git a/frontend/angular.json b/frontend/angular.json index 792f59443..e86ea7f57 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -280,6 +280,56 @@ } } }, + "server": { + "builder": "@angular-devkit/build-angular:server", + "options": { + "outputPath": "dist/mempool/server", + "main": "server.ts", + "tsConfig": "tsconfig.server.json" + }, + "configurations": { + "production": { + "outputHashing": "media", + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "sourceMap": false, + "localize": true, + "optimization": false + } + } + }, + "serve-ssr": { + "builder": "@nguniversal/builders:ssr-dev-server", + "options": { + "browserTarget": "mempool:build", + "serverTarget": "mempool:server" + }, + "configurations": { + "production": { + "browserTarget": "mempool:build:production", + "serverTarget": "mempool:server:production", + "optimization": false, + "sourceMap": true + } + } + }, + "prerender": { + "builder": "@nguniversal/builders:prerender", + "options": { + "browserTarget": "mempool:build:production", + "serverTarget": "mempool:server:production", + "routes": [ + "/" + ] + }, + "configurations": { + "production": {} + } + }, "cypress-run": { "builder": "@cypress/schematic:cypress", "options": { diff --git a/frontend/generate-config.js b/frontend/generate-config.js index 3cc173e00..7d30b9bc3 100644 --- a/frontend/generate-config.js +++ b/frontend/generate-config.js @@ -71,7 +71,7 @@ const newConfig = `(function (window) { window.__env.${obj.key} = ${typeof obj.value === 'string' ? `'${obj.value}'` : obj.value};`, '')} window.__env.GIT_COMMIT_HASH = '${gitCommitHash}'; window.__env.PACKAGE_JSON_VERSION = '${packetJsonVersion}'; - }(this));`; + }(global || this));`; const newConfigTemplate = `(function (window) { window.__env = window.__env || {};${settings.reduce((str, obj) => `${str} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e012f89ef..ab600a8f4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,18 +9,18 @@ "version": "3.0.0-dev", "license": "GNU Affero General Public License v3.0", "dependencies": { - "@angular-devkit/build-angular": "^16.2.0", - "@angular/animations": "^16.2.2", - "@angular/cli": "^16.2.0", - "@angular/common": "^16.2.2", - "@angular/compiler": "^16.2.2", - "@angular/core": "^16.2.2", - "@angular/forms": "^16.2.2", - "@angular/localize": "^16.2.2", - "@angular/platform-browser": "^16.2.2", - "@angular/platform-browser-dynamic": "^16.2.2", - "@angular/platform-server": "^16.2.2", - "@angular/router": "^16.2.2", + "@angular-devkit/build-angular": "^16.1.1", + "@angular/animations": "^16.1.1", + "@angular/cli": "^16.1.1", + "@angular/common": "^16.1.1", + "@angular/compiler": "^16.1.1", + "@angular/core": "^16.1.1", + "@angular/forms": "^16.1.1", + "@angular/localize": "^16.1.1", + "@angular/platform-browser": "^16.1.1", + "@angular/platform-browser-dynamic": "^16.1.1", + "@angular/platform-server": "^16.1.1", + "@angular/router": "^16.1.1", "@fortawesome/angular-fontawesome": "~0.13.0", "@fortawesome/fontawesome-common-types": "~6.5.1", "@fortawesome/fontawesome-svg-core": "~6.5.1", @@ -44,14 +44,17 @@ "zone.js": "~0.13.1" }, "devDependencies": { - "@angular/compiler-cli": "^16.1.5", - "@angular/language-service": "^16.1.5", + "@angular/compiler-cli": "^16.1.1", + "@angular/language-service": "^16.1.1", + "@nguniversal/builders": "16.1.1", + "@nguniversal/express-engine": "16.1.1", "@types/node": "^18.11.9", "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.48.1", "eslint": "^8.31.0", "http-proxy-middleware": "~2.0.6", "prettier": "^3.0.0", + "source-map-support": "^0.5.21", "ts-node": "~10.9.1", "typescript": "~4.9.3" }, @@ -3823,6 +3826,443 @@ "webpack": "^5.54.0" } }, + "node_modules/@nguniversal/builders": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@nguniversal/builders/-/builders-16.1.1.tgz", + "integrity": "sha512-JoGKFqEMFhHP2dg6I/xjj2/kRehdF1GddyAJglRAtgbmyh9dtG9lrE5PMe1iuZYV+vUh6dND3TMhhmMVKPouPw==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "~0.1601.0-next.0", + "@angular-devkit/core": "~16.1.0-next.0", + "@nguniversal/common": "16.1.1", + "browser-sync": "^2.27.10", + "express": "^4.18.2", + "guess-parser": "^0.4.22", + "http-proxy-middleware": "^2.0.6", + "ora": "^5.1.0", + "piscina": "~4.0.0", + "rxjs": "^7.0.0", + "tree-kill": "^1.2.2" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular-devkit/build-angular": "^16.0.0 || ^16.1.0-next.0" + } + }, + "node_modules/@nguniversal/builders/node_modules/@angular-devkit/architect": { + "version": "0.1601.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.8.tgz", + "integrity": "sha512-kOXVGwsQnZvtz2UZNefcEy64Jiwq0eSoQUeozvDXOaYRJABLjPKI2YaarvKC9/Z1SGLuje0o/eRJO4T8aRk9rQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.1.8", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@nguniversal/builders/node_modules/@angular-devkit/core": { + "version": "16.1.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.8.tgz", + "integrity": "sha512-dSRD/+bGanArIXkj+kaU1kDFleZeQMzmBiOXX+pK0Ah9/0Yn1VmY3RZh1zcX9vgIQXV+t7UPrTpOjaERMUtVGw==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@nguniversal/builders/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@nguniversal/builders/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@nguniversal/common": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-16.1.1.tgz", + "integrity": "sha512-8Hj+hKXy34H0reSKRzgTQIJyajU8ZLu1wR7DrBwzrpC6yk9eH6jE+67j6TMfSR9uoKF5nfLaqmnJyUShxHj9tA==", + "dev": true, + "dependencies": { + "critters": "0.0.19", + "jsdom": "22.1.0", + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "^16.0.0 || ^16.1.0-next.0", + "@angular/core": "^16.0.0 || ^16.1.0-next.0" + } + }, + "node_modules/@nguniversal/common/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" + } + }, + "node_modules/@nguniversal/common/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" + } + }, + "node_modules/@nguniversal/common/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" + } + }, + "node_modules/@nguniversal/common/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 + }, + "node_modules/@nguniversal/common/node_modules/critters": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", + "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", + "deprecated": "Please upgrade to the latest version. There is a potential XSS vulnerability in this version", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/@nguniversal/common/node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nguniversal/common/node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nguniversal/common/node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nguniversal/common/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@nguniversal/common/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" + } + }, + "node_modules/@nguniversal/common/node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nguniversal/common/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@nguniversal/common/node_modules/jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/@nguniversal/common/node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/@nguniversal/common/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" + } + }, + "node_modules/@nguniversal/common/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nguniversal/common/node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nguniversal/common/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nguniversal/common/node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nguniversal/common/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nguniversal/common/node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nguniversal/common/node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "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/@nguniversal/common/node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@nguniversal/express-engine": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-16.1.1.tgz", + "integrity": "sha512-N2qWc2Vo3W5TryHtkHKw0d9Iz6a+E8XrB8kf6mAEKakWBIv86wwsRtJArrmf+Dnx75AfojO9hcVE915rjiLesA==", + "dev": true, + "dependencies": { + "@nguniversal/common": "16.1.1", + "tslib": "^2.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "^16.0.0 || ^16.1.0-next.0", + "@angular/core": "^16.0.0 || ^16.1.0-next.0", + "express": "^4.15.2" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4106,8 +4546,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "optional": true, - "peer": true + "devOptional": true }, "node_modules/@tootallnate/once": { "version": "2.0.0", @@ -4221,15 +4660,13 @@ "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==", - "optional": true, - "peer": true + "devOptional": true }, "node_modules/@types/cors": { "version": "2.8.13", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "@types/node": "*" } @@ -5274,6 +5711,15 @@ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "optional": true }, + "node_modules/async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha512-p4jj6Fws4Iy2m0iCmI2am2ZNZCgbdgE+P8F/8csmn2vx7ixXrO2zGcuNsD46X5uZSVecmkEy/M06X2vG8KD6dQ==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -5460,8 +5906,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": "^4.5.0 || >= 5.9" } @@ -5711,6 +6156,487 @@ "resolve": "^1.17.0" } }, + "node_modules/browser-sync": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.29.3.tgz", + "integrity": "sha512-NiM38O6XU84+MN+gzspVmXV2fTOoe+jBqIBx3IBdhZrdeURr6ZgznJr/p+hQ+KzkKEiGH/GcC4SQFSL0jV49bg==", + "dev": true, + "dependencies": { + "browser-sync-client": "^2.29.3", + "browser-sync-ui": "^2.29.3", + "bs-recipes": "1.3.4", + "chalk": "4.1.2", + "chokidar": "^3.5.1", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "^4.0.1", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "^1.18.1", + "immutable": "^3", + "localtunnel": "^2.0.1", + "micromatch": "^4.0.2", + "opn": "5.3.0", + "portscanner": "2.2.0", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "^4.4.1", + "ua-parser-js": "^1.0.33", + "yargs": "^17.3.1" + }, + "bin": { + "browser-sync": "dist/bin.js" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/browser-sync-client": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.29.3.tgz", + "integrity": "sha512-4tK5JKCl7v/3aLbmCBMzpufiYLsB1+UI+7tUXCCp5qF0AllHy/jAqYu6k7hUF3hYtlClKpxExWaR+rH+ny07wQ==", + "dev": true, + "dependencies": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/browser-sync-ui": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.29.3.tgz", + "integrity": "sha512-kBYOIQjU/D/3kYtUIJtj82e797Egk1FB2broqItkr3i4eF1qiHbFCG6srksu9gWhfmuM/TNG76jMfzAdxEPakg==", + "dev": true, + "dependencies": { + "async-each-series": "0.1.1", + "chalk": "4.1.2", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^4.4.1", + "stream-throttle": "^0.1.3" + } + }, + "node_modules/browser-sync-ui/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" + } + }, + "node_modules/browser-sync-ui/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" + } + }, + "node_modules/browser-sync-ui/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" + } + }, + "node_modules/browser-sync-ui/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 + }, + "node_modules/browser-sync-ui/node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/browser-sync-ui/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" + } + }, + "node_modules/browser-sync-ui/node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browser-sync-ui/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" + } + }, + "node_modules/browser-sync/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" + } + }, + "node_modules/browser-sync/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" + } + }, + "node_modules/browser-sync/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/browser-sync/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" + } + }, + "node_modules/browser-sync/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 + }, + "node_modules/browser-sync/node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/browser-sync/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/browser-sync/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, + "node_modules/browser-sync/node_modules/fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha512-V3Z3WZWVUYd8hoCL5xfXJCaHWYzmtwW5XWYSlLgERi8PWd8bx1kUHUk8L1BT57e49oKnDDD180mjfrHc1yA9rg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/browser-sync/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" + } + }, + "node_modules/browser-sync/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browser-sync/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/browser-sync/node_modules/jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha512-oBko6ZHlubVB5mRFkur5vgYR1UyqX+S6Y/oCfLhqNdcc2fYFlDpIoNc7AfKS1KOGcnNAkvsr0grLck9ANM815w==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/browser-sync/node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true, + "bin": { + "mime": "cli.js" + } + }, + "node_modules/browser-sync/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/browser-sync/node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "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.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/browser-sync/node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/browser-sync/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/browser-sync/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/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" + } + }, + "node_modules/browser-sync/node_modules/ua-parser-js": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", + "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/browser-sync/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browser-sync/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/browser-sync/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/browser-sync/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/browser-sync/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/browser-unpack": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.4.2.tgz", @@ -6012,6 +6938,12 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw==", + "dev": true + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -6639,6 +7571,21 @@ "typedarray": "^0.0.6" } }, + "node_modules/connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha512-OO7axMmPpu/2XuX1+2Yrg0ddju31B6xLZMWkJ5rYBu4YRmRVlOjvlY6kw2FJKiAzyxGwnrDUAG4s1Pf0sbBMCQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -6647,6 +7594,48 @@ "node": ">=0.8" } }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha512-ejnvM9ZXYzp6PUPUyQBMBf0Co5VX2gr5H2VQe2Ui2jWXNlxv+PYZo8wpAymJNJdLsG1R4p+M4aynF8KuoUEwRw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -6784,8 +7773,7 @@ "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "object-assign": "^4", "vary": "^1" @@ -7581,6 +8569,18 @@ "node": ">=0.8.0" } }, + "node_modules/dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha512-LmVkry/oDShEgSZPNgqCIp2/TlqtExeGmymru3uCELnfyjY11IzpAproLYs+1X88fXO6DBoYP3ul2Xo2yz2j6A==", + "dev": true, + "bin": { + "dev-ip": "lib/dev-ip.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -7771,6 +8771,100 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "dev": true, + "dependencies": { + "lodash": "^4.17.10" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/eazy-logger": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-4.0.1.tgz", + "integrity": "sha512-2GSFtnnC6U4IEKhEI7+PvdxrmjJ04mdsj3wHZTFiw0tUtG4HCWzTr13ZYTk8XOGnA1xQMaDljoBOYlk3D/MMSw==", + "dev": true, + "dependencies": { + "chalk": "4.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eazy-logger/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" + } + }, + "node_modules/eazy-logger/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" + } + }, + "node_modules/eazy-logger/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" + } + }, + "node_modules/eazy-logger/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 + }, + "node_modules/eazy-logger/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" + } + }, + "node_modules/eazy-logger/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" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -7883,8 +8977,7 @@ "version": "6.5.1", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.1.tgz", "integrity": "sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -7901,12 +8994,54 @@ "node": ">=10.0.0" } }, + "node_modules/engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "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/engine.io-parser": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.1.0.tgz", "integrity": "sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">=10.0.0" } @@ -7915,8 +9050,7 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">= 0.6" } @@ -7925,8 +9059,7 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">=10.0.0" }, @@ -10638,6 +11771,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "dependencies": { + "lodash.isfinite": "^3.3.2" + } + }, "node_modules/is-number-object": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", @@ -11480,6 +12622,12 @@ "fancy-canvas": "0.2.2" } }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", + "dev": true + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -11583,6 +12731,147 @@ "node": ">=8.9.0" } }, + "node_modules/localtunnel": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz", + "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==", + "dev": true, + "dependencies": { + "axios": "0.21.4", + "debug": "4.3.2", + "openurl": "1.1.1", + "yargs": "17.1.1" + }, + "bin": { + "lt": "bin/lt.js" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/localtunnel/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" + } + }, + "node_modules/localtunnel/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/localtunnel/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/localtunnel/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" + } + }, + "node_modules/localtunnel/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 + }, + "node_modules/localtunnel/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/localtunnel/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/localtunnel/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/localtunnel/node_modules/yargs": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", + "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/localtunnel/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -11610,6 +12899,12 @@ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "optional": true }, + "node_modules/lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -12266,6 +13561,12 @@ "node": ">=8" } }, + "node_modules/mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==", + "dev": true + }, "node_modules/mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -12925,8 +14226,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "ee-first": "1.1.1" }, @@ -12996,6 +14296,33 @@ "node": ">= 0.8.0" } }, + "node_modules/openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", + "dev": true + }, + "node_modules/opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "dev": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/opn/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -13583,6 +14910,29 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/portscanner": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", + "dev": true, + "dependencies": { + "async": "^2.6.0", + "is-number-like": "^1.0.3" + }, + "engines": { + "node": ">=0.4", + "npm": ">=1.0.0" + } + }, + "node_modules/portscanner/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, "node_modules/postcss": { "version": "8.4.27", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", @@ -13864,9 +15214,9 @@ } }, "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==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "engines": { "node": ">=6" } @@ -14321,6 +15671,34 @@ "node": ">=0.10.0" } }, + "node_modules/resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha512-U1+0kWC/+4ncRFYqQWTx/3qkfE6a4B/h3XXgmXypfa0SPZ3t7cbbaFk297PjQS/yov24R18h6OZe6iZwj3NSLw==", + "dev": true, + "dependencies": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/resp-modifier/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/resp-modifier/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -14394,6 +15772,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -14424,6 +15808,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha512-CiaiuN6gapkdl+cZUr67W6I8jquN4lkak3vtIsIWCl4XIPP8ffsoyN6/+PuGXnQy8Cu8W2y9Xxh31Rq4M6wUug==", + "dev": true + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -14764,6 +16154,12 @@ "node": ">= 0.8.0" } }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "dev": true + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -15024,8 +16420,7 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz", "integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -15043,8 +16438,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "ws": "~8.11.0" } @@ -15053,8 +16447,7 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">=10.0.0" }, @@ -15071,12 +16464,26 @@ } } }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -15377,6 +16784,22 @@ "readable-stream": "^2.0.2" } }, + "node_modules/stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha512-889+B9vN9dq7/vLbGyuHeZ6/ctf5sNuGWsDy89uNxkFTAgzy0eK7+w5fL3KLNRTkLle7EgZGvHUphZW0Q26MnQ==", + "dev": true, + "dependencies": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + }, + "bin": { + "throttleproxy": "bin/throttleproxy.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/streamroller": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.2.tgz", @@ -17167,6 +18590,15 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "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==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -19754,6 +21186,315 @@ "integrity": "sha512-c9jv4r7GnLTpnPOeF+a9yAm/3/2wwl9lMBU32i9hlY+q/Hqde4PiL95bUOLnRRL1I64DV7BFTlSZqSPgDpFXZQ==", "requires": {} }, + "@nguniversal/builders": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@nguniversal/builders/-/builders-16.1.1.tgz", + "integrity": "sha512-JoGKFqEMFhHP2dg6I/xjj2/kRehdF1GddyAJglRAtgbmyh9dtG9lrE5PMe1iuZYV+vUh6dND3TMhhmMVKPouPw==", + "dev": true, + "requires": { + "@angular-devkit/architect": "~0.1601.0-next.0", + "@angular-devkit/core": "~16.1.0-next.0", + "@nguniversal/common": "16.1.1", + "browser-sync": "^2.27.10", + "express": "^4.18.2", + "guess-parser": "^0.4.22", + "http-proxy-middleware": "^2.0.6", + "ora": "^5.1.0", + "piscina": "~4.0.0", + "rxjs": "^7.0.0", + "tree-kill": "^1.2.2" + }, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.1601.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1601.8.tgz", + "integrity": "sha512-kOXVGwsQnZvtz2UZNefcEy64Jiwq0eSoQUeozvDXOaYRJABLjPKI2YaarvKC9/Z1SGLuje0o/eRJO4T8aRk9rQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "16.1.8", + "rxjs": "7.8.1" + } + }, + "@angular-devkit/core": { + "version": "16.1.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.1.8.tgz", + "integrity": "sha512-dSRD/+bGanArIXkj+kaU1kDFleZeQMzmBiOXX+pK0Ah9/0Yn1VmY3RZh1zcX9vgIQXV+t7UPrTpOjaERMUtVGw==", + "dev": true, + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "7.8.1", + "source-map": "0.7.4" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "@nguniversal/common": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-16.1.1.tgz", + "integrity": "sha512-8Hj+hKXy34H0reSKRzgTQIJyajU8ZLu1wR7DrBwzrpC6yk9eH6jE+67j6TMfSR9uoKF5nfLaqmnJyUShxHj9tA==", + "dev": true, + "requires": { + "critters": "0.0.19", + "jsdom": "22.1.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "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" + } + }, + "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, + "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==", + "dev": true + }, + "critters": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.19.tgz", + "integrity": "sha512-Fm4ZAXsG0VzWy1U30rP4qxbaWGSsqXDgSupJW1OUJGDAs0KWC+j37v7p5a2kZ9BPJvhRzWm3be+Hc9WvQOBUOw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "pretty-bytes": "^5.3.0" + } + }, + "cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "requires": { + "rrweb-cssom": "^0.6.0" + } + }, + "data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + } + }, + "domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "requires": { + "webidl-conversions": "^7.0.0" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "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 + }, + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + } + }, + "saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "requires": { + "punycode": "^2.3.0" + } + }, + "w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "requires": { + "xml-name-validator": "^4.0.0" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + } + }, + "whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true + }, + "whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "requires": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + } + }, + "ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "requires": {} + }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true + } + } + }, + "@nguniversal/express-engine": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-16.1.1.tgz", + "integrity": "sha512-N2qWc2Vo3W5TryHtkHKw0d9Iz6a+E8XrB8kf6mAEKakWBIv86wwsRtJArrmf+Dnx75AfojO9hcVE915rjiLesA==", + "dev": true, + "requires": { + "@nguniversal/common": "16.1.1", + "tslib": "^2.3.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -19976,8 +21717,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "optional": true, - "peer": true + "devOptional": true }, "@tootallnate/once": { "version": "2.0.0", @@ -20078,15 +21818,13 @@ "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==", - "optional": true, - "peer": true + "devOptional": true }, "@types/cors": { "version": "2.8.13", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "@types/node": "*" } @@ -20906,6 +22644,12 @@ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "optional": true }, + "async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha512-p4jj6Fws4Iy2m0iCmI2am2ZNZCgbdgE+P8F/8csmn2vx7ixXrO2zGcuNsD46X5uZSVecmkEy/M06X2vG8KD6dQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -21027,8 +22771,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "optional": true, - "peer": true + "devOptional": true }, "batch": { "version": "0.6.1", @@ -21235,6 +22978,372 @@ "resolve": "^1.17.0" } }, + "browser-sync": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.29.3.tgz", + "integrity": "sha512-NiM38O6XU84+MN+gzspVmXV2fTOoe+jBqIBx3IBdhZrdeURr6ZgznJr/p+hQ+KzkKEiGH/GcC4SQFSL0jV49bg==", + "dev": true, + "requires": { + "browser-sync-client": "^2.29.3", + "browser-sync-ui": "^2.29.3", + "bs-recipes": "1.3.4", + "chalk": "4.1.2", + "chokidar": "^3.5.1", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "^4.0.1", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "^1.18.1", + "immutable": "^3", + "localtunnel": "^2.0.1", + "micromatch": "^4.0.2", + "opn": "5.3.0", + "portscanner": "2.2.0", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "^4.4.1", + "ua-parser-js": "^1.0.33", + "yargs": "^17.3.1" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "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" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "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, + "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==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha512-V3Z3WZWVUYd8hoCL5xfXJCaHWYzmtwW5XWYSlLgERi8PWd8bx1kUHUk8L1BT57e49oKnDDD180mjfrHc1yA9rg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "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 + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha512-oBko6ZHlubVB5mRFkur5vgYR1UyqX+S6Y/oCfLhqNdcc2fYFlDpIoNc7AfKS1KOGcnNAkvsr0grLck9ANM815w==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "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.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + }, + "ua-parser-js": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", + "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "browser-sync-client": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.29.3.tgz", + "integrity": "sha512-4tK5JKCl7v/3aLbmCBMzpufiYLsB1+UI+7tUXCCp5qF0AllHy/jAqYu6k7hUF3hYtlClKpxExWaR+rH+ny07wQ==", + "dev": true, + "requires": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3" + } + }, + "browser-sync-ui": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.29.3.tgz", + "integrity": "sha512-kBYOIQjU/D/3kYtUIJtj82e797Egk1FB2broqItkr3i4eF1qiHbFCG6srksu9gWhfmuM/TNG76jMfzAdxEPakg==", + "dev": true, + "requires": { + "async-each-series": "0.1.1", + "chalk": "4.1.2", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^4.4.1", + "stream-throttle": "^0.1.3" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "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" + } + }, + "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, + "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==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "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==", + "dev": true + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "browser-unpack": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.4.2.tgz", @@ -21486,6 +23595,12 @@ "update-browserslist-db": "^1.0.11" } }, + "bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw==", + "dev": true + }, "buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -21955,6 +24070,56 @@ "typedarray": "^0.0.6" } }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha512-OO7axMmPpu/2XuX1+2Yrg0ddju31B6xLZMWkJ5rYBu4YRmRVlOjvlY6kw2FJKiAzyxGwnrDUAG4s1Pf0sbBMCQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha512-ejnvM9ZXYzp6PUPUyQBMBf0Co5VX2gr5H2VQe2Ui2jWXNlxv+PYZo8wpAymJNJdLsG1R4p+M4aynF8KuoUEwRw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "dev": true + } + } + }, "connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -22058,8 +24223,7 @@ "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "object-assign": "^4", "vary": "^1" @@ -22679,6 +24843,12 @@ "minimist": "^1.1.1" } }, + "dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha512-LmVkry/oDShEgSZPNgqCIp2/TlqtExeGmymru3uCELnfyjY11IzpAproLYs+1X88fXO6DBoYP3ul2Xo2yz2j6A==", + "dev": true + }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -22833,6 +25003,75 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "eazy-logger": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-4.0.1.tgz", + "integrity": "sha512-2GSFtnnC6U4IEKhEI7+PvdxrmjJ04mdsj3wHZTFiw0tUtG4HCWzTr13ZYTk8XOGnA1xQMaDljoBOYlk3D/MMSw==", + "dev": true, + "requires": { + "chalk": "4.1.2" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "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" + } + }, + "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, + "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==", + "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==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -22942,8 +25181,7 @@ "version": "6.5.1", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.1.tgz", "integrity": "sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -22961,15 +25199,41 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "optional": true, - "peer": true + "devOptional": true }, "ws": { "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "optional": true, - "peer": true, + "devOptional": true, + "requires": {} + } + } + }, + "engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "dev": true + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, "requires": {} } } @@ -22978,8 +25242,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.1.0.tgz", "integrity": "sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==", - "optional": true, - "peer": true + "devOptional": true }, "enhanced-resolve": { "version": "5.15.0", @@ -24980,6 +27243,15 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "requires": { + "lodash.isfinite": "^3.3.2" + } + }, "is-number-object": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", @@ -25604,6 +27876,12 @@ "fancy-canvas": "0.2.2" } }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", + "dev": true + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -25677,6 +27955,111 @@ "json5": "^2.1.2" } }, + "localtunnel": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz", + "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==", + "dev": true, + "requires": { + "axios": "0.21.4", + "debug": "4.3.2", + "openurl": "1.1.1", + "yargs": "17.1.1" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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, + "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==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", + "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + } + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -25701,6 +28084,12 @@ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "optional": true }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -26208,6 +28597,12 @@ } } }, + "mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==", + "dev": true + }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -26719,8 +29114,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "ee-first": "1.1.1" } @@ -26769,6 +29163,29 @@ "word-wrap": "~1.2.3" } }, + "openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", + "dev": true + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "dev": true + } + } + }, "ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -27188,6 +29605,27 @@ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", "peer": true }, + "portscanner": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", + "dev": true, + "requires": { + "async": "^2.6.0", + "is-number-like": "^1.0.3" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, "postcss": { "version": "8.4.27", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", @@ -27377,9 +29815,9 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" }, "qjobs": { "version": "1.2.0", @@ -27723,6 +30161,33 @@ } } }, + "resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha512-U1+0kWC/+4ncRFYqQWTx/3qkfE6a4B/h3XXgmXypfa0SPZ3t7cbbaFk297PjQS/yov24R18h6OZe6iZwj3NSLw==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -27773,6 +30238,12 @@ "fsevents": "~2.3.2" } }, + "rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -27786,6 +30257,12 @@ "queue-microtask": "^1.2.2" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha512-CiaiuN6gapkdl+cZUr67W6I8jquN4lkak3vtIsIWCl4XIPP8ffsoyN6/+PuGXnQy8Cu8W2y9Xxh31Rq4M6wUug==", + "dev": true + }, "rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -28047,6 +30524,12 @@ "send": "0.18.0" } }, + "server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "dev": true + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -28235,8 +30718,7 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz", "integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -28251,8 +30733,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "ws": "~8.11.0" }, @@ -28261,18 +30742,28 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "optional": true, - "peer": true, + "devOptional": true, "requires": {} } } }, + "socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + } + }, "socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -28518,6 +31009,16 @@ "readable-stream": "^2.0.2" } }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha512-889+B9vN9dq7/vLbGyuHeZ6/ctf5sNuGWsDy89uNxkFTAgzy0eK7+w5fL3KLNRTkLle7EgZGvHUphZW0Q26MnQ==", + "dev": true, + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, "streamroller": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.2.tgz", @@ -29772,6 +32273,12 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5980e9e46..38d05c4f1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -48,6 +48,9 @@ "prettier": "prettier --write \"src/app/**/*.{js,json,css,scss,less,md,ts,html,component.html}\"", "e2e": "npm run generate-config && npm run ng -- e2e", "e2e:ci": "npm run cypress:run:ci", + "dev:ssr": "npm run generate-config && ng run mempool:serve-ssr", + "serve:ssr": "npm run generate-config && node server.run.js", + "build:ssr": "npm run build && ng run mempool:server:production && ./node_modules/typescript/bin/tsc server.run.ts", "config:defaults:mempool": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true LIQUID_TESTNET_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=mempool BLOCK_WEIGHT_UNITS=4000000 && npm run generate-config", "config:defaults:liquid": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true LIQUID_TESTNET_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=liquid BLOCK_WEIGHT_UNITS=300000 && npm run generate-config", "config:defaults:bisq": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=bisq BLOCK_WEIGHT_UNITS=4000000 && npm run generate-config", @@ -61,18 +64,18 @@ "cypress:run:ci:staging": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-staging 4200 cypress:run:record" }, "dependencies": { - "@angular-devkit/build-angular": "^16.2.0", - "@angular/animations": "^16.2.2", - "@angular/cli": "^16.2.0", - "@angular/common": "^16.2.2", - "@angular/compiler": "^16.2.2", - "@angular/core": "^16.2.2", - "@angular/forms": "^16.2.2", - "@angular/localize": "^16.2.2", - "@angular/platform-browser": "^16.2.2", - "@angular/platform-browser-dynamic": "^16.2.2", - "@angular/platform-server": "^16.2.2", - "@angular/router": "^16.2.2", + "@angular-devkit/build-angular": "^16.1.1", + "@angular/animations": "^16.1.1", + "@angular/cli": "^16.1.1", + "@angular/common": "^16.1.1", + "@angular/compiler": "^16.1.1", + "@angular/core": "^16.1.1", + "@angular/forms": "^16.1.1", + "@angular/localize": "^16.1.1", + "@angular/platform-browser": "^16.1.1", + "@angular/platform-browser-dynamic": "^16.1.1", + "@angular/platform-server": "^16.1.1", + "@angular/router": "^16.1.1", "@fortawesome/angular-fontawesome": "~0.13.0", "@fortawesome/fontawesome-common-types": "~6.5.1", "@fortawesome/fontawesome-svg-core": "~6.5.1", @@ -96,14 +99,17 @@ "zone.js": "~0.13.1" }, "devDependencies": { - "@angular/compiler-cli": "^16.1.5", - "@angular/language-service": "^16.1.5", + "@angular/compiler-cli": "^16.1.1", + "@angular/language-service": "^16.1.1", + "@nguniversal/builders": "16.1.1", + "@nguniversal/express-engine": "16.1.1", "@types/node": "^18.11.9", "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.48.1", "eslint": "^8.31.0", "http-proxy-middleware": "~2.0.6", "prettier": "^3.0.0", + "source-map-support": "^0.5.21", "ts-node": "~10.9.1", "typescript": "~4.9.3" }, diff --git a/frontend/server.run.ts b/frontend/server.run.ts new file mode 100644 index 000000000..273629f6f --- /dev/null +++ b/frontend/server.run.ts @@ -0,0 +1,108 @@ +import 'zone.js/dist/zone-node'; +import './src/resources/config.js'; + +console.log(global); + +import * as domino from 'domino'; +import * as express from 'express'; +import * as fs from 'fs'; +import * as path from 'path'; + +const {readFileSync, existsSync} = require('fs'); +const {createProxyMiddleware} = require('http-proxy-middleware'); + +const template = fs.readFileSync(path.join(process.cwd(), 'dist/mempool/browser/en-US/', 'index.html')).toString(); +const win = domino.createWindow(template); + +// @ts-ignore +win.__env = global.__env; + +// @ts-ignore +win.matchMedia = () => { + return { + matches: true + }; +}; + +// @ts-ignore +win.setTimeout = (fn) => { fn(); }; +win.document.body.scrollTo = (() => {}); +// @ts-ignore +global['window'] = win; +global['document'] = win.document; +// @ts-ignore +global['history'] = { state: { } }; + +global['localStorage'] = { + getItem: () => '', + setItem: () => {}, + removeItem: () => {}, + clear: () => {}, + length: 0, + key: () => '', +}; + +/** + * Return the list of supported and actually active locales + */ +function getActiveLocales() { + const angularConfig = JSON.parse(readFileSync('angular.json', 'utf8')); + + const supportedLocales = [ + angularConfig.projects.mempool.i18n.sourceLocale, + ...Object.keys(angularConfig.projects.mempool.i18n.locales), + ]; + + return supportedLocales.filter(locale => locale === 'en-US' && existsSync(`./dist/mempool/server/${locale}`)); + // return supportedLocales.filter(locale => existsSync(`./dist/mempool/server/${locale}`)); +} + +function app() { + const server = express(); + + // proxy websocket + server.get('/api/v1/ws', createProxyMiddleware({ + target: 'ws://localhost:4200/api/v1/ws', + changeOrigin: true, + ws: true, + logLevel: 'debug' + })); + // proxy API to nginx + server.get('/api/**', createProxyMiddleware({ + // @ts-ignore + target: win.__env.NGINX_PROTOCOL + '://' + win.__env.NGINX_HOSTNAME + ':' + win.__env.NGINX_PORT, + changeOrigin: true, + })); + server.get('/resources/**', express.static('./src')); + + + // map / and /en to en-US + const defaultLocale = 'en-US'; + console.log(`serving default locale: ${defaultLocale}`); + const appServerModule = require(`./dist/mempool/server/${defaultLocale}/main.js`); + server.use('/', appServerModule.app(defaultLocale)); + server.use('/en', appServerModule.app(defaultLocale)); + + // map each locale to its localized main.js + getActiveLocales().forEach(locale => { + console.log('serving locale:', locale); + const appServerModule = require(`./dist/mempool/server/${locale}/main.js`); + + // map everything to itself + server.use(`/${locale}`, appServerModule.app(locale)); + + }); + + return server; +} + +function run() { + const port = process.env.PORT || 4000; + + // Start up the Node server + app().listen(port, () => { + console.log(`Node Express server listening on port ${port}`); + }); +} + +run(); \ No newline at end of file diff --git a/frontend/server.ts b/frontend/server.ts new file mode 100644 index 000000000..b66486d25 --- /dev/null +++ b/frontend/server.ts @@ -0,0 +1,146 @@ +import 'zone.js/dist/zone-node'; +import './src/resources/config.js'; + +import { ngExpressEngine } from '@nguniversal/express-engine'; +import * as express from 'express'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as domino from 'domino'; +import { createProxyMiddleware } from 'http-proxy-middleware'; + +import { join } from 'path'; +import { AppServerModule } from './src/main.server'; +import { APP_BASE_HREF } from '@angular/common'; +import { existsSync } from 'fs'; + +const template = fs.readFileSync(path.join(process.cwd(), 'dist/mempool/browser/en-US/', 'index.html')).toString(); +const win = domino.createWindow(template); + +// @ts-ignore +win.__env = global.__env; + +// @ts-ignore +win.matchMedia = () => { + return { + matches: true + }; +}; + +// @ts-ignore +win.setTimeout = (fn) => { fn(); }; +win.document.body.scrollTo = (() => {}); +// @ts-ignore +global['window'] = win; +global['document'] = win.document; +// @ts-ignore +global['history'] = { state: { } }; + +global['localStorage'] = { + getItem: () => '', + setItem: () => {}, + removeItem: () => {}, + clear: () => {}, + length: 0, + key: () => '', +}; + +// The Express app is exported so that it can be used by serverless Functions. +export function app(locale: string): express.Express { + const server = express(); + const distFolder = join(process.cwd(), `dist/mempool/browser/${locale}`); + const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'; + + // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) + server.engine('html', ngExpressEngine({ + bootstrap: AppServerModule, + })); + + server.set('view engine', 'html'); + server.set('views', distFolder); + + // only handle URLs that actually exist + //server.get(locale, getLocalizedSSR(indexHtml)); + server.get('/', getLocalizedSSR(indexHtml)); + server.get('/tx/*', getLocalizedSSR(indexHtml)); + server.get('/block/*', getLocalizedSSR(indexHtml)); + server.get('/mempool-block/*', getLocalizedSSR(indexHtml)); + server.get('/address/*', getLocalizedSSR(indexHtml)); + server.get('/blocks', getLocalizedSSR(indexHtml)); + server.get('/graphs', getLocalizedSSR(indexHtml)); + server.get('/liquid', getLocalizedSSR(indexHtml)); + server.get('/liquid/tx/*', getLocalizedSSR(indexHtml)); + server.get('/liquid/block/*', getLocalizedSSR(indexHtml)); + server.get('/liquid/mempool-block/*', getLocalizedSSR(indexHtml)); + server.get('/liquid/address/*', getLocalizedSSR(indexHtml)); + server.get('/liquid/asset/*', getLocalizedSSR(indexHtml)); + server.get('/liquid/blocks', getLocalizedSSR(indexHtml)); + server.get('/liquid/graphs', getLocalizedSSR(indexHtml)); + server.get('/liquid/assets', getLocalizedSSR(indexHtml)); + server.get('/liquid/api', getLocalizedSSR(indexHtml)); + server.get('/liquid/tv', getLocalizedSSR(indexHtml)); + server.get('/liquid/status', getLocalizedSSR(indexHtml)); + server.get('/liquid/about', getLocalizedSSR(indexHtml)); + server.get('/testnet', getLocalizedSSR(indexHtml)); + server.get('/testnet/tx/*', getLocalizedSSR(indexHtml)); + server.get('/testnet/block/*', getLocalizedSSR(indexHtml)); + server.get('/testnet/mempool-block/*', getLocalizedSSR(indexHtml)); + server.get('/testnet/address/*', getLocalizedSSR(indexHtml)); + server.get('/testnet/blocks', getLocalizedSSR(indexHtml)); + server.get('/testnet/graphs', getLocalizedSSR(indexHtml)); + server.get('/testnet/api', getLocalizedSSR(indexHtml)); + server.get('/testnet/tv', getLocalizedSSR(indexHtml)); + server.get('/testnet/status', getLocalizedSSR(indexHtml)); + server.get('/testnet/about', getLocalizedSSR(indexHtml)); + server.get('/bisq', getLocalizedSSR(indexHtml)); + server.get('/bisq/tx/*', getLocalizedSSR(indexHtml)); + server.get('/bisq/blocks', getLocalizedSSR(indexHtml)); + server.get('/bisq/block/*', getLocalizedSSR(indexHtml)); + server.get('/bisq/address/*', getLocalizedSSR(indexHtml)); + server.get('/bisq/stats', getLocalizedSSR(indexHtml)); + server.get('/bisq/about', getLocalizedSSR(indexHtml)); + server.get('/bisq/api', getLocalizedSSR(indexHtml)); + server.get('/about', getLocalizedSSR(indexHtml)); + server.get('/api', getLocalizedSSR(indexHtml)); + server.get('/tv', getLocalizedSSR(indexHtml)); + server.get('/status', getLocalizedSSR(indexHtml)); + server.get('/terms-of-service', getLocalizedSSR(indexHtml)); + + // fallback to static file handler so we send HTTP 404 to nginx + server.get('/**', express.static(distFolder, { maxAge: '1y' })); + + return server; +} + +function getLocalizedSSR(indexHtml) { + return (req, res) => { + res.render(indexHtml, { + req, + providers: [ + { provide: APP_BASE_HREF, useValue: req.baseUrl } + ] + }); + } +} + +// only used for development mode +function run(): void { + const port = process.env.PORT || 4000; + + // Start up the Node server + const server = app('en-US'); + server.listen(port, () => { + console.log(`Node Express server listening on port ${port}`); + }); +} + +// Webpack will replace 'require' with '__webpack_require__' +// '__non_webpack_require__' is a proxy to Node 'require' +// The below code is to ensure that the server is run only when not requiring the bundle. +declare const __non_webpack_require__: NodeRequire; +const mainModule = __non_webpack_require__.main; +const moduleFilename = mainModule && mainModule.filename || ''; +if (moduleFilename === __filename || moduleFilename.includes('iisnode')) { + run(); +} + +export * from './src/main.server'; \ No newline at end of file diff --git a/frontend/src/main.server.ts b/frontend/src/main.server.ts new file mode 100644 index 000000000..6121b7d88 --- /dev/null +++ b/frontend/src/main.server.ts @@ -0,0 +1,11 @@ + +import '@angular/localize/init'; +import { enableProdMode } from '@angular/core'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +export { AppServerModule } from './app/app.server.module'; +export { renderModule } from '@angular/platform-server'; diff --git a/frontend/tsconfig.server.json b/frontend/tsconfig.server.json new file mode 100644 index 000000000..34632f4ee --- /dev/null +++ b/frontend/tsconfig.server.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.app.json", + "compilerOptions": { + "outDir": "./out-tsc/server", + "target": "ES2022", + "sourceMap": true, + "types": [ + "node" + ] + }, + "files": [ + "src/main.server.ts", + "server.ts" + ], + "angularCompilerOptions": { + "entryModule": "./src/app/app.server.module#AppServerModule" + } +} \ No newline at end of file From 1bb625f06b90ddb0830ead03cf4cf90cea4f899c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 17:57:48 +0000 Subject: [PATCH 02/24] Cleaner SSR server routing --- frontend/generate-config.js | 2 +- frontend/server.run.ts | 3 --- frontend/server.ts | 52 +++---------------------------------- 3 files changed, 5 insertions(+), 52 deletions(-) diff --git a/frontend/generate-config.js b/frontend/generate-config.js index 7d30b9bc3..c7a81a482 100644 --- a/frontend/generate-config.js +++ b/frontend/generate-config.js @@ -71,7 +71,7 @@ const newConfig = `(function (window) { window.__env.${obj.key} = ${typeof obj.value === 'string' ? `'${obj.value}'` : obj.value};`, '')} window.__env.GIT_COMMIT_HASH = '${gitCommitHash}'; window.__env.PACKAGE_JSON_VERSION = '${packetJsonVersion}'; - }(global || this));`; + }((typeof global !== 'undefined') ? global : this));`; const newConfigTemplate = `(function (window) { window.__env = window.__env || {};${settings.reduce((str, obj) => `${str} diff --git a/frontend/server.run.ts b/frontend/server.run.ts index 273629f6f..58751182c 100644 --- a/frontend/server.run.ts +++ b/frontend/server.run.ts @@ -1,8 +1,6 @@ import 'zone.js/dist/zone-node'; import './src/resources/config.js'; -console.log(global); - import * as domino from 'domino'; import * as express from 'express'; import * as fs from 'fs'; @@ -23,7 +21,6 @@ win.matchMedia = () => { matches: true }; }; - // @ts-ignore win.setTimeout = (fn) => { fn(); }; win.document.body.scrollTo = (() => {}); diff --git a/frontend/server.ts b/frontend/server.ts index b66486d25..e64795be0 100644 --- a/frontend/server.ts +++ b/frontend/server.ts @@ -58,55 +58,11 @@ export function app(locale: string): express.Express { server.set('view engine', 'html'); server.set('views', distFolder); - // only handle URLs that actually exist - //server.get(locale, getLocalizedSSR(indexHtml)); - server.get('/', getLocalizedSSR(indexHtml)); - server.get('/tx/*', getLocalizedSSR(indexHtml)); - server.get('/block/*', getLocalizedSSR(indexHtml)); - server.get('/mempool-block/*', getLocalizedSSR(indexHtml)); - server.get('/address/*', getLocalizedSSR(indexHtml)); - server.get('/blocks', getLocalizedSSR(indexHtml)); - server.get('/graphs', getLocalizedSSR(indexHtml)); - server.get('/liquid', getLocalizedSSR(indexHtml)); - server.get('/liquid/tx/*', getLocalizedSSR(indexHtml)); - server.get('/liquid/block/*', getLocalizedSSR(indexHtml)); - server.get('/liquid/mempool-block/*', getLocalizedSSR(indexHtml)); - server.get('/liquid/address/*', getLocalizedSSR(indexHtml)); - server.get('/liquid/asset/*', getLocalizedSSR(indexHtml)); - server.get('/liquid/blocks', getLocalizedSSR(indexHtml)); - server.get('/liquid/graphs', getLocalizedSSR(indexHtml)); - server.get('/liquid/assets', getLocalizedSSR(indexHtml)); - server.get('/liquid/api', getLocalizedSSR(indexHtml)); - server.get('/liquid/tv', getLocalizedSSR(indexHtml)); - server.get('/liquid/status', getLocalizedSSR(indexHtml)); - server.get('/liquid/about', getLocalizedSSR(indexHtml)); - server.get('/testnet', getLocalizedSSR(indexHtml)); - server.get('/testnet/tx/*', getLocalizedSSR(indexHtml)); - server.get('/testnet/block/*', getLocalizedSSR(indexHtml)); - server.get('/testnet/mempool-block/*', getLocalizedSSR(indexHtml)); - server.get('/testnet/address/*', getLocalizedSSR(indexHtml)); - server.get('/testnet/blocks', getLocalizedSSR(indexHtml)); - server.get('/testnet/graphs', getLocalizedSSR(indexHtml)); - server.get('/testnet/api', getLocalizedSSR(indexHtml)); - server.get('/testnet/tv', getLocalizedSSR(indexHtml)); - server.get('/testnet/status', getLocalizedSSR(indexHtml)); - server.get('/testnet/about', getLocalizedSSR(indexHtml)); - server.get('/bisq', getLocalizedSSR(indexHtml)); - server.get('/bisq/tx/*', getLocalizedSSR(indexHtml)); - server.get('/bisq/blocks', getLocalizedSSR(indexHtml)); - server.get('/bisq/block/*', getLocalizedSSR(indexHtml)); - server.get('/bisq/address/*', getLocalizedSSR(indexHtml)); - server.get('/bisq/stats', getLocalizedSSR(indexHtml)); - server.get('/bisq/about', getLocalizedSSR(indexHtml)); - server.get('/bisq/api', getLocalizedSSR(indexHtml)); - server.get('/about', getLocalizedSSR(indexHtml)); - server.get('/api', getLocalizedSSR(indexHtml)); - server.get('/tv', getLocalizedSSR(indexHtml)); - server.get('/status', getLocalizedSSR(indexHtml)); - server.get('/terms-of-service', getLocalizedSSR(indexHtml)); - // fallback to static file handler so we send HTTP 404 to nginx - server.get('/**', express.static(distFolder, { maxAge: '1y' })); + // static file handler so we send HTTP 404 to nginx + server.get('/**.(css|js|json|ico|webmanifest|png|jpg|jpeg|svg|mp4)*', express.static(distFolder, { maxAge: '1y', fallthrough: false })); + // handle page routes + server.get('/**', getLocalizedSSR(indexHtml)); return server; } From 4e26e1f196f12456db50daa158455e31c5c785f0 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 17:58:35 +0000 Subject: [PATCH 03/24] SSR ResizeObserver shim --- frontend/server.ts | 4 ++++ frontend/shims.ts | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 frontend/shims.ts diff --git a/frontend/server.ts b/frontend/server.ts index e64795be0..29677959d 100644 --- a/frontend/server.ts +++ b/frontend/server.ts @@ -13,6 +13,8 @@ import { AppServerModule } from './src/main.server'; import { APP_BASE_HREF } from '@angular/common'; import { existsSync } from 'fs'; +import { ResizeObserver } from './shims'; + const template = fs.readFileSync(path.join(process.cwd(), 'dist/mempool/browser/en-US/', 'index.html')).toString(); const win = domino.createWindow(template); @@ -29,11 +31,13 @@ win.matchMedia = () => { // @ts-ignore win.setTimeout = (fn) => { fn(); }; win.document.body.scrollTo = (() => {}); +win['ResizeObserver'] = ResizeObserver; // @ts-ignore global['window'] = win; global['document'] = win.document; // @ts-ignore global['history'] = { state: { } }; +global['navigator'] = win.navigator; global['localStorage'] = { getItem: () => '', diff --git a/frontend/shims.ts b/frontend/shims.ts new file mode 100644 index 000000000..50f1b6f33 --- /dev/null +++ b/frontend/shims.ts @@ -0,0 +1,7 @@ +export class ResizeObserver { + constructor() {} + + disconnect() {} + observe() {} + unobserve() {} +} \ No newline at end of file From e6fb93140ca2894445e0cf0de08d5dd1afa2b153 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 18:00:07 +0000 Subject: [PATCH 04/24] Fix default mining pool img fallback behavior --- .../src/app/components/blocks-list/blocks-list.component.html | 2 +- .../src/app/components/pool-ranking/pool-ranking.component.html | 2 +- frontend/src/app/components/pool/pool.component.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html index fd171720f..d82472492 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.html +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -33,7 +33,7 @@
+ onError="this.onerror=null; this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'"> {{ block.extras.pool.name }} {{ block.extras.coinbaseRaw | hex2ascii }} diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.html b/frontend/src/app/components/pool-ranking/pool-ranking.component.html index 85dd16152..0cab4456f 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.html +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.html @@ -102,7 +102,7 @@ {{ pool.rank }} - + {{ pool.name }} {{ pool.lastEstimatedHashrate }} {{ diff --git a/frontend/src/app/components/pool/pool.component.html b/frontend/src/app/components/pool/pool.component.html index 3228facd1..c73f68a46 100644 --- a/frontend/src/app/components/pool/pool.component.html +++ b/frontend/src/app/components/pool/pool.component.html @@ -6,7 +6,7 @@
+ onError="this.onerror=null; this.src = '/resources/mining-pools/default.svg'" class="mr-3">

{{ poolStats.pool.name }}

From a2b9b0c89df189789d9aa8c66bdbcba0ce8230e6 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 21:12:51 +0000 Subject: [PATCH 05/24] Exclude echarts from server-side rendering --- .../block-fees-graph.component.html | 2 +- .../block-health-graph.component.html | 2 +- .../block-rewards-graph.component.html | 2 +- .../block-sizes-weights-graph.component.html | 2 +- .../fee-distribution-graph.component.html | 2 +- .../hashrate-chart.component.html | 2 +- .../hashrate-chart-pools.component.html | 2 +- ...incoming-transactions-graph.component.html | 2 +- .../lbtc-pegs-graph.component.html | 2 +- .../mempool-graph.component.html | 2 +- .../pool-ranking/pool-ranking.component.html | 2 +- .../pool/pool-preview.component.html | 2 +- .../app/components/pool/pool.component.html | 2 +- .../node-fee-chart.component.html | 2 +- .../node-statistics-chart.component.html | 2 +- .../nodes-channels-map.component.html | 2 +- .../node-channels.component.html | 2 +- .../nodes-map/nodes-map.component.html | 8 +++++--- .../nodes-networks-chart.component.html | 2 +- .../nodes-per-country-chart.component.html | 2 +- .../nodes-per-isp-chart.component.html | 2 +- .../lightning-statistics-chart.component.html | 2 +- .../directives/browser-only.directive.ts | 19 +++++++++++++++++++ frontend/src/app/shared/shared.module.ts | 3 +++ 24 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 frontend/src/app/shared/directives/browser-only.directive.ts diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html index 76071be96..9734f8681 100644 --- a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html +++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html @@ -36,7 +36,7 @@
-
diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.html b/frontend/src/app/components/block-health-graph/block-health-graph.component.html index 4cd10f2dd..84a75dd3c 100644 --- a/frontend/src/app/components/block-health-graph/block-health-graph.component.html +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.html @@ -45,7 +45,7 @@
-
diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html index 198153583..7a99ac52e 100644 --- a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html +++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html @@ -37,7 +37,7 @@
-
diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html index 122b5e7ca..002bbc90d 100644 --- a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html +++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html @@ -44,7 +44,7 @@
-
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html index 3465bde35..afdc35e06 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html @@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html index f3d340472..eba2746e0 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html @@ -54,7 +54,7 @@
-
diff --git a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html index bbdc745fe..b1588cbb5 100644 --- a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html +++ b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html @@ -31,7 +31,7 @@
-
diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html index 05f9d5afb..6b59c557e 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html @@ -1,4 +1,4 @@ -
diff --git a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html index 99fb46934..878869505 100644 --- a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html +++ b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html @@ -1,4 +1,4 @@ -
+
\ No newline at end of file diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.html b/frontend/src/app/components/mempool-graph/mempool-graph.component.html index f3ec401cf..1f3621bc3 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.html +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.html @@ -1,4 +1,4 @@ -
+
\ No newline at end of file diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.html b/frontend/src/app/components/pool-ranking/pool-ranking.component.html index 0cab4456f..f5e21e66f 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.html +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.html @@ -76,7 +76,7 @@
-
diff --git a/frontend/src/app/components/pool/pool-preview.component.html b/frontend/src/app/components/pool/pool-preview.component.html index ff5201ae0..5ccb415e6 100644 --- a/frontend/src/app/components/pool/pool-preview.component.html +++ b/frontend/src/app/components/pool/pool-preview.component.html @@ -25,7 +25,7 @@
-
+
diff --git a/frontend/src/app/components/pool/pool.component.html b/frontend/src/app/components/pool/pool.component.html index c73f68a46..ad84c77ce 100644 --- a/frontend/src/app/components/pool/pool.component.html +++ b/frontend/src/app/components/pool/pool.component.html @@ -168,7 +168,7 @@ -
+
diff --git a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html index 468b22acf..4b3a13016 100644 --- a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html +++ b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html @@ -1,6 +1,6 @@

Fee distribution

-
+
diff --git a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html index c5cad52fa..209958fde 100644 --- a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html +++ b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html @@ -1,6 +1,6 @@
-
+
diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html index 7237c709f..50f84db30 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html @@ -1,7 +1,7 @@
-
diff --git a/frontend/src/app/lightning/nodes-channels/node-channels.component.html b/frontend/src/app/lightning/nodes-channels/node-channels.component.html index 8fc63793c..c3a865a0f 100644 --- a/frontend/src/app/lightning/nodes-channels/node-channels.component.html +++ b/frontend/src/app/lightning/nodes-channels/node-channels.component.html @@ -1,6 +1,6 @@

Active channels map

-
+
diff --git a/frontend/src/app/lightning/nodes-map/nodes-map.component.html b/frontend/src/app/lightning/nodes-map/nodes-map.component.html index 7fed096f5..045ab7925 100644 --- a/frontend/src/app/lightning/nodes-map/nodes-map.component.html +++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.html @@ -7,8 +7,10 @@ (Tor nodes excluded)
-
-
+ +
+
+
diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html index 915f2f7ec..cf02b60a8 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html @@ -35,7 +35,7 @@
-
+
diff --git a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html index ed42595ef..5c285e3de 100644 --- a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html +++ b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html @@ -12,7 +12,7 @@
-
diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html index 794ced684..aa005933a 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html @@ -39,7 +39,7 @@
-
diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html index 9bb88ac59..b0bfc8295 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html @@ -42,7 +42,7 @@
-
diff --git a/frontend/src/app/shared/directives/browser-only.directive.ts b/frontend/src/app/shared/directives/browser-only.directive.ts new file mode 100644 index 000000000..97df39e2b --- /dev/null +++ b/frontend/src/app/shared/directives/browser-only.directive.ts @@ -0,0 +1,19 @@ +import { Directive, TemplateRef, ViewContainerRef, Inject, PLATFORM_ID } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; + +@Directive({ + selector: '[browserOnly]' +}) +export class BrowserOnlyDirective { + constructor( + private templateRef: TemplateRef, + private viewContainer: ViewContainerRef, + @Inject(PLATFORM_ID) private platformId: Object + ) { + if (isPlatformBrowser(this.platformId)) { + this.viewContainer.createEmbeddedView(this.templateRef); + } else { + this.viewContainer.clear(); + } + } +} diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 245b68c53..53a5beba5 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -33,6 +33,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { LanguageSelectorComponent } from '../components/language-selector/language-selector.component'; import { FiatSelectorComponent } from '../components/fiat-selector/fiat-selector.component'; import { RateUnitSelectorComponent } from '../components/rate-unit-selector/rate-unit-selector.component'; +import { BrowserOnlyDirective } from './directives/browser-only.directive'; import { ColoredPriceDirective } from './directives/colored-price.directive'; import { NoSanitizePipe } from './pipes/no-sanitize.pipe'; import { MempoolBlocksComponent } from '../components/mempool-blocks/mempool-blocks.component'; @@ -132,6 +133,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir FeeRoundingPipe, FiatCurrencyPipe, ColoredPriceDirective, + BrowserOnlyDirective, BlockchainComponent, BlockViewComponent, EightBlocksComponent, @@ -264,6 +266,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir Decimal2HexPipe, FeeRoundingPipe, ColoredPriceDirective, + BrowserOnlyDirective, NoSanitizePipe, BlockchainComponent, MempoolBlocksComponent, From cfdbd93695d4fdafcf0d274e63a3284cea4798a2 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 21:13:35 +0000 Subject: [PATCH 06/24] Fix SSR matchMedia shim --- frontend/server.ts | 5 +++-- frontend/src/app/shared/pipes/bytes-pipe/utils.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/server.ts b/frontend/server.ts index 29677959d..ffce336f5 100644 --- a/frontend/server.ts +++ b/frontend/server.ts @@ -22,9 +22,10 @@ const win = domino.createWindow(template); win.__env = global.__env; // @ts-ignore -win.matchMedia = () => { +win.matchMedia = (media) => { return { - matches: true + media, + matches: true, }; }; diff --git a/frontend/src/app/shared/pipes/bytes-pipe/utils.ts b/frontend/src/app/shared/pipes/bytes-pipe/utils.ts index 7c88c83bc..138218a43 100644 --- a/frontend/src/app/shared/pipes/bytes-pipe/utils.ts +++ b/frontend/src/app/shared/pipes/bytes-pipe/utils.ts @@ -323,7 +323,7 @@ export function hasTouchScreen(): boolean { // @ts-ignore hasTouchScreen = navigator.msMaxTouchPoints > 0; } else { - const mQ = matchMedia?.('(pointer:coarse)'); + const mQ = window.matchMedia?.('(pointer:coarse)'); if (mQ?.media === '(pointer:coarse)') { hasTouchScreen = !!mQ.matches; } else if ('orientation' in window) { From 6464f6d8bbf29bad575d47cb06b3fabef4f12b9e Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 21:14:17 +0000 Subject: [PATCH 07/24] Exclude webgl block viz from SSR rendering --- .../block-overview-graph.component.html | 2 +- .../block-overview-graph.component.ts | 66 ++++++++++++------- .../app/components/block/block.component.ts | 6 +- .../mempool-block/mempool-block.component.ts | 13 ++-- 4 files changed, 51 insertions(+), 36 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html index 1d13e8b4e..247d7c384 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html @@ -1,7 +1,7 @@
- +
not available
diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index 95305d72f..559e16279 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -94,13 +94,15 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } ngAfterViewInit(): void { - this.canvas.nativeElement.addEventListener('webglcontextlost', this.handleContextLost, false); - this.canvas.nativeElement.addEventListener('webglcontextrestored', this.handleContextRestored, false); - this.gl = this.canvas.nativeElement.getContext('webgl'); + if (this.canvas) { + this.canvas.nativeElement.addEventListener('webglcontextlost', this.handleContextLost, false); + this.canvas.nativeElement.addEventListener('webglcontextrestored', this.handleContextRestored, false); + this.gl = this.canvas.nativeElement.getContext('webgl'); - if (this.gl) { - this.initCanvas(); - this.resizeCanvas(); + if (this.gl) { + this.initCanvas(); + this.resizeCanvas(); + } } } @@ -142,8 +144,10 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On cancelAnimationFrame(this.animationFrameRequest); clearTimeout(this.animationHeartBeat); } - this.canvas.nativeElement.removeEventListener('webglcontextlost', this.handleContextLost); - this.canvas.nativeElement.removeEventListener('webglcontextrestored', this.handleContextRestored); + if (this.canvas) { + this.canvas.nativeElement.removeEventListener('webglcontextlost', this.handleContextLost); + this.canvas.nativeElement.removeEventListener('webglcontextrestored', this.handleContextRestored); + } } clear(direction): void { @@ -209,6 +213,10 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } initCanvas(): void { + if (!this.canvas || !this.gl) { + return; + } + this.gl.clearColor(0.0, 0.0, 0.0, 0.0); this.gl.clear(this.gl.COLOR_BUFFER_BIT); @@ -262,24 +270,26 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On @HostListener('window:resize', ['$event']) resizeCanvas(): void { - this.cssWidth = this.canvas.nativeElement.offsetParent.clientWidth; - this.cssHeight = this.canvas.nativeElement.offsetParent.clientHeight; - this.displayWidth = window.devicePixelRatio * this.cssWidth; - this.displayHeight = window.devicePixelRatio * this.cssHeight; - this.canvas.nativeElement.width = this.displayWidth; - this.canvas.nativeElement.height = this.displayHeight; - if (this.gl) { - this.gl.viewport(0, 0, this.displayWidth, this.displayHeight); - } - if (this.scene) { - this.scene.resize({ width: this.displayWidth, height: this.displayHeight, animate: false }); - this.start(); - } else { - this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution, - blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, - highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset, + if (this.canvas) { + this.cssWidth = this.canvas.nativeElement.offsetParent.clientWidth; + this.cssHeight = this.canvas.nativeElement.offsetParent.clientHeight; + this.displayWidth = window.devicePixelRatio * this.cssWidth; + this.displayHeight = window.devicePixelRatio * this.cssHeight; + this.canvas.nativeElement.width = this.displayWidth; + this.canvas.nativeElement.height = this.displayHeight; + if (this.gl) { + this.gl.viewport(0, 0, this.displayWidth, this.displayHeight); + } + if (this.scene) { + this.scene.resize({ width: this.displayWidth, height: this.displayHeight, animate: false }); + this.start(); + } else { + this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution, + blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, + highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset, colorFunction: this.getColorFunction() }); - this.start(); + this.start(); + } } } @@ -406,6 +416,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On @HostListener('pointerup', ['$event']) onClick(event) { + if (!this.canvas) { + return; + } if (event.target === this.canvas.nativeElement && event.pointerType === 'touch') { this.setPreviewTx(event.offsetX, event.offsetY, true); } else if (event.target === this.canvas.nativeElement) { @@ -417,6 +430,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On @HostListener('pointermove', ['$event']) onPointerMove(event) { + if (!this.canvas) { + return; + } if (event.target === this.canvas.nativeElement) { this.setPreviewTx(event.offsetX, event.offsetY, false); } else { diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index bb36928b0..b43774a7a 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ViewChildren, QueryList } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChildren, QueryList, Inject, PLATFORM_ID } from '@angular/core'; import { Location } from '@angular/common'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ElectrsApiService } from '../../services/electrs-api.service'; @@ -17,6 +17,7 @@ import { seoDescriptionNetwork } from '../../shared/common.utils'; import { PriceService, Price } from '../../services/price.service'; import { CacheService } from '../../services/cache.service'; import { ServicesApiServices } from '../../services/services-api.service'; +import { isPlatformServer } from '@angular/common'; @Component({ selector: 'app-block', @@ -108,8 +109,9 @@ export class BlockComponent implements OnInit, OnDestroy { private priceService: PriceService, private cacheService: CacheService, private servicesApiService: ServicesApiServices, + @Inject(PLATFORM_ID) private platformId: Object, ) { - this.webGlEnabled = detectWebGL(); + this.webGlEnabled = isPlatformServer(this.platformId) || detectWebGL(); } ngOnInit() { diff --git a/frontend/src/app/components/mempool-block/mempool-block.component.ts b/frontend/src/app/components/mempool-block/mempool-block.component.ts index 89fb97dad..e972083a7 100644 --- a/frontend/src/app/components/mempool-block/mempool-block.component.ts +++ b/frontend/src/app/components/mempool-block/mempool-block.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Inject, PLATFORM_ID, ChangeDetectorRef } from '@angular/core'; +import { detectWebGL } from '../../shared/graphs.utils'; import { StateService } from '../../services/state.service'; import { ActivatedRoute, ParamMap } from '@angular/router'; import { switchMap, map, tap, filter } from 'rxjs/operators'; @@ -7,6 +8,7 @@ import { Observable, BehaviorSubject } from 'rxjs'; import { SeoService } from '../../services/seo.service'; import { seoDescriptionNetwork } from '../../shared/common.utils'; import { WebsocketService } from '../../services/websocket.service'; +import { isPlatformServer } from '@angular/common'; @Component({ selector: 'app-mempool-block', @@ -29,8 +31,9 @@ export class MempoolBlockComponent implements OnInit, OnDestroy { private seoService: SeoService, private websocketService: WebsocketService, private cd: ChangeDetectorRef, + @Inject(PLATFORM_ID) private platformId: Object, ) { - this.webGlEnabled = detectWebGL(); + this.webGlEnabled = isPlatformServer(this.platformId) || detectWebGL(); } ngOnInit(): void { @@ -93,9 +96,3 @@ export class MempoolBlockComponent implements OnInit, OnDestroy { this.previewTx = event; } } - -function detectWebGL() { - const canvas = document.createElement('canvas'); - const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - return (gl && gl instanceof WebGLRenderingContext); -} From 10e468d463b8926429aef7e18c200b38edeb1c2d Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 21:14:59 +0000 Subject: [PATCH 08/24] Fix hashrate difficulty SSR state dependency --- .../app/components/hashrate-chart/hashrate-chart.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts index 2bda9a35a..8ee7beea3 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts @@ -326,7 +326,7 @@ export class HashrateChartComponent implements OnInit { }, }, ], - selected: JSON.parse(this.storageService.getValue('hashrate_difficulty_legend')) ?? { + selected: JSON.parse(this.storageService?.getValue('hashrate_difficulty_legend') || 'null') ?? { '$localize`:@@79a9dc5b1caca3cbeb1733a19515edacc5fc7920:Hashrate`': true, '$localize`::Difficulty`': this.network === '', '$localize`Hashrate (MA)`': true, From 29aaeef47bce99f330594c72d32d65c8de9d4e84 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 18 Oct 2023 23:04:21 +0000 Subject: [PATCH 09/24] Fix deprecated SSR state transfer imports --- frontend/src/app/app.server.module.ts | 3 +-- frontend/src/app/services/websocket.service.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/app.server.module.ts b/frontend/src/app/app.server.module.ts index ff4885db1..9833fd7b9 100644 --- a/frontend/src/app/app.server.module.ts +++ b/frontend/src/app/app.server.module.ts @@ -1,6 +1,6 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { NgModule } from '@angular/core'; -import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'; +import { ServerModule } from '@angular/platform-server'; import { AppModule } from './app.module'; import { AppComponent } from './components/app/app.component'; @@ -10,7 +10,6 @@ import { HttpCacheInterceptor } from './services/http-cache.interceptor'; imports: [ AppModule, ServerModule, - ServerTransferStateModule, ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true } diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 2f6bef2d9..54fcad7d4 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -6,7 +6,7 @@ import { Transaction } from '../interfaces/electrs.interface'; import { Subscription } from 'rxjs'; import { ApiService } from './api.service'; import { take } from 'rxjs/operators'; -import { TransferState, makeStateKey } from '@angular/platform-browser'; +import { TransferState, makeStateKey } from '@angular/core'; import { CacheService } from './cache.service'; import { uncompressDeltaChange, uncompressTx } from '../shared/common.utils'; From 5b4132b551875e6fa6f5c6c45b696d9bead4b1ce Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 25 Oct 2023 16:38:05 +0000 Subject: [PATCH 10/24] SSR: fix incoming tx graph init state --- frontend/src/app/dashboard/dashboard.component.html | 4 ++-- frontend/src/app/dashboard/dashboard.component.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index aa28addbf..5fe1f6f2d 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -45,12 +45,12 @@
Incoming Transactions
-
+
diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 005c8c45c..e54527939 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -8,6 +8,7 @@ import { StateService } from '../services/state.service'; import { WebsocketService } from '../services/websocket.service'; import { SeoService } from '../services/seo.service'; import { ActiveFilter, FilterMode, toFlags } from '../shared/filters.utils'; +import { TransferState } from '@angular/core'; interface MempoolBlocksData { blocks: number; @@ -241,7 +242,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { return null; } }), - share(), + shareReplay(1), ); if (this.stateService.network === 'liquid') { From c5822b11a0fddfad95ef1dc66846af7b7b71d66b Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sat, 28 Oct 2023 00:33:29 +0000 Subject: [PATCH 11/24] SSR zone macrotask utilities, solve tx page initial state --- frontend/src/app/app.module.ts | 5 +- frontend/src/app/app.server.module.ts | 9 ++- .../transaction/transaction.component.ts | 17 ++++-- frontend/src/app/injection-tokens.ts | 3 + .../src/app/services/websocket.service.ts | 1 + .../src/app/services/zone-shim.service.ts | 14 +++++ frontend/src/app/services/zone.service.ts | 60 +++++++++++++++++++ 7 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 frontend/src/app/injection-tokens.ts create mode 100644 frontend/src/app/services/zone-shim.service.ts create mode 100644 frontend/src/app/services/zone.service.ts diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 6b7ec7f51..e3f585a25 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -2,6 +2,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { ModuleWithProviders, NgModule } from '@angular/core'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ZONE_SERVICE } from './injection-tokens'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './components/app/app.component'; import { ElectrsApiService } from './services/electrs-api.service'; @@ -13,6 +14,7 @@ import { WebsocketService } from './services/websocket.service'; import { AudioService } from './services/audio.service'; import { SeoService } from './services/seo.service'; import { OpenGraphService } from './services/opengraph.service'; +import { ZoneService } from './services/zone-shim.service'; import { SharedModule } from './shared/shared.module'; import { StorageService } from './services/storage.service'; import { HttpCacheInterceptor } from './services/http-cache.interceptor'; @@ -42,7 +44,8 @@ const providers = [ CapAddressPipe, AppPreloadingStrategy, ServicesApiServices, - { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true } + { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }, + { provide: ZONE_SERVICE, useClass: ZoneService }, ]; @NgModule({ diff --git a/frontend/src/app/app.server.module.ts b/frontend/src/app/app.server.module.ts index 9833fd7b9..10ef157f4 100644 --- a/frontend/src/app/app.server.module.ts +++ b/frontend/src/app/app.server.module.ts @@ -2,9 +2,13 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { NgModule } from '@angular/core'; import { ServerModule } from '@angular/platform-server'; +import { ZONE_SERVICE } from './injection-tokens'; import { AppModule } from './app.module'; import { AppComponent } from './components/app/app.component'; import { HttpCacheInterceptor } from './services/http-cache.interceptor'; +import { StateService } from './services/state.service'; +import { ZoneService } from './services/zone.service'; + @NgModule({ imports: [ @@ -12,8 +16,9 @@ import { HttpCacheInterceptor } from './services/http-cache.interceptor'; ServerModule, ], providers: [ - { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true } + { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }, + { provide: ZONE_SERVICE, useClass: ZoneService }, ], bootstrap: [AppComponent], }) -export class AppServerModule {} +export class AppServerModule {} \ No newline at end of file diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 375742deb..82f26d3d7 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, AfterViewInit, OnDestroy, HostListener, ViewChild, ElementRef } from '@angular/core'; +import { Component, OnInit, AfterViewInit, OnDestroy, HostListener, ViewChild, ElementRef, Inject, ChangeDetectorRef } from '@angular/core'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { @@ -28,6 +28,7 @@ import { Price, PriceService } from '../../services/price.service'; import { isFeatureActive } from '../../bitcoin.utils'; import { ServicesApiServices } from '../../services/services-api.service'; import { EnterpriseService } from '../../services/enterprise.service'; +import { ZONE_SERVICE } from '../../injection-tokens'; interface Pool { id: number; @@ -101,7 +102,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { inputIndex: number; outputIndex: number; graphExpanded: boolean = false; - graphWidth: number = 1000; + graphWidth: number = 1068; graphHeight: number = 360; inOutLimit: number = 150; maxInOut: number = 0; @@ -141,6 +142,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { private priceService: PriceService, private storageService: StorageService, private enterpriseService: EnterpriseService, + private cd: ChangeDetectorRef, + @Inject(ZONE_SERVICE) private zoneService: any, ) {} ngOnInit() { @@ -356,7 +359,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { } }); - this.subscription = this.route.paramMap + this.subscription = this.zoneService.wrapObservable(this.route.paramMap .pipe( switchMap((params: ParamMap) => { const urlMatch = (params.get('id') || '').split(':'); @@ -430,7 +433,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { } return of(tx); }) - ) + )) .subscribe((tx: Transaction) => { if (!tx) { this.fetchCachedTx$.next(this.txId); @@ -503,6 +506,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { ).subscribe(); setTimeout(() => { this.applyFragment(); }, 0); + + this.cd.detectChanges(); }, (error) => { this.error = error; @@ -785,9 +790,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { @HostListener('window:resize', ['$event']) setGraphSize(): void { this.isMobile = window.innerWidth < 850; - if (this.graphContainer?.nativeElement) { + if (this.graphContainer?.nativeElement && this.stateService.isBrowser) { setTimeout(() => { - if (this.graphContainer?.nativeElement) { + if (this.graphContainer?.nativeElement?.clientWidth) { this.graphWidth = this.graphContainer.nativeElement.clientWidth; } else { setTimeout(() => { this.setGraphSize(); }, 1); diff --git a/frontend/src/app/injection-tokens.ts b/frontend/src/app/injection-tokens.ts new file mode 100644 index 000000000..6d923fd45 --- /dev/null +++ b/frontend/src/app/injection-tokens.ts @@ -0,0 +1,3 @@ +import { InjectionToken } from '@angular/core'; + +export const ZONE_SERVICE = new InjectionToken('ZONE_TASK'); \ No newline at end of file diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 54fcad7d4..25829ea3a 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -59,6 +59,7 @@ export class WebsocketService { const theInitData = this.transferState.get(initData, null); if (theInitData) { + this.stateService.isLoadingWebSocket$.next(false); this.handleResponse(theInitData.body); this.startSubscription(false, true); } else { diff --git a/frontend/src/app/services/zone-shim.service.ts b/frontend/src/app/services/zone-shim.service.ts new file mode 100644 index 000000000..003d39f71 --- /dev/null +++ b/frontend/src/app/services/zone-shim.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class ZoneService { + + constructor() { } + + wrapObservable(obs: Observable): Observable { + return obs; + } +} diff --git a/frontend/src/app/services/zone.service.ts b/frontend/src/app/services/zone.service.ts new file mode 100644 index 000000000..210c5f8f0 --- /dev/null +++ b/frontend/src/app/services/zone.service.ts @@ -0,0 +1,60 @@ +import { ApplicationRef, Injectable, NgZone } from '@angular/core'; +import { Observable, Subscriber } from 'rxjs'; + +// global Zone object provided by zone.js +declare const Zone: any; + +@Injectable({ + providedIn: 'root' +}) +export class ZoneService { + + constructor( + private ngZone: NgZone, + private appRef: ApplicationRef, + ) { } + + wrapObservable(obs: Observable): Observable { + return new Observable((subscriber: Subscriber) => { + let task: any; + + this.ngZone.run(() => { + task = Zone.current.scheduleMacroTask('wrapObservable', () => {}, {}, () => {}, () => {}); + }); + + const subscription = obs.subscribe( + value => { + subscriber.next(value); + if (task) { + this.ngZone.run(() => { + this.appRef.tick(); + }); + task.invoke(); + } + }, + err => { + subscriber.error(err); + if (task) { + this.appRef.tick(); + task.invoke(); + } + }, + () => { + subscriber.complete(); + if (task) { + this.appRef.tick(); + task.invoke(); + } + } + ); + + return () => { + subscription.unsubscribe(); + if (task) { + this.appRef.tick(); + task.invoke(); + } + }; + }); + } +} From 1ae5f053169815b9f68ebb8027e28cc8c68296a8 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sat, 28 Oct 2023 23:30:58 +0000 Subject: [PATCH 12/24] SSR: init latest replacements on server side --- .../src/app/services/websocket.service.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 25829ea3a..2256d174d 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -3,7 +3,7 @@ import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; import { WebsocketResponse } from '../interfaces/websocket.interface'; import { StateService } from './state.service'; import { Transaction } from '../interfaces/electrs.interface'; -import { Subscription } from 'rxjs'; +import { firstValueFrom, Subscription } from 'rxjs'; import { ApiService } from './api.service'; import { take } from 'rxjs/operators'; import { TransferState, makeStateKey } from '@angular/core'; @@ -224,6 +224,7 @@ export class WebsocketService { } startTrackRbfSummary() { + this.initRbfSummary(); this.websocketSubject.next({ 'track-rbf-summary': true }); this.isTrackingRbfSummary = true; } @@ -446,4 +447,30 @@ export class WebsocketService { this.websocketSubject.next({'refresh-blocks': true}); } } + + async initRbfSummary(): Promise { + if (!this.stateService.isBrowser) { + const rbfList = await firstValueFrom(this.apiService.getRbfList$(false)); + if (rbfList) { + const rbfSummary = rbfList.slice(0, 6).map(rbfTree => { + let oldFee = 0; + let oldVsize = 0; + for (const replaced of rbfTree.replaces) { + oldFee += replaced.tx.fee; + oldVsize += replaced.tx.vsize; + } + return { + txid: rbfTree.tx.txid, + mined: !!rbfTree.tx.mined, + fullRbf: !!rbfTree.tx.fullRbf, + oldFee, + oldVsize, + newFee: rbfTree.tx.fee, + newVsize: rbfTree.tx.vsize, + }; + }); + this.stateService.rbfLatestSummary$.next(rbfSummary); + } + } + } } From bcd337794a807d66ee59c6994408d90418719f01 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 29 Oct 2023 01:20:26 +0000 Subject: [PATCH 13/24] SSR: fix mining dashboard initial layout --- .../components/mining-dashboard/mining-dashboard.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html index c4fca72eb..6cadddd6b 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html @@ -38,7 +38,7 @@
-
+
From abd7f62b20156217c009b1a0b8031f17960490ee Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 29 Oct 2023 01:21:07 +0000 Subject: [PATCH 14/24] SSR: preserve transferstate api response headers --- .../src/app/dashboard/dashboard.component.ts | 1 - .../app/services/http-cache.interceptor.ts | 26 ++++++++++++------- .../src/app/services/websocket.service.ts | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index e54527939..98b89806c 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -8,7 +8,6 @@ import { StateService } from '../services/state.service'; import { WebsocketService } from '../services/websocket.service'; import { SeoService } from '../services/seo.service'; import { ActiveFilter, FilterMode, toFlags } from '../shared/filters.utils'; -import { TransferState } from '@angular/core'; interface MempoolBlocksData { blocks: number; diff --git a/frontend/src/app/services/http-cache.interceptor.ts b/frontend/src/app/services/http-cache.interceptor.ts index 289919534..c7624887a 100644 --- a/frontend/src/app/services/http-cache.interceptor.ts +++ b/frontend/src/app/services/http-cache.interceptor.ts @@ -1,5 +1,5 @@ import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; -import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http'; +import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse, HttpHeaders } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { tap } from 'rxjs/operators'; import { TransferState, makeStateKey } from '@angular/platform-browser'; @@ -17,14 +17,18 @@ export class HttpCacheInterceptor implements HttpInterceptor { intercept(request: HttpRequest, next: HttpHandler): Observable> { if (this.isBrowser && request.method === 'GET') { - const cachedResponse = this.transferState.get(makeStateKey(request.url), null); - if (cachedResponse) { + const { response, headers } = this.transferState.get(makeStateKey(request.url), null) || {}; + if (response) { + const httpHeaders = new HttpHeaders(); + for (const [k,v] of Object.entries(headers)) { + httpHeaders.set(k,v as string[]); + } const modifiedResponse = new HttpResponse({ - headers: cachedResponse.headers, - body: cachedResponse.body, - status: cachedResponse.status, - statusText: cachedResponse.statusText, - url: cachedResponse.url + headers: httpHeaders, + body: response.body, + status: response.status, + statusText: response.statusText, + url: response.url }); this.transferState.remove(makeStateKey(request.url)); return of(modifiedResponse); @@ -35,7 +39,11 @@ export class HttpCacheInterceptor implements HttpInterceptor { .pipe(tap((event: HttpEvent) => { if (!this.isBrowser && event instanceof HttpResponse) { let keyId = request.url.split('/').slice(3).join('/'); - this.transferState.set(makeStateKey('/' + keyId), event); + const headers = {}; + for (const k of event.headers.keys()) { + headers[k] = event.headers.getAll(k); + } + this.transferState.set(makeStateKey('/' + keyId), { response: event, headers }); } })); } diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 2256d174d..5ef637332 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -57,7 +57,7 @@ export class WebsocketService { this.network = this.stateService.network === 'bisq' && !this.stateService.env.BISQ_SEPARATE_BACKEND ? '' : this.stateService.network; this.websocketSubject = webSocket(this.webSocketUrl.replace('{network}', this.network ? '/' + this.network : '')); - const theInitData = this.transferState.get(initData, null); + const { response: theInitData } = this.transferState.get(initData, null) || {}; if (theInitData) { this.stateService.isLoadingWebSocket$.next(false); this.handleResponse(theInitData.body); From 9cd33825bf729beb907027341e80f85fca004c57 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 29 Oct 2023 01:27:19 +0000 Subject: [PATCH 15/24] SSR: dirty hack to fix initial blockchain scroll --- .../app/components/start/start.component.html | 6 ++++++ .../app/components/start/start.component.ts | 2 +- .../directives/server-only.directive.ts | 19 +++++++++++++++++++ frontend/src/app/shared/shared.module.ts | 3 +++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 frontend/src/app/shared/directives/server-only.directive.ts diff --git a/frontend/src/app/components/start/start.component.html b/frontend/src/app/components/start/start.component.html index e53692837..0f65bb412 100644 --- a/frontend/src/app/components/start/start.component.html +++ b/frontend/src/app/components/start/start.component.html @@ -35,4 +35,10 @@
+ + + pixel + pixel + + diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index 3f28891e2..d8a667a28 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -59,7 +59,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy { hasMenu = false; constructor( - private stateService: StateService, + public stateService: StateService, private cd: ChangeDetectorRef, ) { this.isiOS = ['iPhone','iPod','iPad'].includes((navigator as any)?.userAgentData?.platform || navigator.platform); diff --git a/frontend/src/app/shared/directives/server-only.directive.ts b/frontend/src/app/shared/directives/server-only.directive.ts new file mode 100644 index 000000000..cd853d812 --- /dev/null +++ b/frontend/src/app/shared/directives/server-only.directive.ts @@ -0,0 +1,19 @@ +import { Directive, TemplateRef, ViewContainerRef, Inject, PLATFORM_ID } from '@angular/core'; +import { isPlatformServer } from '@angular/common'; + +@Directive({ + selector: '[serverOnly]' +}) +export class ServerOnlyDirective { + constructor( + private templateRef: TemplateRef, + private viewContainer: ViewContainerRef, + @Inject(PLATFORM_ID) private platformId: Object + ) { + if (isPlatformServer(this.platformId)) { + this.viewContainer.createEmbeddedView(this.templateRef); + } else { + this.viewContainer.clear(); + } + } +} diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 53a5beba5..cdf08635c 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -34,6 +34,7 @@ import { LanguageSelectorComponent } from '../components/language-selector/langu import { FiatSelectorComponent } from '../components/fiat-selector/fiat-selector.component'; import { RateUnitSelectorComponent } from '../components/rate-unit-selector/rate-unit-selector.component'; import { BrowserOnlyDirective } from './directives/browser-only.directive'; +import { ServerOnlyDirective } from './directives/server-only.directive'; import { ColoredPriceDirective } from './directives/colored-price.directive'; import { NoSanitizePipe } from './pipes/no-sanitize.pipe'; import { MempoolBlocksComponent } from '../components/mempool-blocks/mempool-blocks.component'; @@ -134,6 +135,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir FiatCurrencyPipe, ColoredPriceDirective, BrowserOnlyDirective, + ServerOnlyDirective, BlockchainComponent, BlockViewComponent, EightBlocksComponent, @@ -267,6 +269,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir FeeRoundingPipe, ColoredPriceDirective, BrowserOnlyDirective, + ServerOnlyDirective, NoSanitizePipe, BlockchainComponent, MempoolBlocksComponent, From 4fbbff661487cc0e26885b7683781d98fb05c6ee Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 29 Oct 2023 17:48:40 +0000 Subject: [PATCH 16/24] SSR: fix transferstate block ordering --- frontend/src/app/services/websocket.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 5ef637332..61ac15fd3 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -59,6 +59,9 @@ export class WebsocketService { const { response: theInitData } = this.transferState.get(initData, null) || {}; if (theInitData) { + if (theInitData.body.blocks) { + theInitData.body.blocks = theInitData.body.blocks.reverse(); + } this.stateService.isLoadingWebSocket$.next(false); this.handleResponse(theInitData.body); this.startSubscription(false, true); From ab5ee5370a2798ce31713bd74eda05545e32d48c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 29 Oct 2023 18:21:13 +0000 Subject: [PATCH 17/24] SSR: solve block page initial state --- frontend/src/app/app.server.module.ts | 1 - frontend/src/app/components/block/block.component.ts | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/app.server.module.ts b/frontend/src/app/app.server.module.ts index 10ef157f4..4149fa593 100644 --- a/frontend/src/app/app.server.module.ts +++ b/frontend/src/app/app.server.module.ts @@ -6,7 +6,6 @@ import { ZONE_SERVICE } from './injection-tokens'; import { AppModule } from './app.module'; import { AppComponent } from './components/app/app.component'; import { HttpCacheInterceptor } from './services/http-cache.interceptor'; -import { StateService } from './services/state.service'; import { ZoneService } from './services/zone.service'; diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index b43774a7a..5348f4296 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ViewChildren, QueryList, Inject, PLATFORM_ID } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChildren, QueryList, Inject, PLATFORM_ID, ChangeDetectorRef } from '@angular/core'; import { Location } from '@angular/common'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ElectrsApiService } from '../../services/electrs-api.service'; @@ -109,6 +109,7 @@ export class BlockComponent implements OnInit, OnDestroy { private priceService: PriceService, private cacheService: CacheService, private servicesApiService: ServicesApiServices, + private cd: ChangeDetectorRef, @Inject(PLATFORM_ID) private platformId: Object, ) { this.webGlEnabled = isPlatformServer(this.platformId) || detectWebGL(); @@ -320,6 +321,7 @@ export class BlockComponent implements OnInit, OnDestroy { } this.transactions = transactions; this.isLoadingTransactions = false; + this.cd.markForCheck(); }, (error) => { this.error = error; @@ -473,6 +475,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.isLoadingOverview = false; this.setupBlockGraphs(); + this.cd.markForCheck(); }); this.oobSubscription = block$.pipe( From ed73c1e94c500c9f00586c1461fecce0d6f36455 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 31 Oct 2023 19:53:06 +0000 Subject: [PATCH 18/24] SSR: fix clock page timeout --- .../clock-face/clock-face.component.ts | 30 +++++++++++-------- .../app/components/clock/clock.component.ts | 4 +-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/frontend/src/app/components/clock-face/clock-face.component.ts b/frontend/src/app/components/clock-face/clock-face.component.ts index 63d87c436..eec0fa98c 100644 --- a/frontend/src/app/components/clock-face/clock-face.component.ts +++ b/frontend/src/app/components/clock-face/clock-face.component.ts @@ -1,6 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { Subscription, tap, timer } from 'rxjs'; -import { WebsocketService } from '../../services/websocket.service'; import { StateService } from '../../services/state.service'; @Component({ @@ -33,17 +32,20 @@ export class ClockFaceComponent implements OnInit, OnChanges, OnDestroy { } ngOnInit(): void { - this.timeSubscription = timer(0, 250).pipe( - tap(() => { - this.updateTime(); - }) - ).subscribe(); - this.blocksSubscription = this.stateService.blocks$ - .subscribe((blocks) => { - this.blockTimes = blocks.map(block => [block.height, new Date(block.timestamp * 1000)]); - this.blockTimes = this.blockTimes.sort((a, b) => a[1].getTime() - b[1].getTime()); - this.updateSegments(); - }); + if (this.stateService.isBrowser) { + this.timeSubscription = timer(0, 250).pipe( + tap(() => { + console.log('face tick'); + this.updateTime(); + }) + ).subscribe(); + this.blocksSubscription = this.stateService.blocks$ + .subscribe((blocks) => { + this.blockTimes = blocks.map(block => [block.height, new Date(block.timestamp * 1000)]); + this.blockTimes = this.blockTimes.sort((a, b) => a[1].getTime() - b[1].getTime()); + this.updateSegments(); + }); + } } ngOnChanges(): void { @@ -54,7 +56,9 @@ export class ClockFaceComponent implements OnInit, OnChanges, OnDestroy { } ngOnDestroy(): void { - this.timeSubscription.unsubscribe(); + if (this.timeSubscription) { + this.timeSubscription.unsubscribe(); + } } updateTime(): void { diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts index 7ae38583a..f3f778e89 100644 --- a/frontend/src/app/components/clock/clock.component.ts +++ b/frontend/src/app/components/clock/clock.component.ts @@ -110,8 +110,8 @@ export class ClockComponent implements OnInit { @HostListener('window:resize', ['$event']) resizeCanvas(): void { - const windowWidth = this.limitWidth || window.innerWidth; - const windowHeight = this.limitHeight || window.innerHeight; + const windowWidth = this.limitWidth || window.innerWidth || 800; + const windowHeight = this.limitHeight || window.innerHeight || 800; this.chainWidth = windowWidth; this.chainHeight = Math.max(60, windowHeight / 8); this.clockSize = Math.min(800, windowWidth, windowHeight - (1.4 * this.chainHeight)); From 99730d02abc15bff51353b21891d49e7b51d7b19 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 2 Nov 2023 01:29:55 +0000 Subject: [PATCH 19/24] SSR: fix graph loading indicators --- .../block-fee-rates-graph.component.html | 2 +- .../block-fee-rates-graph.component.ts | 2 +- .../block-fees-graph/block-fees-graph.component.html | 2 +- .../block-fees-graph/block-fees-graph.component.ts | 2 ++ .../block-health-graph.component.html | 2 +- .../block-health-graph/block-health-graph.component.ts | 2 +- .../block-overview-graph.component.ts | 2 +- .../block-rewards-graph.component.html | 2 +- .../block-rewards-graph.component.ts | 2 ++ .../block-sizes-weights-graph.component.html | 2 +- .../block-sizes-weights-graph.component.ts | 2 ++ .../fee-distribution-graph.component.html | 2 +- .../fee-distribution-graph.component.ts | 2 +- .../hashrate-chart/hashrate-chart.component.html | 2 +- .../hashrate-chart/hashrate-chart.component.ts | 2 +- .../hashrate-chart-pools.component.html | 2 +- .../hashrate-chart-pools.component.ts | 2 ++ .../incoming-transactions-graph.component.html | 2 +- .../incoming-transactions-graph.component.ts | 2 +- .../lbtc-pegs-graph/lbtc-pegs-graph.component.html | 2 +- .../lbtc-pegs-graph/lbtc-pegs-graph.component.ts | 4 +++- .../mempool-graph/mempool-graph.component.html | 2 +- .../mempool-graph/mempool-graph.component.ts | 2 +- .../pool-ranking/pool-ranking.component.html | 2 +- .../components/pool-ranking/pool-ranking.component.ts | 2 +- frontend/src/app/components/pool/pool.component.html | 2 +- .../node-statistics-chart.component.html | 2 +- .../node-statistics-chart.component.ts | 2 ++ .../nodes-channels-map.component.html | 3 ++- .../nodes-channels-map/nodes-channels-map.component.ts | 2 +- .../app/lightning/nodes-map/nodes-map.component.html | 3 +++ .../app/lightning/nodes-map/nodes-map.component.scss | 10 ++++++++++ .../src/app/lightning/nodes-map/nodes-map.component.ts | 8 +++++++- .../nodes-networks-chart.component.html | 2 +- .../nodes-networks-chart.component.ts | 2 ++ .../nodes-per-country-chart.component.html | 2 +- .../nodes-per-country-chart.component.ts | 2 +- .../nodes-per-country/nodes-per-country.component.ts | 8 ++++++-- 38 files changed, 69 insertions(+), 31 deletions(-) diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html index 8676b8a44..0e01d7b2d 100644 --- a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html @@ -65,7 +65,7 @@
-
+
diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts index 0283b2d00..6c2a1fbaf 100644 --- a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts @@ -55,7 +55,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { private formBuilder: UntypedFormBuilder, private storageService: StorageService, private miningService: MiningService, - private stateService: StateService, + public stateService: StateService, private router: Router, private zone: NgZone, private route: ActivatedRoute, diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html index 9734f8681..4fcbc3595 100644 --- a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html +++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html @@ -39,7 +39,7 @@
-
+
diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts index fc71fb575..895a6f33f 100644 --- a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts +++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts @@ -12,6 +12,7 @@ import { MiningService } from '../../services/mining.service'; import { ActivatedRoute } from '@angular/router'; import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe'; import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-block-fees-graph', @@ -54,6 +55,7 @@ export class BlockFeesGraphComponent implements OnInit { private formBuilder: UntypedFormBuilder, private storageService: StorageService, private miningService: MiningService, + public stateService: StateService, private route: ActivatedRoute, private fiatShortenerPipe: FiatShortenerPipe, private fiatCurrencyPipe: FiatCurrencyPipe, diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.html b/frontend/src/app/components/block-health-graph/block-health-graph.component.html index 84a75dd3c..cfbee79b6 100644 --- a/frontend/src/app/components/block-health-graph/block-health-graph.component.html +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.html @@ -48,7 +48,7 @@
-
+
diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.ts b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts index 4fea6f245..1e105d5e7 100644 --- a/frontend/src/app/components/block-health-graph/block-health-graph.component.ts +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts @@ -52,7 +52,7 @@ export class BlockHealthGraphComponent implements OnInit { private storageService: StorageService, private zone: NgZone, private route: ActivatedRoute, - private stateService: StateService, + public stateService: StateService, private router: Router, ) { this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index 559e16279..522e819c5 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -83,7 +83,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On constructor( readonly ngZone: NgZone, readonly elRef: ElementRef, - private stateService: StateService, + public stateService: StateService, ) { this.webGlEnabled = detectWebGL(); this.vertexArray = new FastVertexArray(512, TxSprite.dataSize); diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html index 7a99ac52e..10e6d304d 100644 --- a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html +++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html @@ -40,7 +40,7 @@
-
+
diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts index 9c987fb57..fe8efa9c7 100644 --- a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts +++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts @@ -12,6 +12,7 @@ import { StorageService } from '../../services/storage.service'; import { ActivatedRoute } from '@angular/router'; import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe'; import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-block-rewards-graph', @@ -54,6 +55,7 @@ export class BlockRewardsGraphComponent implements OnInit { private formBuilder: UntypedFormBuilder, private miningService: MiningService, private storageService: StorageService, + public stateService: StateService, private route: ActivatedRoute, private fiatShortenerPipe: FiatShortenerPipe, private fiatCurrencyPipe: FiatCurrencyPipe, diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html index 002bbc90d..c21a4bebb 100644 --- a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html +++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html @@ -47,7 +47,7 @@
-
+
diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts index 5d01e48e9..76d6e8216 100644 --- a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts +++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts @@ -10,6 +10,7 @@ import { StorageService } from '../../services/storage.service'; import { MiningService } from '../../services/mining.service'; import { ActivatedRoute } from '@angular/router'; import { download, formatterXAxis } from '../../shared/graphs.utils'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-block-sizes-weights-graph', @@ -52,6 +53,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit { private formBuilder: UntypedFormBuilder, private storageService: StorageService, private miningService: MiningService, + public stateService: StateService, private route: ActivatedRoute, ) { } diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html index afdc35e06..945113356 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts index 178d87897..df78cf34d 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts @@ -36,7 +36,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr }; constructor( - private stateService: StateService, + public stateService: StateService, private vbytesPipe: VbytesPipe, ) { } diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html index eba2746e0..4f0c76b88 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html @@ -57,7 +57,7 @@
-
+
diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts index 8ee7beea3..d23688e05 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts @@ -60,7 +60,7 @@ export class HashrateChartComponent implements OnInit { private storageService: StorageService, private miningService: MiningService, private route: ActivatedRoute, - private stateService: StateService + public stateService: StateService ) { } diff --git a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html index b1588cbb5..e62cdd4eb 100644 --- a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html +++ b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html @@ -34,7 +34,7 @@
-
+
diff --git a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts index 3f0e9258f..c69fce2d1 100644 --- a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts +++ b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts @@ -10,6 +10,7 @@ import { StorageService } from '../../services/storage.service'; import { MiningService } from '../../services/mining.service'; import { download } from '../../shared/graphs.utils'; import { ActivatedRoute } from '@angular/router'; +import { StateService } from '../../services/state.service'; interface Hashrate { timestamp: number; @@ -60,6 +61,7 @@ export class HashrateChartPoolsComponent implements OnInit { private cd: ChangeDetectorRef, private storageService: StorageService, private miningService: MiningService, + public stateService: StateService, private route: ActivatedRoute, ) { this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html index 6b59c557e..b3f736d34 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.html @@ -1,6 +1,6 @@
-
+
\ No newline at end of file diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts index 703181eba..f25234854 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts @@ -48,7 +48,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On constructor( @Inject(LOCALE_ID) private locale: string, private storageService: StorageService, - private stateService: StateService, + public stateService: StateService, ) { } ngOnInit() { diff --git a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html index 878869505..841d6b45c 100644 --- a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html +++ b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.html @@ -1,4 +1,4 @@
-
+
\ No newline at end of file diff --git a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts index 25c061550..bc3be513c 100644 --- a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts +++ b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts @@ -1,6 +1,7 @@ import { Component, Inject, LOCALE_ID, ChangeDetectionStrategy, Input, OnChanges, OnInit } from '@angular/core'; import { formatDate, formatNumber } from '@angular/common'; -import { EChartsOption } from '../../graphs/echarts'; +import { EChartsOption } from 'echarts'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-lbtc-pegs-graph', @@ -32,6 +33,7 @@ export class LbtcPegsGraphComponent implements OnInit, OnChanges { }; constructor( + public stateService: StateService, @Inject(LOCALE_ID) private locale: string, ) { } diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.html b/frontend/src/app/components/mempool-graph/mempool-graph.component.html index 1f3621bc3..12b720029 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.html +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.html @@ -1,4 +1,4 @@
-
+
\ No newline at end of file diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts index 79c426fd6..cf4806fbe 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -59,7 +59,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { private vbytesPipe: VbytesPipe, private wubytesPipe: WuBytesPipe, private amountShortenerPipe: AmountShortenerPipe, - private stateService: StateService, + public stateService: StateService, private storageService: StorageService, @Inject(LOCALE_ID) private locale: string, ) { } diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.html b/frontend/src/app/components/pool-ranking/pool-ranking.component.html index f5e21e66f..6753e5324 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.html +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.html @@ -80,7 +80,7 @@ (chartInit)="onChartInit($event)">
-
+
diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts index a6f43909a..11ee6e506 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts @@ -41,7 +41,7 @@ export class PoolRankingComponent implements OnInit { miningStatsObservable$: Observable; constructor( - private stateService: StateService, + public stateService: StateService, private storageService: StorageService, private formBuilder: UntypedFormBuilder, private miningService: MiningService, diff --git a/frontend/src/app/components/pool/pool.component.html b/frontend/src/app/components/pool/pool.component.html index ad84c77ce..8ecb68bc9 100644 --- a/frontend/src/app/components/pool/pool.component.html +++ b/frontend/src/app/components/pool/pool.component.html @@ -169,7 +169,7 @@
-
+
diff --git a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html index 209958fde..5edeaa9fd 100644 --- a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html +++ b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.html @@ -1,7 +1,7 @@
-
+
diff --git a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts index a9308a887..f67c83367 100644 --- a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts +++ b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts @@ -8,6 +8,7 @@ import { StorageService } from '../../services/storage.service'; import { download } from '../../shared/graphs.utils'; import { LightningApiService } from '../lightning-api.service'; import { ActivatedRoute, ParamMap } from '@angular/router'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-node-statistics-chart', @@ -48,6 +49,7 @@ export class NodeStatisticsChartComponent implements OnInit { @Inject(LOCALE_ID) public locale: string, private lightningApiService: LightningApiService, private storageService: StorageService, + public stateService: StateService, private activatedRoute: ActivatedRoute, ) { } diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html index 50f84db30..bc4ea4b86 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.html @@ -6,7 +6,8 @@
-
+ +
diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts index 296d60dec..aab62f2c4 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts @@ -45,7 +45,7 @@ export class NodesChannelsMap implements OnInit { constructor( private seoService: SeoService, private apiService: ApiService, - private stateService: StateService, + public stateService: StateService, private assetsService: AssetsService, private router: Router, private zone: NgZone, diff --git a/frontend/src/app/lightning/nodes-map/nodes-map.component.html b/frontend/src/app/lightning/nodes-map/nodes-map.component.html index 045ab7925..d6b793e25 100644 --- a/frontend/src/app/lightning/nodes-map/nodes-map.component.html +++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.html @@ -12,5 +12,8 @@ (chartInit)="onChartInit($event)" (chartFinished)="onChartFinished($event)">
+
+
+
diff --git a/frontend/src/app/lightning/nodes-map/nodes-map.component.scss b/frontend/src/app/lightning/nodes-map/nodes-map.component.scss index a2f62e9c5..82362a257 100644 --- a/frontend/src/app/lightning/nodes-map/nodes-map.component.scss +++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.scss @@ -63,3 +63,13 @@ .chart.widget { padding: 0px; } + +.loading-spinner { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + @media (max-width: 767.98px) { + top: 550px; + } +} diff --git a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts index bb9e21c4b..054f1ab6f 100644 --- a/frontend/src/app/lightning/nodes-map/nodes-map.component.ts +++ b/frontend/src/app/lightning/nodes-map/nodes-map.component.ts @@ -26,6 +26,7 @@ export class NodesMap implements OnInit, OnChanges { inputNodes$: BehaviorSubject; nodes$: Observable; observable$: Observable; + isLoading: boolean = true; chartInstance = undefined; chartOptions: EChartsOption = {}; @@ -37,7 +38,7 @@ export class NodesMap implements OnInit, OnChanges { @Inject(LOCALE_ID) public locale: string, private seoService: SeoService, private apiService: ApiService, - private stateService: StateService, + public stateService: StateService, private assetsService: AssetsService, private router: Router, private zone: NgZone, @@ -226,6 +227,7 @@ export class NodesMap implements OnInit, OnChanges { }, ] }; + this.isLoading = false; } onChartInit(ec) { @@ -235,6 +237,10 @@ export class NodesMap implements OnInit, OnChanges { this.chartInstance = ec; + this.chartInstance.on('finished', () => { + this.isLoading = false; + }); + this.chartInstance.on('click', (e) => { if (e.data) { this.zone.run(() => { diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html index cf02b60a8..7571beacf 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.html @@ -36,7 +36,7 @@
-
+
diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts index 82c74395b..a7f6da5c2 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts @@ -11,6 +11,7 @@ import { SeoService } from '../../services/seo.service'; import { LightningApiService } from '../lightning-api.service'; import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; import { isMobile } from '../../shared/common.utils'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-nodes-networks-chart', @@ -58,6 +59,7 @@ export class NodesNetworksChartComponent implements OnInit, OnChanges { private formBuilder: UntypedFormBuilder, private storageService: StorageService, private miningService: MiningService, + public stateService: StateService, private amountShortenerPipe: AmountShortenerPipe, ) { } diff --git a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html index 5c285e3de..191a3dbb1 100644 --- a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html +++ b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.html @@ -17,7 +17,7 @@
-
+
diff --git a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts index e305d8959..5d80341fe 100644 --- a/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts +++ b/frontend/src/app/lightning/nodes-per-country-chart/nodes-per-country-chart.component.ts @@ -37,7 +37,7 @@ export class NodesPerCountryChartComponent implements OnInit { private seoService: SeoService, private amountShortenerPipe: AmountShortenerPipe, private zone: NgZone, - private stateService: StateService, + public stateService: StateService, private router: Router, ) { } diff --git a/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts b/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts index 4035b62d4..619ee01c0 100644 --- a/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts +++ b/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { BehaviorSubject, combineLatest, map, Observable, share, tap } from 'rxjs'; import { ApiService } from '../../services/api.service'; @@ -27,6 +27,7 @@ export class NodesPerCountry implements OnInit { constructor( private apiService: ApiService, private seoService: SeoService, + private cd: ChangeDetectorRef, private route: ActivatedRoute, ) { for (let i = 0; i < this.pageSize; ++i) { @@ -94,7 +95,10 @@ export class NodesPerCountry implements OnInit { ispCount: Object.keys(isps).length }; }), - tap(() => this.isLoading = false), + tap(() => { + this.isLoading = false + this.cd.markForCheck(); + }), share() ); From b167848b9b65871797448222675def0713fffc7a Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 2 Nov 2023 23:26:17 +0000 Subject: [PATCH 20/24] SSR: Fix initial state of lightning pages & graphs --- .../app/lightning/lightning-api.service.ts | 33 +++++++++++-------- .../lightning-dashboard.component.ts | 11 +++++-- .../node-fee-chart.component.html | 2 +- .../node-fee-chart.component.scss | 4 ++- .../node-fee-chart.component.ts | 2 ++ .../nodes-channels-map.component.scss | 1 - .../node-channels.component.html | 16 +++++---- .../node-channels.component.scss | 10 +++++- .../nodes-channels/node-channels.component.ts | 2 +- .../nodes-per-isp-chart.component.html | 7 ++-- .../nodes-per-isp-chart.component.ts | 2 +- .../lightning-statistics-chart.component.html | 2 +- .../lightning-statistics-chart.component.ts | 2 ++ 13 files changed, 60 insertions(+), 34 deletions(-) diff --git a/frontend/src/app/lightning/lightning-api.service.ts b/frontend/src/app/lightning/lightning-api.service.ts index ee55fb75d..4be878a18 100644 --- a/frontend/src/app/lightning/lightning-api.service.ts +++ b/frontend/src/app/lightning/lightning-api.service.ts @@ -8,6 +8,7 @@ import { IChannel, INodesRanking, IOldestNodes, ITopNodesPerCapacity, ITopNodesP providedIn: 'root' }) export class LightningApiService { + private apiBaseUrl: string; // base URL is protocol, hostname, and port private apiBasePath = ''; // network path is /testnet, etc. or '' for mainnet private requestCache = new Map, expiry: number }>; @@ -16,6 +17,10 @@ export class LightningApiService { private httpClient: HttpClient, private stateService: StateService, ) { + this.apiBaseUrl = ''; // use relative URL by default + if (!stateService.isBrowser) { // except when inside AU SSR process + this.apiBaseUrl = this.stateService.env.NGINX_PROTOCOL + '://' + this.stateService.env.NGINX_HOSTNAME + ':' + this.stateService.env.NGINX_PORT; + } this.apiBasePath = ''; // assume mainnet by default this.stateService.networkChanged$.subscribe((network) => { if (network === 'bisq' && !this.stateService.env.BISQ_SEPARATE_BACKEND) { @@ -66,15 +71,15 @@ export class LightningApiService { } getNode$(publicKey: string): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey); } getNodeGroup$(name: string): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/group/' + name); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/group/' + name); } getChannel$(shortId: string): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/channels/' + shortId); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/channels/' + shortId); } getChannelsByNodeId$(publicKey: string, index: number = 0, status = 'open'): Observable { @@ -84,57 +89,57 @@ export class LightningApiService { .set('status', status) ; - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/channels', { params, observe: 'response' }); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/channels', { params, observe: 'response' }); } getLatestStatistics$(): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/statistics/latest'); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/statistics/latest'); } listNodeStats$(publicKey: string): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/statistics'); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/statistics'); } getNodeFeeHistogram$(publicKey: string): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/fees/histogram'); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/fees/histogram'); } getNodesRanking$(): Observable { - return this.httpClient.get(this.apiBasePath + '/api/v1/lightning/nodes/rankings'); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/rankings'); } listChannelStats$(publicKey: string): Observable { - return this.httpClient.get(this.apiBasePath + '/channels/' + publicKey + '/statistics'); + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/channels/' + publicKey + '/statistics'); } listStatistics$(interval: string | undefined): Observable { return this.httpClient.get( - this.apiBasePath + '/api/v1/lightning/statistics' + + this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/statistics' + (interval !== undefined ? `/${interval}` : ''), { observe: 'response' } ); } getTopNodesByCapacity$(): Observable { return this.httpClient.get( - this.apiBasePath + '/api/v1/lightning/nodes/rankings/liquidity' + this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/rankings/liquidity' ); } getTopNodesByChannels$(): Observable { return this.httpClient.get( - this.apiBasePath + '/api/v1/lightning/nodes/rankings/connectivity' + this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/rankings/connectivity' ); } getPenaltyClosedChannels$(): Observable { return this.httpClient.get( - this.apiBasePath + '/api/v1/lightning/penalties' + this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/penalties' ); } getOldestNodes$(): Observable { return this.httpClient.get( - this.apiBasePath + '/api/v1/lightning/nodes/rankings/age' + this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/rankings/age' ); } } diff --git a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.ts b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.ts index a8c931da8..fd72cddfe 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.ts +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.ts @@ -1,5 +1,5 @@ -import { AfterViewInit, ChangeDetectionStrategy, Component, HostListener, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; +import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit } from '@angular/core'; +import { Observable, merge } from 'rxjs'; import { share } from 'rxjs/operators'; import { INodesRanking, INodesStatistics } from '../../interfaces/node-api.interface'; import { SeoService } from '../../services/seo.service'; @@ -24,6 +24,7 @@ export class LightningDashboardComponent implements OnInit, AfterViewInit { private seoService: SeoService, private ogService: OpenGraphService, private stateService: StateService, + private cd: ChangeDetectorRef, ) { } ngOnInit(): void { @@ -35,6 +36,12 @@ export class LightningDashboardComponent implements OnInit, AfterViewInit { this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share()); this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share()); + + if (!this.stateService.isBrowser) { + merge(this.nodesRanking$, this.statistics$).subscribe(() => { + this.cd.markForCheck(); + }); + } } ngAfterViewInit(): void { diff --git a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html index 4b3a13016..d8eb9e868 100644 --- a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html +++ b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.html @@ -1,7 +1,7 @@

Fee distribution

-
+
diff --git a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.scss b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.scss index d738daa81..9fd7f2dba 100644 --- a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.scss +++ b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.scss @@ -1,5 +1,7 @@ .full-container { + position: relative; margin-top: 25px; margin-bottom: 25px; min-height: 100%; -} + min-height: 450px; +} \ No newline at end of file diff --git a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts index ad667bcf6..f20a5123c 100644 --- a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts +++ b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts @@ -5,6 +5,7 @@ import { download } from '../../shared/graphs.utils'; import { LightningApiService } from '../lightning-api.service'; import { ActivatedRoute, ParamMap } from '@angular/router'; import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-node-fee-chart', @@ -33,6 +34,7 @@ export class NodeFeeChartComponent implements OnInit { constructor( @Inject(LOCALE_ID) public locale: string, private lightningApiService: LightningApiService, + public stateService: StateService, private activatedRoute: ActivatedRoute, private amountShortenerPipe: AmountShortenerPipe, ) { diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss index 558ad68a6..16482a0da 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss @@ -33,7 +33,6 @@ min-height: 400px; margin-top: 25px; margin-bottom: 25px; - min-height: 100%; } .full-container.widget { height: 250px; diff --git a/frontend/src/app/lightning/nodes-channels/node-channels.component.html b/frontend/src/app/lightning/nodes-channels/node-channels.component.html index c3a865a0f..db4a3e07e 100644 --- a/frontend/src/app/lightning/nodes-channels/node-channels.component.html +++ b/frontend/src/app/lightning/nodes-channels/node-channels.component.html @@ -1,9 +1,11 @@ -
-

Active channels map

-
+
+
+

Active channels map

+
+
+
+ +
+
- -
-
-
diff --git a/frontend/src/app/lightning/nodes-channels/node-channels.component.scss b/frontend/src/app/lightning/nodes-channels/node-channels.component.scss index 4d7b4de0e..78510203f 100644 --- a/frontend/src/app/lightning/nodes-channels/node-channels.component.scss +++ b/frontend/src/app/lightning/nodes-channels/node-channels.component.scss @@ -1,5 +1,13 @@ +.node-channels-container { + position: relative; +} + .loading-spinner { - min-height: 455px; + position: absolute; + top: 0; + left: 0; + right: 0; + width: 100%; z-index: 100; } diff --git a/frontend/src/app/lightning/nodes-channels/node-channels.component.ts b/frontend/src/app/lightning/nodes-channels/node-channels.component.ts index be596d8f9..1954e429a 100644 --- a/frontend/src/app/lightning/nodes-channels/node-channels.component.ts +++ b/frontend/src/app/lightning/nodes-channels/node-channels.component.ts @@ -33,7 +33,7 @@ export class NodeChannels implements OnChanges { private amountShortenerPipe: AmountShortenerPipe, private zone: NgZone, private router: Router, - private stateService: StateService, + public stateService: StateService, ) {} ngOnChanges(): void { diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html index aa005933a..52d74c806 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html @@ -43,10 +43,6 @@ (chartInit)="onChartInit($event)">
-
-
-
-
@@ -74,6 +70,9 @@
+
+
+
diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts index 3d8a4b861..ddcfb81ad 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts @@ -44,7 +44,7 @@ export class NodesPerISPChartComponent implements OnInit { private amountShortenerPipe: AmountShortenerPipe, private router: Router, private zone: NgZone, - private stateService: StateService, + public stateService: StateService, ) { } diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html index b0bfc8295..5fd9d257e 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.html @@ -44,7 +44,7 @@
-
+
diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts index 8bcf01015..2763c319f 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts @@ -11,6 +11,7 @@ import { download } from '../../shared/graphs.utils'; import { LightningApiService } from '../lightning-api.service'; import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; import { isMobile } from '../../shared/common.utils'; +import { StateService } from '../../services/state.service'; @Component({ selector: 'app-lightning-statistics-chart', @@ -55,6 +56,7 @@ export class LightningStatisticsChartComponent implements OnInit, OnChanges { private formBuilder: UntypedFormBuilder, private storageService: StorageService, private miningService: MiningService, + public stateService: StateService, private amountShortenerPipe: AmountShortenerPipe, ) { } From c92608813609326e58b592a9de473f33824b4661 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sat, 4 Nov 2023 17:17:19 +0000 Subject: [PATCH 21/24] SSR: Fix block viz loading indicators --- frontend/src/app/components/block/block.component.html | 6 +++--- .../mempool-block-overview.component.html | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index d7182e6e3..f3cf45f0f 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -109,7 +109,7 @@

Expected Block

- @@ -244,7 +244,7 @@

Actual Block

- diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html index 6fb8dd4d6..f02f1bb4f 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html @@ -1,6 +1,6 @@ Date: Sat, 4 Nov 2023 17:48:27 +0000 Subject: [PATCH 22/24] SSR: placeholder bowtie diagram while loading --- .../tx-bowtie-graph/tx-bowtie-graph.component.html | 10 +++++++++- .../tx-bowtie-graph/tx-bowtie-graph.component.ts | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html index 14e49e21b..9f491affc 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html @@ -1,5 +1,13 @@
- + Date: Thu, 25 Jan 2024 16:08:58 +0000 Subject: [PATCH 23/24] SSR: fix merge/version conflicts --- frontend/server.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/server.ts b/frontend/server.ts index ffce336f5..4651eed1b 100644 --- a/frontend/server.ts +++ b/frontend/server.ts @@ -35,10 +35,15 @@ win.document.body.scrollTo = (() => {}); win['ResizeObserver'] = ResizeObserver; // @ts-ignore global['window'] = win; +// @ts-ignore global['document'] = win.document; // @ts-ignore global['history'] = { state: { } }; -global['navigator'] = win.navigator; +// @ts-ignore +Object.defineProperty(global, 'navigator', { + value: win.navigator, + writable: true +}); global['localStorage'] = { getItem: () => '', From 6e2f17b3d23a02768886af12de3a361d977273cf Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 20 Mar 2024 09:57:05 +0000 Subject: [PATCH 24/24] SSR: Fix more merge/version conflicts --- .../acceleration-fees-graph.component.html | 4 ++-- .../acceleration-fees-graph.component.ts | 8 +++++--- .../accelerator-dashboard.component.html | 12 +----------- .../accelerator-dashboard.component.ts | 8 ++++++-- .../address-graph/address-graph.component.html | 2 +- .../block-fee-rates-graph.component.html | 2 +- .../block-fee-rates-graph.component.ts | 6 +++--- .../block-overview-graph.component.ts | 2 +- frontend/src/app/components/block/block.component.ts | 3 +-- .../eight-blocks/eight-blocks.component.ts | 2 +- .../lbtc-pegs-graph/lbtc-pegs-graph.component.ts | 2 +- .../reserves-ratio/reserves-ratio.component.html | 2 +- .../mempool-block/mempool-block.component.ts | 3 +-- .../mining-dashboard/mining-dashboard.component.html | 2 +- frontend/src/app/dashboard/dashboard.component.html | 4 ++-- frontend/src/app/dashboard/dashboard.component.ts | 11 ++++++++--- .../nodes-channels-map.component.html | 8 +++++--- 17 files changed, 41 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html index 0a567bd0a..cbebb0f86 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html @@ -45,10 +45,10 @@
-
-
+
diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts index 43ad4b69e..edc206407 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnDestroy, OnInit } from '@angular/core'; -import { EChartsOption } from 'echarts'; +import { EChartsOption } from '../../../graphs/echarts'; import { Observable, Subscription, combineLatest, fromEvent, share } from 'rxjs'; import { startWith, switchMap, tap } from 'rxjs/operators'; import { SeoService } from '../../../services/seo.service'; @@ -11,6 +11,7 @@ import { MiningService } from '../../../services/mining.service'; import { ActivatedRoute } from '@angular/router'; import { Acceleration } from '../../../interfaces/node-api.interface'; import { ServicesApiServices } from '../../../services/services-api.service'; +import { StateService } from '../../../services/state.service'; @Component({ selector: 'app-acceleration-fees-graph', @@ -59,6 +60,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { private storageService: StorageService, private miningService: MiningService, private route: ActivatedRoute, + public stateService: StateService, private cd: ChangeDetectorRef, ) { this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); @@ -176,10 +178,10 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { padding: [10, 0, 0, 0], }, type: 'time', - boundaryGap: false, + boundaryGap: [0, 0], axisLine: { onZero: true }, axisLabel: { - formatter: val => formatterXAxisTimeCategory(this.locale, this.timespan, parseInt(val, 10)), + formatter: (val): string => formatterXAxisTimeCategory(this.locale, this.timespan, val), align: 'center', fontSize: 11, lineHeight: 12, diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html index 5e049198a..147e07e69 100644 --- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html @@ -42,7 +42,7 @@   -
+
@@ -66,16 +66,6 @@
- - -
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts index 4874067ec..d4df57020 100644 --- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, HostListener, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, HostListener, Inject, OnInit, PLATFORM_ID } from '@angular/core'; import { SeoService } from '../../../services/seo.service'; import { OpenGraphService } from '../../../services/opengraph.service'; import { WebsocketService } from '../../../services/websocket.service'; @@ -10,6 +10,7 @@ import { hexToColor } from '../../block-overview-graph/utils'; import TxView from '../../block-overview-graph/tx-view'; import { feeLevels, mempoolFeeColors } from '../../../app.constants'; import { ServicesApiServices } from '../../../services/services-api.service'; +import { detectWebGL } from '../../../shared/graphs.utils'; const acceleratedColor: Color = hexToColor('8F5FF6'); const normalColors = mempoolFeeColors.map(hex => hexToColor(hex + '5F')); @@ -30,6 +31,7 @@ export class AcceleratorDashboardComponent implements OnInit { pendingAccelerations$: Observable; minedAccelerations$: Observable; loadingBlocks: boolean = true; + webGlEnabled = true; graphHeight: number = 300; @@ -39,7 +41,9 @@ export class AcceleratorDashboardComponent implements OnInit { private websocketService: WebsocketService, private serviceApiServices: ServicesApiServices, private stateService: StateService, + @Inject(PLATFORM_ID) private platformId: Object, ) { + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); this.seoService.setTitle($localize`:@@a681a4e2011bb28157689dbaa387de0dd0aa0c11:Accelerator Dashboard`); this.ogService.setManualOgImage('accelerator.jpg'); } @@ -48,7 +52,7 @@ export class AcceleratorDashboardComponent implements OnInit { this.onResize(); this.websocketService.want(['blocks', 'mempool-blocks', 'stats']); - this.pendingAccelerations$ = interval(30000).pipe( + this.pendingAccelerations$ = (this.stateService.isBrowser ? interval(30000) : of(null)).pipe( startWith(true), switchMap(() => { return this.serviceApiServices.getAccelerations$().pipe( diff --git a/frontend/src/app/components/address-graph/address-graph.component.html b/frontend/src/app/components/address-graph/address-graph.component.html index fa7b29a99..35808cb14 100644 --- a/frontend/src/app/components/address-graph/address-graph.component.html +++ b/frontend/src/app/components/address-graph/address-graph.component.html @@ -8,7 +8,7 @@
-
diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html index 0e01d7b2d..9c27ecb83 100644 --- a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html @@ -62,7 +62,7 @@
-
diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts index 6c2a1fbaf..0abc55aa7 100644 --- a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnInit } from '@angular/core'; -import { EChartsOption, graphic } from 'echarts'; +import { echarts, EChartsOption } from '../../graphs/echarts'; import { Observable, combineLatest, of } from 'rxjs'; import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; import { ApiService } from '../../services/api.service'; @@ -209,7 +209,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { prepareChartOptions(data, weightMode) { this.chartOptions = { - color: this.widget ? ['#6b6b6b', new graphic.LinearGradient(0, 0, 0, 0.65, [ + color: this.widget ? ['#6b6b6b', new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [ { offset: 0, color: '#F4511E' }, { offset: 0.25, color: '#FB8C00' }, { offset: 0.5, color: '#FFB300' }, @@ -282,7 +282,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { legend: (this.widget || data.series.length === 0) ? undefined : { padding: [10, 75], data: data.legends, - selected: JSON.parse(this.storageService.getValue('fee_rates_legend')) ?? { + selected: JSON.parse(this.storageService.getValue('fee_rates_legend') || 'null') ?? { 'Min': true, '10th': true, '25th': true, diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index 522e819c5..ab6985a25 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -85,7 +85,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On readonly elRef: ElementRef, public stateService: StateService, ) { - this.webGlEnabled = detectWebGL(); + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); this.vertexArray = new FastVertexArray(512, TxSprite.dataSize); this.searchSubscription = this.stateService.searchText$.subscribe((text) => { this.searchText = text; diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index 5348f4296..2602c5ecd 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -17,7 +17,6 @@ import { seoDescriptionNetwork } from '../../shared/common.utils'; import { PriceService, Price } from '../../services/price.service'; import { CacheService } from '../../services/cache.service'; import { ServicesApiServices } from '../../services/services-api.service'; -import { isPlatformServer } from '@angular/common'; @Component({ selector: 'app-block', @@ -112,7 +111,7 @@ export class BlockComponent implements OnInit, OnDestroy { private cd: ChangeDetectorRef, @Inject(PLATFORM_ID) private platformId: Object, ) { - this.webGlEnabled = isPlatformServer(this.platformId) || detectWebGL(); + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); } ngOnInit() { diff --git a/frontend/src/app/components/eight-blocks/eight-blocks.component.ts b/frontend/src/app/components/eight-blocks/eight-blocks.component.ts index 96ab4dee9..81dcc4c5b 100644 --- a/frontend/src/app/components/eight-blocks/eight-blocks.component.ts +++ b/frontend/src/app/components/eight-blocks/eight-blocks.component.ts @@ -95,7 +95,7 @@ export class EightBlocksComponent implements OnInit, OnDestroy { private apiService: ApiService, private bytesPipe: BytesPipe, ) { - this.webGlEnabled = detectWebGL(); + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); } ngOnInit(): void { diff --git a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts index bc3be513c..4359d8fa3 100644 --- a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts +++ b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts @@ -1,6 +1,6 @@ import { Component, Inject, LOCALE_ID, ChangeDetectionStrategy, Input, OnChanges, OnInit } from '@angular/core'; import { formatDate, formatNumber } from '@angular/common'; -import { EChartsOption } from 'echarts'; +import { EChartsOption } from '../../graphs/echarts'; import { StateService } from '../../services/state.service'; @Component({ diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.html b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.html index 64e68624b..a453d854b 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.html +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/frontend/src/app/components/mempool-block/mempool-block.component.ts b/frontend/src/app/components/mempool-block/mempool-block.component.ts index e972083a7..7f41faffb 100644 --- a/frontend/src/app/components/mempool-block/mempool-block.component.ts +++ b/frontend/src/app/components/mempool-block/mempool-block.component.ts @@ -8,7 +8,6 @@ import { Observable, BehaviorSubject } from 'rxjs'; import { SeoService } from '../../services/seo.service'; import { seoDescriptionNetwork } from '../../shared/common.utils'; import { WebsocketService } from '../../services/websocket.service'; -import { isPlatformServer } from '@angular/common'; @Component({ selector: 'app-mempool-block', @@ -33,7 +32,7 @@ export class MempoolBlockComponent implements OnInit, OnDestroy { private cd: ChangeDetectorRef, @Inject(PLATFORM_ID) private platformId: Object, ) { - this.webGlEnabled = isPlatformServer(this.platformId) || detectWebGL(); + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); } ngOnInit(): void { diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html index 6cadddd6b..c4fca72eb 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html @@ -38,7 +38,7 @@
-
+
diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 5fe1f6f2d..813589313 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -1,7 +1,7 @@
- +
Transaction Fees
@@ -29,7 +29,7 @@
-
+
(Tor nodes excluded)
-
-
+ +
+
+